VimEditingEngine.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  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::Insert ? CursorWidth::NARROW : CursorWidth::WIDE;
  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::Visual):
  42. return on_key_in_visual_mode(event);
  43. case (VimMode::Normal):
  44. return on_key_in_normal_mode(event);
  45. default:
  46. ASSERT_NOT_REACHED();
  47. }
  48. return false;
  49. }
  50. bool VimEditingEngine::on_key_in_insert_mode(const KeyEvent& event)
  51. {
  52. if (event.key() == KeyCode::Key_Escape || (event.ctrl() && event.key() == KeyCode::Key_LeftBracket) || (event.ctrl() && event.key() == KeyCode::Key_C)) {
  53. switch_to_normal_mode();
  54. return true;
  55. }
  56. return false;
  57. }
  58. bool VimEditingEngine::on_key_in_normal_mode(const KeyEvent& event)
  59. {
  60. if (m_previous_key == KeyCode::Key_D) {
  61. if (event.key() == KeyCode::Key_D) {
  62. yank(Line);
  63. delete_line();
  64. }
  65. m_previous_key = {};
  66. } else if (m_previous_key == KeyCode::Key_G) {
  67. if (event.key() == KeyCode::Key_G) {
  68. move_to_first_line();
  69. } else if (event.key() == KeyCode::Key_E) {
  70. move_to_end_of_previous_word();
  71. }
  72. m_previous_key = {};
  73. } else if (m_previous_key == KeyCode::Key_Y) {
  74. if (event.key() == KeyCode::Key_Y) {
  75. yank(Line);
  76. }
  77. m_previous_key = {};
  78. } else if (m_previous_key == KeyCode::Key_C) {
  79. if (event.key() == KeyCode::Key_C) {
  80. // Needed because the code to replace the deleted line is called after delete_line() so
  81. // what was the second last line before the delete, is now the last line.
  82. bool was_second_last_line = m_editor->cursor().line() == m_editor->line_count() - 2;
  83. yank(Line);
  84. delete_line();
  85. if (was_second_last_line || (m_editor->cursor().line() != 0 && m_editor->cursor().line() != m_editor->line_count() - 1)) {
  86. move_one_up(event);
  87. move_to_line_end(event);
  88. m_editor->add_code_point(0x0A);
  89. } else if (m_editor->cursor().line() == 0) {
  90. move_to_line_beginning(event);
  91. m_editor->add_code_point(0x0A);
  92. move_one_up(event);
  93. } else if (m_editor->cursor().line() == m_editor->line_count() - 1) {
  94. m_editor->add_code_point(0x0A);
  95. }
  96. switch_to_insert_mode();
  97. }
  98. m_previous_key = {};
  99. } else {
  100. // Handle first any key codes that are to be applied regardless of modifiers.
  101. switch (event.key()) {
  102. case (KeyCode::Key_Dollar):
  103. move_to_line_end(event);
  104. break;
  105. case (KeyCode::Key_Escape):
  106. if (m_editor->on_escape_pressed)
  107. m_editor->on_escape_pressed();
  108. break;
  109. default:
  110. break;
  111. }
  112. // SHIFT is pressed.
  113. if (event.shift() && !event.ctrl() && !event.alt()) {
  114. switch (event.key()) {
  115. case (KeyCode::Key_A):
  116. move_to_line_end(event);
  117. switch_to_insert_mode();
  118. break;
  119. case (KeyCode::Key_G):
  120. move_to_last_line();
  121. break;
  122. case (KeyCode::Key_I):
  123. move_to_line_beginning(event);
  124. switch_to_insert_mode();
  125. break;
  126. case (KeyCode::Key_O):
  127. move_to_line_beginning(event);
  128. m_editor->add_code_point(0x0A);
  129. move_one_up(event);
  130. switch_to_insert_mode();
  131. break;
  132. default:
  133. break;
  134. }
  135. }
  136. // CTRL is pressed.
  137. if (event.ctrl() && !event.shift() && !event.alt()) {
  138. switch (event.key()) {
  139. case (KeyCode::Key_D):
  140. move_half_page_down(event);
  141. break;
  142. case (KeyCode::Key_R):
  143. m_editor->redo();
  144. break;
  145. case (KeyCode::Key_U):
  146. move_half_page_up(event);
  147. break;
  148. default:
  149. break;
  150. }
  151. }
  152. // FIXME: H and L movement keys will move to the previous or next line when reaching the beginning or end
  153. // of the line and pressed again.
  154. // No modifier is pressed.
  155. if (!event.ctrl() && !event.shift() && !event.alt()) {
  156. switch (event.key()) {
  157. case (KeyCode::Key_A):
  158. move_one_right(event);
  159. switch_to_insert_mode();
  160. break;
  161. case (KeyCode::Key_B):
  162. move_to_beginning_of_previous_word();
  163. break;
  164. case (KeyCode::Key_C):
  165. m_previous_key = event.key();
  166. break;
  167. case (KeyCode::Key_Backspace):
  168. case (KeyCode::Key_H):
  169. case (KeyCode::Key_Left):
  170. move_one_left(event);
  171. break;
  172. case (KeyCode::Key_D):
  173. m_previous_key = event.key();
  174. break;
  175. case (KeyCode::Key_E):
  176. move_to_end_of_next_word();
  177. break;
  178. case (KeyCode::Key_G):
  179. m_previous_key = event.key();
  180. break;
  181. case (KeyCode::Key_Down):
  182. case (KeyCode::Key_J):
  183. move_one_down(event);
  184. break;
  185. case (KeyCode::Key_I):
  186. switch_to_insert_mode();
  187. break;
  188. case (KeyCode::Key_K):
  189. case (KeyCode::Key_Up):
  190. move_one_up(event);
  191. break;
  192. case (KeyCode::Key_L):
  193. case (KeyCode::Key_Right):
  194. move_one_right(event);
  195. break;
  196. case (KeyCode::Key_O):
  197. move_to_line_end(event);
  198. m_editor->add_code_point(0x0A);
  199. switch_to_insert_mode();
  200. break;
  201. case (KeyCode::Key_U):
  202. m_editor->undo();
  203. break;
  204. case (KeyCode::Key_W):
  205. move_to_beginning_of_next_word();
  206. break;
  207. case (KeyCode::Key_X):
  208. yank({ m_editor->cursor(), { m_editor->cursor().line(), m_editor->cursor().column() + 1 } });
  209. delete_char();
  210. break;
  211. case (KeyCode::Key_0):
  212. move_to_line_beginning(event);
  213. break;
  214. case (KeyCode::Key_V):
  215. switch_to_visual_mode();
  216. break;
  217. case (KeyCode::Key_Y):
  218. m_previous_key = event.key();
  219. break;
  220. case (KeyCode::Key_P):
  221. put(event);
  222. break;
  223. default:
  224. break;
  225. }
  226. }
  227. }
  228. return true;
  229. }
  230. bool VimEditingEngine::on_key_in_visual_mode(const KeyEvent& event)
  231. {
  232. if (m_previous_key == KeyCode::Key_G) {
  233. if (event.key() == KeyCode::Key_G) {
  234. move_to_first_line();
  235. update_selection_on_cursor_move();
  236. } else if (event.key() == KeyCode::Key_E) {
  237. move_to_end_of_previous_word();
  238. update_selection_on_cursor_move();
  239. }
  240. m_previous_key = {};
  241. } else {
  242. // Handle first any key codes that are to be applied regardless of modifiers.
  243. switch (event.key()) {
  244. case (KeyCode::Key_Dollar):
  245. move_to_line_end(event);
  246. update_selection_on_cursor_move();
  247. break;
  248. case (KeyCode::Key_Escape):
  249. switch_to_normal_mode();
  250. if (m_editor->on_escape_pressed)
  251. m_editor->on_escape_pressed();
  252. break;
  253. default:
  254. break;
  255. }
  256. // SHIFT is pressed.
  257. if (event.shift() && !event.ctrl() && !event.alt()) {
  258. switch (event.key()) {
  259. case (KeyCode::Key_A):
  260. move_to_line_end(event);
  261. switch_to_insert_mode();
  262. break;
  263. case (KeyCode::Key_G):
  264. move_to_last_line();
  265. break;
  266. case (KeyCode::Key_I):
  267. move_to_line_beginning(event);
  268. switch_to_insert_mode();
  269. break;
  270. default:
  271. break;
  272. }
  273. }
  274. // CTRL is pressed.
  275. if (event.ctrl() && !event.shift() && !event.alt()) {
  276. switch (event.key()) {
  277. case (KeyCode::Key_D):
  278. move_half_page_down(event);
  279. update_selection_on_cursor_move();
  280. break;
  281. case (KeyCode::Key_U):
  282. move_half_page_up(event);
  283. update_selection_on_cursor_move();
  284. break;
  285. default:
  286. break;
  287. }
  288. }
  289. // No modifier is pressed.
  290. if (!event.ctrl() && !event.shift() && !event.alt()) {
  291. switch (event.key()) {
  292. case (KeyCode::Key_B):
  293. move_to_beginning_of_previous_word();
  294. update_selection_on_cursor_move();
  295. break;
  296. case (KeyCode::Key_Backspace):
  297. case (KeyCode::Key_H):
  298. case (KeyCode::Key_Left):
  299. move_one_left(event);
  300. update_selection_on_cursor_move();
  301. break;
  302. case (KeyCode::Key_D):
  303. yank(Selection);
  304. m_editor->do_delete();
  305. switch_to_normal_mode();
  306. break;
  307. case (KeyCode::Key_E):
  308. move_to_end_of_next_word();
  309. update_selection_on_cursor_move();
  310. break;
  311. case (KeyCode::Key_G):
  312. m_previous_key = event.key();
  313. break;
  314. case (KeyCode::Key_Down):
  315. case (KeyCode::Key_J):
  316. move_one_down(event);
  317. update_selection_on_cursor_move();
  318. break;
  319. case (KeyCode::Key_K):
  320. case (KeyCode::Key_Up):
  321. move_one_up(event);
  322. update_selection_on_cursor_move();
  323. break;
  324. case (KeyCode::Key_L):
  325. case (KeyCode::Key_Right):
  326. move_one_right(event);
  327. update_selection_on_cursor_move();
  328. break;
  329. case (KeyCode::Key_U):
  330. // FIXME: Set selection to uppercase.
  331. break;
  332. case (KeyCode::Key_W):
  333. move_to_beginning_of_next_word();
  334. update_selection_on_cursor_move();
  335. break;
  336. case (KeyCode::Key_X):
  337. yank(Selection);
  338. m_editor->do_delete();
  339. switch_to_normal_mode();
  340. break;
  341. case (KeyCode::Key_0):
  342. move_to_line_beginning(event);
  343. update_selection_on_cursor_move();
  344. break;
  345. case (KeyCode::Key_V):
  346. switch_to_normal_mode();
  347. break;
  348. case (KeyCode::Key_C):
  349. yank(Selection);
  350. m_editor->do_delete();
  351. switch_to_insert_mode();
  352. break;
  353. case (KeyCode::Key_Y):
  354. yank(Selection);
  355. switch_to_normal_mode();
  356. break;
  357. default:
  358. break;
  359. }
  360. }
  361. }
  362. return true;
  363. }
  364. void VimEditingEngine::switch_to_normal_mode()
  365. {
  366. m_vim_mode = VimMode::Normal;
  367. m_editor->reset_cursor_blink();
  368. m_previous_key = {};
  369. clear_visual_mode_data();
  370. };
  371. void VimEditingEngine::switch_to_insert_mode()
  372. {
  373. m_vim_mode = VimMode::Insert;
  374. m_editor->reset_cursor_blink();
  375. m_previous_key = {};
  376. clear_visual_mode_data();
  377. };
  378. void VimEditingEngine::switch_to_visual_mode()
  379. {
  380. m_vim_mode = VimMode::Visual;
  381. m_editor->reset_cursor_blink();
  382. m_previous_key = {};
  383. m_selection_start_position = m_editor->cursor();
  384. m_editor->selection()->set(m_editor->cursor(), { m_editor->cursor().line(), m_editor->cursor().column() + 1 });
  385. m_editor->did_update_selection();
  386. }
  387. void VimEditingEngine::update_selection_on_cursor_move()
  388. {
  389. auto cursor = m_editor->cursor();
  390. auto start = m_selection_start_position < cursor ? m_selection_start_position : cursor;
  391. auto end = m_selection_start_position < cursor ? cursor : m_selection_start_position;
  392. end.set_column(end.column() + 1);
  393. m_editor->selection()->set(start, end);
  394. m_editor->did_update_selection();
  395. }
  396. void VimEditingEngine::clear_visual_mode_data()
  397. {
  398. if (m_editor->has_selection()) {
  399. m_editor->selection()->clear();
  400. m_editor->did_update_selection();
  401. }
  402. m_selection_start_position = {};
  403. }
  404. void VimEditingEngine::move_half_page_up(const KeyEvent& event)
  405. {
  406. move_up(event, 0.5);
  407. };
  408. void VimEditingEngine::move_half_page_down(const KeyEvent& event)
  409. {
  410. move_down(event, 0.5);
  411. };
  412. void VimEditingEngine::yank(YankType type)
  413. {
  414. m_yank_type = type;
  415. if (type == YankType::Line) {
  416. m_yank_buffer = m_editor->current_line().to_utf8();
  417. } else {
  418. m_yank_buffer = m_editor->selected_text();
  419. }
  420. // When putting this, auto indentation (if enabled) will indent as far as
  421. // is necessary, then any whitespace captured before the yanked text will be placed
  422. // after the indentation, doubling the indentation.
  423. if (m_editor->is_automatic_indentation_enabled())
  424. m_yank_buffer = m_yank_buffer.trim_whitespace(TrimMode::Left);
  425. }
  426. void VimEditingEngine::yank(TextRange range)
  427. {
  428. m_yank_type = YankType::Selection;
  429. m_yank_buffer = m_editor->document().text_in_range(range);
  430. }
  431. void VimEditingEngine::put(const GUI::KeyEvent& event)
  432. {
  433. if (m_yank_type == YankType::Line) {
  434. move_to_line_end(event);
  435. StringBuilder sb = StringBuilder(m_yank_buffer.length() + 1);
  436. sb.append_code_point(0x0A);
  437. sb.append(m_yank_buffer);
  438. m_editor->insert_at_cursor_or_replace_selection(sb.to_string());
  439. m_editor->set_cursor({ m_editor->cursor().line(), m_editor->current_line().first_non_whitespace_column() });
  440. } else {
  441. // FIXME: If attempting to put on the last column a line,
  442. // the buffer will bne placed on the next line due to the move_one_left/right behaviour.
  443. move_one_right(event);
  444. m_editor->insert_at_cursor_or_replace_selection(m_yank_buffer);
  445. move_one_left(event);
  446. }
  447. }
  448. }