2
0

TextView.Delete.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641
  1. namespace Terminal.Gui.Views;
  2. public partial class TextView
  3. {
  4. /// <summary>Deletes all text.</summary>
  5. public void DeleteAll ()
  6. {
  7. if (Lines == 0)
  8. {
  9. return;
  10. }
  11. _selectionStartColumn = 0;
  12. _selectionStartRow = 0;
  13. MoveBottomEndExtend ();
  14. DeleteCharLeft ();
  15. SetNeedsDraw ();
  16. }
  17. /// <summary>Deletes all the selected or a single character at left from the position of the cursor.</summary>
  18. public void DeleteCharLeft ()
  19. {
  20. if (_isReadOnly)
  21. {
  22. return;
  23. }
  24. SetWrapModel ();
  25. if (IsSelecting)
  26. {
  27. _historyText.Add (new () { new (GetCurrentLine ()) }, CursorPosition);
  28. ClearSelectedRegion ();
  29. List<Cell> currentLine = GetCurrentLine ();
  30. _historyText.Add (
  31. new () { new (currentLine) },
  32. CursorPosition,
  33. TextEditingLineStatus.Replaced
  34. );
  35. UpdateWrapModel ();
  36. OnContentsChanged ();
  37. return;
  38. }
  39. if (DeleteTextBackwards ())
  40. {
  41. UpdateWrapModel ();
  42. OnContentsChanged ();
  43. return;
  44. }
  45. UpdateWrapModel ();
  46. DoNeededAction ();
  47. OnContentsChanged ();
  48. }
  49. /// <summary>Deletes all the selected or a single character at right from the position of the cursor.</summary>
  50. public void DeleteCharRight ()
  51. {
  52. if (_isReadOnly)
  53. {
  54. return;
  55. }
  56. SetWrapModel ();
  57. if (IsSelecting)
  58. {
  59. _historyText.Add (new () { new (GetCurrentLine ()) }, CursorPosition);
  60. ClearSelectedRegion ();
  61. List<Cell> currentLine = GetCurrentLine ();
  62. _historyText.Add (
  63. new () { new (currentLine) },
  64. CursorPosition,
  65. TextEditingLineStatus.Replaced
  66. );
  67. UpdateWrapModel ();
  68. OnContentsChanged ();
  69. return;
  70. }
  71. if (DeleteTextForwards ())
  72. {
  73. UpdateWrapModel ();
  74. OnContentsChanged ();
  75. return;
  76. }
  77. UpdateWrapModel ();
  78. DoNeededAction ();
  79. OnContentsChanged ();
  80. }
  81. private bool DeleteTextBackwards ()
  82. {
  83. SetWrapModel ();
  84. if (CurrentColumn > 0)
  85. {
  86. // Delete backwards
  87. List<Cell> currentLine = GetCurrentLine ();
  88. _historyText.Add (new () { new (currentLine) }, CursorPosition);
  89. currentLine.RemoveAt (CurrentColumn - 1);
  90. if (_wordWrap)
  91. {
  92. _wrapNeeded = true;
  93. }
  94. CurrentColumn--;
  95. _historyText.Add (
  96. new () { new (currentLine) },
  97. CursorPosition,
  98. TextEditingLineStatus.Replaced
  99. );
  100. if (CurrentColumn < _leftColumn)
  101. {
  102. _leftColumn--;
  103. SetNeedsDraw ();
  104. }
  105. else
  106. {
  107. // BUGBUG: customized rect aren't supported now because the Redraw isn't using the Intersect method.
  108. //SetNeedsDraw (new (0, currentRow - topRow, 1, Viewport.Width));
  109. SetNeedsDraw ();
  110. }
  111. }
  112. else
  113. {
  114. // Merges the current line with the previous one.
  115. if (CurrentRow == 0)
  116. {
  117. return true;
  118. }
  119. int prowIdx = CurrentRow - 1;
  120. List<Cell> prevRow = _model.GetLine (prowIdx);
  121. _historyText.Add (new () { new (prevRow) }, CursorPosition);
  122. List<List<Cell>> removedLines = new () { new (prevRow) };
  123. removedLines.Add (new (GetCurrentLine ()));
  124. _historyText.Add (
  125. removedLines,
  126. new (CurrentColumn, prowIdx),
  127. TextEditingLineStatus.Removed
  128. );
  129. int prevCount = prevRow.Count;
  130. _model.GetLine (prowIdx).AddRange (GetCurrentLine ());
  131. _model.RemoveLine (CurrentRow);
  132. if (_wordWrap)
  133. {
  134. _wrapNeeded = true;
  135. }
  136. CurrentRow--;
  137. _historyText.Add (
  138. new () { GetCurrentLine () },
  139. new (CurrentColumn, prowIdx),
  140. TextEditingLineStatus.Replaced
  141. );
  142. CurrentColumn = prevCount;
  143. SetNeedsDraw ();
  144. }
  145. UpdateWrapModel ();
  146. return false;
  147. }
  148. private bool DeleteTextForwards ()
  149. {
  150. SetWrapModel ();
  151. List<Cell> currentLine = GetCurrentLine ();
  152. if (CurrentColumn == currentLine.Count)
  153. {
  154. if (CurrentRow + 1 == _model.Count)
  155. {
  156. UpdateWrapModel ();
  157. return true;
  158. }
  159. _historyText.Add (new () { new (currentLine) }, CursorPosition);
  160. List<List<Cell>> removedLines = new () { new (currentLine) };
  161. List<Cell> nextLine = _model.GetLine (CurrentRow + 1);
  162. removedLines.Add (new (nextLine));
  163. _historyText.Add (removedLines, CursorPosition, TextEditingLineStatus.Removed);
  164. currentLine.AddRange (nextLine);
  165. _model.RemoveLine (CurrentRow + 1);
  166. _historyText.Add (
  167. new () { new (currentLine) },
  168. CursorPosition,
  169. TextEditingLineStatus.Replaced
  170. );
  171. if (_wordWrap)
  172. {
  173. _wrapNeeded = true;
  174. }
  175. DoSetNeedsDraw (new (0, CurrentRow - _topRow, Viewport.Width, CurrentRow - _topRow + 1));
  176. }
  177. else
  178. {
  179. _historyText.Add ([ [.. currentLine]], CursorPosition);
  180. currentLine.RemoveAt (CurrentColumn);
  181. _historyText.Add (
  182. [ [.. currentLine]],
  183. CursorPosition,
  184. TextEditingLineStatus.Replaced
  185. );
  186. if (_wordWrap)
  187. {
  188. _wrapNeeded = true;
  189. }
  190. DoSetNeedsDraw (
  191. new (
  192. CurrentColumn - _leftColumn,
  193. CurrentRow - _topRow,
  194. Viewport.Width,
  195. Math.Max (CurrentRow - _topRow + 1, 0)
  196. )
  197. );
  198. }
  199. UpdateWrapModel ();
  200. return false;
  201. }
  202. private void ProcessKillWordForward ()
  203. {
  204. ResetColumnTrack ();
  205. StopSelecting ();
  206. KillWordForward ();
  207. }
  208. private void ProcessKillWordBackward ()
  209. {
  210. ResetColumnTrack ();
  211. KillWordBackward ();
  212. }
  213. private void ProcessDeleteCharRight ()
  214. {
  215. ResetColumnTrack ();
  216. DeleteCharRight ();
  217. }
  218. private void ProcessDeleteCharLeft ()
  219. {
  220. ResetColumnTrack ();
  221. DeleteCharLeft ();
  222. }
  223. private void KillWordForward ()
  224. {
  225. if (_isReadOnly)
  226. {
  227. return;
  228. }
  229. SetWrapModel ();
  230. List<Cell> currentLine = GetCurrentLine ();
  231. _historyText.Add ([ [.. GetCurrentLine ()]], CursorPosition);
  232. if (currentLine.Count == 0 || CurrentColumn == currentLine.Count)
  233. {
  234. DeleteTextForwards ();
  235. _historyText.ReplaceLast (
  236. [ [.. GetCurrentLine ()]],
  237. CursorPosition,
  238. TextEditingLineStatus.Replaced
  239. );
  240. UpdateWrapModel ();
  241. return;
  242. }
  243. (int col, int row)? newPos = _model.WordForward (CurrentColumn, CurrentRow, UseSameRuneTypeForWords);
  244. var restCount = 0;
  245. if (newPos.HasValue && CurrentRow == newPos.Value.row)
  246. {
  247. restCount = newPos.Value.col - CurrentColumn;
  248. currentLine.RemoveRange (CurrentColumn, restCount);
  249. }
  250. else if (newPos.HasValue)
  251. {
  252. restCount = currentLine.Count - CurrentColumn;
  253. currentLine.RemoveRange (CurrentColumn, restCount);
  254. }
  255. if (_wordWrap)
  256. {
  257. _wrapNeeded = true;
  258. }
  259. _historyText.Add (
  260. [ [.. GetCurrentLine ()]],
  261. CursorPosition,
  262. TextEditingLineStatus.Replaced
  263. );
  264. UpdateWrapModel ();
  265. DoSetNeedsDraw (new (0, CurrentRow - _topRow, Viewport.Width, Viewport.Height));
  266. DoNeededAction ();
  267. }
  268. private void KillWordBackward ()
  269. {
  270. if (_isReadOnly)
  271. {
  272. return;
  273. }
  274. SetWrapModel ();
  275. List<Cell> currentLine = GetCurrentLine ();
  276. _historyText.Add ([ [.. GetCurrentLine ()]], CursorPosition);
  277. if (CurrentColumn == 0)
  278. {
  279. DeleteTextBackwards ();
  280. _historyText.ReplaceLast (
  281. [ [.. GetCurrentLine ()]],
  282. CursorPosition,
  283. TextEditingLineStatus.Replaced
  284. );
  285. UpdateWrapModel ();
  286. return;
  287. }
  288. (int col, int row)? newPos = _model.WordBackward (CurrentColumn, CurrentRow, UseSameRuneTypeForWords);
  289. if (newPos.HasValue && CurrentRow == newPos.Value.row)
  290. {
  291. int restCount = CurrentColumn - newPos.Value.col;
  292. currentLine.RemoveRange (newPos.Value.col, restCount);
  293. if (_wordWrap)
  294. {
  295. _wrapNeeded = true;
  296. }
  297. CurrentColumn = newPos.Value.col;
  298. }
  299. else if (newPos.HasValue)
  300. {
  301. int restCount;
  302. if (newPos.Value.row == CurrentRow)
  303. {
  304. restCount = currentLine.Count - CurrentColumn;
  305. currentLine.RemoveRange (CurrentColumn, restCount);
  306. }
  307. else
  308. {
  309. while (CurrentRow != newPos.Value.row)
  310. {
  311. restCount = currentLine.Count;
  312. currentLine.RemoveRange (0, restCount);
  313. CurrentRow--;
  314. currentLine = GetCurrentLine ();
  315. }
  316. }
  317. if (_wordWrap)
  318. {
  319. _wrapNeeded = true;
  320. }
  321. CurrentColumn = newPos.Value.col;
  322. CurrentRow = newPos.Value.row;
  323. }
  324. _historyText.Add (
  325. [ [.. GetCurrentLine ()]],
  326. CursorPosition,
  327. TextEditingLineStatus.Replaced
  328. );
  329. UpdateWrapModel ();
  330. DoSetNeedsDraw (new (0, CurrentRow - _topRow, Viewport.Width, Viewport.Height));
  331. DoNeededAction ();
  332. }
  333. private void KillToLeftStart ()
  334. {
  335. if (_isReadOnly)
  336. {
  337. return;
  338. }
  339. if (_model.Count == 1 && GetCurrentLine ().Count == 0)
  340. {
  341. // Prevents from adding line feeds if there is no more lines.
  342. return;
  343. }
  344. SetWrapModel ();
  345. List<Cell> currentLine = GetCurrentLine ();
  346. var setLastWasKill = true;
  347. if (currentLine.Count > 0 && CurrentColumn == 0)
  348. {
  349. UpdateWrapModel ();
  350. DeleteTextBackwards ();
  351. return;
  352. }
  353. _historyText.Add ([ [.. currentLine]], CursorPosition);
  354. if (currentLine.Count == 0)
  355. {
  356. if (CurrentRow > 0)
  357. {
  358. _model.RemoveLine (CurrentRow);
  359. if (_model.Count > 0 || _lastWasKill)
  360. {
  361. string val = Environment.NewLine;
  362. if (_lastWasKill)
  363. {
  364. AppendClipboard (val);
  365. }
  366. else
  367. {
  368. SetClipboard (val);
  369. }
  370. }
  371. if (_model.Count == 0)
  372. {
  373. // Prevents from adding line feeds if there is no more lines.
  374. setLastWasKill = false;
  375. }
  376. CurrentRow--;
  377. currentLine = _model.GetLine (CurrentRow);
  378. List<List<Cell>> removedLine =
  379. [
  380. [..currentLine],
  381. []
  382. ];
  383. _historyText.Add (
  384. [.. removedLine],
  385. CursorPosition,
  386. TextEditingLineStatus.Removed
  387. );
  388. CurrentColumn = currentLine.Count;
  389. }
  390. }
  391. else
  392. {
  393. int restCount = CurrentColumn;
  394. List<Cell> rest = currentLine.GetRange (0, restCount);
  395. var val = string.Empty;
  396. val += StringFromCells (rest);
  397. if (_lastWasKill)
  398. {
  399. AppendClipboard (val);
  400. }
  401. else
  402. {
  403. SetClipboard (val);
  404. }
  405. currentLine.RemoveRange (0, restCount);
  406. CurrentColumn = 0;
  407. }
  408. _historyText.Add (
  409. [ [.. GetCurrentLine ()]],
  410. CursorPosition,
  411. TextEditingLineStatus.Replaced
  412. );
  413. UpdateWrapModel ();
  414. DoSetNeedsDraw (new (0, CurrentRow - _topRow, Viewport.Width, Viewport.Height));
  415. _lastWasKill = setLastWasKill;
  416. DoNeededAction ();
  417. }
  418. private void KillToEndOfLine ()
  419. {
  420. if (_isReadOnly)
  421. {
  422. return;
  423. }
  424. if (_model.Count == 1 && GetCurrentLine ().Count == 0)
  425. {
  426. // Prevents from adding line feeds if there is no more lines.
  427. return;
  428. }
  429. SetWrapModel ();
  430. List<Cell> currentLine = GetCurrentLine ();
  431. var setLastWasKill = true;
  432. if (currentLine.Count > 0 && CurrentColumn == currentLine.Count)
  433. {
  434. UpdateWrapModel ();
  435. DeleteTextForwards ();
  436. return;
  437. }
  438. _historyText.Add (new () { new (currentLine) }, CursorPosition);
  439. if (currentLine.Count == 0)
  440. {
  441. if (CurrentRow < _model.Count - 1)
  442. {
  443. List<List<Cell>> removedLines = new () { new (currentLine) };
  444. _model.RemoveLine (CurrentRow);
  445. removedLines.Add (new (GetCurrentLine ()));
  446. _historyText.Add (
  447. new (removedLines),
  448. CursorPosition,
  449. TextEditingLineStatus.Removed
  450. );
  451. }
  452. if (_model.Count > 0 || _lastWasKill)
  453. {
  454. string val = Environment.NewLine;
  455. if (_lastWasKill)
  456. {
  457. AppendClipboard (val);
  458. }
  459. else
  460. {
  461. SetClipboard (val);
  462. }
  463. }
  464. if (_model.Count == 0)
  465. {
  466. // Prevents from adding line feeds if there is no more lines.
  467. setLastWasKill = false;
  468. }
  469. }
  470. else
  471. {
  472. int restCount = currentLine.Count - CurrentColumn;
  473. List<Cell> rest = currentLine.GetRange (CurrentColumn, restCount);
  474. var val = string.Empty;
  475. val += StringFromCells (rest);
  476. if (_lastWasKill)
  477. {
  478. AppendClipboard (val);
  479. }
  480. else
  481. {
  482. SetClipboard (val);
  483. }
  484. currentLine.RemoveRange (CurrentColumn, restCount);
  485. }
  486. _historyText.Add (
  487. [ [.. GetCurrentLine ()]],
  488. CursorPosition,
  489. TextEditingLineStatus.Replaced
  490. );
  491. UpdateWrapModel ();
  492. DoSetNeedsDraw (new (0, CurrentRow - _topRow, Viewport.Width, Viewport.Height));
  493. _lastWasKill = setLastWasKill;
  494. DoNeededAction ();
  495. }
  496. }