Code Coverage Statistics for Source File

c:\Tools\SD3\src\Libraries\ICSharpCode.TextEditor\Project\Src\Actions\MiscActions.cs

Sequence Point Coverage
N/A
0 of 0
Branch Coverage
N/A
0 of 0
Lines
922
Highlight: Uncovered Code Covered Code
L V Source
1
// <file>
2
//     <copyright see="prj:///doc/copyright.txt"/>
3
//     <license see="prj:///doc/license.txt"/>
4
//     <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
5
//     <version>$Revision: 2659 $</version>
6
// </file>
7
8
using System;
9
using System.Drawing;
10
using System.Text;
11
12
using ICSharpCode.TextEditor.Document;
13
14
namespace ICSharpCode.TextEditor.Actions
15
{
16
	public class Tab : AbstractEditAction
17
	{
18
		public static string GetIndentationString(IDocument document)
19
		{
20
			return GetIndentationString(document, null);
21
		}
22
		
23
		public static string GetIndentationString(IDocument document, TextArea textArea)
24
		{
25
			StringBuilder indent = new StringBuilder();
26
			
27
			if (document.TextEditorProperties.ConvertTabsToSpaces) {
28
				int tabIndent = document.TextEditorProperties.IndentationSize;
29
				if (textArea != null) {
30
					int column = textArea.TextView.GetVisualColumn(textArea.Caret.Line, textArea.Caret.Column);
31
					indent.Append(new String(' ', tabIndent - column % tabIndent));
32
				} else {
33
					indent.Append(new String(' ', tabIndent));
34
				}
35
			} else {
36
				indent.Append('\t');
37
			}
38
			return indent.ToString();
39
		}
40
		
41
		void InsertTabs(IDocument document, ISelection selection, int y1, int y2)
42
		{
43
			string indentationString = GetIndentationString(document);
44
			for (int i = y2; i >= y1; --i) {
45
				LineSegment line = document.GetLineSegment(i);
46
				if (i == y2 && i == selection.EndPosition.Y && selection.EndPosition.X  == 0) {
47
					continue;
48
				}
49
				
50
				// this bit is optional - but useful if you are using block tabbing to sort out
51
				// a source file with a mixture of tabs and spaces
52
//				string newLine = document.GetText(line.Offset,line.Length);
53
//				document.Replace(line.Offset,line.Length,newLine);
54
				
55
				document.Insert(line.Offset, indentationString);
56
			}
57
		}
58
		
59
		void InsertTabAtCaretPosition(TextArea textArea)
60
		{
61
			switch (textArea.Caret.CaretMode) {
62
				case CaretMode.InsertMode:
63
					textArea.InsertString(GetIndentationString(textArea.Document, textArea));
64
					break;
65
				case CaretMode.OverwriteMode:
66
					string indentStr = GetIndentationString(textArea.Document, textArea);
67
					textArea.ReplaceChar(indentStr[0]);
68
					if (indentStr.Length > 1) {
69
						textArea.InsertString(indentStr.Substring(1));
70
					}
71
					break;
72
			}
73
			textArea.SetDesiredColumn();
74
		}
75
		/// <remarks>
76
		/// Executes this edit action
77
		/// </remarks>
78
		/// <param name="textArea">The <see cref="ItextArea"/> which is used for callback purposes</param>
79
		public override void Execute(TextArea textArea)
80
		{
81
			if (textArea.Document.ReadOnly) {
82
				return;
83
			}
84
			textArea.Document.UndoStack.StartUndoGroup();
85
			if (textArea.SelectionManager.HasSomethingSelected) {
86
				foreach (ISelection selection in textArea.SelectionManager.SelectionCollection) {
87
					int startLine = selection.StartPosition.Y;
88
					int endLine   = selection.EndPosition.Y;
89
					if (startLine != endLine) {
90
						textArea.BeginUpdate();
91
						InsertTabs(textArea.Document, selection, startLine, endLine);
92
						textArea.Document.UpdateQueue.Clear();
93
						textArea.Document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.LinesBetween, startLine, endLine));
94
						textArea.EndUpdate();
95
					} else {
96
						InsertTabAtCaretPosition(textArea);
97
						break;
98
					}
99
				}
100
				textArea.Document.CommitUpdate();
101
				textArea.AutoClearSelection = false;
102
			} else {
103
				InsertTabAtCaretPosition(textArea);
104
			}
105
			textArea.Document.UndoStack.EndUndoGroup();
106
		}
107
	}
108
	
109
	public class ShiftTab : AbstractEditAction
110
	{
111
		void RemoveTabs(IDocument document, ISelection selection, int y1, int y2)
112
		{
113
			document.UndoStack.StartUndoGroup();
114
			for (int i = y2; i >= y1; --i) {
115
				LineSegment line = document.GetLineSegment(i);
116
				if (i == y2 && line.Offset == selection.EndOffset) {
117
					continue;
118
				}
119
				if (line.Length > 0) {
120
					/**** TextPad Strategy:
121
					/// first convert leading whitespace to tabs (controversial! - not all editors work like this)
122
					string newLine = TextUtilities.LeadingWhiteSpaceToTabs(document.GetText(line.Offset,line.Length),document.Properties.Get("TabIndent", 4));
123
					if(newLine.Length > 0 && newLine[0] == '\t') {
124
						document.Replace(line.Offset,line.Length,newLine.Substring(1));
125
						++redocounter;
126
					}
127
					else if(newLine.Length > 0 && newLine[0] == ' ') {
128
						/// there were just some leading spaces but less than TabIndent of them
129
						int leadingSpaces = 1;
130
						for(leadingSpaces = 1; leadingSpaces < newLine.Length && newLine[leadingSpaces] == ' '; leadingSpaces++) {
131
							/// deliberately empty
132
						}
133
						document.Replace(line.Offset,line.Length,newLine.Substring(leadingSpaces));
134
						++redocounter;
135
					}
136
					/// else
137
					/// there were no leading tabs or spaces on this line so do nothing
138
					/// MS Visual Studio 6 strategy:
139
					 ****/
140
//					string temp = document.GetText(line.Offset,line.Length);
141
					if (line.Length > 0) {
142
						int charactersToRemove = 0;
143
						if(document.GetCharAt(line.Offset) == '\t') { // first character is a tab - just remove it
144
							charactersToRemove = 1;
145
						} else if(document.GetCharAt(line.Offset) == ' ') {
146
							int leadingSpaces = 1;
147
							int tabIndent = document.TextEditorProperties.IndentationSize;
148
							for (leadingSpaces = 1; leadingSpaces < line.Length && document.GetCharAt(line.Offset + leadingSpaces) == ' '; leadingSpaces++) {
149
								// deliberately empty
150
							}
151
							if(leadingSpaces >= tabIndent) {
152
								// just remove tabIndent
153
								charactersToRemove = tabIndent;
154
							}
155
							else if(line.Length > leadingSpaces && document.GetCharAt(line.Offset + leadingSpaces) == '\t') {
156
								// remove the leading spaces and the following tab as they add up
157
								// to just one tab stop
158
								charactersToRemove = leadingSpaces+1;
159
							}
160
							else {
161
								// just remove the leading spaces
162
								charactersToRemove = leadingSpaces;
163
							}
164
						}
165
						if (charactersToRemove > 0) {
166
							document.Remove(line.Offset,charactersToRemove);
167
						}
168
					}
169
				}
170
			}
171
			document.UndoStack.EndUndoGroup();
172
		}
173
		
174
		/// <remarks>
175
		/// Executes this edit action
176
		/// </remarks>
177
		/// <param name="textArea">The <see cref="ItextArea"/> which is used for callback purposes</param>
178
		public override void Execute(TextArea textArea)
179
		{
180
			if (textArea.SelectionManager.HasSomethingSelected) {
181
				foreach (ISelection selection in textArea.SelectionManager.SelectionCollection) {
182
					int startLine = selection.StartPosition.Y;
183
					int endLine   = selection.EndPosition.Y;
184
					textArea.BeginUpdate();
185
					RemoveTabs(textArea.Document, selection, startLine, endLine);
186
					textArea.Document.UpdateQueue.Clear();
187
					textArea.Document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.LinesBetween, startLine, endLine));
188
					textArea.EndUpdate();
189
					
190
				}
191
				textArea.AutoClearSelection = false;
192
			} else {
193
				// Pressing Shift-Tab with nothing selected the cursor will move back to the
194
				// previous tab stop. It will stop at the beginning of the line. Also, the desired
195
				// column is updated to that column.
196
				LineSegment line = textArea.Document.GetLineSegmentForOffset(textArea.Caret.Offset);
197
				string startOfLine = textArea.Document.GetText(line.Offset,textArea.Caret.Offset - line.Offset);
198
				int tabIndent = textArea.Document.TextEditorProperties.IndentationSize;
199
				int currentColumn = textArea.Caret.Column;
200
				int remainder = currentColumn % tabIndent;
201
				if (remainder == 0) {
202
					textArea.Caret.DesiredColumn = Math.Max(0, currentColumn - tabIndent);
203
				} else {
204
					textArea.Caret.DesiredColumn = Math.Max(0, currentColumn - remainder);
205
				}
206
				textArea.SetCaretToDesiredColumn();
207
			}
208
		}
209
	}
210
	
211
	public class ToggleComment : AbstractEditAction
212
	{
213
		/// <remarks>
214
		/// Executes this edit action
215
		/// </remarks>
216
		/// <param name="textArea">The <see cref="ItextArea"/> which is used for callback purposes</param>
217
		public override void Execute(TextArea textArea)
218
		{
219
			if (textArea.Document.ReadOnly) {
220
				return;
221
			}
222
			
223
			if (textArea.Document.HighlightingStrategy.Properties.ContainsKey("LineComment")) {
224
				new ToggleLineComment().Execute(textArea);
225
			} else if (textArea.Document.HighlightingStrategy.Properties.ContainsKey("BlockCommentBegin") &&
226
			           textArea.Document.HighlightingStrategy.Properties.ContainsKey("BlockCommentBegin")) {
227
				new ToggleBlockComment().Execute(textArea);
228
			}
229
		}
230
	}
231
	
232
	public class ToggleLineComment : AbstractEditAction
233
	{
234
		int firstLine;
235
		int lastLine;
236
		
237
		void RemoveCommentAt(IDocument document, string comment, ISelection selection, int y1, int y2)
238
		{
239
			firstLine = y1;
240
			lastLine  = y2;
241
			
242
			for (int i = y2; i >= y1; --i) {
243
				LineSegment line = document.GetLineSegment(i);
244
				if (selection != null && i == y2 && line.Offset == selection.Offset + selection.Length) {
245
					--lastLine;
246
					continue;
247
				}
248
				
249
				string lineText = document.GetText(line.Offset, line.Length);
250
				if (lineText.Trim().StartsWith(comment)) {
251
					document.Remove(line.Offset + lineText.IndexOf(comment), comment.Length);
252
				}
253
			}
254
		}
255
		
256
		void SetCommentAt(IDocument document, string comment, ISelection selection, int y1, int y2)
257
		{
258
			firstLine = y1;
259
			lastLine  = y2;
260
			
261
			for (int i = y2; i >= y1; --i) {
262
				LineSegment line = document.GetLineSegment(i);
263
				if (selection != null && i == y2 && line.Offset == selection.Offset + selection.Length) {
264
					--lastLine;
265
					continue;
266
				}
267
				
268
				string lineText = document.GetText(line.Offset, line.Length);
269
				document.Insert(line.Offset, comment);
270
			}
271
		}
272
		
273
		bool ShouldComment(IDocument document, string comment, ISelection selection, int startLine, int endLine)
274
		{
275
			for (int i = endLine; i >= startLine; --i) {
276
				LineSegment line = document.GetLineSegment(i);
277
				if (selection != null && i == endLine && line.Offset == selection.Offset + selection.Length) {
278
					--lastLine;
279
					continue;
280
				}
281
				string lineText = document.GetText(line.Offset, line.Length);
282
				if (!lineText.Trim().StartsWith(comment)) {
283
					return true;
284
				}
285
			}
286
			return false;
287
		}
288
		
289
		/// <remarks>
290
		/// Executes this edit action
291
		/// </remarks>
292
		/// <param name="textArea">The <see cref="ItextArea"/> which is used for callback purposes</param>
293
		public override void Execute(TextArea textArea)
294
		{
295
			if (textArea.Document.ReadOnly) {
296
				return;
297
			}
298
			
299
			string comment = null;
300
			if (textArea.Document.HighlightingStrategy.Properties.ContainsKey("LineComment")) {
301
				comment = textArea.Document.HighlightingStrategy.Properties["LineComment"].ToString();
302
			}
303
			
304
			if (comment == null || comment.Length == 0) {
305
				return;
306
			}
307
			
308
			textArea.Document.UndoStack.StartUndoGroup();
309
			if (textArea.SelectionManager.HasSomethingSelected) {
310
				bool shouldComment = true;
311
				foreach (ISelection selection in textArea.SelectionManager.SelectionCollection) {
312
					if (!ShouldComment(textArea.Document, comment, selection, selection.StartPosition.Y, selection.EndPosition.Y)) {
313
						shouldComment = false;
314
						break;
315
					}
316
				}
317
				
318
				foreach (ISelection selection in textArea.SelectionManager.SelectionCollection) {
319
					textArea.BeginUpdate();
320
					if (shouldComment) {
321
						SetCommentAt(textArea.Document, comment, selection, selection.StartPosition.Y, selection.EndPosition.Y);
322
					} else {
323
						RemoveCommentAt(textArea.Document, comment, selection, selection.StartPosition.Y, selection.EndPosition.Y);
324
					}
325
					textArea.Document.UpdateQueue.Clear();
326
					textArea.Document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.LinesBetween, firstLine, lastLine));
327
					textArea.EndUpdate();
328
				}
329
				textArea.Document.CommitUpdate();
330
				textArea.AutoClearSelection = false;
331
			} else {
332
				textArea.BeginUpdate();
333
				int caretLine = textArea.Caret.Line;
334
				if (ShouldComment(textArea.Document, comment, null, caretLine, caretLine)) {
335
					SetCommentAt(textArea.Document, comment, null, caretLine, caretLine);
336
				} else {
337
					RemoveCommentAt(textArea.Document, comment, null, caretLine, caretLine);
338
				}
339
				textArea.Document.UpdateQueue.Clear();
340
				textArea.Document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.SingleLine, caretLine));
341
				textArea.EndUpdate();
342
			}
343
			textArea.Document.UndoStack.EndUndoGroup();
344
		}
345
	}
346
	
347
	public class ToggleBlockComment : AbstractEditAction
348
	{
349
		/// <remarks>
350
		/// Executes this edit action
351
		/// </remarks>
352
		/// <param name="textArea">The <see cref="ItextArea"/> which is used for callback purposes</param>
353
		public override void Execute(TextArea textArea)
354
		{
355
			if (textArea.Document.ReadOnly) {
356
				return;
357
			}
358
			
359
			string commentStart = null;
360
			if (textArea.Document.HighlightingStrategy.Properties.ContainsKey("BlockCommentBegin")) {
361
				commentStart = textArea.Document.HighlightingStrategy.Properties["BlockCommentBegin"].ToString();
362
			}
363
			
364
			string commentEnd = null;
365
			if (textArea.Document.HighlightingStrategy.Properties.ContainsKey("BlockCommentEnd")) {
366
				commentEnd = textArea.Document.HighlightingStrategy.Properties["BlockCommentEnd"].ToString();
367
			}
368
			
369
			if (commentStart == null || commentStart.Length == 0 || commentEnd == null || commentEnd.Length == 0) {
370
				return;
371
			}
372
			
373
			int selectionStartOffset;
374
			int selectionEndOffset;
375
			
376
			if (textArea.SelectionManager.HasSomethingSelected) {
377
				selectionStartOffset = textArea.SelectionManager.SelectionCollection[0].Offset;
378
				selectionEndOffset = textArea.SelectionManager.SelectionCollection[textArea.SelectionManager.SelectionCollection.Count - 1].EndOffset;
379
			} else {
380
				selectionStartOffset = textArea.Caret.Offset;
381
				selectionEndOffset = selectionStartOffset;
382
			}
383
			
384
			BlockCommentRegion commentRegion = FindSelectedCommentRegion(textArea.Document, commentStart, commentEnd, selectionStartOffset, selectionEndOffset);
385
			
386
			textArea.Document.UndoStack.StartUndoGroup();
387
			if (commentRegion != null) {
388
				RemoveComment(textArea.Document, commentRegion);
389
			} else if (textArea.SelectionManager.HasSomethingSelected) {
390
				SetCommentAt(textArea.Document, selectionStartOffset, selectionEndOffset, commentStart, commentEnd);
391
			}
392
			textArea.Document.UndoStack.EndUndoGroup();
393
			
394
			textArea.Document.CommitUpdate();
395
			textArea.AutoClearSelection = false;
396
		}
397
		
398
		public static BlockCommentRegion FindSelectedCommentRegion(IDocument document, string commentStart, string commentEnd, int selectionStartOffset, int selectionEndOffset)
399
		{
400
			if (document.TextLength == 0) {
401
				return null;
402
			}
403
			
404
			// Find start of comment in selected text.
405
			
406
			int commentEndOffset = -1;
407
			string selectedText = document.GetText(selectionStartOffset, selectionEndOffset - selectionStartOffset);
408
			
409
			int commentStartOffset = selectedText.IndexOf(commentStart);
410
			if (commentStartOffset >= 0) {
411
				commentStartOffset += selectionStartOffset;
412
			}
413
414
			// Find end of comment in selected text.
415
			
416
			if (commentStartOffset >= 0) {
417
				commentEndOffset = selectedText.IndexOf(commentEnd, commentStartOffset + commentStart.Length - selectionStartOffset);
418
			} else {
419
				commentEndOffset = selectedText.IndexOf(commentEnd);
420
			}
421
			
422
			if (commentEndOffset >= 0) {
423
				commentEndOffset += selectionStartOffset;
424
			}
425
			
426
			// Find start of comment before or partially inside the
427
			// selected text.
428
			
429
			int commentEndBeforeStartOffset = -1;
430
			if (commentStartOffset == -1) {
431
				int offset = selectionEndOffset + commentStart.Length - 1;
432
				if (offset > document.TextLength) {
433
					offset = document.TextLength;
434
				}
435
				string text = document.GetText(0, offset);
436
				commentStartOffset = text.LastIndexOf(commentStart);
437
				if (commentStartOffset >= 0) {
438
					// Find end of comment before comment start.
439
					commentEndBeforeStartOffset = text.IndexOf(commentEnd, commentStartOffset, selectionStartOffset - commentStartOffset);
440
					if (commentEndBeforeStartOffset > commentStartOffset) {
441
						commentStartOffset = -1;
442
					}
443
				}
444
			}
445
			
446
			// Find end of comment after or partially after the
447
			// selected text.
448
			
449
			if (commentEndOffset == -1) {
450
				int offset = selectionStartOffset + 1 - commentEnd.Length;
451
				if (offset < 0) {
452
					offset = selectionStartOffset;
453
				}
454
				string text = document.GetText(offset, document.TextLength - offset);
455
				commentEndOffset = text.IndexOf(commentEnd);
456
				if (commentEndOffset >= 0) {
457
					commentEndOffset += offset;
458
				}
459
			}
460
			
461
			if (commentStartOffset != -1 && commentEndOffset != -1) {
462
				return new BlockCommentRegion(commentStart, commentEnd, commentStartOffset, commentEndOffset);
463
			}
464
			
465
			return null;
466
		}
467
		
468
469
		void SetCommentAt(IDocument document, int offsetStart, int offsetEnd, string commentStart, string commentEnd)
470
		{
471
			document.Insert(offsetEnd, commentEnd);
472
			document.Insert(offsetStart, commentStart);
473
		}
474
		
475
		void RemoveComment(IDocument document, BlockCommentRegion commentRegion)
476
		{
477
			document.Remove(commentRegion.EndOffset, commentRegion.CommentEnd.Length);
478
			document.Remove(commentRegion.StartOffset, commentRegion.CommentStart.Length);
479
		}
480
	}
481
	
482
	public class BlockCommentRegion
483
	{
484
		string commentStart = String.Empty;
485
		string commentEnd = String.Empty;
486
		int startOffset = -1;
487
		int endOffset = -1;
488
		
489
		/// <summary>
490
		/// The end offset is the offset where the comment end string starts from.
491
		/// </summary>
492
		public BlockCommentRegion(string commentStart, string commentEnd, int startOffset, int endOffset)
493
		{
494
			this.commentStart = commentStart;
495
			this.commentEnd = commentEnd;
496
			this.startOffset = startOffset;
497
			this.endOffset = endOffset;
498
		}
499
		
500
		public string CommentStart {
501
			get {
502
				return commentStart;
503
			}
504
		}
505
		
506
		public string CommentEnd {
507
			get {
508
				return commentEnd;
509
			}
510
		}
511
		
512
		public int StartOffset {
513
			get {
514
				return startOffset;
515
			}
516
		}
517
		
518
		public int EndOffset {
519
			get {
520
				return endOffset;
521
			}
522
		}
523
		
524
		public override bool Equals(object obj)
525
		{
526
			BlockCommentRegion commentRegion = obj as BlockCommentRegion;
527
			if (commentRegion != null) {
528
				if (commentRegion.commentStart == commentStart &&
529
				    commentRegion.commentEnd == commentEnd &&
530
				    commentRegion.startOffset == startOffset &&
531
				    commentRegion.endOffset == endOffset) {
532
					return true;
533
				}
534
			}
535
			
536
			return false;
537
		}
538
		
539
		public override int GetHashCode()
540
		{
541
			return commentStart.GetHashCode() & commentEnd.GetHashCode() & startOffset.GetHashCode() & endOffset.GetHashCode();
542
		}
543
	}
544
	
545
	public class IndentSelection : AbstractEditAction
546
	{
547
		/// <remarks>
548
		/// Executes this edit action
549
		/// </remarks>
550
		/// <param name="textArea">The <see cref="ItextArea"/> which is used for callback purposes</param>
551
		public override void Execute(TextArea textArea)
552
		{
553
			if (textArea.Document.ReadOnly) {
554
				return;
555
			}
556
			textArea.BeginUpdate();
557
			if (textArea.SelectionManager.HasSomethingSelected) {
558
				foreach (ISelection selection in textArea.SelectionManager.SelectionCollection) {
559
					textArea.Document.FormattingStrategy.IndentLines(textArea, selection.StartPosition.Y, selection.EndPosition.Y);
560
				}
561
			} else {
562
				textArea.Document.FormattingStrategy.IndentLines(textArea, 0, textArea.Document.TotalNumberOfLines - 1);
563
			}
564
			textArea.EndUpdate();
565
			textArea.Refresh();
566
		}
567
	}
568
	
569
	public class Backspace : AbstractEditAction
570
	{
571
		/// <remarks>
572
		/// Executes this edit action
573
		/// </remarks>
574
		/// <param name="textArea">The <see cref="ItextArea"/> which is used for callback purposes</param>
575
		public override void Execute(TextArea textArea)
576
		{
577
			if (textArea.Document.ReadOnly) {
578
				return;
579
			}
580
			if (textArea.SelectionManager.HasSomethingSelected) {
581
				textArea.BeginUpdate();
582
				textArea.Caret.Position = textArea.SelectionManager.SelectionCollection[0].StartPosition;
583
				textArea.SelectionManager.RemoveSelectedText();
584
				textArea.ScrollToCaret();
585
				textArea.EndUpdate();
586
			} else {
587
				if (textArea.Caret.Offset > 0) {
588
					textArea.BeginUpdate();
589
					int curLineNr     = textArea.Document.GetLineNumberForOffset(textArea.Caret.Offset);
590
					int curLineOffset = textArea.Document.GetLineSegment(curLineNr).Offset;
591
					
592
					if (curLineOffset == textArea.Caret.Offset) {
593
						LineSegment line = textArea.Document.GetLineSegment(curLineNr - 1);
594
						bool lastLine = curLineNr == textArea.Document.TotalNumberOfLines;
595
						int lineEndOffset = line.Offset + line.Length;
596
						int lineLength = line.Length;
597
						textArea.Document.Remove(lineEndOffset, curLineOffset - lineEndOffset);
598
						textArea.Caret.Position = new TextLocation(lineLength, curLineNr - 1);
599
						textArea.Document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.PositionToEnd, new TextLocation(0, curLineNr - 1)));
600
						textArea.EndUpdate();
601
					} else {
602
						int caretOffset = textArea.Caret.Offset - 1;
603
						textArea.Caret.Position = textArea.Document.OffsetToPosition(caretOffset);
604
						textArea.Document.Remove(caretOffset, 1);
605
						
606
						textArea.Document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.PositionToLineEnd, new TextLocation(textArea.Caret.Offset - textArea.Document.GetLineSegment(curLineNr).Offset, curLineNr)));
607
						textArea.EndUpdate();
608
					}
609
				}
610
			}
611
		}
612
	}
613
	
614
	public class Delete : AbstractEditAction
615
	{
616
		/// <remarks>
617
		/// Executes this edit action
618
		/// </remarks>
619
		/// <param name="textArea">The <see cref="ItextArea"/> which is used for callback purposes</param>
620
		public override void Execute(TextArea textArea)
621
		{
622
			if (textArea.Document.ReadOnly) {
623
				return;
624
			}
625
			if (textArea.SelectionManager.HasSomethingSelected) {
626
				textArea.BeginUpdate();
627
				textArea.Caret.Position = textArea.SelectionManager.SelectionCollection[0].StartPosition;
628
				textArea.SelectionManager.RemoveSelectedText();
629
				textArea.ScrollToCaret();
630
				textArea.EndUpdate();
631
			} else {
632
				
633
				if (textArea.Caret.Offset < textArea.Document.TextLength) {
634
					textArea.BeginUpdate();
635
					int curLineNr   = textArea.Document.GetLineNumberForOffset(textArea.Caret.Offset);
636
					LineSegment curLine = textArea.Document.GetLineSegment(curLineNr);
637
					
638
					if (curLine.Offset + curLine.Length == textArea.Caret.Offset) {
639
						if (curLineNr + 1 < textArea.Document.TotalNumberOfLines) {
640
							LineSegment nextLine = textArea.Document.GetLineSegment(curLineNr + 1);
641
							
642
							textArea.Document.Remove(textArea.Caret.Offset, nextLine.Offset - textArea.Caret.Offset);
643
							textArea.Document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.PositionToEnd, new TextLocation(0, curLineNr)));
644
						}
645
					} else {
646
						textArea.Document.Remove(textArea.Caret.Offset, 1);
647
//						textArea.Document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.PositionToLineEnd, new TextLocation(textArea.Caret.Offset - textArea.Document.GetLineSegment(curLineNr).Offset, curLineNr)));
648
					}
649
					textArea.UpdateMatchingBracket();
650
					textArea.EndUpdate();
651
				}
652
			}
653
		}
654
	}
655
	
656
	public class MovePageDown : AbstractEditAction
657
	{
658
		/// <remarks>
659
		/// Executes this edit action
660
		/// </remarks>
661
		/// <param name="textArea">The <see cref="ItextArea"/> which is used for callback purposes</param>
662
		public override void Execute(TextArea textArea)
663
		{
664
			int curLineNr           = textArea.Caret.Line;
665
			int requestedLineNumber = Math.Min(textArea.Document.GetNextVisibleLineAbove(curLineNr, textArea.TextView.VisibleLineCount), textArea.Document.TotalNumberOfLines - 1);
666
			
667
			if (curLineNr != requestedLineNumber) {
668
				textArea.Caret.Position = new TextLocation(textArea.Caret.DesiredColumn, requestedLineNumber);
669
			}
670
		}
671
	}
672
	
673
	public class MovePageUp : AbstractEditAction
674
	{
675
		/// <remarks>
676
		/// Executes this edit action
677
		/// </remarks>
678
		/// <param name="textArea">The <see cref="ItextArea"/> which is used for callback purposes</param>
679
		public override void Execute(TextArea textArea)
680
		{
681
			int curLineNr           = textArea.Caret.Line;
682
			int requestedLineNumber = Math.Max(textArea.Document.GetNextVisibleLineBelow(curLineNr, textArea.TextView.VisibleLineCount), 0);
683
			
684
			if (curLineNr != requestedLineNumber) {
685
				textArea.Caret.Position = new TextLocation(textArea.Caret.DesiredColumn, requestedLineNumber);
686
			}
687
		}
688
	}
689
	public class Return : AbstractEditAction
690
	{
691
		/// <remarks>
692
		/// Executes this edit action
693
		/// </remarks>
694
		/// <param name="textArea">The <see cref="ItextArea"/> which is used for callback purposes</param>
695
		public override void Execute(TextArea textArea)
696
		{
697
			if (textArea.Document.ReadOnly) {
698
				return;
699
			}
700
			textArea.BeginUpdate();
701
			textArea.Document.UndoStack.StartUndoGroup();
702
			try {
703
				if (textArea.HandleKeyPress('\n'))
704
					return;
705
				
706
				textArea.InsertString(Environment.NewLine);
707
				
708
				int curLineNr = textArea.Caret.Line;
709
				textArea.Document.FormattingStrategy.FormatLine(textArea, curLineNr, textArea.Caret.Offset, '\n');
710
				textArea.SetDesiredColumn();
711
				
712
				textArea.Document.UpdateQueue.Clear();
713
				textArea.Document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.PositionToEnd, new TextLocation(0, curLineNr - 1)));
714
			} finally {
715
				textArea.Document.UndoStack.EndUndoGroup();
716
				textArea.EndUpdate();
717
			}
718
		}
719
	}
720
	
721
	public class ToggleEditMode : AbstractEditAction
722
	{
723
		/// <remarks>
724
		/// Executes this edit action
725
		/// </remarks>
726
		/// <param name="textArea">The <see cref="ItextArea"/> which is used for callback purposes</param>
727
		public override void Execute(TextArea textArea)
728
		{
729
			if (textArea.Document.ReadOnly) {
730
				return;
731
			}
732
			switch (textArea.Caret.CaretMode) {
733
				case CaretMode.InsertMode:
734
					textArea.Caret.CaretMode = CaretMode.OverwriteMode;
735
					break;
736
				case CaretMode.OverwriteMode:
737
					textArea.Caret.CaretMode = CaretMode.InsertMode;
738
					break;
739
			}
740
		}
741
	}
742
	
743
	public class Undo : AbstractEditAction
744
	{
745
		/// <remarks>
746
		/// Executes this edit action
747
		/// </remarks>
748
		/// <param name="textArea">The <see cref="ItextArea"/> which is used for callback purposes</param>
749
		public override void Execute(TextArea textArea)
750
		{
751
			textArea.MotherTextEditorControl.Undo();
752
		}
753
	}
754
	
755
	public class Redo : AbstractEditAction
756
	{
757
		/// <remarks>
758
		/// Executes this edit action
759
		/// </remarks>
760
		/// <param name="textArea">The <see cref="ItextArea"/> which is used for callback purposes</param>
761
		public override void Execute(TextArea textArea)
762
		{
763
			textArea.MotherTextEditorControl.Redo();
764
		}
765
	}
766
	
767
	/// <summary>
768
	/// handles the ctrl-backspace key
769
	/// functionality attempts to roughly mimic MS Developer studio
770
	/// I will implement this as deleting back to the point that ctrl-leftarrow would
771
	/// take you to
772
	/// </summary>
773
	public class WordBackspace : AbstractEditAction
774
	{
775
		/// <remarks>
776
		/// Executes this edit action
777
		/// </remarks>
778
		/// <param name="textArea">The <see cref="ItextArea"/> which is used for callback purposes</param>
779
		public override void Execute(TextArea textArea)
780
		{
781
			// if anything is selected we will just delete it first
782
			textArea.BeginUpdate();
783
			if (textArea.SelectionManager.HasSomethingSelected) {
784
				textArea.SelectionManager.RemoveSelectedText();
785
				textArea.ScrollToCaret();
786
			}
787
			// now delete from the caret to the beginning of the word
788
			LineSegment line =
789
				textArea.Document.GetLineSegmentForOffset(textArea.Caret.Offset);
790
			// if we are not at the beginning of a line
791
			if(textArea.Caret.Offset > line.Offset) {
792
				int prevWordStart = TextUtilities.FindPrevWordStart(textArea.Document,
793
				                                                    textArea.Caret.Offset);
794
				if(prevWordStart < textArea.Caret.Offset) {
795
					textArea.Document.Remove(prevWordStart,textArea.Caret.Offset -
796
					                         prevWordStart);
797
					textArea.Caret.Position = textArea.Document.OffsetToPosition(prevWordStart);
798
				}
799
			}
800
			// if we are now at the beginning of a line
801
			if(textArea.Caret.Offset == line.Offset) {
802
				// if we are not on the first line
803
				int curLineNr =
804
					textArea.Document.GetLineNumberForOffset(textArea.Caret.Offset);
805
				if(curLineNr > 0) {
806
					// move to the end of the line above
807
					LineSegment lineAbove = textArea.Document.GetLineSegment(curLineNr -
808
					                                                         1);
809
					int endOfLineAbove = lineAbove.Offset + lineAbove.Length;
810
					int charsToDelete = textArea.Caret.Offset - endOfLineAbove;
811
					textArea.Document.Remove(endOfLineAbove,charsToDelete);
812
					textArea.Caret.Position = textArea.Document.OffsetToPosition(endOfLineAbove);
813
				}
814
			}
815
			textArea.SetDesiredColumn();
816
			textArea.EndUpdate();
817
			// if there are now less lines, we need this or there are redraw problems
818
			textArea.Document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.PositionToEnd, new TextLocation(0, textArea.Document.GetLineNumberForOffset(textArea.Caret.Offset))));
819
			textArea.Document.CommitUpdate();
820
		}
821
	}
822
	
823
	/// <summary>
824
	/// handles the ctrl-delete key
825
	/// functionality attempts to mimic MS Developer studio
826
	/// I will implement this as deleting forwardto the point that
827
	/// ctrl-leftarrow would take you to
828
	/// </summary>
829
	public class DeleteWord : Delete
830
	{
831
		/// <remarks>
832
		/// Executes this edit action
833
		/// </remarks>
834
		/// <param name="textArea">The <see cref="ItextArea"/> which is used for callback purposes</param>
835
		public override void Execute(TextArea textArea)
836
		{
837
			// if anything is selected we will just delete it first
838
			textArea.BeginUpdate();
839
			if (textArea.SelectionManager.HasSomethingSelected) {
840
				textArea.SelectionManager.RemoveSelectedText();
841
				textArea.ScrollToCaret();
842
			}
843
			// now delete from the caret to the beginning of the word
844
			LineSegment line =
845
				textArea.Document.GetLineSegmentForOffset(textArea.Caret.Offset);
846
			if(textArea.Caret.Offset == line.Offset + line.Length) {
847
				// if we are at the end of a line
848
				base.Execute(textArea);
849
			} else {
850
				int nextWordStart = TextUtilities.FindNextWordStart(textArea.Document,
851
				                                                    textArea.Caret.Offset);
852
				if(nextWordStart > textArea.Caret.Offset) {
853
					textArea.Document.Remove(textArea.Caret.Offset,nextWordStart -
854
					                         textArea.Caret.Offset);
855
					// cursor never moves with this command
856
				}
857
			}
858
			textArea.UpdateMatchingBracket();
859
			textArea.EndUpdate();
860
			// if there are now less lines, we need this or there are redraw problems
861
			textArea.Document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.PositionToEnd, new TextLocation(0, textArea.Document.GetLineNumberForOffset(textArea.Caret.Offset))));
862
			textArea.Document.CommitUpdate();
863
		}
864
	}
865
	
866
	public class DeleteLine : AbstractEditAction
867
	{
868
		public override void Execute(TextArea textArea)
869
		{
870
			int lineNr = textArea.Caret.Line;
871
			LineSegment line = textArea.Document.GetLineSegment(lineNr);
872
			textArea.Document.Remove(line.Offset, line.TotalLength);
873
			textArea.Caret.Position = textArea.Document.OffsetToPosition(line.Offset);
874
875
			textArea.Document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.PositionToEnd, new TextLocation(0, lineNr)));
876
			textArea.UpdateMatchingBracket();
877
			textArea.Document.CommitUpdate();
878
		}
879
	}
880
	
881
	public class DeleteToLineEnd : AbstractEditAction
882
	{
883
		public override void Execute(TextArea textArea)
884
		{
885
			int lineNr = textArea.Caret.Line;
886
			LineSegment line = textArea.Document.GetLineSegment(lineNr);
887
			
888
			int numRemove = (line.Offset + line.Length) - textArea.Caret.Offset;
889
			if (numRemove > 0) {
890
				textArea.Document.Remove(textArea.Caret.Offset, numRemove);
891
				textArea.Document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.SingleLine, new TextLocation(0, lineNr)));
892
				textArea.Document.CommitUpdate();
893
			}
894
		}
895
	}
896
	
897
	public class GotoMatchingBrace : AbstractEditAction
898
	{
899
		public override void Execute(TextArea textArea)
900
		{
901
			Highlight highlight = textArea.FindMatchingBracketHighlight();
902
			if (highlight != null) {
903
				TextLocation p1 = new TextLocation(highlight.CloseBrace.X + 1, highlight.CloseBrace.Y);
904
				TextLocation p2 = new TextLocation(highlight.OpenBrace.X + 1, highlight.OpenBrace.Y);
905
				if (p1 == textArea.Caret.Position) {
906
					if (textArea.Document.TextEditorProperties.BracketMatchingStyle == BracketMatchingStyle.After) {
907
						textArea.Caret.Position = p2;
908
					} else {
909
						textArea.Caret.Position = new TextLocation(p2.X - 1, p2.Y);
910
					}
911
				} else {
912
					if (textArea.Document.TextEditorProperties.BracketMatchingStyle == BracketMatchingStyle.After) {
913
						textArea.Caret.Position = p1;
914
					} else {
915
						textArea.Caret.Position = new TextLocation(p1.X - 1, p1.Y);
916
					}
917
				}
918
				textArea.SetDesiredColumn();
919
			}
920
		}
921
	}
922
}