vvim.cpp 92 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414
  1. #include "vvim.h"
  2. #include <QKeyEvent>
  3. #include <QTextBlock>
  4. #include <QTextDocument>
  5. #include <QString>
  6. #include <QScrollBar>
  7. #include <QDebug>
  8. #include <QClipboard>
  9. #include <QApplication>
  10. #include <QMimeData>
  11. #include "vconfigmanager.h"
  12. #include "vedit.h"
  13. #include "utils/veditutils.h"
  14. extern VConfigManager vconfig;
  15. const QChar VVim::c_unnamedRegister = QChar('"');
  16. const QChar VVim::c_blackHoleRegister = QChar('_');
  17. const QChar VVim::c_selectionRegister = QChar('+');
  18. VVim::VVim(VEdit *p_editor)
  19. : QObject(p_editor), m_editor(p_editor),
  20. m_editConfig(&p_editor->getConfig()), m_mode(VimMode::Normal),
  21. m_resetPositionInBlock(true), m_regName(c_unnamedRegister)
  22. {
  23. initRegisters();
  24. connect(m_editor, &VEdit::copyAvailable,
  25. this, &VVim::selectionToVisualMode);
  26. }
  27. // Set @p_cursor's position specified by @p_positionInBlock.
  28. // If @p_positionInBlock is bigger than the block's length, move to the end of block.
  29. // Need to setTextCursor() after calling this.
  30. static void setCursorPositionInBlock(QTextCursor &p_cursor, int p_positionInBlock,
  31. QTextCursor::MoveMode p_mode)
  32. {
  33. QTextBlock block = p_cursor.block();
  34. if (block.length() > p_positionInBlock) {
  35. p_cursor.setPosition(block.position() + p_positionInBlock, p_mode);
  36. } else {
  37. p_cursor.movePosition(QTextCursor::EndOfBlock, p_mode, 1);
  38. }
  39. }
  40. // Find the start and end of the spaces @p_cursor locates in (within a single block).
  41. // @p_start and @p_end will be the global position of the start and end of the spaces.
  42. // @p_start will equals to @p_end if @p_cursor is not a space.
  43. static void findCurrentSpace(const QTextCursor &p_cursor, int &p_start, int &p_end)
  44. {
  45. QTextBlock block = p_cursor.block();
  46. QString text = block.text();
  47. int pib = p_cursor.positionInBlock();
  48. if (pib < text.size() && !text[pib].isSpace()) {
  49. p_start = p_end = p_cursor.position();
  50. return;
  51. }
  52. p_start = 0;
  53. for (int i = pib - 1; i >= 0; --i) {
  54. if (!text[i].isSpace()) {
  55. p_start = i + 1;
  56. break;
  57. }
  58. }
  59. p_end = block.length() - 1;
  60. for (int i = pib; i < text.size(); ++i) {
  61. if (!text[i].isSpace()) {
  62. p_end = i;
  63. break;
  64. }
  65. }
  66. p_start += block.position();
  67. p_end += block.position();
  68. }
  69. // Find the start and end of the word @p_cursor locates in (within a single block).
  70. // @p_start and @p_end will be the global position of the start and end of the word.
  71. // @p_start will equals to @p_end if @p_cursor is a space.
  72. static void findCurrentWord(QTextCursor p_cursor, int &p_start, int &p_end)
  73. {
  74. QString text = p_cursor.block().text();
  75. int pib = p_cursor.positionInBlock();
  76. if (pib < text.size() && text[pib].isSpace()) {
  77. p_start = p_end = p_cursor.position();
  78. return;
  79. }
  80. p_cursor.movePosition(QTextCursor::StartOfWord);
  81. p_start = p_cursor.position();
  82. p_cursor.movePosition(QTextCursor::EndOfWord);
  83. p_end = p_cursor.position();
  84. }
  85. // Find the start and end of the WORD @p_cursor locates in (within a single block).
  86. // @p_start and @p_end will be the global position of the start and end of the WORD.
  87. // @p_start will equals to @p_end if @p_cursor is a space.
  88. // Attention: www|sss will select www, which is different from findCurrentWord().
  89. static void findCurrentWORD(const QTextCursor &p_cursor, int &p_start, int &p_end)
  90. {
  91. QTextBlock block = p_cursor.block();
  92. QString text = block.text();
  93. int pib = p_cursor.positionInBlock();
  94. if (pib < text.size() && text[pib].isSpace()) {
  95. p_start = p_end = p_cursor.position();
  96. return;
  97. }
  98. // Find the start.
  99. p_start = 0;
  100. for (int i = pib - 1; i >= 0; --i) {
  101. if (text[i].isSpace()) {
  102. p_start = i + 1;
  103. break;
  104. }
  105. }
  106. // Find the end.
  107. p_end = block.length() - 1;
  108. for (int i = pib; i < text.size(); ++i) {
  109. if (text[i].isSpace()) {
  110. p_end = i;
  111. break;
  112. }
  113. }
  114. p_start += block.position();
  115. p_end += block.position();
  116. }
  117. // Move @p_cursor to skip spaces if current cursor is placed at a space
  118. // (may move across blocks). It will stop by the empty block on the way.
  119. // Forward: wwwwsssss|wwww
  120. // Backward: wwww|ssssswwww
  121. static void moveCursorAcrossSpaces(QTextCursor &p_cursor,
  122. QTextCursor::MoveMode p_mode,
  123. bool p_forward)
  124. {
  125. while (true) {
  126. QTextBlock block = p_cursor.block();
  127. QString text = block.text();
  128. int pib = p_cursor.positionInBlock();
  129. if (p_forward) {
  130. for (; pib < text.size(); ++pib) {
  131. if (!text[pib].isSpace()) {
  132. break;
  133. }
  134. }
  135. if (pib == text.size()) {
  136. // Move to next block.
  137. p_cursor.movePosition(QTextCursor::Down, p_mode, 1);
  138. if (block.blockNumber() == p_cursor.block().blockNumber()) {
  139. // Already at the last block.
  140. p_cursor.movePosition(QTextCursor::EndOfBlock, p_mode, 1);
  141. break;
  142. } else {
  143. p_cursor.movePosition(QTextCursor::StartOfBlock, p_mode, 1);
  144. if (p_cursor.block().length() <= 1) {
  145. break;
  146. }
  147. }
  148. } else {
  149. // Found non-space character.
  150. p_cursor.setPosition(block.position() + pib, p_mode);
  151. break;
  152. }
  153. } else {
  154. int idx = pib - 1;
  155. for (; idx >= 0; --idx) {
  156. if (!text[idx].isSpace()) {
  157. break;
  158. }
  159. }
  160. if (idx == -1) {
  161. // Move to previous block.
  162. p_cursor.movePosition(QTextCursor::Up, p_mode, 1);
  163. if (block.blockNumber() == p_cursor.block().blockNumber()) {
  164. // Already at the first block.
  165. p_cursor.movePosition(QTextCursor::StartOfBlock, p_mode, 1);
  166. break;
  167. } else {
  168. p_cursor.movePosition(QTextCursor::EndOfBlock, p_mode, 1);
  169. if (p_cursor.block().length() <= 1) {
  170. break;
  171. }
  172. }
  173. } else {
  174. // Found non-space character.
  175. p_cursor.setPosition(block.position() + idx + 1, p_mode);
  176. break;
  177. }
  178. }
  179. }
  180. }
  181. // Expand the selection of @p_cursor to contain additional spaces at the two ends
  182. // within a block.
  183. void expandSelectionAcrossSpacesWithinBlock(QTextCursor &p_cursor)
  184. {
  185. QTextBlock block = p_cursor.block();
  186. QString text = block.text();
  187. int start = p_cursor.selectionStart() - block.position();
  188. int end = p_cursor.selectionEnd() - block.position();
  189. for (int i = start - 1; i >= 0; --i) {
  190. if (!text[i].isSpace()) {
  191. start = i + 1;
  192. break;
  193. }
  194. }
  195. for (int i = end; i < text.size(); ++i) {
  196. if (!text[i].isSpace()) {
  197. end = i;
  198. break;
  199. }
  200. }
  201. start += block.position();
  202. end += block.position();
  203. if (start == p_cursor.selectionStart() && end == p_cursor.selectionEnd()) {
  204. return;
  205. }
  206. if (p_cursor.anchor() <= p_cursor.position()) {
  207. p_cursor.setPosition(start, QTextCursor::MoveAnchor);
  208. p_cursor.setPosition(end, QTextCursor::KeepAnchor);
  209. } else {
  210. p_cursor.setPosition(end, QTextCursor::MoveAnchor);
  211. p_cursor.setPosition(start, QTextCursor::KeepAnchor);
  212. }
  213. }
  214. // In Change action, after deleting selected block text, we need to insert a new
  215. // block for user input.
  216. // @p_deletionStart is the global position of the start of the deletion.
  217. // Should be called immediately after the deletion.
  218. static void insertChangeBlockAfterDeletion(QTextCursor &p_cursor, int p_deletionStart)
  219. {
  220. if (p_cursor.position() < p_deletionStart) {
  221. // Insert a new block below.
  222. p_cursor.movePosition(QTextCursor::EndOfBlock);
  223. p_cursor.insertBlock();
  224. } else {
  225. // Insert a new block above.
  226. p_cursor.insertBlock();
  227. p_cursor.movePosition(QTextCursor::PreviousBlock);
  228. }
  229. if (vconfig.getAutoIndent()) {
  230. VEditUtils::indentBlockAsPreviousBlock(p_cursor);
  231. }
  232. }
  233. bool VVim::handleKeyPressEvent(QKeyEvent *p_event)
  234. {
  235. bool ret = false;
  236. int modifiers = p_event->modifiers();
  237. int key = p_event->key();
  238. bool resetPositionInBlock = true;
  239. Key keyInfo(key, modifiers);
  240. bool unindent = false;
  241. // Handle Insert mode key press.
  242. if (VimMode::Insert == m_mode) {
  243. if (key == Qt::Key_Escape
  244. || (key == Qt::Key_BracketLeft && modifiers == Qt::ControlModifier)) {
  245. // Clear selection and enter Normal mode.
  246. clearSelection();
  247. setMode(VimMode::Normal);
  248. goto clear_accept;
  249. }
  250. // Let it be handled outside VVim.
  251. goto exit;
  252. }
  253. // Ctrl and Shift may be sent out first.
  254. if (key == Qt::Key_Control || key == Qt::Key_Shift) {
  255. goto accept;
  256. }
  257. m_pendingKeys.append(keyInfo);
  258. if (expectingRegisterName()) {
  259. // Expecting a register name.
  260. QChar reg = keyToRegisterName(keyInfo);
  261. if (!reg.isNull()) {
  262. // We should keep m_pendingKeys.
  263. m_keys.clear();
  264. m_tokens.clear();
  265. setRegister(reg);
  266. if (m_registers[reg].isNamedRegister()) {
  267. m_registers[reg].m_append = (modifiers == Qt::ShiftModifier);
  268. } else {
  269. Q_ASSERT(!m_registers[reg].m_append);
  270. }
  271. goto accept;
  272. }
  273. goto clear_accept;
  274. }
  275. if (expectingCharacterTarget()) {
  276. // Expecting a target character for f/F/t/T.
  277. Movement mm = Movement::Invalid;
  278. const Key &aKey = m_keys.first();
  279. if (aKey.m_key == Qt::Key_F) {
  280. if (aKey.m_modifiers == Qt::NoModifier) {
  281. mm = Movement::FindForward;
  282. } else {
  283. mm = Movement::FindBackward;
  284. }
  285. } else {
  286. if (aKey.m_modifiers == Qt::NoModifier) {
  287. mm = Movement::TillForward;
  288. } else {
  289. mm = Movement::TillBackward;
  290. }
  291. }
  292. V_ASSERT(mm != Movement::Invalid);
  293. tryAddMoveAction();
  294. addMovementToken(mm, keyInfo);
  295. m_lastFindToken = m_tokens.last();
  296. processCommand(m_tokens);
  297. goto clear_accept;
  298. }
  299. // We will add key to m_keys. If all m_keys can combined to a token, add
  300. // a new token to m_tokens, clear m_keys and try to process m_tokens.
  301. switch (key) {
  302. case Qt::Key_0:
  303. {
  304. if (modifiers == Qt::NoModifier) {
  305. if (!m_keys.isEmpty()) {
  306. // Repeat.
  307. V_ASSERT(m_keys.last().isDigit());
  308. m_keys.append(keyInfo);
  309. resetPositionInBlock = false;
  310. goto accept;
  311. } else {
  312. // StartOfLine.
  313. tryAddMoveAction();
  314. m_tokens.append(Token(Movement::StartOfLine));
  315. processCommand(m_tokens);
  316. }
  317. }
  318. break;
  319. }
  320. case Qt::Key_1:
  321. case Qt::Key_2:
  322. case Qt::Key_3:
  323. case Qt::Key_4:
  324. case Qt::Key_5:
  325. case Qt::Key_6:
  326. case Qt::Key_7:
  327. case Qt::Key_8:
  328. case Qt::Key_9:
  329. {
  330. if (modifiers == Qt::NoModifier) {
  331. if (!m_keys.isEmpty() && numberFromKeySequence(m_keys) == -1) {
  332. // Invalid sequence.
  333. break;
  334. }
  335. m_keys.append(keyInfo);
  336. resetPositionInBlock = false;
  337. goto accept;
  338. }
  339. break;
  340. }
  341. case Qt::Key_Left:
  342. case Qt::Key_Down:
  343. case Qt::Key_Up:
  344. case Qt::Key_Right:
  345. case Qt::Key_H:
  346. case Qt::Key_J:
  347. case Qt::Key_K:
  348. case Qt::Key_L:
  349. {
  350. if (modifiers == Qt::NoModifier) {
  351. // Check if we could generate a Repeat token.
  352. tryGetRepeatToken(m_keys, m_tokens);
  353. // Generate a Movement token.
  354. Movement mm = Movement::Invalid;
  355. if (!m_keys.isEmpty()) {
  356. // gj, gk.
  357. Key gKey(Qt::Key_G);
  358. if (m_keys.size() == 1 && m_keys.at(0) == gKey) {
  359. if (key == Qt::Key_J) {
  360. mm = Movement::VisualDown;
  361. } else if (key == Qt::Key_K) {
  362. mm = Movement::VisualUp;
  363. } else {
  364. break;
  365. }
  366. } else {
  367. // Not a valid sequence.
  368. break;
  369. }
  370. } else {
  371. // h, j, k, l.
  372. switch (key) {
  373. case Qt::Key_H:
  374. case Qt::Key_Left:
  375. mm = Movement::Left;
  376. break;
  377. case Qt::Key_L:
  378. case Qt::Key_Right:
  379. mm = Movement::Right;
  380. break;
  381. case Qt::Key_J:
  382. case Qt::Key_Down:
  383. mm = Movement::Down;
  384. break;
  385. case Qt::Key_K:
  386. case Qt::Key_Up:
  387. mm = Movement::Up;
  388. break;
  389. default:
  390. V_ASSERT(false);
  391. }
  392. }
  393. V_ASSERT(mm != Movement::Invalid);
  394. tryAddMoveAction();
  395. m_tokens.append(Token(mm));
  396. processCommand(m_tokens);
  397. resetPositionInBlock = false;
  398. }
  399. break;
  400. }
  401. case Qt::Key_I:
  402. {
  403. if (modifiers == Qt::NoModifier) {
  404. if (hasActionTokenValidForTextObject()) {
  405. // Inner text object.
  406. if (!m_keys.isEmpty()) {
  407. // Invalid sequence;
  408. break;
  409. }
  410. m_keys.append(keyInfo);
  411. goto accept;
  412. }
  413. // Enter Insert mode.
  414. if (m_mode == VimMode::Normal) {
  415. setMode(VimMode::Insert);
  416. }
  417. } else if (modifiers == Qt::ShiftModifier) {
  418. QTextCursor cursor = m_editor->textCursor();
  419. if (m_mode == VimMode::Normal) {
  420. // Insert at the first non-space character.
  421. VEditUtils::moveCursorFirstNonSpaceCharacter(cursor, QTextCursor::MoveAnchor);
  422. } else if (m_mode == VimMode::Visual || m_mode == VimMode::VisualLine) {
  423. // Insert at the start of line.
  424. cursor.movePosition(QTextCursor::StartOfBlock,
  425. QTextCursor::MoveAnchor,
  426. 1);
  427. }
  428. m_editor->setTextCursor(cursor);
  429. setMode(VimMode::Insert);
  430. }
  431. break;
  432. }
  433. case Qt::Key_A:
  434. {
  435. if (modifiers == Qt::NoModifier) {
  436. if (hasActionTokenValidForTextObject()) {
  437. // Around text object.
  438. if (!m_keys.isEmpty()) {
  439. // Invalid sequence;
  440. break;
  441. }
  442. m_keys.append(keyInfo);
  443. goto accept;
  444. }
  445. // Enter Insert mode.
  446. // Move cursor back one character.
  447. if (m_mode == VimMode::Normal) {
  448. QTextCursor cursor = m_editor->textCursor();
  449. V_ASSERT(!cursor.hasSelection());
  450. if (!cursor.atBlockEnd()) {
  451. cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, 1);
  452. m_editor->setTextCursor(cursor);
  453. }
  454. setMode(VimMode::Insert);
  455. }
  456. } else if (modifiers == Qt::ShiftModifier) {
  457. // Insert at the end of line.
  458. QTextCursor cursor = m_editor->textCursor();
  459. if (m_mode == VimMode::Normal) {
  460. cursor.movePosition(QTextCursor::EndOfBlock,
  461. QTextCursor::MoveAnchor,
  462. 1);
  463. m_editor->setTextCursor(cursor);
  464. } else if (m_mode == VimMode::Visual || m_mode == VimMode::VisualLine) {
  465. if (!cursor.atBlockEnd()) {
  466. cursor.clearSelection();
  467. cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, 1);
  468. m_editor->setTextCursor(cursor);
  469. }
  470. }
  471. setMode(VimMode::Insert);
  472. }
  473. break;
  474. }
  475. case Qt::Key_O:
  476. {
  477. if (modifiers == Qt::NoModifier || modifiers == Qt::ShiftModifier) {
  478. // Insert a new block under/above current block and enter insert mode.
  479. bool insertAbove = modifiers == Qt::ShiftModifier;
  480. if (m_mode == VimMode::Normal) {
  481. QTextCursor cursor = m_editor->textCursor();
  482. cursor.beginEditBlock();
  483. cursor.movePosition(insertAbove ? QTextCursor::StartOfBlock
  484. : QTextCursor::EndOfBlock,
  485. QTextCursor::MoveAnchor,
  486. 1);
  487. cursor.insertBlock();
  488. if (insertAbove) {
  489. cursor.movePosition(QTextCursor::PreviousBlock,
  490. QTextCursor::MoveAnchor,
  491. 1);
  492. }
  493. if (vconfig.getAutoIndent()) {
  494. VEditUtils::indentBlockAsPreviousBlock(cursor);
  495. if (vconfig.getAutoList()) {
  496. VEditUtils::insertListMarkAsPreviousBlock(cursor);
  497. }
  498. }
  499. cursor.endEditBlock();
  500. m_editor->setTextCursor(cursor);
  501. setMode(VimMode::Insert);
  502. }
  503. break;
  504. }
  505. break;
  506. }
  507. case Qt::Key_S:
  508. {
  509. if (modifiers == Qt::NoModifier) {
  510. // 1. If there is selection, delete the selected text.
  511. // 2. Otherwise, if cursor is not at the end of block, delete the
  512. // character after current cursor.
  513. // 3. Enter Insert mode.
  514. QTextCursor cursor = m_editor->textCursor();
  515. if (cursor.hasSelection() || !cursor.atBlockEnd()) {
  516. cursor.deleteChar();
  517. m_editor->setTextCursor(cursor);
  518. }
  519. setMode(VimMode::Insert);
  520. }
  521. break;
  522. }
  523. case Qt::Key_Dollar:
  524. {
  525. if (modifiers == Qt::ShiftModifier) {
  526. // $, move to end of line.
  527. tryGetRepeatToken(m_keys, m_tokens);
  528. if (m_keys.isEmpty()) {
  529. tryAddMoveAction();
  530. m_tokens.append(Token(Movement::EndOfLine));
  531. processCommand(m_tokens);
  532. }
  533. }
  534. break;
  535. }
  536. case Qt::Key_G:
  537. {
  538. Movement mm = Movement::Invalid;
  539. if (modifiers == Qt::NoModifier) {
  540. tryGetRepeatToken(m_keys, m_tokens);
  541. if (m_keys.isEmpty()) {
  542. // First g, pend it.
  543. m_keys.append(keyInfo);
  544. goto accept;
  545. } else if (m_keys.size() == 1 && m_keys.at(0) == keyInfo) {
  546. // gg, go to a certain line or first line.
  547. if (!m_tokens.isEmpty() && m_tokens.last().isRepeat()) {
  548. mm = Movement::LineJump;
  549. } else {
  550. mm = Movement::StartOfDocument;
  551. }
  552. }
  553. } else if (modifiers == Qt::ShiftModifier) {
  554. tryGetRepeatToken(m_keys, m_tokens);
  555. if (m_keys.isEmpty()) {
  556. // G, go to a certain line or the last line.
  557. if (!m_tokens.isEmpty() && m_tokens.last().isRepeat()) {
  558. mm = Movement::LineJump;
  559. } else {
  560. mm = Movement::EndOfDocument;
  561. }
  562. }
  563. }
  564. if (mm != Movement::Invalid) {
  565. tryAddMoveAction();
  566. m_tokens.append(Token(mm));
  567. processCommand(m_tokens);
  568. }
  569. break;
  570. }
  571. // Should be kept together with Qt::Key_PageUp.
  572. case Qt::Key_B:
  573. {
  574. if (modifiers == Qt::ControlModifier) {
  575. // Ctrl+B, page up, fall through.
  576. modifiers = Qt::NoModifier;
  577. } else if (modifiers == Qt::NoModifier || modifiers == Qt::ShiftModifier) {
  578. tryGetRepeatToken(m_keys, m_tokens);
  579. if (!m_keys.isEmpty()) {
  580. // Not a valid sequence.
  581. break;
  582. }
  583. // b, go to the start of previous or current word.
  584. Movement mm = Movement::WordBackward;
  585. if (modifiers == Qt::ShiftModifier) {
  586. // B, go to the start of previous or current WORD.
  587. mm = Movement::WORDBackward;
  588. }
  589. tryAddMoveAction();
  590. m_tokens.append(Token(mm));
  591. processCommand(m_tokens);
  592. break;
  593. } else {
  594. break;
  595. }
  596. }
  597. case Qt::Key_PageUp:
  598. {
  599. if (modifiers == Qt::NoModifier) {
  600. tryGetRepeatToken(m_keys, m_tokens);
  601. if (!m_keys.isEmpty()) {
  602. // Not a valid sequence.
  603. break;
  604. }
  605. Movement mm = Movement::PageUp;
  606. tryAddMoveAction();
  607. m_tokens.append(Token(mm));
  608. processCommand(m_tokens);
  609. resetPositionInBlock = false;
  610. }
  611. break;
  612. }
  613. case Qt::Key_U:
  614. {
  615. if (modifiers == Qt::ControlModifier) {
  616. // Ctrl+U, HalfPageUp.
  617. tryGetRepeatToken(m_keys, m_tokens);
  618. if (!m_keys.isEmpty()) {
  619. // Not a valid sequence.
  620. break;
  621. }
  622. Movement mm = Movement::HalfPageUp;
  623. tryAddMoveAction();
  624. m_tokens.append(Token(mm));
  625. processCommand(m_tokens);
  626. resetPositionInBlock = false;
  627. } else if (m_keys.isEmpty() && m_tokens.isEmpty() && modifiers == Qt::NoModifier) {
  628. // u, Undo.
  629. break;
  630. } else {
  631. bool toLower = modifiers == Qt::NoModifier;
  632. tryGetRepeatToken(m_keys, m_tokens);
  633. if (hasActionToken()) {
  634. // guu/gUU.
  635. if ((toLower && checkActionToken(Action::ToLower))
  636. || (!toLower && checkActionToken(Action::ToUpper))) {
  637. addRangeToken(Range::Line);
  638. processCommand(m_tokens);
  639. break;
  640. } else {
  641. // An invalid sequence.
  642. break;
  643. }
  644. } else if (checkPendingKey(Key(Qt::Key_G))) {
  645. // gu/gU, ToLower/ToUpper action.
  646. if (m_mode == VimMode::Visual || m_mode == VimMode::VisualLine) {
  647. QTextCursor cursor = m_editor->textCursor();
  648. cursor.beginEditBlock();
  649. // Different from Vim:
  650. // If there is no selection in Visual mode, we do nothing.
  651. convertCaseOfSelectedText(cursor, toLower);
  652. cursor.endEditBlock();
  653. m_editor->setTextCursor(cursor);
  654. setMode(VimMode::Normal);
  655. break;
  656. }
  657. addActionToken(toLower ? Action::ToLower : Action::ToUpper);
  658. m_keys.clear();
  659. goto accept;
  660. } else {
  661. // An invalid sequence.
  662. break;
  663. }
  664. }
  665. break;
  666. }
  667. // Ctrl+F is used for Find dialog, not used here.
  668. case Qt::Key_PageDown:
  669. {
  670. if (modifiers == Qt::NoModifier) {
  671. tryGetRepeatToken(m_keys, m_tokens);
  672. if (!m_keys.isEmpty()) {
  673. // Not a valid sequence.
  674. break;
  675. }
  676. Movement mm = Movement::PageDown;
  677. tryAddMoveAction();
  678. m_tokens.append(Token(mm));
  679. processCommand(m_tokens);
  680. resetPositionInBlock = false;
  681. }
  682. break;
  683. }
  684. case Qt::Key_D:
  685. {
  686. if (modifiers == Qt::ControlModifier) {
  687. // Ctrl+D, HalfPageDown.
  688. tryGetRepeatToken(m_keys, m_tokens);
  689. if (!m_keys.isEmpty()) {
  690. // Not a valid sequence.
  691. break;
  692. }
  693. Movement mm = Movement::HalfPageDown;
  694. tryAddMoveAction();
  695. m_tokens.append(Token(mm));
  696. processCommand(m_tokens);
  697. resetPositionInBlock = false;
  698. } else if (modifiers == Qt::NoModifier) {
  699. // d, delete action.
  700. tryGetRepeatToken(m_keys, m_tokens);
  701. if (hasActionToken()) {
  702. // This is another d, something like dd.
  703. if (checkActionToken(Action::Delete)) {
  704. addRangeToken(Range::Line);
  705. processCommand(m_tokens);
  706. break;
  707. } else {
  708. // An invalid sequence.
  709. break;
  710. }
  711. } else {
  712. // The first d, an Action.
  713. if (m_mode == VimMode::Visual || m_mode == VimMode::VisualLine) {
  714. QTextCursor cursor = m_editor->textCursor();
  715. cursor.beginEditBlock();
  716. // Different from Vim:
  717. // If there is no selection in Visual mode, we do nothing.
  718. if (cursor.hasSelection()) {
  719. deleteSelectedText(cursor, m_mode == VimMode::VisualLine);
  720. } else if (m_mode == VimMode::VisualLine) {
  721. VEditUtils::removeBlock(cursor);
  722. saveToRegister("\n");
  723. }
  724. cursor.endEditBlock();
  725. m_editor->setTextCursor(cursor);
  726. setMode(VimMode::Normal);
  727. break;
  728. }
  729. addActionToken(Action::Delete);
  730. goto accept;
  731. }
  732. } else if (modifiers == Qt::ShiftModifier) {
  733. tryGetRepeatToken(m_keys, m_tokens);
  734. if (!hasActionToken() && m_mode == VimMode::Normal) {
  735. // D, same as d$.
  736. addActionToken(Action::Delete);
  737. addMovementToken(Movement::EndOfLine);
  738. processCommand(m_tokens);
  739. }
  740. break;
  741. }
  742. break;
  743. }
  744. // Should be kept together with Qt::Key_Escape.
  745. case Qt::Key_BracketLeft:
  746. {
  747. if (modifiers == Qt::ControlModifier) {
  748. // fallthrough.
  749. } else {
  750. break;
  751. }
  752. }
  753. case Qt::Key_Escape:
  754. {
  755. // Clear selection and enter normal mode.
  756. clearSelection();
  757. setMode(VimMode::Normal);
  758. break;
  759. }
  760. case Qt::Key_V:
  761. {
  762. if (modifiers == Qt::NoModifier) {
  763. // Toggle Visual Mode.
  764. clearSelection();
  765. VimMode mode = VimMode::Visual;
  766. if (m_mode == VimMode::Visual) {
  767. mode = VimMode::Normal;
  768. }
  769. setMode(mode);
  770. } else if (modifiers == Qt::ShiftModifier) {
  771. // Visual Line Mode.
  772. clearSelection();
  773. VimMode mode = VimMode::VisualLine;
  774. if (m_mode == VimMode::VisualLine) {
  775. mode = VimMode::Normal;
  776. }
  777. setMode(mode);
  778. if (m_mode == VimMode::VisualLine) {
  779. QTextCursor cursor = m_editor->textCursor();
  780. expandSelectionToWholeLines(cursor);
  781. m_editor->setTextCursor(cursor);
  782. }
  783. }
  784. break;
  785. }
  786. case Qt::Key_AsciiCircum:
  787. {
  788. if (modifiers == Qt::ShiftModifier) {
  789. // ~, go to first non-space character of current line (block).
  790. tryGetRepeatToken(m_keys, m_tokens);
  791. if (!m_keys.isEmpty()) {
  792. // Not a valid sequence.
  793. break;
  794. }
  795. Movement mm = Movement::FirstCharacter;
  796. tryAddMoveAction();
  797. m_tokens.append(Token(mm));
  798. processCommand(m_tokens);
  799. }
  800. break;
  801. }
  802. case Qt::Key_W:
  803. {
  804. if (modifiers == Qt::NoModifier || modifiers == Qt::ShiftModifier) {
  805. bool shift = modifiers == Qt::ShiftModifier;
  806. tryGetRepeatToken(m_keys, m_tokens);
  807. if (checkPendingKey(Key(Qt::Key_I)) || checkPendingKey(Key(Qt::Key_A))) {
  808. // WordInner/WORDInner/WordAournd/WORDAround.
  809. bool around = checkPendingKey(Key(Qt::Key_A));
  810. Range range = Range::Invalid;
  811. if (shift) {
  812. if (around) {
  813. range = Range::WORDAround;
  814. } else {
  815. range = Range::WORDInner;
  816. }
  817. } else {
  818. if (around) {
  819. range = Range::WordAround;
  820. } else {
  821. range = Range::WordInner;
  822. }
  823. }
  824. addRangeToken(range);
  825. processCommand(m_tokens);
  826. break;
  827. } else if (!m_keys.isEmpty()) {
  828. // Not a valid sequence.
  829. break;
  830. }
  831. // w, go to the start of next word.
  832. Movement mm = Movement::WordForward;
  833. if (shift) {
  834. // W, go to the start of next WORD.
  835. mm = Movement::WORDForward;
  836. }
  837. tryAddMoveAction();
  838. addMovementToken(mm);
  839. processCommand(m_tokens);
  840. break;
  841. }
  842. break;
  843. }
  844. case Qt::Key_E:
  845. {
  846. // e, E, ge, gE.
  847. if (modifiers == Qt::NoModifier || modifiers == Qt::ShiftModifier) {
  848. tryGetRepeatToken(m_keys, m_tokens);
  849. Movement mm = Movement::Invalid;
  850. if (!m_keys.isEmpty()) {
  851. if (m_keys.size() == 1 && m_keys.at(0) == Key(Qt::Key_G)) {
  852. // ge, gE.
  853. if (modifiers == Qt::NoModifier) {
  854. mm = Movement::BackwardEndOfWord;
  855. } else {
  856. mm = Movement::BackwardEndOfWORD;
  857. }
  858. } else {
  859. // Not a valid sequence.
  860. break;
  861. }
  862. } else {
  863. // e, E.
  864. if (modifiers == Qt::NoModifier) {
  865. mm = Movement::ForwardEndOfWord;
  866. } else {
  867. mm = Movement::ForwardEndOfWORD;
  868. }
  869. }
  870. tryAddMoveAction();
  871. m_tokens.append(Token(mm));
  872. processCommand(m_tokens);
  873. }
  874. break;
  875. }
  876. case Qt::Key_QuoteDbl:
  877. {
  878. if (modifiers == Qt::ShiftModifier) {
  879. // Specify a register.
  880. if (!m_keys.isEmpty() || !m_tokens.isEmpty()) {
  881. // Invalid sequence.
  882. break;
  883. }
  884. m_keys.append(keyInfo);
  885. goto accept;
  886. }
  887. break;
  888. }
  889. case Qt::Key_X:
  890. {
  891. if (modifiers == Qt::ShiftModifier || modifiers == Qt::NoModifier) {
  892. // x, or X to delete one char.
  893. tryGetRepeatToken(m_keys, m_tokens);
  894. if (!m_keys.isEmpty()) {
  895. break;
  896. }
  897. if (!hasActionToken()) {
  898. addActionToken(Action::Delete);
  899. addMovementToken(modifiers == Qt::ShiftModifier ? Movement::Left
  900. : Movement::Right);
  901. processCommand(m_tokens);
  902. }
  903. break;
  904. }
  905. break;
  906. }
  907. case Qt::Key_Y:
  908. {
  909. if (modifiers == Qt::NoModifier) {
  910. // y, copy action.
  911. tryGetRepeatToken(m_keys, m_tokens);
  912. if (hasActionToken()) {
  913. // This is another y, something like yy.
  914. if (checkActionToken(Action::Copy)) {
  915. addRangeToken(Range::Line);
  916. processCommand(m_tokens);
  917. } else {
  918. // An invalid sequence.
  919. break;
  920. }
  921. } else {
  922. // The first y, an Action.
  923. if (m_mode == VimMode::Visual || m_mode == VimMode::VisualLine) {
  924. copySelectedText(m_mode == VimMode::VisualLine);
  925. setMode(VimMode::Normal);
  926. break;
  927. }
  928. addActionToken(Action::Copy);
  929. goto accept;
  930. }
  931. } else if (modifiers == Qt::ShiftModifier) {
  932. tryGetRepeatToken(m_keys, m_tokens);
  933. if (!hasActionToken() && m_mode == VimMode::Normal) {
  934. // Y, same as yy.
  935. addRangeToken(Range::Line);
  936. processCommand(m_tokens);
  937. }
  938. break;
  939. }
  940. break;
  941. }
  942. case Qt::Key_P:
  943. {
  944. if (modifiers == Qt::NoModifier || modifiers == Qt::ShiftModifier) {
  945. // p/P, paste/pastebefore action.
  946. tryGetRepeatToken(m_keys, m_tokens);
  947. if (hasActionToken() || !m_keys.isEmpty()) {
  948. // An invalid sequence.
  949. break;
  950. }
  951. addActionToken(modifiers == Qt::NoModifier ? Action::Paste
  952. : Action::PasteBefore);
  953. processCommand(m_tokens);
  954. break;
  955. }
  956. break;
  957. }
  958. case Qt::Key_C:
  959. {
  960. if (modifiers == Qt::NoModifier) {
  961. // c, change action.
  962. tryGetRepeatToken(m_keys, m_tokens);
  963. if (hasActionToken()) {
  964. // This is another c, something like cc.
  965. if (checkActionToken(Action::Change)) {
  966. addRangeToken(Range::Line);
  967. processCommand(m_tokens);
  968. break;
  969. } else {
  970. // An invalid sequence.
  971. break;
  972. }
  973. } else {
  974. // The first c, an action.
  975. if (m_mode == VimMode::Visual || m_mode == VimMode::VisualLine) {
  976. QTextCursor cursor = m_editor->textCursor();
  977. int pos = cursor.selectionStart();
  978. cursor.beginEditBlock();
  979. // Different from Vim:
  980. // If there is no selection in Visual mode, we do nothing.
  981. if (cursor.hasSelection()) {
  982. deleteSelectedText(cursor, m_mode == VimMode::VisualLine);
  983. if (m_mode == VimMode::VisualLine) {
  984. insertChangeBlockAfterDeletion(cursor, pos);
  985. }
  986. } else if (m_mode == VimMode::VisualLine) {
  987. saveToRegister("\n");
  988. }
  989. cursor.endEditBlock();
  990. m_editor->setTextCursor(cursor);
  991. setMode(VimMode::Insert);
  992. break;
  993. }
  994. addActionToken(Action::Change);
  995. goto accept;
  996. }
  997. } else if (modifiers == Qt::ShiftModifier) {
  998. tryGetRepeatToken(m_keys, m_tokens);
  999. if (!hasActionToken() && m_mode == VimMode::Normal) {
  1000. // C, same as c$.
  1001. addActionToken(Action::Change);
  1002. addMovementToken(Movement::EndOfLine);
  1003. processCommand(m_tokens);
  1004. }
  1005. break;
  1006. }
  1007. break;
  1008. }
  1009. case Qt::Key_Less:
  1010. unindent = true;
  1011. // Fall through.
  1012. case Qt::Key_Greater:
  1013. {
  1014. if (modifiers == Qt::ShiftModifier) {
  1015. // >/<, Indent/Unindent.
  1016. tryGetRepeatToken(m_keys, m_tokens);
  1017. if (hasActionToken()) {
  1018. // This is another >/<, something like >>/<<.
  1019. if ((!unindent && checkActionToken(Action::Indent))
  1020. || (unindent && checkActionToken(Action::UnIndent))) {
  1021. addRangeToken(Range::Line);
  1022. processCommand(m_tokens);
  1023. break;
  1024. } else {
  1025. // An invalid sequence.
  1026. break;
  1027. }
  1028. } else {
  1029. // The first >/<, an Action.
  1030. if (m_mode == VimMode::Visual || m_mode == VimMode::VisualLine) {
  1031. QTextCursor cursor = m_editor->textCursor();
  1032. VEditUtils::indentSelectedBlocks(m_editor->document(),
  1033. cursor,
  1034. m_editConfig->m_tabSpaces,
  1035. !unindent);
  1036. setMode(VimMode::Normal);
  1037. break;
  1038. }
  1039. addActionToken(unindent ? Action::UnIndent : Action::Indent);
  1040. goto accept;
  1041. }
  1042. }
  1043. break;
  1044. }
  1045. case Qt::Key_F:
  1046. {
  1047. if (m_mode == VimMode::VisualLine) {
  1048. break;
  1049. }
  1050. if (modifiers == Qt::NoModifier || modifiers == Qt::ShiftModifier) {
  1051. // f/F, find forward/backward within a block.
  1052. tryGetRepeatToken(m_keys, m_tokens);
  1053. if (m_keys.isEmpty()) {
  1054. m_keys.append(keyInfo);
  1055. goto accept;
  1056. }
  1057. break;
  1058. }
  1059. break;
  1060. }
  1061. case Qt::Key_T:
  1062. {
  1063. if (m_mode == VimMode::VisualLine) {
  1064. break;
  1065. }
  1066. if (modifiers == Qt::NoModifier || modifiers == Qt::ShiftModifier) {
  1067. // t/T, find till forward/backward within a block.
  1068. tryGetRepeatToken(m_keys, m_tokens);
  1069. if (m_keys.isEmpty()) {
  1070. m_keys.append(keyInfo);
  1071. goto accept;
  1072. }
  1073. break;
  1074. }
  1075. break;
  1076. }
  1077. case Qt::Key_Comma:
  1078. {
  1079. if (m_mode == VimMode::VisualLine) {
  1080. break;
  1081. }
  1082. // ,, repeat last find target movement, but reversely.
  1083. tryGetRepeatToken(m_keys, m_tokens);
  1084. if (m_keys.isEmpty()) {
  1085. repeatLastFindMovement(true);
  1086. break;
  1087. }
  1088. break;
  1089. }
  1090. case Qt::Key_Semicolon:
  1091. {
  1092. if (m_mode == VimMode::VisualLine) {
  1093. break;
  1094. }
  1095. // ;, repeat last find target movement.
  1096. tryGetRepeatToken(m_keys, m_tokens);
  1097. if (m_keys.isEmpty()) {
  1098. repeatLastFindMovement(false);
  1099. break;
  1100. }
  1101. break;
  1102. }
  1103. default:
  1104. break;
  1105. }
  1106. clear_accept:
  1107. resetState();
  1108. accept:
  1109. p_event->accept();
  1110. ret = true;
  1111. exit:
  1112. m_resetPositionInBlock = resetPositionInBlock;
  1113. emit vimStatusUpdated(this);
  1114. return ret;
  1115. }
  1116. void VVim::resetState()
  1117. {
  1118. m_keys.clear();
  1119. m_tokens.clear();
  1120. m_pendingKeys.clear();
  1121. setRegister(c_unnamedRegister);
  1122. m_resetPositionInBlock = true;
  1123. }
  1124. VimMode VVim::getMode() const
  1125. {
  1126. return m_mode;
  1127. }
  1128. void VVim::setMode(VimMode p_mode)
  1129. {
  1130. if (m_mode != p_mode) {
  1131. clearSelection();
  1132. m_mode = p_mode;
  1133. resetState();
  1134. emit modeChanged(m_mode);
  1135. emit vimStatusUpdated(this);
  1136. }
  1137. }
  1138. void VVim::processCommand(QList<Token> &p_tokens)
  1139. {
  1140. if (p_tokens.isEmpty()) {
  1141. return;
  1142. }
  1143. V_ASSERT(p_tokens.at(0).isAction());
  1144. for (int i = 0; i < p_tokens.size(); ++i) {
  1145. qDebug() << "token" << i << p_tokens[i].toString();
  1146. }
  1147. Token act = p_tokens.takeFirst();
  1148. switch (act.m_action) {
  1149. case Action::Move:
  1150. processMoveAction(p_tokens);
  1151. break;
  1152. case Action::Delete:
  1153. processDeleteAction(p_tokens);
  1154. break;
  1155. case Action::Copy:
  1156. processCopyAction(p_tokens);
  1157. break;
  1158. case Action::Paste:
  1159. processPasteAction(p_tokens, false);
  1160. break;
  1161. case Action::PasteBefore:
  1162. processPasteAction(p_tokens, true);
  1163. break;
  1164. case Action::Change:
  1165. processChangeAction(p_tokens);
  1166. break;
  1167. case Action::Indent:
  1168. processIndentAction(p_tokens, true);
  1169. break;
  1170. case Action::UnIndent:
  1171. processIndentAction(p_tokens, false);
  1172. break;
  1173. case Action::ToLower:
  1174. processToLowerAction(p_tokens, true);
  1175. break;
  1176. case Action::ToUpper:
  1177. processToLowerAction(p_tokens, false);
  1178. break;
  1179. default:
  1180. p_tokens.clear();
  1181. break;
  1182. }
  1183. Q_ASSERT(p_tokens.isEmpty());
  1184. }
  1185. int VVim::numberFromKeySequence(const QList<Key> &p_keys)
  1186. {
  1187. int num = 0;
  1188. for (auto const & key : p_keys) {
  1189. if (key.isDigit()) {
  1190. num = num * 10 + key.toDigit();
  1191. } else {
  1192. return -1;
  1193. }
  1194. }
  1195. return num == 0 ? -1 : num;
  1196. }
  1197. bool VVim::tryGetRepeatToken(QList<Key> &p_keys, QList<Token> &p_tokens)
  1198. {
  1199. if (!p_keys.isEmpty()) {
  1200. int repeat = numberFromKeySequence(p_keys);
  1201. if (repeat != -1) {
  1202. p_tokens.append(Token(repeat));
  1203. p_keys.clear();
  1204. return true;
  1205. }
  1206. }
  1207. return false;
  1208. }
  1209. void VVim::processMoveAction(QList<Token> &p_tokens)
  1210. {
  1211. // Only moving left/right could change this.
  1212. static int positionInBlock = 0;
  1213. Token to = p_tokens.takeFirst();
  1214. V_ASSERT(to.isRepeat() || to.isMovement());
  1215. Token mvToken;
  1216. int repeat = -1;
  1217. if (to.isRepeat()) {
  1218. repeat = to.m_repeat;
  1219. mvToken = p_tokens.takeFirst();
  1220. } else {
  1221. mvToken = to;
  1222. }
  1223. if (!mvToken.isMovement() || !p_tokens.isEmpty()) {
  1224. p_tokens.clear();
  1225. return;
  1226. }
  1227. QTextCursor cursor = m_editor->textCursor();
  1228. if (m_resetPositionInBlock) {
  1229. positionInBlock = cursor.positionInBlock();
  1230. }
  1231. QTextCursor::MoveMode moveMode = (m_mode == VimMode::Visual
  1232. || m_mode == VimMode::VisualLine)
  1233. ? QTextCursor::KeepAnchor
  1234. : QTextCursor::MoveAnchor;
  1235. bool hasMoved = processMovement(cursor, m_editor->document(),
  1236. moveMode, mvToken, repeat);
  1237. if (hasMoved) {
  1238. // Maintain positionInBlock.
  1239. switch (mvToken.m_movement) {
  1240. case Movement::Left:
  1241. case Movement::Right:
  1242. positionInBlock = cursor.positionInBlock();
  1243. break;
  1244. case Movement::Up:
  1245. case Movement::Down:
  1246. case Movement::PageUp:
  1247. case Movement::PageDown:
  1248. case Movement::HalfPageUp:
  1249. case Movement::HalfPageDown:
  1250. setCursorPositionInBlock(cursor, positionInBlock, moveMode);
  1251. break;
  1252. default:
  1253. break;
  1254. }
  1255. if (m_mode == VimMode::VisualLine) {
  1256. expandSelectionToWholeLines(cursor);
  1257. }
  1258. m_editor->setTextCursor(cursor);
  1259. }
  1260. }
  1261. #define ADDKEY(x, y) case (x): {ch = (y); break;}
  1262. // Returns NULL QChar if invalid.
  1263. static QChar keyToChar(int p_key, int p_modifiers)
  1264. {
  1265. if (p_modifiers == Qt::ControlModifier) {
  1266. return QChar();
  1267. }
  1268. if (p_key >= Qt::Key_0 && p_key <= Qt::Key_9) {
  1269. return QChar('0' + (p_key - Qt::Key_0));
  1270. } else if (p_key >= Qt::Key_A && p_key <= Qt::Key_Z) {
  1271. if (p_modifiers == Qt::ShiftModifier) {
  1272. return QChar('A' + (p_key - Qt::Key_A));
  1273. } else {
  1274. return QChar('a' + (p_key - Qt::Key_A));
  1275. }
  1276. }
  1277. QChar ch;
  1278. switch (p_key) {
  1279. ADDKEY(Qt::Key_Tab, '\t');
  1280. ADDKEY(Qt::Key_Space, ' ');
  1281. ADDKEY(Qt::Key_Exclam, '!');
  1282. ADDKEY(Qt::Key_QuoteDbl, '"');
  1283. ADDKEY(Qt::Key_NumberSign, '#');
  1284. ADDKEY(Qt::Key_Dollar, '$');
  1285. ADDKEY(Qt::Key_Percent, '%');
  1286. ADDKEY(Qt::Key_Ampersand, '&');
  1287. ADDKEY(Qt::Key_Apostrophe, '\'');
  1288. ADDKEY(Qt::Key_ParenLeft, '(');
  1289. ADDKEY(Qt::Key_ParenRight, ')');
  1290. ADDKEY(Qt::Key_Asterisk, '*');
  1291. ADDKEY(Qt::Key_Plus, '+');
  1292. ADDKEY(Qt::Key_Comma, ',');
  1293. ADDKEY(Qt::Key_Minus, '-');
  1294. ADDKEY(Qt::Key_Period, '.');
  1295. ADDKEY(Qt::Key_Slash, '/');
  1296. ADDKEY(Qt::Key_Colon, ':');
  1297. ADDKEY(Qt::Key_Semicolon, ';');
  1298. ADDKEY(Qt::Key_Less, '<');
  1299. ADDKEY(Qt::Key_Equal, '=');
  1300. ADDKEY(Qt::Key_Greater, '>');
  1301. ADDKEY(Qt::Key_Question, '?');
  1302. ADDKEY(Qt::Key_At, '@');
  1303. ADDKEY(Qt::Key_BracketLeft, '[');
  1304. ADDKEY(Qt::Key_Backslash, '\\');
  1305. ADDKEY(Qt::Key_BracketRight, ']');
  1306. ADDKEY(Qt::Key_AsciiCircum, '^');
  1307. ADDKEY(Qt::Key_Underscore, '_');
  1308. ADDKEY(Qt::Key_QuoteLeft, '`');
  1309. ADDKEY(Qt::Key_BraceLeft, '{');
  1310. ADDKEY(Qt::Key_Bar, '|');
  1311. ADDKEY(Qt::Key_BraceRight, '}');
  1312. ADDKEY(Qt::Key_AsciiTilde, '~');
  1313. default:
  1314. break;
  1315. }
  1316. return ch;
  1317. }
  1318. bool VVim::processMovement(QTextCursor &p_cursor, const QTextDocument *p_doc,
  1319. QTextCursor::MoveMode p_moveMode,
  1320. const Token &p_token, int p_repeat)
  1321. {
  1322. V_ASSERT(p_token.isMovement());
  1323. bool hasMoved = false;
  1324. bool inclusive = true;
  1325. bool forward = true;
  1326. switch (p_token.m_movement) {
  1327. case Movement::Left:
  1328. {
  1329. if (p_repeat == -1) {
  1330. p_repeat = 1;
  1331. }
  1332. int pib = p_cursor.positionInBlock();
  1333. p_repeat = qMin(pib, p_repeat);
  1334. if (p_repeat > 0) {
  1335. p_cursor.movePosition(QTextCursor::Left, p_moveMode, p_repeat);
  1336. hasMoved = true;
  1337. }
  1338. break;
  1339. }
  1340. case Movement::Right:
  1341. {
  1342. if (p_repeat == -1) {
  1343. p_repeat = 1;
  1344. }
  1345. int pib = p_cursor.positionInBlock();
  1346. int length = p_cursor.block().length();
  1347. if (length - pib <= p_repeat) {
  1348. p_repeat = length - pib - 1;
  1349. }
  1350. if (p_repeat > 0) {
  1351. p_cursor.movePosition(QTextCursor::Right, p_moveMode, p_repeat);
  1352. hasMoved = true;
  1353. }
  1354. break;
  1355. }
  1356. case Movement::Up:
  1357. {
  1358. if (p_repeat == -1) {
  1359. p_repeat = 1;
  1360. }
  1361. p_repeat = qMin(p_cursor.block().blockNumber(), p_repeat);
  1362. if (p_repeat > 0) {
  1363. p_cursor.movePosition(QTextCursor::PreviousBlock, p_moveMode, p_repeat);
  1364. hasMoved = true;
  1365. }
  1366. break;
  1367. }
  1368. case Movement::Down:
  1369. {
  1370. if (p_repeat == -1) {
  1371. p_repeat = 1;
  1372. }
  1373. int blockCount = p_doc->blockCount();
  1374. p_repeat = qMin(blockCount - 1 - p_cursor.block().blockNumber(), p_repeat);
  1375. if (p_repeat > 0) {
  1376. p_cursor.movePosition(QTextCursor::NextBlock, p_moveMode, p_repeat);
  1377. hasMoved = true;
  1378. }
  1379. break;
  1380. }
  1381. case Movement::VisualUp:
  1382. {
  1383. if (p_repeat == -1) {
  1384. p_repeat = 1;
  1385. }
  1386. p_cursor.movePosition(QTextCursor::Up, p_moveMode, p_repeat);
  1387. hasMoved = true;
  1388. break;
  1389. }
  1390. case Movement::VisualDown:
  1391. {
  1392. if (p_repeat == -1) {
  1393. p_repeat = 1;
  1394. }
  1395. p_cursor.movePosition(QTextCursor::Down, p_moveMode, p_repeat);
  1396. hasMoved = true;
  1397. break;
  1398. }
  1399. case Movement::PageUp:
  1400. {
  1401. if (p_repeat == -1) {
  1402. p_repeat = 1;
  1403. }
  1404. int blockStep = blockCountOfPageStep() * p_repeat;
  1405. int block = p_cursor.block().blockNumber();
  1406. block = qMax(0, block - blockStep);
  1407. p_cursor.setPosition(p_doc->findBlockByNumber(block).position(), p_moveMode);
  1408. hasMoved = true;
  1409. break;
  1410. }
  1411. case Movement::PageDown:
  1412. {
  1413. if (p_repeat == -1) {
  1414. p_repeat = 1;
  1415. }
  1416. int blockStep = blockCountOfPageStep() * p_repeat;
  1417. int block = p_cursor.block().blockNumber();
  1418. block = qMin(block + blockStep, p_doc->blockCount() - 1);
  1419. p_cursor.setPosition(p_doc->findBlockByNumber(block).position(), p_moveMode);
  1420. hasMoved = true;
  1421. break;
  1422. }
  1423. case Movement::HalfPageUp:
  1424. {
  1425. if (p_repeat == -1) {
  1426. p_repeat = 1;
  1427. }
  1428. int blockStep = blockCountOfPageStep();
  1429. int halfBlockStep = qMax(blockStep / 2, 1);
  1430. blockStep = p_repeat * halfBlockStep;
  1431. int block = p_cursor.block().blockNumber();
  1432. block = qMax(0, block - blockStep);
  1433. p_cursor.setPosition(p_doc->findBlockByNumber(block).position(), p_moveMode);
  1434. hasMoved = true;
  1435. break;
  1436. }
  1437. case Movement::HalfPageDown:
  1438. {
  1439. if (p_repeat == -1) {
  1440. p_repeat = 1;
  1441. }
  1442. int blockStep = blockCountOfPageStep();
  1443. int halfBlockStep = qMax(blockStep / 2, 1);
  1444. blockStep = p_repeat * halfBlockStep;
  1445. int block = p_cursor.block().blockNumber();
  1446. block = qMin(block + blockStep, p_doc->blockCount() - 1);
  1447. p_cursor.setPosition(p_doc->findBlockByNumber(block).position(), p_moveMode);
  1448. hasMoved = true;
  1449. break;
  1450. }
  1451. case Movement::StartOfLine:
  1452. {
  1453. Q_ASSERT(p_repeat == -1);
  1454. // Start of the Line (block).
  1455. if (!p_cursor.atBlockStart()) {
  1456. p_cursor.movePosition(QTextCursor::StartOfBlock, p_moveMode, 1);
  1457. hasMoved = true;
  1458. }
  1459. break;
  1460. }
  1461. case Movement::EndOfLine:
  1462. {
  1463. // End of line (block).
  1464. if (p_repeat == -1) {
  1465. p_repeat = 1;
  1466. } else if (p_repeat > 1) {
  1467. // Move down (p_repeat-1) blocks.
  1468. p_cursor.movePosition(QTextCursor::NextBlock, p_moveMode, p_repeat - 1);
  1469. }
  1470. // Move to the end of block.
  1471. p_cursor.movePosition(QTextCursor::EndOfBlock, p_moveMode, 1);
  1472. hasMoved = true;
  1473. break;
  1474. }
  1475. case Movement::FirstCharacter:
  1476. {
  1477. // p_repeat is not considered in this command.
  1478. // If all the block is space, just move to the end of block; otherwise,
  1479. // move to the first non-space character.
  1480. VEditUtils::moveCursorFirstNonSpaceCharacter(p_cursor, p_moveMode);
  1481. hasMoved = true;
  1482. break;
  1483. }
  1484. case Movement::LineJump:
  1485. {
  1486. // Jump to the first non-space character of @p_repeat line (block).
  1487. V_ASSERT(p_repeat > 0);
  1488. // @p_repeat starts from 1 while block number starts from 0.
  1489. QTextBlock block = p_doc->findBlockByNumber(p_repeat - 1);
  1490. if (block.isValid()) {
  1491. p_cursor.setPosition(block.position(), p_moveMode);
  1492. } else {
  1493. // Go beyond the document.
  1494. p_cursor.movePosition(QTextCursor::End, p_moveMode, 1);
  1495. }
  1496. VEditUtils::moveCursorFirstNonSpaceCharacter(p_cursor, p_moveMode);
  1497. hasMoved = true;
  1498. break;
  1499. }
  1500. case Movement::StartOfDocument:
  1501. {
  1502. // Jump to the first non-space character of the start of the document.
  1503. V_ASSERT(p_repeat == -1);
  1504. p_cursor.movePosition(QTextCursor::Start, p_moveMode, 1);
  1505. VEditUtils::moveCursorFirstNonSpaceCharacter(p_cursor, p_moveMode);
  1506. hasMoved = true;
  1507. break;
  1508. }
  1509. case Movement::EndOfDocument:
  1510. {
  1511. // Jump to the first non-space character of the end of the document.
  1512. V_ASSERT(p_repeat == -1);
  1513. p_cursor.movePosition(QTextCursor::End, p_moveMode, 1);
  1514. VEditUtils::moveCursorFirstNonSpaceCharacter(p_cursor, p_moveMode);
  1515. hasMoved = true;
  1516. break;
  1517. }
  1518. case Movement::WordForward:
  1519. {
  1520. // Go to the start of next word.
  1521. if (p_repeat == -1) {
  1522. p_repeat = 1;
  1523. }
  1524. p_cursor.movePosition(QTextCursor::NextWord, p_moveMode, p_repeat);
  1525. hasMoved = true;
  1526. break;
  1527. }
  1528. case Movement::WORDForward:
  1529. {
  1530. // Go to the start of next WORD.
  1531. if (p_repeat == -1) {
  1532. p_repeat = 1;
  1533. }
  1534. for (int i = 0; i < p_repeat; ++i) {
  1535. int start, end;
  1536. // [start, end] is current WORD.
  1537. findCurrentWORD(p_cursor, start, end);
  1538. // Move cursor to end of current WORD.
  1539. p_cursor.setPosition(end, p_moveMode);
  1540. // Skip spaces.
  1541. moveCursorAcrossSpaces(p_cursor, p_moveMode, true);
  1542. }
  1543. hasMoved = true;
  1544. break;
  1545. }
  1546. case Movement::ForwardEndOfWord:
  1547. {
  1548. // Go to the end of current word or next word.
  1549. if (p_repeat == -1) {
  1550. p_repeat = 1;
  1551. }
  1552. int pos = p_cursor.position();
  1553. // First move to the end of current word.
  1554. p_cursor.movePosition(QTextCursor::EndOfWord, p_moveMode, 1);
  1555. if (pos != p_cursor.position()) {
  1556. // We did move.
  1557. p_repeat -= 1;
  1558. }
  1559. if (p_repeat) {
  1560. p_cursor.movePosition(QTextCursor::NextWord, p_moveMode, p_repeat);
  1561. p_cursor.movePosition(QTextCursor::EndOfWord, p_moveMode);
  1562. }
  1563. hasMoved = true;
  1564. break;
  1565. }
  1566. case Movement::ForwardEndOfWORD:
  1567. {
  1568. // Go to the end of current WORD or next WORD.
  1569. if (p_repeat == -1) {
  1570. p_repeat = 1;
  1571. }
  1572. for (int i = 0; i < p_repeat; ++i) {
  1573. // Skip spaces.
  1574. moveCursorAcrossSpaces(p_cursor, p_moveMode, true);
  1575. int start, end;
  1576. // [start, end] is current WORD.
  1577. findCurrentWORD(p_cursor, start, end);
  1578. // Move cursor to the end of current WORD.
  1579. p_cursor.setPosition(end, p_moveMode);
  1580. }
  1581. hasMoved = true;
  1582. break;
  1583. }
  1584. case Movement::WordBackward:
  1585. {
  1586. // Go to the start of previous word or current word.
  1587. if (p_repeat == -1) {
  1588. p_repeat = 1;
  1589. }
  1590. int pos = p_cursor.position();
  1591. // first move to the start of current word.
  1592. p_cursor.movePosition(QTextCursor::StartOfWord, p_moveMode, 1);
  1593. if (pos != p_cursor.position()) {
  1594. // We did move.
  1595. p_repeat -= 1;
  1596. }
  1597. if (p_repeat) {
  1598. p_cursor.movePosition(QTextCursor::PreviousWord, p_moveMode, p_repeat);
  1599. }
  1600. hasMoved = true;
  1601. break;
  1602. }
  1603. case Movement::WORDBackward:
  1604. {
  1605. // Go to the start of previous WORD or current WORD.
  1606. if (p_repeat == -1) {
  1607. p_repeat = 1;
  1608. }
  1609. for (int i = 0; i < p_repeat; ++i) {
  1610. // Skip Spaces.
  1611. moveCursorAcrossSpaces(p_cursor, p_moveMode, false);
  1612. int start, end;
  1613. // [start, end] is current WORD.
  1614. findCurrentWORD(p_cursor, start, end);
  1615. // Move cursor to the start of current WORD.
  1616. p_cursor.setPosition(start, p_moveMode);
  1617. }
  1618. hasMoved = true;
  1619. break;
  1620. }
  1621. case Movement::BackwardEndOfWord:
  1622. {
  1623. // Go to the end of previous word.
  1624. if (p_repeat == -1) {
  1625. p_repeat = 1;
  1626. }
  1627. int pib = p_cursor.positionInBlock();
  1628. if (!(pib > 0 && p_cursor.block().text()[pib -1].isSpace())) {
  1629. ++p_repeat;
  1630. }
  1631. p_cursor.movePosition(QTextCursor::PreviousWord, p_moveMode, p_repeat);
  1632. p_cursor.movePosition(QTextCursor::EndOfWord, p_moveMode, 1);
  1633. hasMoved = true;
  1634. break;
  1635. }
  1636. case Movement::BackwardEndOfWORD:
  1637. {
  1638. // Go to the end of previous WORD.
  1639. if (p_repeat == -1) {
  1640. p_repeat = 1;
  1641. }
  1642. for (int i = 0; i < p_repeat; ++i) {
  1643. int start, end;
  1644. findCurrentWORD(p_cursor, start, end);
  1645. p_cursor.setPosition(start, p_moveMode);
  1646. moveCursorAcrossSpaces(p_cursor, p_moveMode, false);
  1647. }
  1648. hasMoved = true;
  1649. break;
  1650. }
  1651. case Movement::TillBackward:
  1652. forward = false;
  1653. // Fall through.
  1654. case Movement::TillForward:
  1655. inclusive = false;
  1656. goto handle_target;
  1657. case Movement::FindBackward:
  1658. forward = false;
  1659. // Fall through.
  1660. case Movement::FindForward:
  1661. {
  1662. handle_target:
  1663. const Key &key = p_token.m_key;
  1664. QChar target = keyToChar(key.m_key, key.m_modifiers);
  1665. if (!target.isNull()) {
  1666. hasMoved = VEditUtils::findTargetWithinBlock(p_cursor, p_moveMode,
  1667. target, forward, inclusive);
  1668. }
  1669. break;
  1670. }
  1671. default:
  1672. break;
  1673. }
  1674. return hasMoved;
  1675. }
  1676. bool VVim::selectRange(QTextCursor &p_cursor, const QTextDocument *p_doc,
  1677. Range p_range, int p_repeat)
  1678. {
  1679. bool hasMoved = false;
  1680. QTextCursor::MoveMode moveMode = QTextCursor::KeepAnchor;
  1681. bool around = false;
  1682. Q_UNUSED(p_doc);
  1683. switch (p_range) {
  1684. case Range::Line:
  1685. {
  1686. // Current line and next (p_repeat - 1) lines.
  1687. if (p_repeat == -1) {
  1688. p_repeat = 1;
  1689. }
  1690. if (p_repeat > 1) {
  1691. p_cursor.movePosition(QTextCursor::NextBlock, moveMode, p_repeat - 1);
  1692. }
  1693. expandSelectionToWholeLines(p_cursor);
  1694. hasMoved = true;
  1695. break;
  1696. }
  1697. case Range::WordAround:
  1698. around = true;
  1699. // Fall through.
  1700. case Range::WordInner:
  1701. {
  1702. Q_ASSERT(p_repeat == -1);
  1703. bool spaces = false;
  1704. int start, end;
  1705. findCurrentWord(p_cursor, start, end);
  1706. if (start == end) {
  1707. // Select the space between previous word and next word.
  1708. findCurrentSpace(p_cursor, start, end);
  1709. spaces = true;
  1710. }
  1711. if (start != end) {
  1712. p_cursor.setPosition(start, QTextCursor::MoveAnchor);
  1713. p_cursor.setPosition(end, moveMode);
  1714. hasMoved = true;
  1715. if (around) {
  1716. if (spaces) {
  1717. // Select the word by the end of spaces.
  1718. if (!p_cursor.atBlockEnd()) {
  1719. p_cursor.movePosition(QTextCursor::EndOfWord, moveMode);
  1720. }
  1721. } else {
  1722. // Select additional spaces at two ends.
  1723. expandSelectionAcrossSpacesWithinBlock(p_cursor);
  1724. }
  1725. }
  1726. }
  1727. break;
  1728. }
  1729. case Range::WORDAround:
  1730. around = true;
  1731. // Fall through.
  1732. case Range::WORDInner:
  1733. {
  1734. Q_ASSERT(p_repeat == -1);
  1735. bool spaces = false;
  1736. int start, end;
  1737. findCurrentSpace(p_cursor, start, end);
  1738. if (start == end) {
  1739. findCurrentWORD(p_cursor, start, end);
  1740. } else {
  1741. // Select the space between previous WORD and next WORD.
  1742. spaces = true;
  1743. }
  1744. if (start != end) {
  1745. p_cursor.setPosition(start, QTextCursor::MoveAnchor);
  1746. p_cursor.setPosition(end, moveMode);
  1747. hasMoved = true;
  1748. if (around) {
  1749. if (spaces) {
  1750. // Select the WORD by the end of spaces.
  1751. if (!p_cursor.atBlockEnd()) {
  1752. // Skip spaces (mainly across block).
  1753. moveCursorAcrossSpaces(p_cursor, moveMode, true);
  1754. // [start, end] is current WORD.
  1755. findCurrentWORD(p_cursor, start, end);
  1756. // Move cursor to the end of current WORD.
  1757. p_cursor.setPosition(end, moveMode);
  1758. }
  1759. } else {
  1760. // Select additional spaces at two ends.
  1761. expandSelectionAcrossSpacesWithinBlock(p_cursor);
  1762. }
  1763. }
  1764. }
  1765. break;
  1766. }
  1767. default:
  1768. break;
  1769. }
  1770. return hasMoved;
  1771. }
  1772. void VVim::processDeleteAction(QList<Token> &p_tokens)
  1773. {
  1774. Token to = p_tokens.takeFirst();
  1775. int repeat = -1;
  1776. if (to.isRepeat()) {
  1777. repeat = to.m_repeat;
  1778. to = p_tokens.takeFirst();
  1779. }
  1780. if ((!to.isMovement() && !to.isRange()) || !p_tokens.isEmpty()) {
  1781. p_tokens.clear();
  1782. return;
  1783. }
  1784. QTextCursor cursor = m_editor->textCursor();
  1785. QTextDocument *doc = m_editor->document();
  1786. bool hasMoved = false;
  1787. QTextCursor::MoveMode moveMode = QTextCursor::KeepAnchor;
  1788. if (to.isRange()) {
  1789. cursor.beginEditBlock();
  1790. hasMoved = selectRange(cursor, doc, to.m_range, repeat);
  1791. bool around = false;
  1792. if (hasMoved) {
  1793. switch (to.m_range) {
  1794. case Range::Line:
  1795. {
  1796. // dd, delete current line.
  1797. if (repeat == -1) {
  1798. repeat = 1;
  1799. }
  1800. if (cursor.hasSelection()) {
  1801. deleteSelectedText(cursor, true);
  1802. } else {
  1803. VEditUtils::removeBlock(cursor);
  1804. }
  1805. message(tr("%1 fewer %2").arg(repeat).arg(repeat > 1 ? tr("lines")
  1806. : tr("line")));
  1807. qDebug() << "delete" << repeat << "lines";
  1808. break;
  1809. }
  1810. case Range::WordAround:
  1811. around = true;
  1812. // Fall through.
  1813. case Range::WordInner:
  1814. {
  1815. if (cursor.hasSelection()) {
  1816. deleteSelectedText(cursor, false);
  1817. }
  1818. qDebug() << "delete" << (around ? "around" : "inner") << "word";
  1819. break;
  1820. }
  1821. case Range::WORDAround:
  1822. around = true;
  1823. // Fall through.
  1824. case Range::WORDInner:
  1825. {
  1826. if (cursor.hasSelection()) {
  1827. deleteSelectedText(cursor, false);
  1828. }
  1829. qDebug() << "delete" << (around ? "around" : "inner") << "WORD";
  1830. break;
  1831. }
  1832. default:
  1833. return;
  1834. }
  1835. }
  1836. cursor.endEditBlock();
  1837. goto exit;
  1838. }
  1839. V_ASSERT(to.isMovement());
  1840. // Filter out not supported movement for DELETE action.
  1841. switch (to.m_movement) {
  1842. case Movement::PageUp:
  1843. case Movement::PageDown:
  1844. case Movement::HalfPageUp:
  1845. case Movement::HalfPageDown:
  1846. return;
  1847. default:
  1848. break;
  1849. }
  1850. cursor.beginEditBlock();
  1851. hasMoved = processMovement(cursor, doc, moveMode, to, repeat);
  1852. if (repeat == -1) {
  1853. repeat = 1;
  1854. }
  1855. if (hasMoved) {
  1856. bool clearEmptyBlock = false;
  1857. switch (to.m_movement) {
  1858. case Movement::Up:
  1859. {
  1860. expandSelectionToWholeLines(cursor);
  1861. clearEmptyBlock = true;
  1862. qDebug() << "delete up" << repeat << "lines";
  1863. break;
  1864. }
  1865. case Movement::Down:
  1866. {
  1867. expandSelectionToWholeLines(cursor);
  1868. clearEmptyBlock = true;
  1869. qDebug() << "delete down" << repeat << "lines";
  1870. break;
  1871. }
  1872. case Movement::EndOfLine:
  1873. {
  1874. // End of line (block).
  1875. if (repeat > 1) {
  1876. clearEmptyBlock = true;
  1877. }
  1878. qDebug() << "delete till end of" << repeat << "line";
  1879. break;
  1880. }
  1881. case Movement::LineJump:
  1882. {
  1883. expandSelectionToWholeLines(cursor);
  1884. clearEmptyBlock = true;
  1885. qDebug() << "delete till line" << repeat;
  1886. break;
  1887. }
  1888. case Movement::StartOfDocument:
  1889. {
  1890. expandSelectionToWholeLines(cursor);
  1891. clearEmptyBlock = true;
  1892. qDebug() << "delete till start of document";
  1893. break;
  1894. }
  1895. case Movement::EndOfDocument:
  1896. {
  1897. expandSelectionToWholeLines(cursor);
  1898. clearEmptyBlock = true;
  1899. qDebug() << "delete till end of document";
  1900. break;
  1901. }
  1902. default:
  1903. break;
  1904. }
  1905. if (clearEmptyBlock) {
  1906. int nrBlock = VEditUtils::selectedBlockCount(cursor);
  1907. message(tr("%1 fewer %2").arg(nrBlock).arg(nrBlock > 1 ? tr("lines")
  1908. : tr("line")));
  1909. }
  1910. deleteSelectedText(cursor, clearEmptyBlock);
  1911. }
  1912. cursor.endEditBlock();
  1913. exit:
  1914. if (hasMoved) {
  1915. m_editor->setTextCursor(cursor);
  1916. }
  1917. }
  1918. void VVim::processCopyAction(QList<Token> &p_tokens)
  1919. {
  1920. Token to = p_tokens.takeFirst();
  1921. int repeat = -1;
  1922. if (to.isRepeat()) {
  1923. repeat = to.m_repeat;
  1924. to = p_tokens.takeFirst();
  1925. }
  1926. if ((!to.isMovement() && !to.isRange()) || !p_tokens.isEmpty()) {
  1927. p_tokens.clear();
  1928. return;
  1929. }
  1930. QTextCursor cursor = m_editor->textCursor();
  1931. QTextDocument *doc = m_editor->document();
  1932. int oriPos = cursor.position();
  1933. bool changed = false;
  1934. QTextCursor::MoveMode moveMode = QTextCursor::KeepAnchor;
  1935. if (to.isRange()) {
  1936. cursor.beginEditBlock();
  1937. changed = selectRange(cursor, doc, to.m_range, repeat);
  1938. bool around = false;
  1939. if (changed) {
  1940. switch (to.m_range) {
  1941. case Range::Line:
  1942. {
  1943. // yy, copy current line.
  1944. if (repeat == -1) {
  1945. repeat = 1;
  1946. }
  1947. if (cursor.hasSelection()) {
  1948. copySelectedText(cursor, true);
  1949. } else {
  1950. saveToRegister("\n");
  1951. }
  1952. message(tr("%1 %2 yanked").arg(repeat).arg(repeat > 1 ? tr("lines")
  1953. : tr("line")));
  1954. qDebug() << "copy" << repeat << "lines";
  1955. break;
  1956. }
  1957. case Range::WordAround:
  1958. around = true;
  1959. // Fall through.
  1960. case Range::WordInner:
  1961. {
  1962. if (cursor.hasSelection()) {
  1963. copySelectedText(cursor, false);
  1964. }
  1965. qDebug() << "copy" << (around ? "around" : "inner") << "word";
  1966. break;
  1967. }
  1968. case Range::WORDAround:
  1969. around = true;
  1970. // Fall through.
  1971. case Range::WORDInner:
  1972. {
  1973. if (cursor.hasSelection()) {
  1974. copySelectedText(cursor, false);
  1975. }
  1976. qDebug() << "copy" << (around ? "around" : "inner") << "WORD";
  1977. break;
  1978. }
  1979. default:
  1980. return;
  1981. }
  1982. }
  1983. if (cursor.position() != oriPos) {
  1984. cursor.setPosition(oriPos);
  1985. changed = true;
  1986. }
  1987. cursor.endEditBlock();
  1988. goto exit;
  1989. }
  1990. V_ASSERT(to.isMovement());
  1991. // Filter out not supported movement for DELETE action.
  1992. switch (to.m_movement) {
  1993. case Movement::PageUp:
  1994. case Movement::PageDown:
  1995. case Movement::HalfPageUp:
  1996. case Movement::HalfPageDown:
  1997. return;
  1998. default:
  1999. break;
  2000. }
  2001. cursor.beginEditBlock();
  2002. changed = processMovement(cursor, doc, moveMode, to, repeat);
  2003. if (repeat == -1) {
  2004. repeat = 1;
  2005. }
  2006. if (changed) {
  2007. bool addNewLine = false;
  2008. switch (to.m_movement) {
  2009. case Movement::Up:
  2010. {
  2011. expandSelectionToWholeLines(cursor);
  2012. addNewLine = true;
  2013. qDebug() << "copy up" << repeat << "lines";
  2014. break;
  2015. }
  2016. case Movement::Down:
  2017. {
  2018. expandSelectionToWholeLines(cursor);
  2019. addNewLine = true;
  2020. qDebug() << "copy down" << repeat << "lines";
  2021. break;
  2022. }
  2023. case Movement::EndOfLine:
  2024. {
  2025. // End of line (block).
  2026. // Do not need to add new line even if repeat > 1.
  2027. qDebug() << "copy till end of" << repeat << "line";
  2028. break;
  2029. }
  2030. case Movement::LineJump:
  2031. {
  2032. expandSelectionToWholeLines(cursor);
  2033. addNewLine = true;
  2034. qDebug() << "copy till line" << repeat;
  2035. break;
  2036. }
  2037. case Movement::StartOfDocument:
  2038. {
  2039. expandSelectionToWholeLines(cursor);
  2040. addNewLine = true;
  2041. qDebug() << "copy till start of document";
  2042. break;
  2043. }
  2044. case Movement::EndOfDocument:
  2045. {
  2046. expandSelectionToWholeLines(cursor);
  2047. addNewLine = true;
  2048. qDebug() << "copy till end of document";
  2049. break;
  2050. }
  2051. default:
  2052. break;
  2053. }
  2054. if (addNewLine) {
  2055. int nrBlock = VEditUtils::selectedBlockCount(cursor);
  2056. message(tr("%1 %2 yanked").arg(nrBlock).arg(nrBlock > 1 ? tr("lines")
  2057. : tr("line")));
  2058. }
  2059. copySelectedText(cursor, addNewLine);
  2060. if (cursor.position() != oriPos) {
  2061. cursor.setPosition(oriPos);
  2062. }
  2063. }
  2064. cursor.endEditBlock();
  2065. exit:
  2066. if (changed) {
  2067. m_editor->setTextCursor(cursor);
  2068. }
  2069. }
  2070. void VVim::processPasteAction(QList<Token> &p_tokens, bool p_pasteBefore)
  2071. {
  2072. int repeat = 1;
  2073. if (!p_tokens.isEmpty()) {
  2074. Token to = p_tokens.takeFirst();
  2075. if (!p_tokens.isEmpty() || !to.isRepeat()) {
  2076. p_tokens.clear();
  2077. return;
  2078. }
  2079. repeat = to.m_repeat;
  2080. }
  2081. Register &reg = m_registers[m_regName];
  2082. QString value = reg.read();
  2083. if (value.isEmpty()) {
  2084. return;
  2085. }
  2086. QString text;
  2087. text.reserve(repeat * value.size() + 1);
  2088. for (int i = 0; i < repeat; ++i) {
  2089. text.append(value);
  2090. }
  2091. QTextCursor cursor = m_editor->textCursor();
  2092. cursor.beginEditBlock();
  2093. if (reg.isBlock()) {
  2094. if (p_pasteBefore) {
  2095. cursor.movePosition(QTextCursor::StartOfBlock);
  2096. cursor.insertBlock();
  2097. cursor.movePosition(QTextCursor::PreviousBlock);
  2098. } else {
  2099. cursor.movePosition(QTextCursor::EndOfBlock);
  2100. cursor.insertBlock();
  2101. }
  2102. // inserBlock() already insert a new line, so eliminate one here.
  2103. cursor.insertText(text.left(text.size() - 1));
  2104. int nrBlock = text.count('\n');
  2105. if (nrBlock > 0) {
  2106. message(tr("%1 more %2").arg(nrBlock).arg(nrBlock > 1 ? tr("lines")
  2107. : tr("line")));
  2108. }
  2109. } else {
  2110. if (!p_pasteBefore && !cursor.atBlockEnd()) {
  2111. // Insert behind current cursor.
  2112. cursor.movePosition(QTextCursor::Right);
  2113. }
  2114. cursor.insertText(text);
  2115. }
  2116. cursor.endEditBlock();
  2117. m_editor->setTextCursor(cursor);
  2118. qDebug() << "text pasted" << text;
  2119. }
  2120. void VVim::processChangeAction(QList<Token> &p_tokens)
  2121. {
  2122. Token to = p_tokens.takeFirst();
  2123. int repeat = -1;
  2124. if (to.isRepeat()) {
  2125. repeat = to.m_repeat;
  2126. to = p_tokens.takeFirst();
  2127. }
  2128. if ((!to.isMovement() && !to.isRange()) || !p_tokens.isEmpty()) {
  2129. p_tokens.clear();
  2130. return;
  2131. }
  2132. QTextCursor cursor = m_editor->textCursor();
  2133. QTextDocument *doc = m_editor->document();
  2134. bool hasMoved = false;
  2135. QTextCursor::MoveMode moveMode = QTextCursor::KeepAnchor;
  2136. if (to.isRange()) {
  2137. cursor.beginEditBlock();
  2138. hasMoved = selectRange(cursor, doc, to.m_range, repeat);
  2139. bool around = false;
  2140. if (hasMoved) {
  2141. int pos = cursor.selectionStart();
  2142. switch (to.m_range) {
  2143. case Range::Line:
  2144. {
  2145. // cc, change current line.
  2146. if (repeat == -1) {
  2147. repeat = 1;
  2148. }
  2149. if (cursor.hasSelection()) {
  2150. deleteSelectedText(cursor, true);
  2151. insertChangeBlockAfterDeletion(cursor, pos);
  2152. } else {
  2153. saveToRegister("\n");
  2154. }
  2155. qDebug() << "change" << repeat << "lines";
  2156. break;
  2157. }
  2158. case Range::WordAround:
  2159. around = true;
  2160. // Fall through.
  2161. case Range::WordInner:
  2162. {
  2163. if (cursor.hasSelection()) {
  2164. deleteSelectedText(cursor, false);
  2165. } else {
  2166. saveToRegister("\n");
  2167. }
  2168. qDebug() << "delete" << (around ? "around" : "inner") << "word";
  2169. break;
  2170. }
  2171. case Range::WORDAround:
  2172. around = true;
  2173. // Fall through.
  2174. case Range::WORDInner:
  2175. {
  2176. if (cursor.hasSelection()) {
  2177. deleteSelectedText(cursor, false);
  2178. } else {
  2179. saveToRegister("\n");
  2180. }
  2181. qDebug() << "delete" << (around ? "around" : "inner") << "WORD";
  2182. break;
  2183. }
  2184. default:
  2185. return;
  2186. }
  2187. }
  2188. cursor.endEditBlock();
  2189. goto exit;
  2190. }
  2191. V_ASSERT(to.isMovement());
  2192. // Filter out not supported movement for Change action.
  2193. switch (to.m_movement) {
  2194. case Movement::PageUp:
  2195. case Movement::PageDown:
  2196. case Movement::HalfPageUp:
  2197. case Movement::HalfPageDown:
  2198. return;
  2199. default:
  2200. break;
  2201. }
  2202. cursor.beginEditBlock();
  2203. hasMoved = processMovement(cursor, doc, moveMode, to, repeat);
  2204. if (repeat == -1) {
  2205. repeat = 1;
  2206. }
  2207. if (hasMoved) {
  2208. bool clearEmptyBlock = false;
  2209. switch (to.m_movement) {
  2210. case Movement::Left:
  2211. {
  2212. qDebug() << "change backward" << repeat << "chars";
  2213. break;
  2214. }
  2215. case Movement::Right:
  2216. {
  2217. qDebug() << "change forward" << repeat << "chars";
  2218. break;
  2219. }
  2220. case Movement::Up:
  2221. {
  2222. expandSelectionToWholeLines(cursor);
  2223. clearEmptyBlock = true;
  2224. qDebug() << "change up" << repeat << "lines";
  2225. break;
  2226. }
  2227. case Movement::Down:
  2228. {
  2229. expandSelectionToWholeLines(cursor);
  2230. clearEmptyBlock = true;
  2231. qDebug() << "change down" << repeat << "lines";
  2232. break;
  2233. }
  2234. case Movement::VisualUp:
  2235. {
  2236. qDebug() << "change visual up" << repeat << "lines";
  2237. break;
  2238. }
  2239. case Movement::VisualDown:
  2240. {
  2241. qDebug() << "change visual down" << repeat << "lines";
  2242. break;
  2243. }
  2244. case Movement::StartOfLine:
  2245. {
  2246. qDebug() << "change till start of line";
  2247. break;
  2248. }
  2249. case Movement::EndOfLine:
  2250. {
  2251. // End of line (block).
  2252. if (repeat > 1) {
  2253. clearEmptyBlock = true;
  2254. }
  2255. qDebug() << "change till end of" << repeat << "line";
  2256. break;
  2257. }
  2258. case Movement::FirstCharacter:
  2259. {
  2260. qDebug() << "change till first non-space character";
  2261. break;
  2262. }
  2263. case Movement::LineJump:
  2264. {
  2265. expandSelectionToWholeLines(cursor);
  2266. clearEmptyBlock = true;
  2267. qDebug() << "change till line" << repeat;
  2268. break;
  2269. }
  2270. case Movement::StartOfDocument:
  2271. {
  2272. expandSelectionToWholeLines(cursor);
  2273. clearEmptyBlock = true;
  2274. qDebug() << "change till start of document";
  2275. break;
  2276. }
  2277. case Movement::EndOfDocument:
  2278. {
  2279. expandSelectionToWholeLines(cursor);
  2280. clearEmptyBlock = true;
  2281. qDebug() << "change till end of document";
  2282. break;
  2283. }
  2284. case Movement::WordForward:
  2285. {
  2286. qDebug() << "change" << repeat << "words forward";
  2287. break;
  2288. }
  2289. case Movement::WORDForward:
  2290. {
  2291. qDebug() << "change" << repeat << "WORDs forward";
  2292. break;
  2293. }
  2294. case Movement::ForwardEndOfWord:
  2295. {
  2296. qDebug() << "change" << repeat << "end of words forward";
  2297. break;
  2298. }
  2299. case Movement::ForwardEndOfWORD:
  2300. {
  2301. qDebug() << "change" << repeat << "end of WORDs forward";
  2302. break;
  2303. }
  2304. case Movement::WordBackward:
  2305. {
  2306. qDebug() << "change" << repeat << "words backward";
  2307. break;
  2308. }
  2309. case Movement::WORDBackward:
  2310. {
  2311. qDebug() << "change" << repeat << "WORDs backward";
  2312. break;
  2313. }
  2314. case Movement::BackwardEndOfWord:
  2315. {
  2316. qDebug() << "change" << repeat << "end of words backward";
  2317. break;
  2318. }
  2319. case Movement::BackwardEndOfWORD:
  2320. {
  2321. qDebug() << "change" << repeat << "end of WORDs backward";
  2322. break;
  2323. }
  2324. default:
  2325. break;
  2326. }
  2327. if (cursor.hasSelection()) {
  2328. int pos = cursor.selectionStart();
  2329. bool allDeleted = false;
  2330. if (pos == 0) {
  2331. QTextBlock block = m_editor->document()->lastBlock();
  2332. if (block.position() + block.length() - 1 == cursor.selectionEnd()) {
  2333. allDeleted = true;
  2334. }
  2335. }
  2336. deleteSelectedText(cursor, clearEmptyBlock);
  2337. if (clearEmptyBlock && !allDeleted) {
  2338. insertChangeBlockAfterDeletion(cursor, pos);
  2339. }
  2340. }
  2341. }
  2342. cursor.endEditBlock();
  2343. exit:
  2344. if (hasMoved) {
  2345. m_editor->setTextCursor(cursor);
  2346. }
  2347. setMode(VimMode::Insert);
  2348. }
  2349. void VVim::processIndentAction(QList<Token> &p_tokens, bool p_isIndent)
  2350. {
  2351. Token to = p_tokens.takeFirst();
  2352. int repeat = -1;
  2353. if (to.isRepeat()) {
  2354. repeat = to.m_repeat;
  2355. to = p_tokens.takeFirst();
  2356. }
  2357. if ((!to.isMovement() && !to.isRange()) || !p_tokens.isEmpty()) {
  2358. p_tokens.clear();
  2359. return;
  2360. }
  2361. QTextCursor cursor = m_editor->textCursor();
  2362. QTextDocument *doc = m_editor->document();
  2363. if (to.isRange()) {
  2364. selectRange(cursor, doc, to.m_range, repeat);
  2365. switch (to.m_range) {
  2366. case Range::Line:
  2367. {
  2368. // >>/<<, indent/unindent current line.
  2369. if (repeat == -1) {
  2370. repeat = 1;
  2371. }
  2372. VEditUtils::indentSelectedBlocks(doc,
  2373. cursor,
  2374. m_editConfig->m_tabSpaces,
  2375. p_isIndent);
  2376. if (p_isIndent) {
  2377. message(tr("%1 %2 >ed 1 time").arg(repeat).arg(repeat > 1 ? tr("lines")
  2378. : tr("line")));
  2379. } else {
  2380. message(tr("%1 %2 <ed 1 time").arg(repeat).arg(repeat > 1 ? tr("lines")
  2381. : tr("line")));
  2382. }
  2383. break;
  2384. }
  2385. case Range::WordAround:
  2386. // Fall through.
  2387. case Range::WordInner:
  2388. // Fall through.
  2389. case Range::WORDAround:
  2390. // Fall through.
  2391. case Range::WORDInner:
  2392. {
  2393. cursor.clearSelection();
  2394. VEditUtils::indentSelectedBlocks(doc,
  2395. cursor,
  2396. m_editConfig->m_tabSpaces,
  2397. p_isIndent);
  2398. break;
  2399. }
  2400. default:
  2401. return;
  2402. }
  2403. return;
  2404. }
  2405. V_ASSERT(to.isMovement());
  2406. // Filter out not supported movement for Indent/UnIndent action.
  2407. switch (to.m_movement) {
  2408. case Movement::PageUp:
  2409. case Movement::PageDown:
  2410. case Movement::HalfPageUp:
  2411. case Movement::HalfPageDown:
  2412. return;
  2413. default:
  2414. break;
  2415. }
  2416. processMovement(cursor,
  2417. doc,
  2418. QTextCursor::KeepAnchor,
  2419. to,
  2420. repeat);
  2421. int nrBlock = VEditUtils::selectedBlockCount(cursor);
  2422. if (p_isIndent) {
  2423. message(tr("%1 %2 >ed 1 time").arg(nrBlock).arg(nrBlock > 1 ? tr("lines")
  2424. : tr("line")));
  2425. } else {
  2426. message(tr("%1 %2 <ed 1 time").arg(nrBlock).arg(nrBlock > 1 ? tr("lines")
  2427. : tr("line")));
  2428. }
  2429. VEditUtils::indentSelectedBlocks(doc,
  2430. cursor,
  2431. m_editConfig->m_tabSpaces,
  2432. p_isIndent);
  2433. }
  2434. void VVim::processToLowerAction(QList<Token> &p_tokens, bool p_toLower)
  2435. {
  2436. Token to = p_tokens.takeFirst();
  2437. int repeat = -1;
  2438. if (to.isRepeat()) {
  2439. repeat = to.m_repeat;
  2440. to = p_tokens.takeFirst();
  2441. }
  2442. if ((!to.isMovement() && !to.isRange()) || !p_tokens.isEmpty()) {
  2443. p_tokens.clear();
  2444. return;
  2445. }
  2446. QTextCursor cursor = m_editor->textCursor();
  2447. QTextDocument *doc = m_editor->document();
  2448. bool changed = false;
  2449. QTextCursor::MoveMode moveMode = QTextCursor::KeepAnchor;
  2450. int oriPos = cursor.position();
  2451. if (to.isRange()) {
  2452. cursor.beginEditBlock();
  2453. changed = selectRange(cursor, doc, to.m_range, repeat);
  2454. if (changed) {
  2455. oriPos = cursor.selectionStart();
  2456. convertCaseOfSelectedText(cursor, p_toLower);
  2457. if (to.m_range == Range::Line) {
  2458. message(tr("%1 %2 changed").arg(repeat == -1 ? 1 : repeat)
  2459. .arg(repeat > 1 ? tr("lines") : tr("line")));
  2460. }
  2461. cursor.setPosition(oriPos);
  2462. }
  2463. cursor.endEditBlock();
  2464. goto exit;
  2465. }
  2466. V_ASSERT(to.isMovement());
  2467. // Filter out not supported movement for ToLower/ToUpper action.
  2468. switch (to.m_movement) {
  2469. case Movement::PageUp:
  2470. case Movement::PageDown:
  2471. case Movement::HalfPageUp:
  2472. case Movement::HalfPageDown:
  2473. return;
  2474. default:
  2475. break;
  2476. }
  2477. cursor.beginEditBlock();
  2478. changed = processMovement(cursor,
  2479. doc,
  2480. moveMode,
  2481. to,
  2482. repeat);
  2483. if (repeat == -1) {
  2484. repeat = 1;
  2485. }
  2486. if (changed) {
  2487. oriPos = cursor.selectionStart();
  2488. bool isBlock = false;
  2489. switch (to.m_movement) {
  2490. case Movement::Up:
  2491. {
  2492. isBlock = true;
  2493. expandSelectionToWholeLines(cursor);
  2494. break;
  2495. }
  2496. case Movement::Down:
  2497. {
  2498. isBlock = true;
  2499. expandSelectionToWholeLines(cursor);
  2500. break;
  2501. }
  2502. case Movement::LineJump:
  2503. {
  2504. isBlock = true;
  2505. expandSelectionToWholeLines(cursor);
  2506. break;
  2507. }
  2508. case Movement::StartOfDocument:
  2509. {
  2510. isBlock = true;
  2511. expandSelectionToWholeLines(cursor);
  2512. break;
  2513. }
  2514. case Movement::EndOfDocument:
  2515. {
  2516. isBlock = true;
  2517. expandSelectionToWholeLines(cursor);
  2518. break;
  2519. }
  2520. default:
  2521. break;
  2522. }
  2523. if (isBlock) {
  2524. int nrBlock = VEditUtils::selectedBlockCount(cursor);
  2525. message(tr("%1 %2 changed").arg(nrBlock).arg(nrBlock > 1 ? tr("lines")
  2526. : tr("line")));
  2527. }
  2528. convertCaseOfSelectedText(cursor, p_toLower);
  2529. cursor.setPosition(oriPos);
  2530. }
  2531. cursor.endEditBlock();
  2532. exit:
  2533. if (changed) {
  2534. m_editor->setTextCursor(cursor);
  2535. }
  2536. }
  2537. bool VVim::clearSelection()
  2538. {
  2539. QTextCursor cursor = m_editor->textCursor();
  2540. if (cursor.hasSelection()) {
  2541. cursor.clearSelection();
  2542. m_editor->setTextCursor(cursor);
  2543. return true;
  2544. }
  2545. return false;
  2546. }
  2547. int VVim::blockCountOfPageStep() const
  2548. {
  2549. int lineCount = m_editor->document()->blockCount();
  2550. QScrollBar *bar = m_editor->verticalScrollBar();
  2551. int steps = (bar->maximum() - bar->minimum() + bar->pageStep());
  2552. int pageLineCount = lineCount * (bar->pageStep() * 1.0 / steps);
  2553. return pageLineCount;
  2554. }
  2555. void VVim::selectionToVisualMode(bool p_hasText)
  2556. {
  2557. if (p_hasText && m_mode == VimMode::Normal) {
  2558. // Enter visual mode.
  2559. setMode(VimMode::Visual);
  2560. }
  2561. }
  2562. void VVim::expandSelectionToWholeLines(QTextCursor &p_cursor)
  2563. {
  2564. QTextDocument *doc = m_editor->document();
  2565. int curPos = p_cursor.position();
  2566. int anchorPos = p_cursor.anchor();
  2567. QTextBlock curBlock = doc->findBlock(curPos);
  2568. QTextBlock anchorBlock = doc->findBlock(anchorPos);
  2569. if (curPos >= anchorPos) {
  2570. p_cursor.setPosition(anchorBlock.position(), QTextCursor::MoveAnchor);
  2571. p_cursor.setPosition(curBlock.position() + curBlock.length() - 1,
  2572. QTextCursor::KeepAnchor);
  2573. } else {
  2574. p_cursor.setPosition(anchorBlock.position() + anchorBlock.length() - 1,
  2575. QTextCursor::MoveAnchor);
  2576. p_cursor.setPosition(curBlock.position(),
  2577. QTextCursor::KeepAnchor);
  2578. }
  2579. }
  2580. void VVim::initRegisters()
  2581. {
  2582. m_registers.clear();
  2583. for (char ch = 'a'; ch <= 'z'; ++ch) {
  2584. m_registers[QChar(ch)] = Register(QChar(ch));
  2585. }
  2586. m_registers[c_unnamedRegister] = Register(c_unnamedRegister);
  2587. m_registers[c_blackHoleRegister] = Register(c_blackHoleRegister);
  2588. m_registers[c_selectionRegister] = Register(c_selectionRegister);
  2589. }
  2590. bool VVim::expectingRegisterName() const
  2591. {
  2592. return m_keys.size() == 1
  2593. && m_keys.at(0) == Key(Qt::Key_QuoteDbl, Qt::ShiftModifier);
  2594. }
  2595. bool VVim::expectingCharacterTarget() const
  2596. {
  2597. if (m_keys.size() != 1) {
  2598. return false;
  2599. }
  2600. const Key &key = m_keys.first();
  2601. return (key == Key(Qt::Key_F, Qt::NoModifier)
  2602. || key == Key(Qt::Key_F, Qt::ShiftModifier)
  2603. || key == Key(Qt::Key_T, Qt::NoModifier)
  2604. || key == Key(Qt::Key_T, Qt::ShiftModifier));
  2605. }
  2606. QChar VVim::keyToRegisterName(const Key &p_key) const
  2607. {
  2608. if (p_key.isAlphabet()) {
  2609. return p_key.toAlphabet().toLower();
  2610. }
  2611. switch (p_key.m_key) {
  2612. case Qt::Key_QuoteDbl:
  2613. if (p_key.m_modifiers == Qt::ShiftModifier) {
  2614. return c_unnamedRegister;
  2615. }
  2616. break;
  2617. case Qt::Key_Plus:
  2618. if (p_key.m_modifiers == Qt::ShiftModifier) {
  2619. return c_selectionRegister;
  2620. }
  2621. break;
  2622. case Qt::Key_Underscore:
  2623. if (p_key.m_modifiers == Qt::ShiftModifier) {
  2624. return c_blackHoleRegister;
  2625. }
  2626. break;
  2627. default:
  2628. break;
  2629. }
  2630. return QChar();
  2631. }
  2632. bool VVim::hasActionToken() const
  2633. {
  2634. // There will be only one action token and it is placed at the front.
  2635. bool has = false;
  2636. if (m_tokens.isEmpty()) {
  2637. return false;
  2638. }
  2639. if (m_tokens.at(0).isAction()) {
  2640. has = true;
  2641. }
  2642. for (int i = 1; i < m_tokens.size(); ++i) {
  2643. V_ASSERT(!m_tokens.at(i).isAction());
  2644. }
  2645. return has;
  2646. }
  2647. bool VVim::hasActionTokenValidForTextObject() const
  2648. {
  2649. if (hasActionToken()) {
  2650. Action act = m_tokens.first().m_action;
  2651. if (act == Action::Delete
  2652. || act == Action::Copy
  2653. || act == Action::Change
  2654. || act == Action::ToLower
  2655. || act == Action::ToUpper) {
  2656. return true;
  2657. }
  2658. }
  2659. return false;
  2660. }
  2661. bool VVim::checkActionToken(Action p_action) const
  2662. {
  2663. if (hasActionToken()) {
  2664. return m_tokens.first().m_action == p_action;
  2665. }
  2666. return false;
  2667. }
  2668. bool VVim::checkPendingKey(const Key &p_key) const
  2669. {
  2670. return (m_keys.size() == 1 && m_keys.first() == p_key);
  2671. }
  2672. void VVim::tryAddMoveAction()
  2673. {
  2674. if (!hasActionToken()) {
  2675. addActionToken(Action::Move);
  2676. }
  2677. }
  2678. void VVim::addActionToken(Action p_action)
  2679. {
  2680. V_ASSERT(!hasActionToken());
  2681. m_tokens.prepend(Token(p_action));
  2682. }
  2683. const VVim::Token *VVim::getActionToken() const
  2684. {
  2685. V_ASSERT(hasActionToken());
  2686. return &m_tokens.first();
  2687. }
  2688. void VVim::addRangeToken(Range p_range)
  2689. {
  2690. m_tokens.append(Token(p_range));
  2691. }
  2692. void VVim::addMovementToken(Movement p_movement)
  2693. {
  2694. m_tokens.append(Token(p_movement));
  2695. }
  2696. void VVim::addMovementToken(Movement p_movement, Key p_key)
  2697. {
  2698. m_tokens.append(Token(p_movement, p_key));
  2699. }
  2700. void VVim::deleteSelectedText(QTextCursor &p_cursor, bool p_clearEmptyBlock)
  2701. {
  2702. if (p_cursor.hasSelection()) {
  2703. QString deletedText = VEditUtils::selectedText(p_cursor);
  2704. p_cursor.removeSelectedText();
  2705. if (p_clearEmptyBlock && p_cursor.block().length() == 1) {
  2706. deletedText += "\n";
  2707. VEditUtils::removeBlock(p_cursor);
  2708. }
  2709. saveToRegister(deletedText);
  2710. }
  2711. }
  2712. void VVim::copySelectedText(bool p_addNewLine)
  2713. {
  2714. QTextCursor cursor = m_editor->textCursor();
  2715. if (cursor.hasSelection()) {
  2716. cursor.beginEditBlock();
  2717. copySelectedText(cursor, p_addNewLine);
  2718. cursor.endEditBlock();
  2719. m_editor->setTextCursor(cursor);
  2720. }
  2721. }
  2722. void VVim::copySelectedText(QTextCursor &p_cursor, bool p_addNewLine)
  2723. {
  2724. if (p_cursor.hasSelection()) {
  2725. QString text = VEditUtils::selectedText(p_cursor);
  2726. p_cursor.clearSelection();
  2727. if (p_addNewLine) {
  2728. text += "\n";
  2729. }
  2730. saveToRegister(text);
  2731. }
  2732. }
  2733. void VVim::convertCaseOfSelectedText(QTextCursor &p_cursor, bool p_toLower)
  2734. {
  2735. if (p_cursor.hasSelection()) {
  2736. QTextDocument *doc = p_cursor.document();
  2737. int start = p_cursor.selectionStart();
  2738. int end = p_cursor.selectionEnd();
  2739. p_cursor.clearSelection();
  2740. p_cursor.setPosition(start);
  2741. int pos = p_cursor.position();
  2742. while (pos < end) {
  2743. QChar ch = doc->characterAt(pos);
  2744. bool modified = false;
  2745. if (p_toLower) {
  2746. if (ch.isUpper()) {
  2747. ch = ch.toLower();
  2748. modified = true;
  2749. }
  2750. } else if (ch.isLower()) {
  2751. ch = ch.toUpper();
  2752. modified = true;
  2753. }
  2754. if (modified) {
  2755. p_cursor.deleteChar();
  2756. p_cursor.insertText(ch);
  2757. } else {
  2758. p_cursor.movePosition(QTextCursor::NextCharacter);
  2759. }
  2760. pos = p_cursor.position();
  2761. }
  2762. }
  2763. }
  2764. void VVim::saveToRegister(const QString &p_text)
  2765. {
  2766. QString text(p_text);
  2767. VEditUtils::removeObjectReplacementCharacter(text);
  2768. qDebug() << QString("save text(%1) to register(%2)").arg(text).arg(m_regName);
  2769. Register &reg = m_registers[m_regName];
  2770. reg.update(text);
  2771. if (!reg.isBlackHoleRegister() && !reg.isUnnamedRegister()) {
  2772. // Save it to unnamed register.
  2773. m_registers[c_unnamedRegister].update(reg.m_value);
  2774. }
  2775. }
  2776. void VVim::Register::update(const QString &p_value)
  2777. {
  2778. QChar newLine('\n');
  2779. bool newIsBlock = false;
  2780. if (p_value.endsWith(newLine)) {
  2781. newIsBlock = true;
  2782. }
  2783. bool oriIsBlock = isBlock();
  2784. if (isNamedRegister() && m_append) {
  2785. // Append @p_value to m_value.
  2786. if (newIsBlock) {
  2787. if (oriIsBlock) {
  2788. m_value += p_value;
  2789. } else {
  2790. m_value.append(newLine);
  2791. m_value += p_value;
  2792. }
  2793. } else if (oriIsBlock) {
  2794. m_value += p_value;
  2795. m_value.append(newLine);
  2796. } else {
  2797. m_value += p_value;
  2798. }
  2799. } else {
  2800. // Set m_value to @p_value.
  2801. m_value = p_value;
  2802. }
  2803. if (isSelectionRegister()) {
  2804. // Change system clipboard.
  2805. QClipboard *clipboard = QApplication::clipboard();
  2806. clipboard->setText(m_value);
  2807. }
  2808. }
  2809. const QString &VVim::Register::read()
  2810. {
  2811. if (isSelectionRegister()) {
  2812. // Update from system clipboard.
  2813. QClipboard *clipboard = QApplication::clipboard();
  2814. const QMimeData *mimeData = clipboard->mimeData();
  2815. if (mimeData->hasText()) {
  2816. m_value = mimeData->text();
  2817. } else {
  2818. m_value.clear();
  2819. }
  2820. }
  2821. return m_value;
  2822. }
  2823. void VVim::repeatLastFindMovement(bool p_reverse)
  2824. {
  2825. if (!m_lastFindToken.isValid()) {
  2826. return;
  2827. }
  2828. V_ASSERT(m_lastFindToken.isMovement());
  2829. Movement mm = m_lastFindToken.m_movement;
  2830. Key key = m_lastFindToken.m_key;
  2831. V_ASSERT(key.isValid());
  2832. if (p_reverse) {
  2833. switch (mm) {
  2834. case Movement::FindForward:
  2835. mm = Movement::FindBackward;
  2836. break;
  2837. case Movement::FindBackward:
  2838. mm = Movement::FindForward;
  2839. break;
  2840. case Movement::TillForward:
  2841. mm = Movement::TillBackward;
  2842. break;
  2843. case Movement::TillBackward:
  2844. mm = Movement::TillForward;
  2845. break;
  2846. default:
  2847. break;
  2848. }
  2849. }
  2850. tryAddMoveAction();
  2851. addMovementToken(mm, key);
  2852. processCommand(m_tokens);
  2853. }
  2854. void VVim::message(const QString &p_msg)
  2855. {
  2856. qDebug() << "vim msg:" << p_msg;
  2857. emit vimMessage(p_msg);
  2858. }
  2859. const QMap<QChar, VVim::Register> &VVim::getRegisters() const
  2860. {
  2861. return m_registers;
  2862. }
  2863. QChar VVim::getCurrentRegisterName() const
  2864. {
  2865. return m_regName;
  2866. }
  2867. QString VVim::getPendingKeys() const
  2868. {
  2869. QString str;
  2870. for (auto const & key : m_pendingKeys) {
  2871. str.append(keyToChar(key.m_key, key.m_modifiers));
  2872. }
  2873. return str;
  2874. }
  2875. void VVim::setRegister(QChar p_reg)
  2876. {
  2877. m_regName = p_reg;
  2878. }