vedit.cpp 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427
  1. #include <QtWidgets>
  2. #include <QVector>
  3. #include <QDebug>
  4. #include "vedit.h"
  5. #include "vnote.h"
  6. #include "vconfigmanager.h"
  7. #include "vtableofcontent.h"
  8. #include "utils/vutils.h"
  9. #include "utils/veditutils.h"
  10. #include "utils/vmetawordmanager.h"
  11. #include "veditoperations.h"
  12. #include "vedittab.h"
  13. #include "dialog/vinsertlinkdialog.h"
  14. #include "utils/viconutils.h"
  15. extern VConfigManager *g_config;
  16. extern VNote *g_vnote;
  17. extern VMetaWordManager *g_mwMgr;
  18. VEdit::VEdit(VFile *p_file, QWidget *p_parent)
  19. : QTextEdit(p_parent), m_file(p_file),
  20. m_editOps(NULL), m_enableInputMethod(true)
  21. {
  22. const int labelTimerInterval = 500;
  23. const int extraSelectionHighlightTimer = 500;
  24. const int labelSize = 64;
  25. m_selectedWordColor = QColor(g_config->getEditorSelectedWordBg());
  26. m_searchedWordColor = QColor(g_config->getEditorSearchedWordBg());
  27. m_searchedWordCursorColor = QColor(g_config->getEditorSearchedWordCursorBg());
  28. m_incrementalSearchedWordColor = QColor(g_config->getEditorIncrementalSearchedWordBg());
  29. m_trailingSpaceColor = QColor(g_config->getEditorTrailingSpaceBg());
  30. QPixmap wrapPixmap(":/resources/icons/search_wrap.svg");
  31. m_wrapLabel = new QLabel(this);
  32. m_wrapLabel->setPixmap(wrapPixmap.scaled(labelSize, labelSize));
  33. m_wrapLabel->hide();
  34. m_labelTimer = new QTimer(this);
  35. m_labelTimer->setSingleShot(true);
  36. m_labelTimer->setInterval(labelTimerInterval);
  37. connect(m_labelTimer, &QTimer::timeout,
  38. this, &VEdit::labelTimerTimeout);
  39. m_highlightTimer = new QTimer(this);
  40. m_highlightTimer->setSingleShot(true);
  41. m_highlightTimer->setInterval(extraSelectionHighlightTimer);
  42. connect(m_highlightTimer, &QTimer::timeout,
  43. this, &VEdit::doHighlightExtraSelections);
  44. m_extraSelections.resize((int)SelectionId::MaxSelection);
  45. updateFontAndPalette();
  46. m_config.init(QFontMetrics(font()), false);
  47. updateConfig();
  48. connect(this, &VEdit::cursorPositionChanged,
  49. this, &VEdit::handleCursorPositionChanged);
  50. connect(this, &VEdit::selectionChanged,
  51. this, &VEdit::highlightSelectedWord);
  52. m_lineNumberArea = new LineNumberArea(this);
  53. connect(document(), &QTextDocument::blockCountChanged,
  54. this, &VEdit::updateLineNumberAreaMargin);
  55. connect(this, &QTextEdit::textChanged,
  56. this, &VEdit::updateLineNumberArea);
  57. connect(verticalScrollBar(), &QScrollBar::valueChanged,
  58. this, &VEdit::updateLineNumberArea);
  59. updateLineNumberAreaMargin();
  60. connect(document(), &QTextDocument::contentsChange,
  61. this, &VEdit::updateBlockLineDistanceHeight);
  62. }
  63. VEdit::~VEdit()
  64. {
  65. }
  66. void VEdit::updateConfig()
  67. {
  68. m_config.update(QFontMetrics(font()));
  69. if (m_config.m_tabStopWidth > 0) {
  70. setTabStopWidth(m_config.m_tabStopWidth);
  71. }
  72. emit configUpdated();
  73. }
  74. void VEdit::beginEdit()
  75. {
  76. updateFontAndPalette();
  77. updateConfig();
  78. setReadOnlyAndHighlight(false);
  79. setModified(false);
  80. }
  81. void VEdit::endEdit()
  82. {
  83. setReadOnlyAndHighlight(true);
  84. }
  85. void VEdit::saveFile()
  86. {
  87. Q_ASSERT(m_file->isModifiable());
  88. if (!document()->isModified()) {
  89. return;
  90. }
  91. m_file->setContent(toHtml());
  92. setModified(false);
  93. }
  94. void VEdit::reloadFile()
  95. {
  96. setHtml(m_file->getContent());
  97. setModified(false);
  98. }
  99. bool VEdit::scrollToBlock(int p_blockNumber)
  100. {
  101. QTextBlock block = document()->findBlockByNumber(p_blockNumber);
  102. if (block.isValid()) {
  103. VEditUtils::scrollBlockInPage(this, block.blockNumber(), 0);
  104. moveCursor(QTextCursor::EndOfBlock);
  105. return true;
  106. }
  107. return false;
  108. }
  109. bool VEdit::isModified() const
  110. {
  111. return document()->isModified();
  112. }
  113. void VEdit::setModified(bool p_modified)
  114. {
  115. document()->setModified(p_modified);
  116. }
  117. void VEdit::insertImage()
  118. {
  119. if (m_editOps) {
  120. m_editOps->insertImage();
  121. }
  122. }
  123. void VEdit::insertLink()
  124. {
  125. if (!m_editOps) {
  126. return;
  127. }
  128. QString text;
  129. QString linkText, linkUrl;
  130. QTextCursor cursor = textCursor();
  131. if (cursor.hasSelection()) {
  132. text = VEditUtils::selectedText(cursor).trimmed();
  133. // Only pure space is accepted.
  134. QRegExp reg("[\\S ]*");
  135. if (reg.exactMatch(text)) {
  136. QUrl url = QUrl::fromUserInput(text,
  137. m_file->fetchBasePath());
  138. QRegExp urlReg("[\\.\\\\/]");
  139. if (url.isValid()
  140. && text.contains(urlReg)) {
  141. // Url.
  142. linkUrl = text;
  143. } else {
  144. // Text.
  145. linkText = text;
  146. }
  147. }
  148. }
  149. VInsertLinkDialog dialog(tr("Insert Link"),
  150. "",
  151. "",
  152. linkText,
  153. linkUrl,
  154. this);
  155. if (dialog.exec() == QDialog::Accepted) {
  156. linkText = dialog.getLinkText();
  157. linkUrl = dialog.getLinkUrl();
  158. Q_ASSERT(!linkText.isEmpty() && !linkUrl.isEmpty());
  159. m_editOps->insertLink(linkText, linkUrl);
  160. }
  161. }
  162. bool VEdit::peekText(const QString &p_text, uint p_options, bool p_forward)
  163. {
  164. if (p_text.isEmpty()) {
  165. makeBlockVisible(document()->findBlock(textCursor().selectionStart()));
  166. highlightIncrementalSearchedWord(QTextCursor());
  167. return false;
  168. }
  169. bool wrapped = false;
  170. QTextCursor retCursor;
  171. bool found = findTextHelper(p_text, p_options, p_forward,
  172. p_forward ? textCursor().position() + 1
  173. : textCursor().position(),
  174. wrapped, retCursor);
  175. if (found) {
  176. makeBlockVisible(document()->findBlock(retCursor.selectionStart()));
  177. highlightIncrementalSearchedWord(retCursor);
  178. }
  179. return found;
  180. }
  181. // Use QTextEdit::find() instead of QTextDocument::find() because the later has
  182. // bugs in searching backward.
  183. bool VEdit::findTextHelper(const QString &p_text, uint p_options,
  184. bool p_forward, int p_start,
  185. bool &p_wrapped, QTextCursor &p_cursor)
  186. {
  187. p_wrapped = false;
  188. bool found = false;
  189. // Options
  190. QTextDocument::FindFlags findFlags;
  191. bool caseSensitive = false;
  192. if (p_options & FindOption::CaseSensitive) {
  193. findFlags |= QTextDocument::FindCaseSensitively;
  194. caseSensitive = true;
  195. }
  196. if (p_options & FindOption::WholeWordOnly) {
  197. findFlags |= QTextDocument::FindWholeWords;
  198. }
  199. if (!p_forward) {
  200. findFlags |= QTextDocument::FindBackward;
  201. }
  202. // Use regular expression
  203. bool useRegExp = false;
  204. QRegExp exp;
  205. if (p_options & FindOption::RegularExpression) {
  206. useRegExp = true;
  207. exp = QRegExp(p_text,
  208. caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive);
  209. }
  210. // Store current state of the cursor.
  211. QTextCursor cursor = textCursor();
  212. if (cursor.position() != p_start) {
  213. if (p_start < 0) {
  214. p_start = 0;
  215. } else if (p_start > document()->characterCount()) {
  216. p_start = document()->characterCount();
  217. }
  218. QTextCursor startCursor = cursor;
  219. startCursor.setPosition(p_start);
  220. setTextCursor(startCursor);
  221. }
  222. while (!found) {
  223. if (useRegExp) {
  224. found = find(exp, findFlags);
  225. } else {
  226. found = find(p_text, findFlags);
  227. }
  228. if (p_wrapped) {
  229. break;
  230. }
  231. if (!found) {
  232. // Wrap to the other end of the document to search again.
  233. p_wrapped = true;
  234. QTextCursor wrapCursor = textCursor();
  235. if (p_forward) {
  236. wrapCursor.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor);
  237. } else {
  238. wrapCursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
  239. }
  240. setTextCursor(wrapCursor);
  241. }
  242. }
  243. if (found) {
  244. p_cursor = textCursor();
  245. }
  246. // Restore the original cursor.
  247. setTextCursor(cursor);
  248. return found;
  249. }
  250. QList<QTextCursor> VEdit::findTextAll(const QString &p_text, uint p_options)
  251. {
  252. QList<QTextCursor> results;
  253. if (p_text.isEmpty()) {
  254. return results;
  255. }
  256. // Options
  257. QTextDocument::FindFlags findFlags;
  258. bool caseSensitive = false;
  259. if (p_options & FindOption::CaseSensitive) {
  260. findFlags |= QTextDocument::FindCaseSensitively;
  261. caseSensitive = true;
  262. }
  263. if (p_options & FindOption::WholeWordOnly) {
  264. findFlags |= QTextDocument::FindWholeWords;
  265. }
  266. // Use regular expression
  267. bool useRegExp = false;
  268. QRegExp exp;
  269. if (p_options & FindOption::RegularExpression) {
  270. useRegExp = true;
  271. exp = QRegExp(p_text,
  272. caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive);
  273. }
  274. int startPos = 0;
  275. QTextCursor cursor;
  276. QTextDocument *doc = document();
  277. while (true) {
  278. if (useRegExp) {
  279. cursor = doc->find(exp, startPos, findFlags);
  280. } else {
  281. cursor = doc->find(p_text, startPos, findFlags);
  282. }
  283. if (cursor.isNull()) {
  284. break;
  285. } else {
  286. results.append(cursor);
  287. startPos = cursor.selectionEnd();
  288. }
  289. }
  290. return results;
  291. }
  292. bool VEdit::findText(const QString &p_text, uint p_options, bool p_forward,
  293. QTextCursor *p_cursor, QTextCursor::MoveMode p_moveMode)
  294. {
  295. clearIncrementalSearchedWordHighlight();
  296. if (p_text.isEmpty()) {
  297. clearSearchedWordHighlight();
  298. return false;
  299. }
  300. QTextCursor cursor = textCursor();
  301. bool wrapped = false;
  302. QTextCursor retCursor;
  303. int matches = 0;
  304. int start = p_forward ? cursor.position() + 1 : cursor.position();
  305. if (p_cursor) {
  306. start = p_forward ? p_cursor->position() + 1 : p_cursor->position();
  307. }
  308. bool found = findTextHelper(p_text, p_options, p_forward, start,
  309. wrapped, retCursor);
  310. if (found) {
  311. Q_ASSERT(!retCursor.isNull());
  312. if (wrapped) {
  313. showWrapLabel();
  314. }
  315. if (p_cursor) {
  316. p_cursor->setPosition(retCursor.selectionStart(), p_moveMode);
  317. } else {
  318. cursor.setPosition(retCursor.selectionStart(), p_moveMode);
  319. setTextCursor(cursor);
  320. }
  321. highlightSearchedWord(p_text, p_options);
  322. highlightSearchedWordUnderCursor(retCursor);
  323. matches = m_extraSelections[(int)SelectionId::SearchedKeyword].size();
  324. } else {
  325. clearSearchedWordHighlight();
  326. }
  327. if (matches == 0) {
  328. statusMessage(tr("Found no match"));
  329. } else {
  330. statusMessage(tr("Found %1 %2").arg(matches)
  331. .arg(matches > 1 ? tr("matches") : tr("match")));
  332. }
  333. return found;
  334. }
  335. void VEdit::replaceText(const QString &p_text, uint p_options,
  336. const QString &p_replaceText, bool p_findNext)
  337. {
  338. QTextCursor cursor = textCursor();
  339. bool wrapped = false;
  340. QTextCursor retCursor;
  341. bool found = findTextHelper(p_text, p_options, true,
  342. cursor.position(), wrapped, retCursor);
  343. if (found) {
  344. if (retCursor.selectionStart() == cursor.position()) {
  345. // Matched.
  346. retCursor.beginEditBlock();
  347. retCursor.insertText(p_replaceText);
  348. retCursor.endEditBlock();
  349. setTextCursor(retCursor);
  350. }
  351. if (p_findNext) {
  352. findText(p_text, p_options, true);
  353. }
  354. }
  355. }
  356. void VEdit::replaceTextAll(const QString &p_text, uint p_options,
  357. const QString &p_replaceText)
  358. {
  359. // Replace from the start to the end and restore the cursor.
  360. QTextCursor cursor = textCursor();
  361. int nrReplaces = 0;
  362. QTextCursor tmpCursor = cursor;
  363. tmpCursor.setPosition(0);
  364. setTextCursor(tmpCursor);
  365. int start = tmpCursor.position();
  366. while (true) {
  367. bool wrapped = false;
  368. QTextCursor retCursor;
  369. bool found = findTextHelper(p_text, p_options, true,
  370. start, wrapped, retCursor);
  371. if (!found) {
  372. break;
  373. } else {
  374. if (wrapped) {
  375. // Wrap back.
  376. break;
  377. }
  378. nrReplaces++;
  379. retCursor.beginEditBlock();
  380. retCursor.insertText(p_replaceText);
  381. retCursor.endEditBlock();
  382. setTextCursor(retCursor);
  383. start = retCursor.position();
  384. }
  385. }
  386. // Restore cursor position.
  387. cursor.clearSelection();
  388. setTextCursor(cursor);
  389. qDebug() << "replace all" << nrReplaces << "occurences";
  390. emit statusMessage(tr("Replace %1 %2").arg(nrReplaces)
  391. .arg(nrReplaces > 1 ? tr("occurences")
  392. : tr("occurence")));
  393. }
  394. void VEdit::showWrapLabel()
  395. {
  396. int labelW = m_wrapLabel->width();
  397. int labelH = m_wrapLabel->height();
  398. int x = (width() - labelW) / 2;
  399. int y = (height() - labelH) / 2;
  400. if (x < 0) {
  401. x = 0;
  402. }
  403. if (y < 0) {
  404. y = 0;
  405. }
  406. m_wrapLabel->move(x, y);
  407. m_wrapLabel->show();
  408. m_labelTimer->stop();
  409. m_labelTimer->start();
  410. }
  411. void VEdit::labelTimerTimeout()
  412. {
  413. m_wrapLabel->hide();
  414. }
  415. void VEdit::updateFontAndPalette()
  416. {
  417. setFont(g_config->getBaseEditFont());
  418. setPalette(g_config->getBaseEditPalette());
  419. }
  420. void VEdit::highlightExtraSelections(bool p_now)
  421. {
  422. m_highlightTimer->stop();
  423. if (p_now) {
  424. doHighlightExtraSelections();
  425. } else {
  426. m_highlightTimer->start();
  427. }
  428. }
  429. void VEdit::doHighlightExtraSelections()
  430. {
  431. int nrExtra = m_extraSelections.size();
  432. Q_ASSERT(nrExtra == (int)SelectionId::MaxSelection);
  433. QList<QTextEdit::ExtraSelection> extraSelects;
  434. for (int i = 0; i < nrExtra; ++i) {
  435. extraSelects.append(m_extraSelections[i]);
  436. }
  437. setExtraSelections(extraSelects);
  438. }
  439. void VEdit::highlightCurrentLine()
  440. {
  441. QList<QTextEdit::ExtraSelection> &selects = m_extraSelections[(int)SelectionId::CurrentLine];
  442. if (g_config->getHighlightCursorLine() && !isReadOnly()) {
  443. // Need to highlight current line.
  444. selects.clear();
  445. // A long block maybe splited into multiple visual lines.
  446. QTextEdit::ExtraSelection select;
  447. select.format.setBackground(m_config.m_cursorLineBg);
  448. select.format.setProperty(QTextFormat::FullWidthSelection, true);
  449. QTextCursor cursor = textCursor();
  450. if (m_config.m_highlightWholeBlock) {
  451. cursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::MoveAnchor, 1);
  452. QTextBlock block = cursor.block();
  453. int blockEnd = block.position() + block.length();
  454. int pos = -1;
  455. while (cursor.position() < blockEnd && pos != cursor.position()) {
  456. QTextEdit::ExtraSelection newSelect = select;
  457. newSelect.cursor = cursor;
  458. selects.append(newSelect);
  459. pos = cursor.position();
  460. cursor.movePosition(QTextCursor::Down, QTextCursor::MoveAnchor, 1);
  461. }
  462. } else {
  463. cursor.clearSelection();
  464. select.cursor = cursor;
  465. selects.append(select);
  466. }
  467. } else {
  468. // Need to clear current line highlight.
  469. if (selects.isEmpty()) {
  470. return;
  471. }
  472. selects.clear();
  473. }
  474. highlightExtraSelections(true);
  475. }
  476. void VEdit::highlightSelectedWord()
  477. {
  478. QList<QTextEdit::ExtraSelection> &selects = m_extraSelections[(int)SelectionId::SelectedWord];
  479. if (!g_config->getHighlightSelectedWord()) {
  480. if (!selects.isEmpty()) {
  481. selects.clear();
  482. highlightExtraSelections(true);
  483. }
  484. return;
  485. }
  486. QString text = textCursor().selectedText().trimmed();
  487. if (text.isEmpty() || wordInSearchedSelection(text)) {
  488. selects.clear();
  489. highlightExtraSelections(true);
  490. return;
  491. }
  492. QTextCharFormat format;
  493. format.setBackground(m_selectedWordColor);
  494. highlightTextAll(text, FindOption::CaseSensitive, SelectionId::SelectedWord,
  495. format);
  496. }
  497. // Do not highlight trailing spaces with current cursor right behind.
  498. static void trailingSpaceFilter(VEdit *p_editor, QList<QTextEdit::ExtraSelection> &p_result)
  499. {
  500. QTextCursor cursor = p_editor->textCursor();
  501. if (!cursor.atBlockEnd()) {
  502. return;
  503. }
  504. int cursorPos = cursor.position();
  505. for (auto it = p_result.begin(); it != p_result.end(); ++it) {
  506. if (it->cursor.selectionEnd() == cursorPos) {
  507. p_result.erase(it);
  508. // There will be only one.
  509. return;
  510. }
  511. }
  512. }
  513. void VEdit::highlightTrailingSpace()
  514. {
  515. if (!g_config->getEnableTrailingSpaceHighlight()) {
  516. QList<QTextEdit::ExtraSelection> &selects = m_extraSelections[(int)SelectionId::TrailingSapce];
  517. if (!selects.isEmpty()) {
  518. selects.clear();
  519. highlightExtraSelections(true);
  520. }
  521. return;
  522. }
  523. QTextCharFormat format;
  524. format.setBackground(m_trailingSpaceColor);
  525. QString text("\\s+$");
  526. highlightTextAll(text, FindOption::RegularExpression,
  527. SelectionId::TrailingSapce, format,
  528. trailingSpaceFilter);
  529. }
  530. bool VEdit::wordInSearchedSelection(const QString &p_text)
  531. {
  532. QString text = p_text.trimmed();
  533. QList<QTextEdit::ExtraSelection> &selects = m_extraSelections[(int)SelectionId::SearchedKeyword];
  534. for (int i = 0; i < selects.size(); ++i) {
  535. QString searchedWord = selects[i].cursor.selectedText();
  536. if (text == searchedWord.trimmed()) {
  537. return true;
  538. }
  539. }
  540. return false;
  541. }
  542. void VEdit::highlightTextAll(const QString &p_text, uint p_options,
  543. SelectionId p_id, QTextCharFormat p_format,
  544. void (*p_filter)(VEdit *, QList<QTextEdit::ExtraSelection> &))
  545. {
  546. QList<QTextEdit::ExtraSelection> &selects = m_extraSelections[(int)p_id];
  547. if (!p_text.isEmpty()) {
  548. selects.clear();
  549. QList<QTextCursor> occurs = findTextAll(p_text, p_options);
  550. for (int i = 0; i < occurs.size(); ++i) {
  551. QTextEdit::ExtraSelection select;
  552. select.format = p_format;
  553. select.cursor = occurs[i];
  554. selects.append(select);
  555. }
  556. } else {
  557. if (selects.isEmpty()) {
  558. return;
  559. }
  560. selects.clear();
  561. }
  562. if (p_filter) {
  563. p_filter(this, selects);
  564. }
  565. highlightExtraSelections();
  566. }
  567. void VEdit::highlightSearchedWord(const QString &p_text, uint p_options)
  568. {
  569. QList<QTextEdit::ExtraSelection> &selects = m_extraSelections[(int)SelectionId::SearchedKeyword];
  570. if (!g_config->getHighlightSearchedWord() || p_text.isEmpty()) {
  571. if (!selects.isEmpty()) {
  572. selects.clear();
  573. highlightExtraSelections(true);
  574. }
  575. return;
  576. }
  577. QTextCharFormat format;
  578. format.setBackground(m_searchedWordColor);
  579. highlightTextAll(p_text, p_options, SelectionId::SearchedKeyword, format);
  580. }
  581. void VEdit::highlightSearchedWordUnderCursor(const QTextCursor &p_cursor)
  582. {
  583. QList<QTextEdit::ExtraSelection> &selects = m_extraSelections[(int)SelectionId::SearchedKeywordUnderCursor];
  584. if (!p_cursor.hasSelection()) {
  585. if (!selects.isEmpty()) {
  586. selects.clear();
  587. highlightExtraSelections(true);
  588. }
  589. return;
  590. }
  591. selects.clear();
  592. QTextEdit::ExtraSelection select;
  593. select.format.setBackground(m_searchedWordCursorColor);
  594. select.cursor = p_cursor;
  595. selects.append(select);
  596. highlightExtraSelections(true);
  597. }
  598. void VEdit::highlightIncrementalSearchedWord(const QTextCursor &p_cursor)
  599. {
  600. QList<QTextEdit::ExtraSelection> &selects = m_extraSelections[(int)SelectionId::IncrementalSearchedKeyword];
  601. if (!g_config->getHighlightSearchedWord() || !p_cursor.hasSelection()) {
  602. if (!selects.isEmpty()) {
  603. selects.clear();
  604. highlightExtraSelections(true);
  605. }
  606. return;
  607. }
  608. selects.clear();
  609. QTextEdit::ExtraSelection select;
  610. select.format.setBackground(m_incrementalSearchedWordColor);
  611. select.cursor = p_cursor;
  612. selects.append(select);
  613. highlightExtraSelections(true);
  614. }
  615. void VEdit::clearSearchedWordHighlight()
  616. {
  617. clearIncrementalSearchedWordHighlight(false);
  618. clearSearchedWordUnderCursorHighlight(false);
  619. QList<QTextEdit::ExtraSelection> &selects = m_extraSelections[(int)SelectionId::SearchedKeyword];
  620. if (selects.isEmpty()) {
  621. return;
  622. }
  623. selects.clear();
  624. highlightExtraSelections(true);
  625. }
  626. void VEdit::clearSearchedWordUnderCursorHighlight(bool p_now)
  627. {
  628. QList<QTextEdit::ExtraSelection> &selects = m_extraSelections[(int)SelectionId::SearchedKeywordUnderCursor];
  629. if (selects.isEmpty()) {
  630. return;
  631. }
  632. selects.clear();
  633. highlightExtraSelections(p_now);
  634. }
  635. void VEdit::clearIncrementalSearchedWordHighlight(bool p_now)
  636. {
  637. QList<QTextEdit::ExtraSelection> &selects = m_extraSelections[(int)SelectionId::IncrementalSearchedKeyword];
  638. if (selects.isEmpty()) {
  639. return;
  640. }
  641. selects.clear();
  642. highlightExtraSelections(p_now);
  643. }
  644. void VEdit::contextMenuEvent(QContextMenuEvent *p_event)
  645. {
  646. QMenu *menu = createStandardContextMenu();
  647. menu->setToolTipsVisible(true);
  648. const QList<QAction *> actions = menu->actions();
  649. if (!textCursor().hasSelection()) {
  650. VEditTab *editTab = dynamic_cast<VEditTab *>(parent());
  651. V_ASSERT(editTab);
  652. if (editTab->isEditMode()) {
  653. QAction *saveExitAct = new QAction(VIconUtils::menuIcon(":/resources/icons/save_exit.svg"),
  654. tr("&Save Changes And Read"), this);
  655. saveExitAct->setToolTip(tr("Save changes and exit edit mode"));
  656. connect(saveExitAct, &QAction::triggered,
  657. this, &VEdit::handleSaveExitAct);
  658. QAction *discardExitAct = new QAction(VIconUtils::menuIcon(":/resources/icons/discard_exit.svg"),
  659. tr("&Discard Changes And Read"), this);
  660. discardExitAct->setToolTip(tr("Discard changes and exit edit mode"));
  661. connect(discardExitAct, &QAction::triggered,
  662. this, &VEdit::handleDiscardExitAct);
  663. menu->insertAction(actions.isEmpty() ? NULL : actions[0], discardExitAct);
  664. menu->insertAction(discardExitAct, saveExitAct);
  665. if (!actions.isEmpty()) {
  666. menu->insertSeparator(actions[0]);
  667. }
  668. } else if (m_file->isModifiable()) {
  669. // HTML.
  670. QAction *editAct= new QAction(VIconUtils::menuIcon(":/resources/icons/edit_note.svg"),
  671. tr("&Edit"), this);
  672. editAct->setToolTip(tr("Edit current note"));
  673. connect(editAct, &QAction::triggered,
  674. this, &VEdit::handleEditAct);
  675. menu->insertAction(actions.isEmpty() ? NULL : actions[0], editAct);
  676. // actions does not contain editAction.
  677. if (!actions.isEmpty()) {
  678. menu->insertSeparator(actions[0]);
  679. }
  680. }
  681. }
  682. alterContextMenu(menu, actions);
  683. menu->exec(p_event->globalPos());
  684. delete menu;
  685. }
  686. void VEdit::handleSaveExitAct()
  687. {
  688. emit saveAndRead();
  689. }
  690. void VEdit::handleDiscardExitAct()
  691. {
  692. emit discardAndRead();
  693. }
  694. void VEdit::handleEditAct()
  695. {
  696. emit editNote();
  697. }
  698. VFile *VEdit::getFile() const
  699. {
  700. return m_file;
  701. }
  702. void VEdit::handleCursorPositionChanged()
  703. {
  704. static QTextCursor lastCursor;
  705. QTextCursor cursor = textCursor();
  706. if (lastCursor.isNull() || cursor.blockNumber() != lastCursor.blockNumber()) {
  707. highlightCurrentLine();
  708. highlightTrailingSpace();
  709. } else {
  710. // Judge whether we have trailing space at current line.
  711. QString text = cursor.block().text();
  712. if (text.rbegin()->isSpace()) {
  713. highlightTrailingSpace();
  714. }
  715. // Handle word-wrap in one block.
  716. // Highlight current line if in different visual line.
  717. if ((lastCursor.positionInBlock() - lastCursor.columnNumber()) !=
  718. (cursor.positionInBlock() - cursor.columnNumber())) {
  719. highlightCurrentLine();
  720. }
  721. }
  722. lastCursor = cursor;
  723. }
  724. VEditConfig &VEdit::getConfig()
  725. {
  726. return m_config;
  727. }
  728. void VEdit::mousePressEvent(QMouseEvent *p_event)
  729. {
  730. if (p_event->button() == Qt::LeftButton
  731. && p_event->modifiers() == Qt::ControlModifier
  732. && !textCursor().hasSelection()) {
  733. m_oriMouseX = p_event->x();
  734. m_oriMouseY = p_event->y();
  735. m_readyToScroll = true;
  736. m_mouseMoveScrolled = false;
  737. p_event->accept();
  738. return;
  739. }
  740. m_readyToScroll = false;
  741. m_mouseMoveScrolled = false;
  742. QTextEdit::mousePressEvent(p_event);
  743. emit selectionChangedByMouse(textCursor().hasSelection());
  744. }
  745. void VEdit::mouseReleaseEvent(QMouseEvent *p_event)
  746. {
  747. if (m_mouseMoveScrolled || m_readyToScroll) {
  748. viewport()->setCursor(Qt::IBeamCursor);
  749. m_readyToScroll = false;
  750. m_mouseMoveScrolled = false;
  751. p_event->accept();
  752. return;
  753. }
  754. m_readyToScroll = false;
  755. m_mouseMoveScrolled = false;
  756. QTextEdit::mouseReleaseEvent(p_event);
  757. }
  758. void VEdit::mouseMoveEvent(QMouseEvent *p_event)
  759. {
  760. const int threshold = 5;
  761. if (m_readyToScroll) {
  762. int deltaX = p_event->x() - m_oriMouseX;
  763. int deltaY = p_event->y() - m_oriMouseY;
  764. if (qAbs(deltaX) >= threshold || qAbs(deltaY) >= threshold) {
  765. m_oriMouseX = p_event->x();
  766. m_oriMouseY = p_event->y();
  767. if (!m_mouseMoveScrolled) {
  768. m_mouseMoveScrolled = true;
  769. viewport()->setCursor(Qt::SizeAllCursor);
  770. }
  771. QScrollBar *verBar = verticalScrollBar();
  772. QScrollBar *horBar = horizontalScrollBar();
  773. if (verBar->isVisible()) {
  774. verBar->setValue(verBar->value() - deltaY);
  775. }
  776. if (horBar->isVisible()) {
  777. horBar->setValue(horBar->value() - deltaX);
  778. }
  779. }
  780. p_event->accept();
  781. return;
  782. }
  783. QTextEdit::mouseMoveEvent(p_event);
  784. emit selectionChangedByMouse(textCursor().hasSelection());
  785. }
  786. void VEdit::requestUpdateVimStatus()
  787. {
  788. if (m_editOps) {
  789. m_editOps->requestUpdateVimStatus();
  790. } else {
  791. emit vimStatusUpdated(NULL);
  792. }
  793. }
  794. bool VEdit::jumpTitle(bool p_forward, int p_relativeLevel, int p_repeat)
  795. {
  796. Q_UNUSED(p_forward);
  797. Q_UNUSED(p_relativeLevel);
  798. Q_UNUSED(p_repeat);
  799. return false;
  800. }
  801. QVariant VEdit::inputMethodQuery(Qt::InputMethodQuery p_query) const
  802. {
  803. if (p_query == Qt::ImEnabled) {
  804. return m_enableInputMethod;
  805. }
  806. return QTextEdit::inputMethodQuery(p_query);
  807. }
  808. void VEdit::setInputMethodEnabled(bool p_enabled)
  809. {
  810. if (m_enableInputMethod != p_enabled) {
  811. m_enableInputMethod = p_enabled;
  812. QInputMethod *im = QGuiApplication::inputMethod();
  813. im->reset();
  814. // Ask input method to query current state, which will call inputMethodQuery().
  815. im->update(Qt::ImEnabled);
  816. }
  817. }
  818. void VEdit::decorateText(TextDecoration p_decoration)
  819. {
  820. if (m_editOps) {
  821. m_editOps->decorateText(p_decoration);
  822. }
  823. }
  824. void VEdit::updateLineNumberAreaMargin()
  825. {
  826. int width = 0;
  827. if (g_config->getEditorLineNumber()) {
  828. width = m_lineNumberArea->calculateWidth();
  829. }
  830. setViewportMargins(width, 0, 0, 0);
  831. }
  832. void VEdit::updateLineNumberArea()
  833. {
  834. if (g_config->getEditorLineNumber()) {
  835. if (!m_lineNumberArea->isVisible()) {
  836. updateLineNumberAreaMargin();
  837. m_lineNumberArea->show();
  838. }
  839. m_lineNumberArea->update();
  840. } else if (m_lineNumberArea->isVisible()) {
  841. updateLineNumberAreaMargin();
  842. m_lineNumberArea->hide();
  843. }
  844. }
  845. void VEdit::resizeEvent(QResizeEvent *p_event)
  846. {
  847. QTextEdit::resizeEvent(p_event);
  848. if (g_config->getEditorLineNumber()) {
  849. QRect rect = contentsRect();
  850. m_lineNumberArea->setGeometry(QRect(rect.left(),
  851. rect.top(),
  852. m_lineNumberArea->calculateWidth(),
  853. rect.height()));
  854. }
  855. }
  856. void VEdit::lineNumberAreaPaintEvent(QPaintEvent *p_event)
  857. {
  858. int lineNumberType = g_config->getEditorLineNumber();
  859. if (!lineNumberType) {
  860. updateLineNumberAreaMargin();
  861. m_lineNumberArea->hide();
  862. return;
  863. }
  864. QPainter painter(m_lineNumberArea);
  865. painter.fillRect(p_event->rect(), g_config->getEditorLineNumberBg());
  866. QAbstractTextDocumentLayout *layout = document()->documentLayout();
  867. QTextBlock block = firstVisibleBlock();
  868. if (!block.isValid()) {
  869. return;
  870. }
  871. int blockNumber = block.blockNumber();
  872. int offsetY = contentOffsetY();
  873. QRectF rect = layout->blockBoundingRect(block);
  874. int top = offsetY + (int)rect.y();
  875. int bottom = top + (int)rect.height();
  876. int eventTop = p_event->rect().top();
  877. int eventBtm = p_event->rect().bottom();
  878. const int digitHeight = m_lineNumberArea->getDigitHeight();
  879. const int curBlockNumber = textCursor().block().blockNumber();
  880. const QString &fg = g_config->getEditorLineNumberFg();
  881. const int lineDistanceHeight = m_config.m_lineDistanceHeight;
  882. painter.setPen(fg);
  883. // Display line number only in code block.
  884. if (lineNumberType == 3) {
  885. if (m_file->getDocType() != DocType::Markdown) {
  886. return;
  887. }
  888. int number = 0;
  889. while (block.isValid() && top <= eventBtm) {
  890. int blockState = block.userState();
  891. switch (blockState) {
  892. case HighlightBlockState::CodeBlockStart:
  893. Q_ASSERT(number == 0);
  894. number = 1;
  895. break;
  896. case HighlightBlockState::CodeBlockEnd:
  897. number = 0;
  898. break;
  899. case HighlightBlockState::CodeBlock:
  900. if (number == 0) {
  901. // Need to find current line number in code block.
  902. QTextBlock startBlock = block.previous();
  903. while (startBlock.isValid()) {
  904. if (startBlock.userState() == HighlightBlockState::CodeBlockStart) {
  905. number = block.blockNumber() - startBlock.blockNumber();
  906. break;
  907. }
  908. startBlock = startBlock.previous();
  909. }
  910. }
  911. break;
  912. default:
  913. break;
  914. }
  915. if (blockState == HighlightBlockState::CodeBlock) {
  916. if (block.isVisible() && bottom >= eventTop) {
  917. QString numberStr = QString::number(number);
  918. painter.drawText(0,
  919. top + 2,
  920. m_lineNumberArea->width(),
  921. digitHeight,
  922. Qt::AlignRight,
  923. numberStr);
  924. }
  925. ++number;
  926. }
  927. block = block.next();
  928. top = bottom;
  929. bottom = top + (int)layout->blockBoundingRect(block).height() + lineDistanceHeight;
  930. }
  931. return;
  932. }
  933. // Handle lineNumberType 1 and 2.
  934. Q_ASSERT(lineNumberType == 1 || lineNumberType == 2);
  935. while (block.isValid() && top <= eventBtm) {
  936. if (block.isVisible() && bottom >= eventTop) {
  937. bool currentLine = false;
  938. int number = blockNumber + 1;
  939. if (lineNumberType == 2) {
  940. number = blockNumber - curBlockNumber;
  941. if (number == 0) {
  942. currentLine = true;
  943. number = blockNumber + 1;
  944. } else if (number < 0) {
  945. number = -number;
  946. }
  947. } else if (blockNumber == curBlockNumber) {
  948. currentLine = true;
  949. }
  950. QString numberStr = QString::number(number);
  951. if (currentLine) {
  952. QFont font = painter.font();
  953. font.setBold(true);
  954. painter.setFont(font);
  955. }
  956. painter.drawText(0,
  957. top + 2,
  958. m_lineNumberArea->width(),
  959. digitHeight,
  960. Qt::AlignRight,
  961. numberStr);
  962. if (currentLine) {
  963. QFont font = painter.font();
  964. font.setBold(false);
  965. painter.setFont(font);
  966. }
  967. }
  968. block = block.next();
  969. top = bottom;
  970. bottom = top + (int)layout->blockBoundingRect(block).height() + lineDistanceHeight;
  971. ++blockNumber;
  972. }
  973. }
  974. int VEdit::contentOffsetY()
  975. {
  976. int offsety = 0;
  977. QScrollBar *sb = verticalScrollBar();
  978. offsety = sb->value();
  979. return -offsety;
  980. }
  981. QTextBlock VEdit::firstVisibleBlock()
  982. {
  983. QTextDocument *doc = document();
  984. QAbstractTextDocumentLayout *layout = doc->documentLayout();
  985. int offsetY = contentOffsetY();
  986. // Binary search.
  987. int idx = -1;
  988. int start = 0, end = doc->blockCount() - 1;
  989. while (start <= end) {
  990. int mid = start + (end - start) / 2;
  991. QTextBlock block = doc->findBlockByNumber(mid);
  992. if (!block.isValid()) {
  993. break;
  994. }
  995. int y = offsetY + (int)layout->blockBoundingRect(block).y();
  996. if (y == 0) {
  997. return block;
  998. } else if (y < 0) {
  999. start = mid + 1;
  1000. } else {
  1001. if (idx == -1 || mid < idx) {
  1002. idx = mid;
  1003. }
  1004. end = mid - 1;
  1005. }
  1006. }
  1007. if (idx != -1) {
  1008. return doc->findBlockByNumber(idx);
  1009. }
  1010. // Linear search.
  1011. qDebug() << "fall back to linear search for first visible block";
  1012. QTextBlock block = doc->begin();
  1013. while (block.isValid()) {
  1014. int y = offsetY + (int)layout->blockBoundingRect(block).y();
  1015. if (y >= 0) {
  1016. return block;
  1017. }
  1018. block = block.next();
  1019. }
  1020. return QTextBlock();
  1021. }
  1022. int LineNumberArea::calculateWidth() const
  1023. {
  1024. int bc = m_document->blockCount();
  1025. if (m_blockCount == bc) {
  1026. return m_width;
  1027. }
  1028. const_cast<LineNumberArea *>(this)->m_blockCount = bc;
  1029. int digits = 1;
  1030. int max = qMax(1, m_blockCount);
  1031. while (max >= 10) {
  1032. max /= 10;
  1033. ++digits;
  1034. }
  1035. int width = m_digitWidth * digits;
  1036. const_cast<LineNumberArea *>(this)->m_width = width;
  1037. return m_width;
  1038. }
  1039. void VEdit::makeBlockVisible(const QTextBlock &p_block)
  1040. {
  1041. if (!p_block.isValid() || !p_block.isVisible()) {
  1042. return;
  1043. }
  1044. QScrollBar *vbar = verticalScrollBar();
  1045. if (!vbar || !vbar->isVisible()) {
  1046. // No vertical scrollbar. No need to scroll.
  1047. return;
  1048. }
  1049. QAbstractTextDocumentLayout *layout = document()->documentLayout();
  1050. int height = rect().height();
  1051. QScrollBar *hbar = horizontalScrollBar();
  1052. if (hbar && hbar->isVisible()) {
  1053. height -= hbar->height();
  1054. }
  1055. bool moved = false;
  1056. QRectF rect = layout->blockBoundingRect(p_block);
  1057. int y = contentOffsetY() + (int)rect.y();
  1058. int rectHeight = (int)rect.height();
  1059. // Handle the case rectHeight >= height.
  1060. if (rectHeight >= height) {
  1061. if (y <= 0) {
  1062. if (y + rectHeight < height) {
  1063. // Need to scroll up.
  1064. while (y + rectHeight < height && vbar->value() > vbar->minimum()) {
  1065. moved = true;
  1066. vbar->setValue(vbar->value() - vbar->singleStep());
  1067. rect = layout->blockBoundingRect(p_block);
  1068. rectHeight = (int)rect.height();
  1069. y = contentOffsetY() + (int)rect.y();
  1070. }
  1071. }
  1072. } else {
  1073. // Need to scroll down.
  1074. while (y > 0 && vbar->value() < vbar->maximum()) {
  1075. moved = true;
  1076. vbar->setValue(vbar->value() + vbar->singleStep());
  1077. rect = layout->blockBoundingRect(p_block);
  1078. rectHeight = (int)rect.height();
  1079. y = contentOffsetY() + (int)rect.y();
  1080. }
  1081. }
  1082. if (moved) {
  1083. qDebug() << "scroll to make huge block visible";
  1084. }
  1085. return;
  1086. }
  1087. while (y < 0 && vbar->value() > vbar->minimum()) {
  1088. moved = true;
  1089. vbar->setValue(vbar->value() - vbar->singleStep());
  1090. rect = layout->blockBoundingRect(p_block);
  1091. rectHeight = (int)rect.height();
  1092. y = contentOffsetY() + (int)rect.y();
  1093. }
  1094. if (moved) {
  1095. qDebug() << "scroll page down to make block visible";
  1096. return;
  1097. }
  1098. while (y + rectHeight > height && vbar->value() < vbar->maximum()) {
  1099. moved = true;
  1100. vbar->setValue(vbar->value() + vbar->singleStep());
  1101. rect = layout->blockBoundingRect(p_block);
  1102. rectHeight = (int)rect.height();
  1103. y = contentOffsetY() + (int)rect.y();
  1104. }
  1105. if (moved) {
  1106. qDebug() << "scroll page up to make block visible";
  1107. }
  1108. }
  1109. bool VEdit::isBlockVisible(const QTextBlock &p_block)
  1110. {
  1111. if (!p_block.isValid() || !p_block.isVisible()) {
  1112. return false;
  1113. }
  1114. QScrollBar *vbar = verticalScrollBar();
  1115. if (!vbar || !vbar->isVisible()) {
  1116. // No vertical scrollbar.
  1117. return true;
  1118. }
  1119. QAbstractTextDocumentLayout *layout = document()->documentLayout();
  1120. int height = rect().height();
  1121. QScrollBar *hbar = horizontalScrollBar();
  1122. if (hbar && hbar->isVisible()) {
  1123. height -= hbar->height();
  1124. }
  1125. QRectF rect = layout->blockBoundingRect(p_block);
  1126. int y = contentOffsetY() + (int)rect.y();
  1127. int rectHeight = (int)rect.height();
  1128. return (y >= 0 && y < height) || (y < 0 && y + rectHeight > 0);
  1129. }
  1130. void VEdit::alterContextMenu(QMenu *p_menu, const QList<QAction *> &p_actions)
  1131. {
  1132. Q_UNUSED(p_menu);
  1133. Q_UNUSED(p_actions);
  1134. }
  1135. void VEdit::updateBlockLineDistanceHeight(int p_pos,
  1136. int p_charsRemoved,
  1137. int p_charsAdded)
  1138. {
  1139. if ((p_charsRemoved == 0 && p_charsAdded == 0)
  1140. || m_config.m_lineDistanceHeight <= 0) {
  1141. return;
  1142. }
  1143. QTextDocument *doc = document();
  1144. QTextBlock block = doc->findBlock(p_pos);
  1145. QTextBlock lastBlock = doc->findBlock(p_pos + p_charsRemoved + p_charsAdded);
  1146. QTextCursor cursor(block);
  1147. bool changed = false;
  1148. while (block.isValid()) {
  1149. cursor.setPosition(block.position());
  1150. QTextBlockFormat fmt = cursor.blockFormat();
  1151. if (fmt.lineHeightType() != QTextBlockFormat::LineDistanceHeight
  1152. || fmt.lineHeight() != m_config.m_lineDistanceHeight) {
  1153. fmt.setLineHeight(m_config.m_lineDistanceHeight,
  1154. QTextBlockFormat::LineDistanceHeight);
  1155. if (!changed) {
  1156. changed = true;
  1157. cursor.joinPreviousEditBlock();
  1158. }
  1159. cursor.mergeBlockFormat(fmt);
  1160. qDebug() << "merge block format line distance" << block.blockNumber();
  1161. }
  1162. if (block == lastBlock) {
  1163. break;
  1164. }
  1165. block = block.next();
  1166. }
  1167. if (changed) {
  1168. cursor.endEditBlock();
  1169. }
  1170. }
  1171. void VEdit::evaluateMagicWords()
  1172. {
  1173. QString text;
  1174. QTextCursor cursor = textCursor();
  1175. if (!cursor.hasSelection()) {
  1176. // Get the WORD in current cursor.
  1177. int start, end;
  1178. VEditUtils::findCurrentWORD(cursor, start, end);
  1179. if (start == end) {
  1180. return;
  1181. } else {
  1182. cursor.setPosition(start);
  1183. cursor.setPosition(end, QTextCursor::KeepAnchor);
  1184. }
  1185. }
  1186. text = VEditUtils::selectedText(cursor);
  1187. Q_ASSERT(!text.isEmpty());
  1188. QString evaText = g_mwMgr->evaluate(text);
  1189. if (text != evaText) {
  1190. qDebug() << "evaluateMagicWords" << text << evaText;
  1191. cursor.insertText(evaText);
  1192. if (m_editOps) {
  1193. m_editOps->setVimMode(VimMode::Insert);
  1194. }
  1195. setTextCursor(cursor);
  1196. }
  1197. }
  1198. void VEdit::setReadOnlyAndHighlight(bool p_readonly)
  1199. {
  1200. setReadOnly(p_readonly);
  1201. highlightCurrentLine();
  1202. }