VimEditingEngine.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. /*
  2. * Copyright (c) 2020, the SerenityOS developers.
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright notice, this
  9. * list of conditions and the following disclaimer.
  10. *
  11. * 2. Redistributions in binary form must reproduce the above copyright notice,
  12. * this list of conditions and the following disclaimer in the documentation
  13. * and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  19. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  21. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  22. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  23. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  24. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #include <LibGUI/Event.h>
  27. #include <LibGUI/TextEditor.h>
  28. #include <LibGUI/VimEditingEngine.h>
  29. namespace GUI {
  30. CursorWidth VimEditingEngine::cursor_width() const
  31. {
  32. return m_vim_mode == VimMode::Normal ? CursorWidth::WIDE : CursorWidth::NARROW;
  33. }
  34. bool VimEditingEngine::on_key(const KeyEvent& event)
  35. {
  36. if (EditingEngine::on_key(event))
  37. return true;
  38. switch (m_vim_mode) {
  39. case (VimMode::Insert):
  40. return on_key_in_insert_mode(event);
  41. case (VimMode::Normal):
  42. return on_key_in_normal_mode(event);
  43. default:
  44. ASSERT_NOT_REACHED();
  45. }
  46. return false;
  47. }
  48. bool VimEditingEngine::on_key_in_insert_mode(const KeyEvent& event)
  49. {
  50. if (event.key() == KeyCode::Key_Escape || (event.ctrl() && event.key() == KeyCode::Key_LeftBracket) || (event.ctrl() && event.key() == KeyCode::Key_C)) {
  51. switch_to_normal_mode();
  52. return true;
  53. }
  54. return false;
  55. }
  56. bool VimEditingEngine::on_key_in_normal_mode(const KeyEvent& event)
  57. {
  58. if (m_previous_key == KeyCode::Key_D) {
  59. if (event.key() == KeyCode::Key_D) {
  60. delete_line();
  61. }
  62. m_previous_key = {};
  63. } else if (m_previous_key == KeyCode::Key_G) {
  64. if (event.key() == KeyCode::Key_G) {
  65. move_to_first_line();
  66. }
  67. m_previous_key = {};
  68. } else {
  69. // Handle first any key codes that are to be applied regardless of modifiers.
  70. switch (event.key()) {
  71. case (KeyCode::Key_Dollar):
  72. move_to_line_end(event);
  73. break;
  74. case (KeyCode::Key_Escape):
  75. if (m_editor->on_escape_pressed)
  76. m_editor->on_escape_pressed();
  77. break;
  78. default:
  79. break;
  80. }
  81. // SHIFT is pressed.
  82. if (event.shift() && !event.ctrl() && !event.alt()) {
  83. switch (event.key()) {
  84. case (KeyCode::Key_A):
  85. move_to_line_end(event);
  86. switch_to_insert_mode();
  87. break;
  88. case (KeyCode::Key_G):
  89. move_to_last_line();
  90. break;
  91. case (KeyCode::Key_I):
  92. move_to_line_beginning(event);
  93. switch_to_insert_mode();
  94. break;
  95. case (KeyCode::Key_O):
  96. move_to_line_beginning(event);
  97. m_editor->add_code_point(0x0A);
  98. move_one_up(event);
  99. switch_to_insert_mode();
  100. break;
  101. default:
  102. break;
  103. }
  104. }
  105. // CTRL is pressed.
  106. if (event.ctrl() && !event.shift() && !event.alt()) {
  107. switch (event.key()) {
  108. case (KeyCode::Key_D):
  109. move_half_page_down(event);
  110. break;
  111. case (KeyCode::Key_R):
  112. m_editor->redo();
  113. break;
  114. case (KeyCode::Key_U):
  115. move_half_page_up(event);
  116. break;
  117. default:
  118. break;
  119. }
  120. }
  121. // No modifier is pressed.
  122. if (!event.ctrl() && !event.shift() && !event.alt()) {
  123. switch (event.key()) {
  124. case (KeyCode::Key_A):
  125. move_one_right(event);
  126. switch_to_insert_mode();
  127. break;
  128. case (KeyCode::Key_B):
  129. move_to_previous_span(event); // FIXME: This probably isn't 100% correct.
  130. break;
  131. case (KeyCode::Key_Backspace):
  132. case (KeyCode::Key_H):
  133. case (KeyCode::Key_Left):
  134. move_one_left(event);
  135. break;
  136. case (KeyCode::Key_D):
  137. case (KeyCode::Key_G):
  138. m_previous_key = event.key();
  139. break;
  140. case (KeyCode::Key_Down):
  141. case (KeyCode::Key_J):
  142. move_one_down(event);
  143. break;
  144. case (KeyCode::Key_I):
  145. switch_to_insert_mode();
  146. break;
  147. case (KeyCode::Key_K):
  148. case (KeyCode::Key_Up):
  149. move_one_up(event);
  150. break;
  151. case (KeyCode::Key_L):
  152. case (KeyCode::Key_Right):
  153. move_one_right(event);
  154. break;
  155. case (KeyCode::Key_O):
  156. move_to_line_end(event);
  157. m_editor->add_code_point(0x0A);
  158. switch_to_insert_mode();
  159. break;
  160. case (KeyCode::Key_U):
  161. m_editor->undo();
  162. break;
  163. case (KeyCode::Key_W):
  164. move_to_next_span(event); // FIXME: This probably isn't 100% correct.
  165. break;
  166. case (KeyCode::Key_X):
  167. delete_char();
  168. break;
  169. case (KeyCode::Key_0):
  170. move_to_line_beginning(event);
  171. break;
  172. default:
  173. break;
  174. }
  175. }
  176. }
  177. return true;
  178. }
  179. void VimEditingEngine::switch_to_normal_mode()
  180. {
  181. m_vim_mode = VimMode::Normal;
  182. m_editor->reset_cursor_blink();
  183. };
  184. void VimEditingEngine::switch_to_insert_mode()
  185. {
  186. m_vim_mode = VimMode::Insert;
  187. m_editor->reset_cursor_blink();
  188. };
  189. void VimEditingEngine::move_half_page_up(const KeyEvent& event)
  190. {
  191. move_up(event, 0.5);
  192. };
  193. void VimEditingEngine::move_half_page_down(const KeyEvent& event)
  194. {
  195. move_down(event, 0.5);
  196. };
  197. }