public static CommandRange InnerBlock(TextEditorData editor, char openingChar, char closingChar) { var range = Block(editor, openingChar, closingChar); if (range.Length == 0) return CommandRange.Empty; int start = range.Start + 1; int end = range.End - 2; var line = editor.GetLine(editor.OffsetToLineNumber(range.Start)); // exclude newline if it comes just after opening char if (line.EndOffsetIncludingDelimiter - start <= line.DelimiterLength) start += line.DelimiterLength; // exclude whitespace that comes just before the closing char... line = editor.GetLine(editor.OffsetToLineNumber(range.End)); while (Char.IsWhiteSpace(editor.Text[end]) && end >= line.Offset) end--; //.. but only if newline comes after it if (end >= line.Offset) end = range.End - 2; else end -= line.PreviousLine.DelimiterLength; if (start > end + 1) return new CommandRange(start, start); return new CommandRange(start, end+1); }
public static CommandRange QuotedString(TextEditorData editor, char quotationChar) { var start = editor.Caret.Offset; var end = editor.Caret.Offset; var lineOffset = editor.GetLine(editor.Caret.Line).Offset; var lineEndOffset = editor.GetLine(editor.Caret.Line).EndOffset - 1; // Line includes \n if (editor.Text[start] == quotationChar) { // Check if we're on closing char start = lineOffset; var openingCandidate = -1; while (start < end) { if (editor.Text[start] == quotationChar & openingCandidate != -1) openingCandidate = -1; else if (editor.Text[start] == quotationChar) openingCandidate = start; start = start + 1; } if (openingCandidate != -1) { start = openingCandidate; } else { // not on closing char, let's find closing one start = editor.Caret.Offset; end = start + 1; while (end < lineEndOffset & editor.Text[end] != quotationChar) end++; } } else { while (start >= lineOffset & editor.Text[start] != quotationChar) start--; while (end < lineEndOffset & editor.Text[end] != quotationChar) end++; } if (start < 0 || end > lineEndOffset || start == end) return CommandRange.Empty; var endIncludingTrailingWhiteSpace = end; var startIncludingTrailingWhiteSpace = start; // expand to include all trailing white space while (endIncludingTrailingWhiteSpace < lineEndOffset && Char.IsWhiteSpace(editor.Text[endIncludingTrailingWhiteSpace + 1])) endIncludingTrailingWhiteSpace++; // if there's no trailing white space then include leading if (endIncludingTrailingWhiteSpace == end) { while (startIncludingTrailingWhiteSpace > lineOffset && Char.IsWhiteSpace(editor.Text[startIncludingTrailingWhiteSpace - 1])) startIncludingTrailingWhiteSpace--; } return new CommandRange(Math.Min(start, startIncludingTrailingWhiteSpace), Math.Max(end, endIncludingTrailingWhiteSpace) + 1); }
static void RemoveCharBeforCaret (TextEditorData data) { if (!data.IsSomethingSelected && MonoDevelop.Ide.Editor.DefaultSourceEditorOptions.Instance.AutoInsertMatchingBracket) { if (data.Caret.Offset > 0) { var line = data.GetLine (data.Caret.Line); var stack = line.StartSpan.Clone(); if (stack.Any (s => s.Color == "string.other")) { DeleteActions.Backspace (data); return; } stack = line.StartSpan.Clone(); if (stack.Any (s => s.Color == "string.other")) { DeleteActions.Backspace (data); return; } char ch = data.Document.GetCharAt (data.Caret.Offset - 1); int idx = open.IndexOf (ch); if (idx >= 0) { int nextCharOffset = GetNextNonWsCharOffset (data, data.Caret.Offset); if (nextCharOffset >= 0 && closing[idx] == data.Document.GetCharAt (nextCharOffset)) { data.Remove (data.Caret.Offset, nextCharOffset - data.Caret.Offset + 1); } } } } DeleteActions.Backspace (data); }
static void RemoveCharBeforCaret (TextEditorData data) { if (((ISourceEditorOptions)data.Options).AutoInsertMatchingBracket) { if (data.Caret.Offset > 0) { var line = data.GetLine (data.Caret.Line); var stack = line.StartSpan.Clone(); if (stack.Any (s => s.Color == "string.other")) { DeleteActions.Backspace (data); return; } stack = line.StartSpan.Clone(); if (stack.Any (s => s.Color == "string.other")) { DeleteActions.Backspace (data); return; } char ch = data.Document.GetCharAt (data.Caret.Offset - 1); int idx = open.IndexOf (ch); if (idx >= 0) { int nextCharOffset = GetNextNonWsCharOffset (data, data.Caret.Offset); if (nextCharOffset >= 0 && closing[idx] == data.Document.GetCharAt (nextCharOffset)) { bool updateToEnd = data.Document.OffsetToLineNumber (nextCharOffset) != data.Caret.Line; data.Remove (data.Caret.Offset, nextCharOffset - data.Caret.Offset + 1); } } } } DeleteActions.Backspace (data); }
// TODO: move this somewhere else? extend TextEditor? public static void SetSelectLines(TextEditorData editor, int start, int end) { start = Math.Min(start, editor.LineCount); end = Math.Min(end, editor.LineCount); var startLine = start > end ? editor.GetLine(end) : editor.GetLine(start); var endLine = start > end ? editor.GetLine(start) : editor.GetLine(end); editor.SetSelection(startLine.Offset, endLine.EndOffsetIncludingDelimiter); }
static void NewLineSmartIndent(TextEditorData data) { using (var undo = data.OpenUndoGroup()) { data.EnsureCaretIsNotVirtual(); var oldCaretLine = data.Caret.Location.Line; var indentString = data.IndentationTracker.GetIndentationString(data.Caret.Line); data.InsertAtCaret(data.EolMarker); if (data.HasIndentationTracker) { // Don't insert the indent string if the EOL insertion modified the caret location in an unexpected fashion // (This likely means someone has custom logic regarding insertion of the EOL) if (data.Caret.Location.Line == oldCaretLine + 1 && data.Caret.Location.Column == 1) { var line = data.GetLine(data.Caret.Line); var currentIndent = line.GetIndentation(data.Document); var currentCalculatedIndent = data.IndentationTracker.GetIndentationString(data.Caret.Line); if (!string.IsNullOrEmpty(currentCalculatedIndent)) { indentString = currentCalculatedIndent; } if (indentString != currentIndent) { data.InsertAtCaret(indentString); } } } } }
internal static int GetStartOfLineOffset(TextEditorData data, DocumentLocation loc) { var line = data.Document.GetLine(loc.Line); loc = new DocumentLocation(loc.Line, line.Length + 1); // handle folding var foldings = data.Document.GetFoldingsFromOffset(line.Offset); FoldSegment segment = null; foreach (FoldSegment folding in foldings) { if (folding.IsFolded) { if (segment != null && segment.Offset < folding.Offset) { continue; } segment = folding; } } if (segment != null) { loc = data.Document.OffsetToLocation(segment.StartLine.Offset); } line = data.GetLine(loc.Line); return(line.Offset); }
internal static int GetEndOfLineOffset(TextEditorData data, DocumentLocation loc, bool includeDelimiter = true) { var line = data.Document.GetLine(loc.Line); loc = new DocumentLocation(loc.Line, line.Length + 1); // handle folding var foldings = data.Document.GetStartFoldings(loc.Line); FoldSegment segment = null; foreach (FoldSegment folding in foldings) { if (folding.IsFolded && folding.Contains(data.Document.LocationToOffset(loc))) { segment = folding; break; } } if (segment != null) { loc = data.Document.OffsetToLocation(segment.EndLine.Offset + segment.EndColumn - 1); } line = data.GetLine(loc.Line); return(includeDelimiter ? line.EndOffsetIncludingDelimiter : line.EndOffset); }
public static void InsertNewLine(TextEditorData data) { if (!data.CanEditSelection) { return; } using (var undo = data.OpenUndoGroup()) { if (data.IsSomethingSelected) { data.DeleteSelectedText(); } switch (data.Options.IndentStyle) { case IndentStyle.None: data.InsertAtCaret(data.EolMarker); break; case IndentStyle.Auto: data.EnsureCaretIsNotVirtual(); var sb = new StringBuilder(data.EolMarker); sb.Append(data.Document.GetLineIndent(data.Caret.Line)); data.InsertAtCaret(sb.ToString()); break; case IndentStyle.Smart: if (!data.HasIndentationTracker) { goto case IndentStyle.Auto; } NewLineSmartIndent(data); break; case IndentStyle.Virtual: if (!data.HasIndentationTracker) { goto case IndentStyle.Auto; } var oldLine = data.Caret.Line; var curLine = data.GetLine(oldLine); var indentCol = data.GetVirtualIndentationColumn(data.Caret.Location); if (curLine.Length >= data.Caret.Column) { NewLineSmartIndent(data); data.FixVirtualIndentation(); data.FixVirtualIndentation(oldLine); break; } data.Insert(data.Caret.Offset, data.EolMarker); data.FixVirtualIndentation(oldLine); data.Caret.Column = indentCol; break; default: throw new ArgumentOutOfRangeException(); } } }
public static void LineStart(TextEditorData editor) { CaretMoveActions.LineStart(editor); var line = editor.GetLine(editor.Caret.Line); while (editor.Caret.Offset < line.EndOffset && Char.IsWhiteSpace(editor.Text[editor.Caret.Offset])) editor.Caret.Offset++; }
public static void CaretLine(TextEditorData data) { if (data.Document.LineCount <= 1 || !data.CanEdit(data.Caret.Line)) { return; } using (var undo = data.OpenUndoGroup()) { if (data.IsSomethingSelected) { var startLine = data.GetLine(data.MainSelection.Start.Line); var endLine = data.GetLine(data.MainSelection.End.Line); data.Remove(startLine.Offset, endLine.EndOffsetIncludingDelimiter - startLine.Offset); return; } var start = GetStartOfLineOffset(data, data.Caret.Location); var end = GetEndOfLineOffset(data, data.Caret.Location); data.Remove(start, end - start); data.Caret.Column = DocumentLocation.MinColumn; } }
static int PastePlainText(TextEditorData data, int offset, string text, bool preserveSelection = false, byte[] copyData = null) { int inserted = 0; var undo = data.OpenUndoGroup(); try { var version = data.Document.Version; if (!preserveSelection) { data.DeleteSelectedText(!data.IsSomethingSelected || data.MainSelection.SelectionMode != MonoDevelop.Ide.Editor.SelectionMode.Block); } int startLine = data.Caret.Line; data.EnsureCaretIsNotVirtual(); if (data.IsSomethingSelected && data.MainSelection.SelectionMode == MonoDevelop.Ide.Editor.SelectionMode.Block) { var selection = data.MainSelection; var visualInsertLocation = data.LogicalToVisualLocation(selection.Anchor); var changes = new List <Microsoft.CodeAnalysis.Text.TextChange> (); for (int lineNumber = selection.MinLine; lineNumber <= selection.MaxLine; lineNumber++) { var lineSegment = data.GetLine(lineNumber); int insertOffset = lineSegment.GetLogicalColumn(data, visualInsertLocation.Column) - 1; string textToInsert; if (lineSegment.Length < insertOffset) { int visualLastColumn = lineSegment.GetVisualColumn(data, lineSegment.Length + 1); int charsToInsert = visualInsertLocation.Column - visualLastColumn; int spaceCount = charsToInsert % data.Options.TabSize; textToInsert = new string ('\t', (charsToInsert - spaceCount) / data.Options.TabSize) + new string (' ', spaceCount) + text; insertOffset = lineSegment.Length; } else { textToInsert = text; } changes.Add(new Microsoft.CodeAnalysis.Text.TextChange(new Microsoft.CodeAnalysis.Text.TextSpan(lineSegment.Offset + insertOffset, 0), textToInsert)); inserted = textToInsert.Length; } data.Document.ApplyTextChanges(changes); } else { offset = version.MoveOffsetTo(data.Document.Version, offset); inserted = data.PasteText(offset, text, copyData, ref undo); } data.FixVirtualIndentation(startLine); } finally { undo.Dispose(); } return(inserted); }
public static CommandRange QuotedString(TextEditorData editor, char quotationChar) { CommandRange range = FindQuotes(editor, quotationChar); var lineOffset = editor.GetLine(editor.Caret.Line).Offset; var lineEndOffset = editor.GetLine(editor.Caret.Line).EndOffset - 1; // Line includes \n var endIncludingTrailingWhiteSpace = range.End; var startIncludingTrailingWhiteSpace = range.Start; // expand to include all trailing white space while (endIncludingTrailingWhiteSpace < lineEndOffset && Char.IsWhiteSpace(editor.Text[endIncludingTrailingWhiteSpace + 1])) endIncludingTrailingWhiteSpace++; // if there's no trailing white space then include leading if (endIncludingTrailingWhiteSpace == range.End) { while (startIncludingTrailingWhiteSpace > lineOffset && Char.IsWhiteSpace(editor.Text[startIncludingTrailingWhiteSpace - 1])) startIncludingTrailingWhiteSpace--; } return new CommandRange(Math.Min(range.Start, startIncludingTrailingWhiteSpace), Math.Max(range.End, endIncludingTrailingWhiteSpace) + 1); }
public static void ExpandSelectionToLine(TextEditorData data) { var curLineSegment = data.GetLine(data.Caret.Line).SegmentIncludingDelimiter; var range = data.SelectionRange; var selection = TextSegment.FromBounds( System.Math.Min(range.Offset, curLineSegment.Offset), System.Math.Max(range.EndOffset, curLineSegment.EndOffset)); data.Caret.PreserveSelection = true; data.Caret.Offset = selection.EndOffset; data.Caret.PreserveSelection = false; data.SelectionRange = selection; }
string GetIndent(int lineNumber, int column) { var line = data.GetLine(lineNumber); if (line == null) { return(""); } int offset = line.Offset + Math.Min(line.Length, column - 1); stateTracker.Update(offset); return(stateTracker.NextLineIndent); }
internal void UpdateCaretPosition(DocumentChangeEventArgs e) { if (e.AnchorMovementType == AnchorMovementType.BeforeInsertion && caretOffset == e.Offset) { return; } var curVersion = TextEditorData.Version; if (offsetVersion == null) { offsetVersion = curVersion; return; } var newOffset = offsetVersion.MoveOffsetTo(curVersion, caretOffset); offsetVersion = curVersion; if (newOffset == caretOffset || !AutoUpdatePosition) { return; } DocumentLocation old = Location; var newLocation = TextEditorData.OffsetToLocation(newOffset); int newColumn = newLocation.Column; var curLine = TextEditorData.GetLine(newLocation.Line); if (TextEditorData.HasIndentationTracker && TextEditorData.Options.IndentStyle == IndentStyle.Virtual && curLine.Length == 0) { var indentColumn = TextEditorData.GetVirtualIndentationColumn(Location); if (column == indentColumn) { newColumn = indentColumn; } } if (AllowCaretBehindLineEnd) { if (curLine != null && column > curLine.Length) { newColumn = column; } } line = newLocation.Line; column = newColumn; SetDesiredColumn(); UpdateCaretOffset(); OnPositionChanged(new DocumentLocationEventArgs(old)); }
public virtual void HandleSpecialSelectionKey(TextEditorData textEditorData, int unicodeKey) { string start, end; GetSelectionSurroundings(textEditorData, unicodeKey, out start, out end); if (textEditorData.MainSelection.SelectionMode == SelectionMode.Block) { var selection = textEditorData.MainSelection; int startCol = System.Math.Min(selection.Anchor.Column, selection.Lead.Column) - 1; int endCol = System.Math.Max(selection.Anchor.Column, selection.Lead.Column); for (int lineNumber = selection.MinLine; lineNumber <= selection.MaxLine; lineNumber++) { DocumentLine lineSegment = textEditorData.GetLine(lineNumber); if (lineSegment.Offset + startCol < lineSegment.EndOffset) { textEditorData.Insert(lineSegment.Offset + startCol, start); } if (lineSegment.Offset + endCol < lineSegment.EndOffset) { textEditorData.Insert(lineSegment.Offset + endCol, end); } } textEditorData.MainSelection = new Selection( new DocumentLocation(selection.Anchor.Line, endCol == selection.Anchor.Column ? endCol + start.Length : startCol + 1 + start.Length), new DocumentLocation(selection.Lead.Line, endCol == selection.Anchor.Column ? startCol + 1 + start.Length : endCol + start.Length), Mono.TextEditor.SelectionMode.Block); textEditorData.Document.CommitMultipleLineUpdate(textEditorData.MainSelection.MinLine, textEditorData.MainSelection.MaxLine); } else { int anchorOffset = textEditorData.MainSelection.GetAnchorOffset(textEditorData); int leadOffset = textEditorData.MainSelection.GetLeadOffset(textEditorData); if (leadOffset < anchorOffset) { int tmp = anchorOffset; anchorOffset = leadOffset; leadOffset = tmp; } textEditorData.Insert(anchorOffset, start); textEditorData.Insert(leadOffset >= anchorOffset ? leadOffset + start.Length : leadOffset, end); textEditorData.SetSelection(anchorOffset + start.Length, leadOffset + start.Length); } }
public static void Right(TextEditorData editor) { if (!Platform.IsMac) { if (editor.Caret.Offset < editor.GetLine(editor.Caret.Line).EndOffset) CaretMoveActions.Right(editor); } else { using (var undo = editor.OpenUndoGroup()) { DocumentLine line = editor.GetLine(editor.Caret.Line); if (editor.Caret.Column < line.Length) editor.Caret.Column = editor.Caret.Column + 1; } } }
static int PastePlainText(TextEditorData data, int offset, string text, bool preserveSelection = false, byte[] copyData = null) { int inserted = 0; var undo = data.OpenUndoGroup(); var version = data.Document.Version; if (!preserveSelection) { data.DeleteSelectedText(!data.IsSomethingSelected || data.MainSelection.SelectionMode != SelectionMode.Block); } data.EnsureCaretIsNotVirtual(); if (data.IsSomethingSelected && data.MainSelection.SelectionMode == SelectionMode.Block) { var selection = data.MainSelection; var visualInsertLocation = data.LogicalToVisualLocation(selection.Anchor); for (int lineNumber = selection.MinLine; lineNumber <= selection.MaxLine; lineNumber++) { var lineSegment = data.GetLine(lineNumber); int insertOffset = lineSegment.GetLogicalColumn(data, visualInsertLocation.Column) - 1; string textToInsert; if (lineSegment.Length < insertOffset) { int visualLastColumn = lineSegment.GetVisualColumn(data, lineSegment.Length + 1); int charsToInsert = visualInsertLocation.Column - visualLastColumn; int spaceCount = charsToInsert % data.Options.TabSize; textToInsert = new string ('\t', (charsToInsert - spaceCount) / data.Options.TabSize) + new string (' ', spaceCount) + text; insertOffset = lineSegment.Length; } else { textToInsert = text; } inserted = data.Insert(lineSegment.Offset + insertOffset, textToInsert); } } else { offset = version.MoveOffsetTo(data.Document.Version, offset); inserted = data.PasteText(offset, text, copyData, ref undo); } undo.Dispose(); return(inserted); }
internal void UpdateCaretPosition(TextChangeEventArgs e) { //if (e.AnchorMovementType == AnchorMovementType.BeforeInsertion && caretOffset == e.Offset) { // offsetVersion = TextEditorData.Version; // return; //} var curVersion = TextEditorData.Version; var newOffset = e.GetNewOffset(caretOffset); if (!AutoUpdatePosition) { return; } DocumentLocation old = Location; var newLocation = TextEditorData.OffsetToLocation(newOffset); int newColumn = newLocation.Column; var curLine = TextEditorData.GetLine(newLocation.Line); if (TextEditorData.HasIndentationTracker && TextEditorData.Options.IndentStyle == IndentStyle.Virtual && curLine.Length == 0) { var indentColumn = TextEditorData.GetVirtualIndentationColumn(newLocation); if (column == indentColumn) { newColumn = indentColumn; } } if (AllowCaretBehindLineEnd) { if (curLine != null && column > curLine.Length) { newColumn = column; } } line = newLocation.Line; column = newColumn; SetDesiredColumn(); UpdateCaretOffset(); OnPositionChanged(new CaretLocationEventArgs(old, currentBuffer ?? TextEditorData.Document.TextBuffer.CurrentSnapshot, CaretChangeReason.BufferChange)); }
public override void HandleSpecialSelectionKey (TextEditorData textEditorData,uint unicodeKey) { string start, end; GetSelectionSurroundings (textEditorData, unicodeKey, out start, out end); var selection = textEditorData.MainSelection; if (textEditorData.MainSelection.SelectionMode == SelectionMode.Block) { int startCol = System.Math.Min (selection.Anchor.Column, selection.Lead.Column) - 1; int endCol = System.Math.Max (selection.Anchor.Column, selection.Lead.Column); for (int lineNumber = selection.MinLine; lineNumber <= selection.MaxLine; lineNumber++) { DocumentLine lineSegment = textEditorData.GetLine (lineNumber); if (lineSegment.Offset + startCol < lineSegment.EndOffset) textEditorData.Insert (lineSegment.Offset + startCol, start); if (lineSegment.Offset + endCol < lineSegment.EndOffset) textEditorData.Insert (lineSegment.Offset + endCol, end); } textEditorData.MainSelection = new Selection ( new DocumentLocation (selection.Anchor.Line, endCol == selection.Anchor.Column ? endCol + start.Length : startCol + 1 + start.Length), new DocumentLocation (selection.Lead.Line, endCol == selection.Anchor.Column ? startCol + 1 + start.Length : endCol + start.Length), Mono.TextEditor.SelectionMode.Block); textEditorData.Document.CommitMultipleLineUpdate (textEditorData.MainSelection.MinLine, textEditorData.MainSelection.MaxLine); } else { int anchorOffset = selection.GetAnchorOffset (textEditorData); int leadOffset = selection.GetLeadOffset (textEditorData); if (leadOffset < anchorOffset) { int tmp = anchorOffset; anchorOffset = leadOffset; leadOffset = tmp; } textEditorData.Insert (anchorOffset, start); textEditorData.Insert (leadOffset >= anchorOffset ? leadOffset + start.Length : leadOffset, end); // textEditorData.SetSelection (anchorOffset + start.Length, leadOffset + start.Length); if (CSharpTextEditorIndentation.OnTheFlyFormatting) { var l1 = textEditorData.GetLineByOffset (anchorOffset); var l2 = textEditorData.GetLineByOffset (leadOffset); OnTheFlyFormatter.Format (document, l1.Offset, l2.EndOffsetIncludingDelimiter); } } }
// for markup syntax mode the syntax highlighting information need to be taken into account // when calculating the selection offsets. static int PosToOffset(TextEditorData data, DocumentLocation loc) { DocumentLine line = data.GetLine(loc.Line); if (line == null) { return(0); } var startChunk = data.GetChunks(line, line.Offset, line.LengthIncludingDelimiter); int col = 1; foreach (var chunk in startChunk) { if (col <= loc.Column && loc.Column < col + chunk.Length) { return(chunk.Offset - col + loc.Column); } col += chunk.Length; } return(line.Offset + line.Length); }
// for markup syntax mode the syntax highlighting information need to be taken into account // when calculating the selection offsets. int PosToOffset(TextEditorData data, DocumentLocation loc) { LineSegment line = data.GetLine(loc.Line); if (line == null) { return(0); } Chunk startChunk = data.Document.SyntaxMode.GetChunks(data.Document, data.Parent.ColorStyle, line, line.Offset, line.Length); int col = 1; for (Chunk chunk = startChunk; chunk != null; chunk = chunk != null ? chunk.Next : null) { if (col <= loc.Column && loc.Column < col + chunk.Length) { return(chunk.Offset - col + loc.Column); } col += chunk.Length; } return(line.Offset + line.EditableLength); }
public static List<InsertionPoint> GetInsertionPoints (TextEditorData data, ParsedDocument parsedDocument, IType type) { if (data == null) throw new ArgumentNullException ("data"); if (parsedDocument == null) throw new ArgumentNullException ("parsedDocument"); if (type == null) throw new ArgumentNullException ("type"); List<InsertionPoint> result = new List<InsertionPoint> (); int offset = data.LocationToOffset (type.BodyRegion.Start.Line, type.BodyRegion.Start.Column); if (offset < 0) return result; while (offset < data.Length && data.GetCharAt (offset) != '{') { offset++; } var realStartLocation = data.OffsetToLocation (offset); result.Add (GetInsertionPosition (data.Document, realStartLocation.Line, realStartLocation.Column)); result[0].LineBefore = NewLineInsertion.None; foreach (IMember member in type.Members) { DomLocation domLocation = member.BodyRegion.End; if (domLocation.Line <= 0) { LineSegment lineSegment = data.GetLine (member.Location.Line); if (lineSegment == null) continue; domLocation = new DomLocation (member.Location.Line, lineSegment.EditableLength + 1); } result.Add (GetInsertionPosition (data.Document, domLocation.Line, domLocation.Column)); } result[result.Count - 1].LineAfter = NewLineInsertion.None; CheckStartPoint (data.Document, result[0], result.Count == 1); if (result.Count > 1) { result.RemoveAt (result.Count - 1); NewLineInsertion insertLine; var lineBefore = data.GetLine (type.BodyRegion.End.Line - 1); if (lineBefore != null && lineBefore.EditableLength == lineBefore.GetIndentation (data.Document).Length) { insertLine = NewLineInsertion.None; } else { insertLine = NewLineInsertion.Eol; } // search for line start var line = data.GetLine (type.BodyRegion.End.Line); int col = type.BodyRegion.End.Column - 1; while (col > 1 && char.IsWhiteSpace (data.GetCharAt (line.Offset + col - 2))) col--; result.Add (new InsertionPoint (new DocumentLocation (type.BodyRegion.End.Line, col), insertLine, NewLineInsertion.Eol)); CheckEndPoint (data.Document, result[result.Count - 1], result.Count == 1); } foreach (var region in parsedDocument.UserRegions.Where (r => type.BodyRegion.Contains (r.Region))) { result.Add (new InsertionPoint (new DocumentLocation (region.Region.Start.Line + 1, 1), NewLineInsertion.Eol, NewLineInsertion.Eol)); result.Add (new InsertionPoint (new DocumentLocation (region.Region.End.Line, 1), NewLineInsertion.Eol, NewLineInsertion.Eol)); result.Add (new InsertionPoint (new DocumentLocation (region.Region.End.Line + 1, 1), NewLineInsertion.Eol, NewLineInsertion.Eol)); } result.Sort ((left, right) => left.Location.CompareTo (right.Location)); return result; }
public static List<InsertionPoint> GetInsertionPoints (TextEditorData data, ParsedDocument parsedDocument, IUnresolvedTypeDefinition type) { if (data == null) throw new ArgumentNullException ("data"); if (parsedDocument == null) throw new ArgumentNullException ("parsedDocument"); if (type == null) throw new ArgumentNullException ("type"); // update type from parsed document, since this is always newer. //type = parsedDocument.GetInnermostTypeDefinition (type.GetLocation ()) ?? type; List<InsertionPoint> result = new List<InsertionPoint> (); int offset = data.LocationToOffset (type.Region.Begin); if (offset < 0 || type.BodyRegion.IsEmpty) return result; while (offset < data.Length && data.GetCharAt (offset) != '{') { offset++; } var realStartLocation = data.OffsetToLocation (offset); result.Add (GetInsertionPosition (data.Document, realStartLocation.Line, realStartLocation.Column)); result [0].LineBefore = NewLineInsertion.None; foreach (var member in type.Members) { TextLocation domLocation = member.BodyRegion.End; if (domLocation.Line <= 0) { DocumentLine lineSegment = data.GetLine (member.Region.BeginLine); if (lineSegment == null) continue; domLocation = new TextLocation (member.Region.BeginLine, lineSegment.Length + 1); } result.Add (GetInsertionPosition (data.Document, domLocation.Line, domLocation.Column)); } foreach (var nestedType in type.NestedTypes) { TextLocation domLocation = nestedType.BodyRegion.End; if (domLocation.Line <= 0) { DocumentLine lineSegment = data.GetLine (nestedType.Region.BeginLine); if (lineSegment == null) continue; domLocation = new TextLocation (nestedType.Region.BeginLine, lineSegment.Length + 1); } result.Add (GetInsertionPosition (data.Document, domLocation.Line, domLocation.Column)); } result [result.Count - 1].LineAfter = NewLineInsertion.None; CheckStartPoint (data.Document, result [0], result.Count == 1); if (result.Count > 1) { result.RemoveAt (result.Count - 1); NewLineInsertion insertLine; var lineBefore = data.GetLine (type.BodyRegion.EndLine - 1); if (lineBefore != null && lineBefore.Length == lineBefore.GetIndentation (data.Document).Length) { insertLine = NewLineInsertion.None; } else { insertLine = NewLineInsertion.Eol; } // search for line start int col = type.BodyRegion.EndColumn - 1; var line = data.GetLine (type.BodyRegion.EndLine); if (line != null) { while (col > 1 && char.IsWhiteSpace (data.GetCharAt (line.Offset + col - 2))) col--; } result.Add (new InsertionPoint (new DocumentLocation (type.BodyRegion.EndLine, col), insertLine, NewLineInsertion.Eol)); CheckEndPoint (data.Document, result [result.Count - 1], result.Count == 1); } foreach (var region in parsedDocument.UserRegions.Where (r => type.BodyRegion.IsInside (r.Region.Begin))) { result.Add (new InsertionPoint (new DocumentLocation (region.Region.BeginLine + 1, 1), NewLineInsertion.Eol, NewLineInsertion.Eol)); result.Add (new InsertionPoint (new DocumentLocation (region.Region.EndLine, 1), NewLineInsertion.Eol, NewLineInsertion.Eol)); result.Add (new InsertionPoint (new DocumentLocation (region.Region.EndLine + 1, 1), NewLineInsertion.Eol, NewLineInsertion.Eol)); } result.Sort ((left, right) => left.Location.CompareTo (right.Location)); return result; }
// for markup syntax mode the syntax highlighting information need to be taken into account // when calculating the selection offsets. int PosToOffset (TextEditorData data, DocumentLocation loc) { LineSegment line = data.GetLine (loc.Line); if (line == null) return 0; Chunk startChunk = data.Document.SyntaxMode.GetChunks (data.Document, data.Parent.ColorStyle, line, line.Offset, line.Length); int col = 1; for (Chunk chunk = startChunk; chunk != null; chunk = chunk != null ? chunk.Next : null) { if (col <= loc.Column && loc.Column < col + chunk.Length) return chunk.Offset - col + loc.Column; col += chunk.Length; } return line.Offset + line.EditableLength; }
public static void Backspace(TextEditorData data, Action <TextEditorData> removeCharBeforeCaret) { if (!data.CanEditSelection) { return; } using (var undo = data.OpenUndoGroup()) { if (data.IsSomethingSelected) { var visualAnchorLocation = data.LogicalToVisualLocation(data.MainSelection.Anchor); var visualLeadLocation = data.LogicalToVisualLocation(data.MainSelection.Lead); // case: zero width block selection if (data.MainSelection.SelectionMode == SelectionMode.Block && visualAnchorLocation.Column == visualLeadLocation.Column) { var col = data.MainSelection.Lead.Column; if (col <= DocumentLocation.MinColumn) { data.ClearSelection(); return; } bool preserve = data.Caret.PreserveSelection; data.Caret.PreserveSelection = true; for (int lineNumber = data.MainSelection.MinLine; lineNumber <= data.MainSelection.MaxLine; lineNumber++) { var lineSegment = data.Document.GetLine(lineNumber); int insertOffset = lineSegment.GetLogicalColumn(data, visualAnchorLocation.Column - 1) - 1; data.Remove(lineSegment.Offset + insertOffset, 1); } var visualColumn = data.GetLine(data.Caret.Location.Line).GetVisualColumn(data, col - 1); data.MainSelection = new Selection( new DocumentLocation(data.MainSelection.Anchor.Line, data.GetLine(data.MainSelection.Anchor.Line).GetLogicalColumn(data, visualColumn)), new DocumentLocation(data.MainSelection.Lead.Line, data.GetLine(data.MainSelection.Lead.Line).GetLogicalColumn(data, visualColumn)), SelectionMode.Block ); data.Caret.PreserveSelection = preserve; data.Document.CommitMultipleLineUpdate(data.MainSelection.MinLine, data.MainSelection.MaxLine); return; } data.DeleteSelectedText(data.MainSelection.SelectionMode != SelectionMode.Block); return; } if (data.Caret.Line == DocumentLocation.MinLine && data.Caret.Column == DocumentLocation.MinColumn) { return; } // Virtual indentation needs to be fixed before to have the same behavior // if it's there or not (otherwise user has to press multiple backspaces in some cases) data.EnsureCaretIsNotVirtual(); DocumentLine line = data.Document.GetLine(data.Caret.Line); if (data.Caret.Column > line.Length + 1) { data.Caret.Column = line.Length + 1; } else if (data.Caret.Offset == line.Offset) { DocumentLine lineAbove = data.Document.GetLine(data.Caret.Line - 1); if (lineAbove.Length == 0 && data.HasIndentationTracker && data.Options.IndentStyle == IndentStyle.Virtual) { data.Caret.Location = new DocumentLocation(data.Caret.Line - 1, data.IndentationTracker.GetVirtualIndentationColumn(data.Caret.Line - 1, 1)); data.Replace(lineAbove.EndOffsetIncludingDelimiter - lineAbove.DelimiterLength, lineAbove.DelimiterLength, data.IndentationTracker.GetIndentationString(data.Caret.Line - 1, 1)); } else { data.Remove(lineAbove.EndOffsetIncludingDelimiter - lineAbove.DelimiterLength, lineAbove.DelimiterLength); } } else { removeCharBeforeCaret(data); } // Needs to be fixed after, the line may just contain the indentation data.FixVirtualIndentation(); } }
public static void Backspace (TextEditorData data, Action<TextEditorData> removeCharBeforeCaret) { if (!data.CanEditSelection) return; using (var undo = data.OpenUndoGroup ()) { if (data.IsSomethingSelected) { var visualAnchorLocation = data.LogicalToVisualLocation (data.MainSelection.Anchor); var visualLeadLocation = data.LogicalToVisualLocation (data.MainSelection.Lead); // case: zero width block selection if (data.MainSelection.SelectionMode == SelectionMode.Block && visualAnchorLocation.Column == visualLeadLocation.Column) { var col = data.MainSelection.Lead.Column; if (col <= DocumentLocation.MinColumn) { data.ClearSelection (); return; } bool preserve = data.Caret.PreserveSelection; data.Caret.PreserveSelection = true; for (int lineNumber = data.MainSelection.MinLine; lineNumber <= data.MainSelection.MaxLine; lineNumber++) { var lineSegment = data.Document.GetLine (lineNumber); int insertOffset = lineSegment.GetLogicalColumn (data, visualAnchorLocation.Column - 1) - 1; data.Remove (lineSegment.Offset + insertOffset, 1); } var visualColumn = data.GetLine (data.Caret.Location.Line).GetVisualColumn (data, col - 1); data.MainSelection = new Selection ( new DocumentLocation (data.MainSelection.Anchor.Line, data.GetLine (data.MainSelection.Anchor.Line).GetLogicalColumn (data, visualColumn)), new DocumentLocation (data.MainSelection.Lead.Line, data.GetLine (data.MainSelection.Lead.Line).GetLogicalColumn (data, visualColumn)), SelectionMode.Block ); data.Caret.PreserveSelection = preserve; data.Document.CommitMultipleLineUpdate (data.MainSelection.MinLine, data.MainSelection.MaxLine); return; } data.DeleteSelectedText (data.MainSelection.SelectionMode != SelectionMode.Block); return; } if (data.Caret.Line == DocumentLocation.MinLine && data.Caret.Column == DocumentLocation.MinColumn) return; // Virtual indentation needs to be fixed before to have the same behavior // if it's there or not (otherwise user has to press multiple backspaces in some cases) data.EnsureCaretIsNotVirtual (); DocumentLine line = data.Document.GetLine (data.Caret.Line); if (data.Caret.Column > line.Length + 1) { data.Caret.Column = line.Length + 1; } else if (data.Caret.Offset == line.Offset) { DocumentLine lineAbove = data.Document.GetLine (data.Caret.Line - 1); if (lineAbove.Length == 0 && data.HasIndentationTracker && data.Options.IndentStyle == IndentStyle.Virtual) { data.Caret.Location = new DocumentLocation (data.Caret.Line - 1, data.IndentationTracker.GetVirtualIndentationColumn (data.Caret.Line - 1, 1)); data.Replace (lineAbove.EndOffsetIncludingDelimiter - lineAbove.DelimiterLength, lineAbove.DelimiterLength, data.IndentationTracker.GetIndentationString (data.Caret.Line - 1, 1)); } else { data.Remove (lineAbove.EndOffsetIncludingDelimiter - lineAbove.DelimiterLength, lineAbove.DelimiterLength); } } else { removeCharBeforeCaret (data); } // Needs to be fixed after, the line may just contain the indentation data.FixVirtualIndentation (); } }
static DocumentLocation LimitColumn (TextEditorData data, DocumentLocation loc) { return new DocumentLocation (loc.Line, System.Math.Min (loc.Column, data.GetLine (loc.Line).Length + 1)); }
internal static int GetStartOfLineOffset (TextEditorData data, DocumentLocation loc) { var line = data.Document.GetLine (loc.Line); loc = new DocumentLocation (loc.Line, line.Length + 1); // handle folding var foldings = data.Document.GetFoldingsFromOffset (line.Offset); FoldSegment segment = null; foreach (FoldSegment folding in foldings) { if (folding.IsFolded) { if (segment != null && segment.Offset < folding.Offset) continue; segment = folding; } } if (segment != null) loc = data.Document.OffsetToLocation (segment.StartLine.Offset); line = data.GetLine (loc.Line); return line.Offset; }
public static void CaretLine (TextEditorData data) { if (data.Document.LineCount <= 1 || !data.CanEdit (data.Caret.Line)) return; using (var undo = data.OpenUndoGroup ()) { if (data.IsSomethingSelected) { var startLine = data.GetLine (data.MainSelection.Start.Line); var endLine = data.GetLine (data.MainSelection.End.Line); data.Remove (startLine.Offset, endLine.EndOffsetIncludingDelimiter - startLine.Offset); return; } var start = GetStartOfLineOffset (data, data.Caret.Location); var end = GetEndOfLineOffset (data, data.Caret.Location); data.Remove (start, end - start); data.Caret.Column = DocumentLocation.MinColumn; } }
private static CommandRange FindQuotes(TextEditorData editor, char quotationChar) { var start = editor.Caret.Offset; var end = editor.Caret.Offset; var lineOffset = editor.GetLine(editor.Caret.Line).Offset; var lineEndOffset = editor.GetLine(editor.Caret.Line).EndOffset - 1; // Line includes \n if (editor.Text[start] == quotationChar) { // Check if we're on closing char start = lineOffset; var openingCandidate = -1; while (start < end) { if (editor.Text[start] == quotationChar & openingCandidate != -1) openingCandidate = -1; else if (editor.Text[start] == quotationChar) openingCandidate = start; start = start + 1; } if (openingCandidate != -1) { start = openingCandidate; } else { // not on closing char, let's find closing one start = editor.Caret.Offset; end = start + 1; while (end < lineEndOffset & editor.Text[end] != quotationChar) end++; } } else { while (start >= lineOffset & editor.Text[start] != quotationChar) start--; while (end < lineEndOffset & editor.Text[end] != quotationChar) end++; } if (start < lineOffset || end > lineEndOffset || start == end) return CommandRange.Empty; return new CommandRange(start, end); }
private Tuple<DocumentLine, NumberBookmark> GetLineWithBookmark(TextEditorData editor) { var bookmark = BookmarkService.Instance.GetBookmarkLocal(editor.FileName, this.BookmarkNumber); if (bookmark == null) return null; return new Tuple<DocumentLine, NumberBookmark>(editor.GetLine(bookmark.LineNumber), bookmark); }
int CorrectFormatting (TextEditorData data, int start, int end) { int delta = 0; int lineNumber = data.OffsetToLineNumber (start); LineSegment line = data.GetLine (lineNumber); if (line.Offset < start) lineNumber++; line = data.GetLine (lineNumber); if (line == null) return 0; bool wholeDocument = end >= data.Document.Length; do { string indent = line.GetIndentation (data.Document); StringBuilder newIndent = new StringBuilder (); int col = 1; if (data.Options.TabsToSpaces) { foreach (char ch in indent) { if (ch == '\t') { int tabWidth = TextViewMargin.GetNextTabstop (data, col) - col; newIndent.Append (new string (' ', tabWidth)); col += tabWidth; } else { newIndent.Append (ch); } } } else { for (int i = 0; i < indent.Length; i++) { char ch = indent [i]; if (ch == '\t') { int tabWidth = TextViewMargin.GetNextTabstop (data, col) - col; newIndent.Append (ch); col += tabWidth; } else { int tabWidth = TextViewMargin.GetNextTabstop (data, col) - col; newIndent.Append ('\t'); col += tabWidth; while (tabWidth-- > 0 && i + 1 < indent.Length) { if (indent [i + 1] != ' ') break; i++; } } } } if (indent.Length == line.EditableLength) newIndent.Length = 0; if (line.DelimiterLength != 0) { delta -= line.DelimiterLength; delta += data.EolMarker.Length; data.Replace (line.Offset + line.EditableLength, line.DelimiterLength, data.EolMarker); if (!wholeDocument) { end -= line.DelimiterLength; end += data.EolMarker.Length; } } string replaceWith = newIndent.ToString (); if (indent != replaceWith) { int count = (indent ?? "").Length; delta -= count; delta += data.Replace (line.Offset, count, replaceWith); if (!wholeDocument) end = end - count + replaceWith.Length; } lineNumber++; line = data.GetLine (lineNumber); } while (line != null && (wholeDocument || line.EndOffset <= end)); return delta; }
static void IndentCode (TextEditorData data, string lineIndent) { for (int i = 1; i < data.LineCount; i++) { var line = data.GetLine (i + 1); if (line.Length > 0) data.Insert (line.Offset, lineIndent); } }
internal static int GetEndOfLineOffset (TextEditorData data, DocumentLocation loc, bool includeDelimiter = true) { var line = data.Document.GetLine (loc.Line); loc = new DocumentLocation (loc.Line, line.Length + 1); // handle folding var foldings = data.Document.GetStartFoldings (loc.Line); FoldSegment segment = null; foreach (FoldSegment folding in foldings) { if (folding.IsFolded && folding.Contains (data.Document.LocationToOffset (loc))) { segment = folding; break; } } if (segment != null) loc = data.Document.OffsetToLocation (segment.EndLine.Offset + segment.EndColumn - 1); line = data.GetLine (loc.Line); return includeDelimiter ? line.EndOffsetIncludingDelimiter : line.EndOffset; }
public static void InsertNewLine(TextEditorData data) { if (!data.CanEditSelection) { return; } using (var undo = data.OpenUndoGroup()) { if (data.IsSomethingSelected) { var end = data.MainSelection.End; data.DeleteSelectedText(); if (end.Column == 1) { CaretMoveActions.InternalCaretMoveHome(data, true, false); return; } } switch (data.Options.IndentStyle) { case IndentStyle.None: data.InsertAtCaret(data.EolMarker); break; case IndentStyle.Auto: data.EnsureCaretIsNotVirtual(); var indent = data.Document.GetLineIndent(data.Caret.Line); data.InsertAtCaret(data.EolMarker); data.EnsureCaretIsNotVirtual(); if (data.GetLine(data.Caret.Line).Length == 0) { data.InsertAtCaret(indent); } break; case IndentStyle.Smart: if (!data.HasIndentationTracker) { goto case IndentStyle.Auto; } NewLineSmartIndent(data); break; case IndentStyle.Virtual: if (!data.HasIndentationTracker) { goto case IndentStyle.Auto; } var oldLine = data.Caret.Line; var curLine = data.GetLine(oldLine); var indentCol = data.GetVirtualIndentationColumn(data.Caret.Location); if (curLine.Length >= data.Caret.Column) { NewLineSmartIndent(data); data.FixVirtualIndentation(); data.FixVirtualIndentation(oldLine); break; } data.Insert(data.Caret.Offset, data.EolMarker); data.FixVirtualIndentation(oldLine); data.Caret.Column = indentCol; break; default: throw new ArgumentOutOfRangeException(); } } }
protected void InsertCharacter(uint unicodeKey) { if (!textEditorData.CanEdit(Data.Caret.Line)) { return; } HideMouseCursor(); using (var undo = Document.OpenUndoGroup()) { textEditorData.DeleteSelectedText(textEditorData.IsSomethingSelected ? textEditorData.MainSelection.SelectionMode != SelectionMode.Block : true); char ch = (char)unicodeKey; if (!char.IsControl(ch) && textEditorData.CanEdit(Caret.Line)) { LineSegment line = Document.GetLine(Caret.Line); if (Caret.IsInInsertMode || Caret.Column >= line.EditableLength + 1) { string text = Caret.Column > line.EditableLength + 1 ? textEditorData.GetVirtualSpaces(Caret.Line, Caret.Column) + ch.ToString() : ch.ToString(); if (textEditorData.IsSomethingSelected && textEditorData.MainSelection.SelectionMode == SelectionMode.Block) { int length = 0; var visualInsertLocation = editor.LogicalToVisualLocation(Caret.Location); for (int lineNumber = textEditorData.MainSelection.MinLine; lineNumber <= textEditorData.MainSelection.MaxLine; lineNumber++) { LineSegment lineSegment = textEditorData.GetLine(lineNumber); int insertOffset = lineSegment.GetLogicalColumn(textEditorData, visualInsertLocation.Column) - 1; string textToInsert; if (lineSegment.EditableLength < insertOffset) { int visualLastColumn = lineSegment.GetVisualColumn(textEditorData, lineSegment.EditableLength + 1); int charsToInsert = visualInsertLocation.Column - visualLastColumn; int spaceCount = charsToInsert % editor.Options.TabSize; textToInsert = new string ('\t', (charsToInsert - spaceCount) / editor.Options.TabSize) + new string (' ', spaceCount) + text; insertOffset = lineSegment.EditableLength; } else { textToInsert = text; } length = textEditorData.Insert(lineSegment.Offset + insertOffset, textToInsert); } Caret.PreserveSelection = true; Caret.Column += length - 1; textEditorData.MainSelection.Lead = new DocumentLocation(textEditorData.MainSelection.Lead.Line, Caret.Column + 1); textEditorData.MainSelection.Anchor = new DocumentLocation(textEditorData.MainSelection.Anchor.Line, Caret.Column + 1); Document.CommitMultipleLineUpdate(textEditorData.MainSelection.MinLine, textEditorData.MainSelection.MaxLine); } else { int length = textEditorData.Insert(Caret.Offset, text); Caret.Column += length - 1; } } else { int length = textEditorData.Replace(Caret.Offset, 1, ch.ToString()); if (length > 1) { Caret.Offset += length - 1; } } // That causes unnecessary redraws: // bool autoScroll = Caret.AutoScrollToCaret; Caret.Column++; if (Caret.PreserveSelection) { Caret.PreserveSelection = false; } // Caret.AutoScrollToCaret = autoScroll; // if (autoScroll) // Editor.ScrollToCaret (); // Document.RequestUpdate (new LineUpdate (Caret.Line)); // Document.CommitDocumentUpdate (); } } Document.OptimizeTypedUndo(); }
public static void InsertNewLine (TextEditorData data) { if (!data.CanEditSelection) return; using (var undo = data.OpenUndoGroup ()) { if (data.IsSomethingSelected) data.DeleteSelectedText (); switch (data.Options.IndentStyle) { case IndentStyle.None: data.InsertAtCaret (data.EolMarker); break; case IndentStyle.Auto: data.EnsureCaretIsNotVirtual (); var sb = new StringBuilder (data.EolMarker); sb.Append (data.Document.GetLineIndent (data.Caret.Line)); data.InsertAtCaret (sb.ToString ()); break; case IndentStyle.Smart: if (!data.HasIndentationTracker) goto case IndentStyle.Auto; NewLineSmartIndent (data); break; case IndentStyle.Virtual: if (!data.HasIndentationTracker) goto case IndentStyle.Auto; var oldLine = data.Caret.Line; var curLine = data.GetLine (oldLine); var indentCol = data.GetVirtualIndentationColumn (data.Caret.Location); if (curLine.Length >= data.Caret.Column) { NewLineSmartIndent (data); data.FixVirtualIndentation (); data.FixVirtualIndentation (oldLine); break; } data.Insert (data.Caret.Offset, data.EolMarker); data.FixVirtualIndentation (oldLine); data.Caret.Column = indentCol; break; default: throw new ArgumentOutOfRangeException (); } } }
// for markup syntax mode the syntax highlighting information need to be taken into account // when calculating the selection offsets. int PosToOffset (TextEditorData data, DocumentLocation loc) { LineSegment line = data.GetLine (loc.Line); if (line == null) return 0; var startChunk = data.GetChunks (line, line.Offset, line.LengthIncludingDelimiter); int col = 1; foreach (Chunk chunk in startChunk) { if (col <= loc.Column && loc.Column < col + chunk.Length) return chunk.Offset - col + loc.Column; col += chunk.Length; } return line.Offset + line.Length; }
static int PastePlainText (TextEditorData data, int offset, string text, bool preserveSelection = false) { int inserted = 0; using (var undo = data.OpenUndoGroup ()) { var version = data.Document.Version; if (!preserveSelection) data.DeleteSelectedText (!data.IsSomethingSelected || data.MainSelection.SelectionMode != SelectionMode.Block); data.EnsureCaretIsNotVirtual (); if (data.IsSomethingSelected && data.MainSelection.SelectionMode == SelectionMode.Block) { var selection = data.MainSelection; var visualInsertLocation = data.LogicalToVisualLocation (selection.Anchor); for (int lineNumber = selection.MinLine; lineNumber <= selection.MaxLine; lineNumber++) { var lineSegment = data.GetLine (lineNumber); int insertOffset = lineSegment.GetLogicalColumn (data, visualInsertLocation.Column) - 1; string textToInsert; if (lineSegment.Length < insertOffset) { int visualLastColumn = lineSegment.GetVisualColumn (data, lineSegment.Length + 1); int charsToInsert = visualInsertLocation.Column - visualLastColumn; int spaceCount = charsToInsert % data.Options.TabSize; textToInsert = new string ('\t', (charsToInsert - spaceCount) / data.Options.TabSize) + new string (' ', spaceCount) + text; insertOffset = lineSegment.Length; } else { textToInsert = text; } inserted = data.Insert (lineSegment.Offset + insertOffset, textToInsert); } } else { offset = version.MoveOffsetTo (data.Document.Version, offset); inserted = data.PasteText (offset, text); } } return inserted; }
static int PasteFrom(Clipboard clipboard, TextEditorData data, bool preserveSelection, int insertionOffset, bool preserveState) { int result = -1; if (!data.CanEdit(data.Document.OffsetToLineNumber(insertionOffset))) { return(result); } if (clipboard.WaitIsTargetAvailable(CopyOperation.MD_ATOM)) { clipboard.RequestContents(CopyOperation.MD_ATOM, delegate(Clipboard clp, SelectionData selectionData) { if (selectionData.Length > 0) { byte[] selBytes = selectionData.Data; string text = System.Text.Encoding.UTF8.GetString(selBytes, 1, selBytes.Length - 1); bool pasteBlock = (selBytes [0] & 1) == 1; bool pasteLine = (selBytes [0] & 2) == 2; if (!pasteBlock && !pasteLine) { return; } data.Document.BeginAtomicUndo(); if (preserveSelection && data.IsSomethingSelected) { data.DeleteSelectedText(); } data.Caret.PreserveSelection = true; if (pasteBlock) { string[] lines = text.Split('\r'); int lineNr = data.Document.OffsetToLineNumber(insertionOffset); int col = insertionOffset - data.Document.GetLine(lineNr).Offset; int visCol = data.Document.GetLine(lineNr).GetVisualColumn(data, col); LineSegment curLine; int lineCol = col; result = 0; for (int i = 0; i < lines.Length; i++) { while (data.Document.LineCount <= lineNr + i) { data.Insert(data.Document.Length, Environment.NewLine); result += Environment.NewLine.Length; } curLine = data.Document.GetLine(lineNr + i); if (lines [i].Length > 0) { lineCol = curLine.GetLogicalColumn(data, visCol); if (curLine.EditableLength + 1 < lineCol) { result += lineCol - curLine.EditableLength; data.Insert(curLine.Offset + curLine.EditableLength, new string (' ', lineCol - curLine.EditableLength)); } data.Insert(curLine.Offset + lineCol, lines [i]); result += lines [i].Length; } if (!preserveState) { data.Caret.Offset = curLine.Offset + lineCol + lines [i].Length; } } } else if (pasteLine) { result = text.Length; LineSegment curLine = data.Document.GetLine(data.Caret.Line); data.Insert(curLine.Offset, text + data.EolMarker); if (!preserveState) { data.Caret.Offset += text.Length + data.EolMarker.Length; } } /* data.MainSelection = new Selection (data.Document.OffsetToLocation (insertionOffset), * data.Caret.Location, * lines.Length > 1 ? SelectionMode.Block : SelectionMode.Normal);*/ if (!preserveState) { data.ClearSelection(); } data.Caret.PreserveSelection = false; data.Document.EndAtomicUndo(); } }); } if (result < 0 && clipboard.WaitIsTextAvailable()) { clipboard.RequestText(delegate(Clipboard clp, string text) { if (string.IsNullOrEmpty(text)) { return; } data.Document.BeginAtomicUndo(); int caretPos = data.Caret.Offset; if (data.IsSomethingSelected && data.MainSelection.SelectionMode == SelectionMode.Block) { data.Caret.PreserveSelection = true; data.DeleteSelectedText(false); int textLength = 0; int minLine = data.MainSelection.MinLine; int maxLine = data.MainSelection.MaxLine; var visualInsertLocation = data.LogicalToVisualLocation(data.Caret.Location); for (int lineNumber = minLine; lineNumber <= maxLine; lineNumber++) { LineSegment lineSegment = data.GetLine(lineNumber); int insertOffset = lineSegment.GetLogicalColumn(data, visualInsertLocation.Column) - 1; if (lineSegment.EditableLength < insertOffset) { int visualLastColumn = lineSegment.GetVisualColumn(data, lineSegment.EditableLength + 1); int charsToInsert = visualInsertLocation.Column - visualLastColumn; int spaceCount = charsToInsert % data.Options.TabSize; string textToInsert = new string ('\t', (charsToInsert - spaceCount) / data.Options.TabSize) + new string (' ', spaceCount) + text; insertOffset = lineSegment.EditableLength; data.Insert(lineSegment.Offset + insertOffset, textToInsert); data.PasteText(lineSegment.Offset + insertOffset, textToInsert); } else { textLength = data.Insert(lineSegment.Offset + insertOffset, text); data.PasteText(lineSegment.Offset + insertOffset, text); } } data.Caret.Offset += textLength; data.MainSelection.Anchor = new DocumentLocation(System.Math.Max(DocumentLocation.MinLine, data.Caret.Line == minLine ? maxLine : minLine), System.Math.Max(DocumentLocation.MinColumn, data.Caret.Column - textLength)); data.MainSelection.Lead = new DocumentLocation(data.Caret.Line, data.Caret.Column); data.Caret.PreserveSelection = false; data.Document.CommitMultipleLineUpdate(data.MainSelection.MinLine, data.MainSelection.MaxLine); } else { ISegment selection = data.SelectionRange; if (preserveSelection && data.IsSomethingSelected) { data.DeleteSelectedText(); } data.Caret.PreserveSelection = true; //int oldLine = data.Caret.Line; int textLength = data.Insert(insertionOffset, text); result = textLength; if (data.IsSomethingSelected && data.SelectionRange.Offset >= insertionOffset) { data.SelectionRange.Offset += textLength; } if (data.IsSomethingSelected && data.MainSelection.GetAnchorOffset(data) >= insertionOffset) { data.MainSelection.Anchor = data.Document.OffsetToLocation(data.MainSelection.GetAnchorOffset(data) + textLength); } data.Caret.PreserveSelection = false; if (!preserveState) { data.Caret.Offset += textLength; } else { if (caretPos >= insertionOffset) { data.Caret.Offset += textLength; } if (selection != null) { int offset = selection.Offset; if (offset >= insertionOffset) { offset += textLength; } data.SelectionRange = new Segment(offset, selection.Length); } } data.PasteText(insertionOffset, text); } data.Document.EndAtomicUndo(); }); } return(result); }
public static void Right(TextEditorData editor) { if (editor.GetLine(editor.Caret.Line).EndOffset - editor.Caret.Offset - 1 > 0) CaretMoveActions.Right(editor); }
static DocumentLocation LimitColumn(TextEditorData data, DocumentLocation loc) { return(new DocumentLocation(loc.Line, System.Math.Min(loc.Column, data.GetLine(loc.Line).Length + 1))); }
public static void ExpandSelectionToLine (TextEditorData data) { using (var undoGroup = data.OpenUndoGroup ()) { var curLineSegment = data.GetLine (data.Caret.Line).SegmentIncludingDelimiter; var range = data.SelectionRange; var selection = TextSegment.FromBounds ( System.Math.Min (range.Offset, curLineSegment.Offset), System.Math.Max (range.EndOffset, curLineSegment.EndOffset)); data.Caret.PreserveSelection = true; data.Caret.Offset = selection.EndOffset; data.Caret.PreserveSelection = false; data.SelectionRange = selection; } }
public static void InsertNewLine (TextEditorData data) { if (!data.CanEditSelection) return; using (var undo = data.OpenUndoGroup ()) { if (data.IsSomethingSelected) { var end = data.MainSelection.End; data.DeleteSelectedText (); if (end.Column == 1) { CaretMoveActions.InternalCaretMoveHome (data, true, false); return; } } switch (data.Options.IndentStyle) { case IndentStyle.None: data.InsertAtCaret (data.EolMarker); break; case IndentStyle.Auto: data.EnsureCaretIsNotVirtual (); var indent = data.Document.GetLineIndent (data.Caret.Line); data.InsertAtCaret (data.EolMarker); data.EnsureCaretIsNotVirtual (); if (data.GetLine (data.Caret.Line).Length == 0) data.InsertAtCaret (indent); break; case IndentStyle.Smart: if (!data.HasIndentationTracker) goto case IndentStyle.Auto; NewLineSmartIndent (data); break; case IndentStyle.Virtual: if (!data.HasIndentationTracker) goto case IndentStyle.Auto; var oldLine = data.Caret.Line; var curLine = data.GetLine (oldLine); var indentCol = data.GetVirtualIndentationColumn (data.Caret.Location); if (curLine.Length >= data.Caret.Column) { NewLineSmartIndent (data); data.FixVirtualIndentation (); data.FixVirtualIndentation (oldLine); break; } data.Insert (data.Caret.Offset, data.EolMarker); data.FixVirtualIndentation (oldLine); data.Caret.Column = indentCol; break; default: throw new ArgumentOutOfRangeException (); } } }
static int PasteFrom (Clipboard clipboard, TextEditorData data, bool preserveSelection, int insertionOffset, bool preserveState) { int result = -1; if (!data.CanEdit (data.Document.OffsetToLineNumber (insertionOffset))) return result; if (clipboard.WaitIsTargetAvailable (CopyOperation.MD_ATOM)) { clipboard.RequestContents (CopyOperation.MD_ATOM, delegate(Clipboard clp, SelectionData selectionData) { if (selectionData.Length > 0) { byte[] selBytes = selectionData.Data; string text = System.Text.Encoding.UTF8.GetString (selBytes, 1, selBytes.Length - 1); bool pasteBlock = (selBytes [0] & 1) == 1; bool pasteLine = (selBytes [0] & 2) == 2; using (var undo = data.OpenUndoGroup ()) { if (preserveSelection && data.IsSomethingSelected) data.DeleteSelectedText (); data.Caret.PreserveSelection = true; if (pasteBlock) { string[] lines = text.Split ('\r'); int lineNr = data.Document.OffsetToLineNumber (insertionOffset); int col = insertionOffset - data.Document.GetLine (lineNr).Offset; int visCol = data.Document.GetLine (lineNr).GetVisualColumn (data, col); DocumentLine curLine; int lineCol = col; result = 0; for (int i = 0; i < lines.Length; i++) { while (data.Document.LineCount <= lineNr + i) { data.Insert (data.Document.TextLength, Environment.NewLine); result += Environment.NewLine.Length; } curLine = data.Document.GetLine (lineNr + i); if (lines [i].Length > 0) { lineCol = curLine.GetLogicalColumn (data, visCol); if (curLine.Length + 1 < lineCol) { result += lineCol - curLine.Length; data.Insert (curLine.Offset + curLine.Length, new string (' ', lineCol - curLine.Length)); } data.Insert (curLine.Offset + lineCol, lines [i]); result += lines [i].Length; } if (!preserveState) data.Caret.Offset = curLine.Offset + lineCol + lines [i].Length; } } else if (pasteLine) { result = text.Length; DocumentLine curLine = data.Document.GetLine (data.Caret.Line); data.Insert (curLine.Offset, text + data.EolMarker); } else { int offset = data.Caret.Offset; data.InsertAtCaret (text); data.PasteText (offset, text, data.Caret.Offset - offset); } /* data.MainSelection = new Selection (data.Document.OffsetToLocation (insertionOffset), data.Caret.Location, lines.Length > 1 ? SelectionMode.Block : SelectionMode.Normal);*/ if (!preserveState) data.ClearSelection (); data.Caret.PreserveSelection = false; } } }); // we got MD_ATOM text - no need to request text. (otherwise buffer may get copied twice). return result; } if (result < 0 && clipboard.WaitIsTextAvailable ()) { clipboard.RequestText (delegate(Clipboard clp, string text) { if (string.IsNullOrEmpty (text)) return; using (var undo = data.OpenUndoGroup ()) { int caretPos = data.Caret.Offset; if (data.IsSomethingSelected && data.MainSelection.SelectionMode == SelectionMode.Block) { data.Caret.PreserveSelection = true; data.DeleteSelectedText (false); int textLength = 0; int minLine = data.MainSelection.MinLine; int maxLine = data.MainSelection.MaxLine; var visualInsertLocation = data.LogicalToVisualLocation (data.Caret.Location); for (int lineNumber = minLine; lineNumber <= maxLine; lineNumber++) { DocumentLine lineSegment = data.GetLine (lineNumber); int insertOffset = lineSegment.GetLogicalColumn (data, visualInsertLocation.Column) - 1; if (lineSegment.Length < insertOffset) { int visualLastColumn = lineSegment.GetVisualColumn (data, lineSegment.Length + 1); int charsToInsert = visualInsertLocation.Column - visualLastColumn; int spaceCount = charsToInsert % data.Options.TabSize; string textToInsert = new string ('\t', (charsToInsert - spaceCount) / data.Options.TabSize) + new string (' ', spaceCount) + text; insertOffset = lineSegment.Length; int insertedChars = data.Insert (lineSegment.Offset + insertOffset, textToInsert); data.PasteText (lineSegment.Offset + insertOffset, textToInsert, insertedChars); } else { textLength = data.Insert (lineSegment.Offset + insertOffset, text); data.PasteText (lineSegment.Offset + insertOffset, text, textLength); } } data.MainSelection.Anchor = new DocumentLocation (System.Math.Max (DocumentLocation.MinLine, data.Caret.Line == minLine ? maxLine : minLine), System.Math.Max (DocumentLocation.MinColumn, data.Caret.Column - textLength)); data.MainSelection.Lead = new DocumentLocation (data.Caret.Line, data.Caret.Column); data.Caret.PreserveSelection = false; data.Document.CommitMultipleLineUpdate (data.MainSelection.MinLine, data.MainSelection.MaxLine); } else { TextSegment selection = data.SelectionRange; if (preserveSelection && data.IsSomethingSelected) data.DeleteSelectedText (); data.Caret.PreserveSelection = true; //int oldLine = data.Caret.Line; int textLength = data.Insert (insertionOffset, text); result = textLength; if (data.IsSomethingSelected && data.SelectionRange.Offset >= insertionOffset) data.SelectionRange = new TextSegment (data.SelectionRange.Offset + textLength, data.SelectionRange.Length); if (data.IsSomethingSelected && data.MainSelection.GetAnchorOffset (data) >= insertionOffset) data.MainSelection.Anchor = data.Document.OffsetToLocation (data.MainSelection.GetAnchorOffset (data) + textLength); data.Caret.PreserveSelection = false; if (!preserveState) { } else { if (!selection.IsInvalid) { int offset = selection.Offset; if (offset >= insertionOffset) offset += textLength; data.SelectionRange = new TextSegment (offset, selection.Length); } } data.PasteText (insertionOffset, text, textLength); } } }); } return result; }
public static void Backspace(TextEditorData data, Action <TextEditorData> removeCharBeforeCaret) { if (!data.CanEditSelection) { return; } DocumentLine line; bool smartBackspace = false; using (var undo = data.OpenUndoGroup()) { if (data.IsSomethingSelected) { var visualAnchorLocation = data.LogicalToVisualLocation(data.MainSelection.Anchor); var visualLeadLocation = data.LogicalToVisualLocation(data.MainSelection.Lead); // case: zero width block selection if (data.MainSelection.SelectionMode == SelectionMode.Block && visualAnchorLocation.Column == visualLeadLocation.Column) { var col = data.MainSelection.Lead.Column; if (col <= DocumentLocation.MinColumn) { data.ClearSelection(); return; } bool preserve = data.Caret.PreserveSelection; data.Caret.PreserveSelection = true; var changes = new List <Microsoft.CodeAnalysis.Text.TextChange> (); for (int lineNumber = data.MainSelection.MinLine; lineNumber <= data.MainSelection.MaxLine; lineNumber++) { var lineSegment = data.Document.GetLine(lineNumber); int insertOffset = lineSegment.GetLogicalColumn(data, visualAnchorLocation.Column - 1) - 1; changes.Add(new Microsoft.CodeAnalysis.Text.TextChange(new Microsoft.CodeAnalysis.Text.TextSpan(lineSegment.Offset + insertOffset, 1), "")); } data.Document.ApplyTextChanges(changes); var visualColumn = data.GetLine(data.Caret.Location.Line).GetVisualColumn(data, col - 1); data.MainSelection = new MonoDevelop.Ide.Editor.Selection( new DocumentLocation(data.MainSelection.Anchor.Line, data.GetLine(data.MainSelection.Anchor.Line).GetLogicalColumn(data, visualColumn)), new DocumentLocation(data.MainSelection.Lead.Line, data.GetLine(data.MainSelection.Lead.Line).GetLogicalColumn(data, visualColumn)), SelectionMode.Block ); data.Caret.PreserveSelection = preserve; data.Document.CommitMultipleLineUpdate(data.MainSelection.MinLine, data.MainSelection.MaxLine); return; } data.DeleteSelectedText(data.MainSelection.SelectionMode != SelectionMode.Block); return; } if (data.Caret.Line == DocumentLocation.MinLine && data.Caret.Column == DocumentLocation.MinColumn) { return; } // Virtual indentation needs to be fixed before to have the same behavior // if it's there or not (otherwise user has to press multiple backspaces in some cases) data.EnsureCaretIsNotVirtual(); line = data.Document.GetLine(data.Caret.Line); // smart backspace (delete indentation) if (data.HasIndentationTracker && (data.IndentationTracker.SupportedFeatures & IndentationTrackerFeatures.SmartBackspace) != 0 && (data.Options.IndentStyle == IndentStyle.Smart || data.Options.IndentStyle == IndentStyle.Virtual) && data.Options.SmartBackspace) { if (data.Caret.Column == data.GetVirtualIndentationColumn(data.Caret.Location)) { bool isAllIndent = line.GetIndentation(data.Document).Length == data.Caret.Column - 1; if (isAllIndent) { if (!data.Options.GenerateFormattingUndoStep) { SmartBackspace(data, line); return; } smartBackspace = true; } } } // normal backspace. if (data.Caret.Column > line.Length + 1) { data.Caret.Column = line.Length + 1; } else if (data.Caret.Offset == line.Offset) { DocumentLine lineAbove = data.Document.GetLine(data.Caret.Line - 1); if (lineAbove.Length == 0 && data.HasIndentationTracker && data.Options.IndentStyle == IndentStyle.Virtual) { data.Caret.Location = new DocumentLocation(data.Caret.Line - 1, data.GetVirtualIndentationColumn(data.Caret.Line - 1, 1)); data.Replace(lineAbove.EndOffsetIncludingDelimiter - lineAbove.DelimiterLength, lineAbove.DelimiterLength, data.GetIndentationString(data.Caret.Line - 1, 1)); } else { data.Remove(lineAbove.EndOffsetIncludingDelimiter - lineAbove.DelimiterLength, lineAbove.DelimiterLength); } } else { removeCharBeforeCaret(data); } // Needs to be fixed after, the line may just contain the indentation data.FixVirtualIndentation(); } if (data.Options.GenerateFormattingUndoStep && smartBackspace) { using (var undo = data.OpenUndoGroup()) { data.EnsureCaretIsNotVirtual(); SmartBackspace(data, line); } } }
private InsertionPoint GetInsertionPoint(MonoDevelop.Ide.Gui.Document document, IType type) { data = document.Editor; if (data == null) { throw new System.ArgumentNullException ("data"); } var parsedDocument = document.ParsedDocument; if (parsedDocument == null) { throw new System.ArgumentNullException ("parsedDocument"); } if (type == null) { throw new System.ArgumentNullException ("type"); } type = (parsedDocument.CompilationUnit.GetTypeAt (type.Location) ?? type); DomRegion domRegion = type.BodyRegion; var start = type.BodyRegion.Start.Line; indent = data.GetLine(start).GetIndentation(data.Document); DomLocation domLocation = domRegion.End; int num = data.LocationToOffset (domLocation.Line, 1); while (num < data.Length && data.GetCharAt(num) != '}') { num++; } num++; DocumentLocation documentLocation = data.OffsetToLocation (num); LineSegment lineAfterClassEnd = data.GetLine (domLocation.Line + 1); NewLineInsertion lineAfter; if (lineAfterClassEnd != null && lineAfterClassEnd.EditableLength == lineAfterClassEnd.GetIndentation (data.Document).Length) lineAfter = NewLineInsertion.BlankLine; else lineAfter = NewLineInsertion.None; return new InsertionPoint (documentLocation, NewLineInsertion.None, lineAfter); }
protected void InsertCharacter(uint unicodeKey) { if (!textEditorData.CanEdit(Data.Caret.Line)) { return; } HideMouseCursor(); using (var undo = Document.OpenUndoGroup()) { if (textEditorData.IsSomethingSelected && textEditorData.Options.EnableSelectionWrappingKeys && IsSpecialKeyForSelection(unicodeKey)) { textEditorData.SelectionSurroundingProvider.HandleSpecialSelectionKey(textEditorData, unicodeKey); return; } textEditorData.DeleteSelectedText( textEditorData.IsSomethingSelected ? textEditorData.MainSelection.SelectionMode != SelectionMode.Block : true); // Needs to be called after delete text, delete text handles virtual caret postitions itself, // but afterwards the virtual position may need to be restored. textEditorData.EnsureCaretIsNotVirtual(); char ch = (char)unicodeKey; if (!char.IsControl(ch) && textEditorData.CanEdit(Caret.Line)) { DocumentLine line = Document.GetLine(Caret.Line); if (Caret.IsInInsertMode || Caret.Column >= line.Length + 1) { string text = ch.ToString(); if (textEditorData.IsSomethingSelected && textEditorData.MainSelection.SelectionMode == SelectionMode.Block) { var visualInsertLocation = textEditorData.LogicalToVisualLocation(Caret.Location); var selection = textEditorData.MainSelection; Caret.PreserveSelection = true; for (int lineNumber = selection.MinLine; lineNumber <= selection.MaxLine; lineNumber++) { DocumentLine lineSegment = textEditorData.GetLine(lineNumber); int insertOffset = lineSegment.GetLogicalColumn(textEditorData, visualInsertLocation.Column) - 1; string textToInsert; if (lineSegment.Length < insertOffset) { int visualLastColumn = lineSegment.GetVisualColumn(textEditorData, lineSegment.Length + 1); int charsToInsert = visualInsertLocation.Column - visualLastColumn; int spaceCount = charsToInsert % editor.Options.TabSize; textToInsert = new string ('\t', (charsToInsert - spaceCount) / editor.Options.TabSize) + new string (' ', spaceCount) + text; insertOffset = lineSegment.Length; } else { textToInsert = text; } textEditorData.Insert(lineSegment.Offset + insertOffset, textToInsert); } var visualColumn = textEditorData.GetLine(Caret.Location.Line).GetVisualColumn(textEditorData, Caret.Column); textEditorData.MainSelection = new Selection( new DocumentLocation(selection.Anchor.Line, textEditorData.GetLine(selection.Anchor.Line).GetLogicalColumn(textEditorData, visualColumn)), new DocumentLocation(selection.Lead.Line, textEditorData.GetLine(selection.Lead.Line).GetLogicalColumn(textEditorData, visualColumn)), SelectionMode.Block ); Document.CommitMultipleLineUpdate(textEditorData.MainSelection.MinLine, textEditorData.MainSelection.MaxLine); } else { textEditorData.Insert(Caret.Offset, text); } } else { textEditorData.Replace(Caret.Offset, 1, ch.ToString()); } // That causes unnecessary redraws: // bool autoScroll = Caret.AutoScrollToCaret; // Caret.Column++; if (Caret.PreserveSelection) { Caret.PreserveSelection = false; } // Caret.AutoScrollToCaret = autoScroll; // if (autoScroll) // Editor.ScrollToCaret (); // Document.RequestUpdate (new LineUpdate (Caret.Line)); // Document.CommitDocumentUpdate (); } } Document.OptimizeTypedUndo(); }