PageRenderTime 130ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/main/src/core/Mono.Texteditor/Mono.TextEditor/CaretMoveActions.cs

https://github.com/azeno/monodevelop
C# | 342 lines | 267 code | 43 blank | 32 comment | 70 complexity | 6c69229f8810240fea2501c9ab92eed5 MD5 | raw file
  1. //
  2. // CaretMoveActions.cs
  3. //
  4. // Author:
  5. // Mike Krüger <mkrueger@novell.com>
  6. // Michael Hutchinson <mhutchinson@novell.com>
  7. //
  8. // Copyright (C) 2007-2008 Novell, Inc (http://www.novell.com)
  9. //
  10. // Permission is hereby granted, free of charge, to any person obtaining
  11. // a copy of this software and associated documentation files (the
  12. // "Software"), to deal in the Software without restriction, including
  13. // without limitation the rights to use, copy, modify, merge, publish,
  14. // distribute, sublicense, and/or sell copies of the Software, and to
  15. // permit persons to whom the Software is furnished to do so, subject to
  16. // the following conditions:
  17. //
  18. // The above copyright notice and this permission notice shall be
  19. // included in all copies or substantial portions of the Software.
  20. //
  21. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  22. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  23. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  24. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  25. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  26. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  27. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  28. //
  29. using System;
  30. using System.Collections.Generic;
  31. using System.Diagnostics;
  32. using System.Text;
  33. using Gtk;
  34. using Mono.TextEditor.Highlighting;
  35. namespace Mono.TextEditor
  36. {
  37. public static class CaretMoveActions
  38. {
  39. public static void Left (TextEditorData data)
  40. {
  41. if (Platform.IsMac && data.IsSomethingSelected && !data.Caret.PreserveSelection) {
  42. data.Caret.Offset = System.Math.Min (data.SelectionAnchor, data.Caret.Offset);
  43. data.ClearSelection ();
  44. return;
  45. }
  46. LineSegment line = data.Document.GetLine (data.Caret.Line);
  47. IEnumerable<FoldSegment> foldings = data.Document.GetEndFoldings (line);
  48. FoldSegment segment = null;
  49. foreach (FoldSegment folding in foldings) {
  50. if (folding.IsFolded && folding.EndColumn == data.Caret.Column) {
  51. segment = folding;
  52. break;
  53. }
  54. }
  55. if (segment != null) {
  56. data.Caret.Location = data.Document.OffsetToLocation (segment.StartLine.Offset + segment.Column);
  57. return;
  58. }
  59. if (data.Caret.Column > DocumentLocation.MinColumn) {
  60. if (data.Caret.Column > line.EditableLength + 1) {
  61. data.Caret.Column = line.EditableLength + 1;
  62. } else {
  63. data.Caret.Column--;
  64. }
  65. } else if (data.Caret.Line > DocumentLocation.MinLine) {
  66. LineSegment prevLine = data.Document.GetLine (data.Caret.Line - 1);
  67. data.Caret.Location = new DocumentLocation (data.Caret.Line - 1, prevLine.EditableLength + 1);
  68. }
  69. }
  70. public static void PreviousWord (TextEditorData data)
  71. {
  72. data.Caret.Offset = data.FindPrevWordOffset (data.Caret.Offset);
  73. }
  74. public static void PreviousSubword (TextEditorData data)
  75. {
  76. data.Caret.Offset = data.FindPrevSubwordOffset (data.Caret.Offset);
  77. }
  78. public static void Right (TextEditorData data)
  79. {
  80. if (Platform.IsMac && data.IsSomethingSelected && !data.Caret.PreserveSelection) {
  81. data.Caret.Offset = System.Math.Max (data.SelectionAnchor, data.Caret.Offset);
  82. data.ClearSelection ();
  83. return;
  84. }
  85. LineSegment line = data.Document.GetLine (data.Caret.Line);
  86. IEnumerable<FoldSegment> foldings = data.Document.GetStartFoldings (line);
  87. FoldSegment segment = null;
  88. foreach (FoldSegment folding in foldings) {
  89. if (folding.IsFolded && folding.Column == data.Caret.Column) {
  90. segment = folding;
  91. break;
  92. }
  93. }
  94. if (segment != null) {
  95. data.Caret.Location = data.Document.OffsetToLocation (segment.EndLine.Offset + segment.EndColumn);
  96. return;
  97. }
  98. if (data.Caret.Column < line.EditableLength + 1 || data.Caret.AllowCaretBehindLineEnd) {
  99. if (data.Caret.Column >= line.EditableLength + 1) {
  100. int nextColumn = data.GetNextVirtualColumn (data.Caret.Line, data.Caret.Column);
  101. if (data.Caret.Column != nextColumn) {
  102. data.Caret.Column = nextColumn;
  103. } else {
  104. data.Caret.Location = new DocumentLocation (data.Caret.Line + 1, DocumentLocation.MinColumn);
  105. data.Caret.CheckCaretPosition ();
  106. }
  107. } else {
  108. data.Caret.Column++;
  109. }
  110. } else if (data.Caret.Line + 1 <= data.Document.LineCount) {
  111. data.Caret.Location = new DocumentLocation (data.Caret.Line + 1, DocumentLocation.MinColumn);
  112. }
  113. }
  114. public static void NextWord (TextEditorData data)
  115. {
  116. data.Caret.Offset = data.FindNextWordOffset (data.Caret.Offset);
  117. }
  118. public static void NextSubword (TextEditorData data)
  119. {
  120. data.Caret.Offset = data.FindNextSubwordOffset (data.Caret.Offset);
  121. }
  122. public static void Up (TextEditorData data)
  123. {
  124. int desiredColumn = data.Caret.DesiredColumn;
  125. //on Mac, when deselecting and moving up/down a line, column is always the column of the selection's start
  126. if (Platform.IsMac && data.IsSomethingSelected && !data.Caret.PreserveSelection) {
  127. int col = data.MainSelection.Anchor > data.MainSelection.Lead ? data.MainSelection.Lead.Column : data.MainSelection.Anchor.Column;
  128. int line = data.MainSelection.MinLine - 1;
  129. data.ClearSelection ();
  130. data.Caret.Location = (line >= DocumentLocation.MinLine) ? new DocumentLocation (line, col) : new DocumentLocation (DocumentLocation.MinLine, DocumentLocation.MinColumn);
  131. data.Caret.SetToDesiredColumn (desiredColumn);
  132. return;
  133. }
  134. if (data.Caret.Line > DocumentLocation.MinLine) {
  135. int visualLine = data.Document.LogicalToVisualLine (data.Caret.Line);
  136. int line = data.Document.VisualToLogicalLine (visualLine - 1);
  137. int offset = data.Document.LocationToOffset (line, data.Caret.Column);
  138. data.Caret.Offset = MoveCaretOutOfFolding (data, offset);
  139. data.Caret.SetToDesiredColumn (desiredColumn);
  140. } else {
  141. ToDocumentStart (data);
  142. }
  143. }
  144. static int MoveCaretOutOfFolding (TextEditorData data, int offset)
  145. {
  146. IEnumerable<FoldSegment> foldings = data.Document.GetFoldingsFromOffset (offset);
  147. foreach (FoldSegment folding in foldings) {
  148. if (folding.IsFolded) {
  149. if (offset < folding.EndOffset)
  150. offset = folding.EndOffset;
  151. }
  152. }
  153. return offset;
  154. }
  155. public static void Down (TextEditorData data)
  156. {
  157. //on Mac, when deselecting and moving up/down a line, column is always the column of the selection's start
  158. if (Platform.IsMac && data.IsSomethingSelected && !data.Caret.PreserveSelection) {
  159. int col = data.MainSelection.Anchor > data.MainSelection.Lead ? data.MainSelection.Lead.Column : data.MainSelection.Anchor.Column;
  160. int line = data.MainSelection.MaxLine + 1;
  161. data.ClearSelection ();
  162. if (line <= data.Document.LineCount) {
  163. int offset = data.Document.LocationToOffset (line, col);
  164. data.Caret.SetToOffsetWithDesiredColumn (MoveCaretOutOfFolding (data, offset));
  165. } else {
  166. data.Caret.Offset = data.Document.Length;
  167. }
  168. return;
  169. }
  170. if (data.Caret.Line < data.Document.LineCount) {
  171. int nextLine = data.Document.LogicalToVisualLine (data.Caret.Line) + 1;
  172. int line = data.Document.VisualToLogicalLine (nextLine);
  173. int offset = data.Document.LocationToOffset (line, data.Caret.Column);
  174. data.Caret.SetToOffsetWithDesiredColumn (MoveCaretOutOfFolding (data, offset));
  175. } else {
  176. ToDocumentEnd (data);
  177. }
  178. }
  179. static int GetHomeMark (Document document, LineSegment line)
  180. {
  181. int result;
  182. for (result = 0; result < line.EditableLength; result++)
  183. if (!Char.IsWhiteSpace (document.GetCharAt (line.Offset + result)))
  184. return result + 1;
  185. return result + 1;
  186. }
  187. static void InternalCaretMoveHome (TextEditorData data, bool firstNonWhitespace, bool hop)
  188. {
  189. if (!data.Caret.PreserveSelection)
  190. data.ClearSelection ();
  191. DocumentLocation newLocation = data.Caret.Location;
  192. LineSegment line = data.Document.GetLine (data.Caret.Line);
  193. if (firstNonWhitespace) {
  194. int homeMark = GetHomeMark (data.Document, line);
  195. if (hop) {
  196. newLocation.Column = data.Caret.Column == homeMark ? DocumentLocation.MinColumn : homeMark;
  197. } else {
  198. newLocation.Column = homeMark;
  199. }
  200. } else {
  201. newLocation.Column = DocumentLocation.MinColumn;
  202. }
  203. // handle folding
  204. IEnumerable<FoldSegment> foldings = data.Document.GetEndFoldings (line);
  205. FoldSegment segment = null;
  206. foreach (FoldSegment folding in foldings) {
  207. if (folding.IsFolded && folding.Contains (data.Document.LocationToOffset (newLocation))) {
  208. segment = folding;
  209. break;
  210. }
  211. }
  212. if (segment != null)
  213. newLocation = data.Document.OffsetToLocation (segment.StartLine.Offset);
  214. if (newLocation != data.Caret.Location)
  215. data.Caret.Location = newLocation;
  216. }
  217. public static void LineHome (TextEditorData data)
  218. {
  219. InternalCaretMoveHome (data, true, true);
  220. }
  221. public static void LineStart (TextEditorData data)
  222. {
  223. InternalCaretMoveHome (data, false, false);
  224. }
  225. public static void LineFirstNonWhitespace (TextEditorData data)
  226. {
  227. InternalCaretMoveHome (data, true, false);
  228. }
  229. public static void LineEnd (TextEditorData data)
  230. {
  231. if (!data.Caret.PreserveSelection)
  232. data.ClearSelection ();
  233. DocumentLocation newLocation = data.Caret.Location;
  234. LineSegment line = data.Document.GetLine (data.Caret.Line);
  235. newLocation.Column = line.EditableLength + 1;
  236. // handle folding
  237. IEnumerable<FoldSegment> foldings = data.Document.GetStartFoldings (line);
  238. FoldSegment segment = null;
  239. foreach (FoldSegment folding in foldings) {
  240. if (folding.IsFolded && folding.Contains (data.Document.LocationToOffset (newLocation))) {
  241. segment = folding;
  242. break;
  243. }
  244. }
  245. if (segment != null)
  246. newLocation = data.Document.OffsetToLocation (segment.EndLine.Offset + segment.EndColumn);
  247. if (newLocation != data.Caret.Location)
  248. data.Caret.Location = newLocation;
  249. if (data.Caret.AllowCaretBehindLineEnd) {
  250. int nextColumn = data.GetNextVirtualColumn (data.Caret.Line, data.Caret.Column);
  251. if (nextColumn != data.Caret.Column)
  252. data.Caret.Column = nextColumn;
  253. }
  254. }
  255. public static void ToDocumentStart (TextEditorData data)
  256. {
  257. if (!data.Caret.PreserveSelection)
  258. data.ClearSelection ();
  259. data.Caret.Location = new DocumentLocation (DocumentLocation.MinLine, DocumentLocation.MinColumn);
  260. }
  261. public static void ToDocumentEnd (TextEditorData data)
  262. {
  263. if (!data.Caret.PreserveSelection)
  264. data.ClearSelection ();
  265. data.Caret.Offset = data.Document.Length;
  266. }
  267. public static double LineHeight { get; set; }
  268. public static void PageUp (TextEditorData data)
  269. {
  270. int pageLines = (int)((data.VAdjustment.PageSize + ((int)data.VAdjustment.Value % LineHeight)) / LineHeight);
  271. int visualLine = data.Document.LogicalToVisualLine (data.Caret.Line);
  272. visualLine -= pageLines;
  273. int line = System.Math.Max (data.Document.VisualToLogicalLine (visualLine), DocumentLocation.MinLine);
  274. int offset = data.Document.LocationToOffset (line, data.Caret.Column);
  275. ScrollActions.PageUp (data);
  276. data.Caret.Offset = MoveCaretOutOfFolding (data, offset);
  277. }
  278. public static void PageDown (TextEditorData data)
  279. {
  280. int pageLines = (int)((data.VAdjustment.PageSize + ((int)data.VAdjustment.Value % LineHeight)) / LineHeight);
  281. int visualLine = data.Document.LogicalToVisualLine (data.Caret.Line);
  282. visualLine += pageLines;
  283. int line = System.Math.Min (data.Document.VisualToLogicalLine (visualLine), data.Document.LineCount);
  284. int offset = data.Document.LocationToOffset (line, data.Caret.Column);
  285. ScrollActions.PageDown (data);
  286. data.Caret.Offset = MoveCaretOutOfFolding (data, offset);
  287. }
  288. public static void UpLineStart (TextEditorData data)
  289. {
  290. Up (data);
  291. LineStart (data);
  292. }
  293. public static void DownLineEnd (TextEditorData data)
  294. {
  295. Down (data);
  296. LineEnd (data);
  297. }
  298. }
  299. }