private bool ApplyOverlap(Token token, int start, int end, VisualLine visualLine) { if (token.Start >= end) { return(false); } if (token.End <= start) { return(true); } int overlapStart = Math.Max(start, token.Start); int overlapEnd = Math.Min(end, token.End); int offset = visualLine.FirstDocumentLine.Offset; overlapStart = visualLine.GetVisualColumn(overlapStart - offset); overlapEnd = visualLine.GetVisualColumn(overlapEnd - offset); void ApplyColorizerElements(VisualLineElement lineElement) { foreach (IColorizerElement <Token> colorizerElement in Elements) { colorizerElement.Apply(lineElement, token); } } ChangeVisualElements(overlapStart, overlapEnd, ApplyColorizerElements); return(true); }
/// <summary> /// Validates the visual column of the caret using the specified visual line. /// The visual line must contain the caret offset. /// </summary> void RevalidateVisualColumn(VisualLine visualLine) { if (visualLine == null) { throw new ArgumentNullException("visualLine"); } // mark column as validated visualColumnValid = true; int caretOffset = textView.Document.GetOffset(position); int firstDocumentLineOffset = visualLine.FirstDocumentLine.Offset; if (position.VisualColumn < 0) { position.VisualColumn = visualLine.GetVisualColumn(caretOffset - firstDocumentLineOffset); } else { int offsetFromVisualColumn = visualLine.GetRelativeOffset(position.VisualColumn); offsetFromVisualColumn += firstDocumentLineOffset; if (offsetFromVisualColumn != caretOffset) { position.VisualColumn = visualLine.GetVisualColumn(caretOffset - firstDocumentLineOffset); } else { if (position.VisualColumn > visualLine.VisualLength) { position.VisualColumn = visualLine.VisualLength; } } } // search possible caret position (first try forwards) int newVisualColumn = visualLine.GetNextCaretPosition(position.VisualColumn - 1, LogicalDirection.Forward, CaretPositioningMode.Normal); if (newVisualColumn < 0) { // then try backwards newVisualColumn = visualLine.GetNextCaretPosition(position.VisualColumn + 1, LogicalDirection.Backward, CaretPositioningMode.Normal); } if (newVisualColumn < 0) { throw ThrowUtil.NoValidCaretPosition(); } if (newVisualColumn != position.VisualColumn) { int newOffset = visualLine.GetRelativeOffset(newVisualColumn) + firstDocumentLineOffset; this.Position = new TextViewPosition(textView.Document.GetLocation(newOffset), newVisualColumn); } }
int GetOffsetFromMousePositionFirstTextLineOnly(Point positionRelativeToTextView, out int visualColumn) { visualColumn = 0; TextView textView = textArea.TextView; Point pos = positionRelativeToTextView; if (pos.Y < 0) { pos.Y = 0; } if (pos.Y > textView.ActualHeight) { pos.Y = textView.ActualHeight; } pos += textView.ScrollOffset; if (pos.Y > textView.DocumentHeight) { pos.Y = textView.DocumentHeight - ExtensionMethods.Epsilon; } VisualLine line = textView.GetVisualLineFromVisualTop(pos.Y); if (line != null) { visualColumn = line.GetVisualColumn(line.TextLines.First(), pos.X, textArea.Selection.EnableVirtualSpace); return(line.GetRelativeOffset(visualColumn) + line.FirstDocumentLine.Offset); } return(-1); }
int GetOffsetFromMousePosition(Point positionRelativeToTextView, out int visualColumn, out bool isAtEndOfLine) { visualColumn = 0; TextView textView = textArea.TextView; Point pos = positionRelativeToTextView; if (pos.Y < 0) { pos.Y = 0; } if (pos.Y > textView.ActualHeight) { pos.Y = textView.ActualHeight; } pos += textView.ScrollOffset; if (pos.Y >= textView.DocumentHeight) { pos.Y = textView.DocumentHeight - 0.01; } VisualLine line = textView.GetVisualLineFromVisualTop(pos.Y); if (line != null) { var textLine = line.GetTextLineByVisualYPosition(pos.Y); visualColumn = line.GetVisualColumn(textLine, pos.X, textArea.Selection.EnableVirtualSpace); isAtEndOfLine = (visualColumn >= line.GetTextLineVisualStartColumn(textLine) + textLine.Length); return(line.GetRelativeOffset(visualColumn) + line.FirstDocumentLine.Offset); } isAtEndOfLine = false; return(-1); }
public static ISegment GetWholeWordSegment(TextDocument document, TextEditor textEditor, LogicalDirection direction = LogicalDirection.Forward) { TextArea textArea = textEditor.TextArea; TextView textView = textArea.TextView; if (textView == null) { return(null); } Point pos = textArea.TextView.GetVisualPosition(textArea.Caret.Position, VisualYPosition.LineMiddle) - textArea.TextView.ScrollOffset; VisualLine line = textView.GetVisualLine(textEditor.TextArea.Caret.Position.Line); if (line != null) { int visualColumn = line.GetVisualColumn(pos, textArea.Selection.EnableVirtualSpace); int wordStartVc; if (line.VisualLength == visualColumn) { wordStartVc = line.GetNextCaretPosition(visualColumn, LogicalDirection.Backward, CaretPositioningMode.WordStartOrSymbol, textArea.Selection.EnableVirtualSpace); } else { wordStartVc = line.GetNextCaretPosition(visualColumn + 1, LogicalDirection.Backward, CaretPositioningMode.WordStartOrSymbol, textArea.Selection.EnableVirtualSpace); } if (wordStartVc == -1) { wordStartVc = 0; } int wordEndVc = line.GetNextCaretPosition(wordStartVc, direction, CaretPositioningMode.WordBorderOrSymbol, textArea.Selection.EnableVirtualSpace); if (wordEndVc == -1) { wordEndVc = line.VisualLength; } if (visualColumn < wordStartVc || (direction == LogicalDirection.Forward && visualColumn > wordEndVc)) { return(new SimpleSegment()); } if (direction == LogicalDirection.Backward && wordStartVc > wordEndVc) { int temp = wordEndVc; wordEndVc = wordStartVc; wordStartVc = temp; } int relOffset = line.FirstDocumentLine.Offset; int wordStartOffset = line.GetRelativeOffset(wordStartVc) + relOffset; int wordEndOffset = line.GetRelativeOffset(wordEndVc) + relOffset; return(new SimpleSegment(wordStartOffset, wordEndOffset - wordStartOffset)); } return(null); }
void CalculateSegments() { DocumentLine nextLine = document.GetLineByNumber(Math.Min(startLine, endLine)); do { VisualLine vl = textArea.TextView.GetOrConstructVisualLine(nextLine); int startVC = vl.GetVisualColumn(new Point(startXPos, 0), true); int endVC = vl.GetVisualColumn(new Point(endXPos, 0), true); int baseOffset = vl.FirstDocumentLine.Offset; int startOffset = baseOffset + vl.GetRelativeOffset(startVC); int endOffset = baseOffset + vl.GetRelativeOffset(endVC); segments.Add(new SelectionSegment(startOffset, startVC, endOffset, endVC)); nextLine = vl.LastDocumentLine.NextLine; } while (nextLine != null && nextLine.LineNumber <= Math.Max(startLine, endLine)); }
/// <summary> /// Changes a part of the current document line. /// </summary> /// <param name="startOffset">Start offset of the region to change</param> /// <param name="endOffset">End offset of the region to change</param> /// <param name="action">Action that changes an individual <see cref="VisualLineElement"/>.</param> protected void ChangeLinePart(int startOffset, int endOffset, Action <VisualLineElement> action) { if (startOffset < currentDocumentLineStartOffset || startOffset > currentDocumentLineEndOffset) { throw new ArgumentOutOfRangeException("startOffset", startOffset, String.Format("Value must be between {0} and {1}", currentDocumentLineStartOffset, currentDocumentLineEndOffset)); } if (endOffset < startOffset || endOffset > currentDocumentLineEndOffset) { throw new ArgumentOutOfRangeException("endOffset", endOffset, String.Format("Value must be between {0} and {1}", startOffset, currentDocumentLineEndOffset)); } VisualLine vl = this.CurrentContext.VisualLine; int visualStart = vl.GetVisualColumn(startOffset - firstLineStart); int visualEnd = vl.GetVisualColumn(endOffset - firstLineStart); if (visualStart < visualEnd) { ChangeVisualElements(visualStart, visualEnd, action); } }
int GetTextLineIndexFromOffset(List <TextLine> textLines, int offset) { int lineNumber = TextView.Document.GetLineByOffset(offset).LineNumber; VisualLine vl = TextView.GetVisualLine(lineNumber); if (vl != null) { int relOffset = offset - vl.FirstDocumentLine.Offset; TextLine line = vl.GetTextLine(vl.GetVisualColumn(relOffset)); return(textLines.IndexOf(line)); } return(-1); }
private bool ApplyOverlap(Expression expression, int start, int end, VisualLine visualLine) { if (expression.StartToken.Start >= end) { return(false); } if (expression.EndToken.End <= start) { return(true); } int overlapStart = Math.Max(start, expression.StartToken.Start); int overlapEnd = Math.Min(end, expression.EndToken.End); int offset = visualLine.FirstDocumentLine.Offset; overlapStart = visualLine.GetVisualColumn(overlapStart - offset); overlapEnd = visualLine.GetVisualColumn(overlapEnd - offset); IEnumerable <IColorizerElement <Expression> > elements = Elements .Where(x => x.CanApply(expression)); void ApplyColorizerElements(VisualLineElement lineElement) { foreach (IColorizerElement <Expression> colorizerElement in elements) { colorizerElement.Apply(lineElement, expression); } } if (elements.Count() > 0) { ChangeVisualElements(overlapStart, overlapEnd, ApplyColorizerElements); } return(true); }
private void OnTextEditorMouseHover(object sender, MouseEventArgs eventArgs) { // Find offset under mouse cursor. var mousePos = eventArgs.GetPosition(_textEditor.TextArea.TextView); double verticalOffset = _textEditor.VerticalOffset; VisualLine visualLine = _textEditor.TextArea.TextView.GetVisualLineFromVisualTop(mousePos.Y + verticalOffset); if (visualLine == null) { return; } double horizontalOffset = _textEditor.HorizontalOffset; int visualColumn = visualLine.GetVisualColumn(mousePos + new Vector(horizontalOffset, verticalOffset)); int relativeOffset = visualLine.GetRelativeOffset(visualColumn); int offset = visualLine.FirstDocumentLine.Offset + relativeOffset; // Get word at mouse cursor. var text = TextUtilities.GetIdentifierAt(_textEditor.Document, offset); // Get region at mouse cursor. ShaderRegion region = _parser.IdentifyRegion(_textEditor.Document, offset); NamedObjectCollection <NamedCompletionData>[] lookupTables = GetToolTipLookupTables(region); if (lookupTables != null) { // Look up symbol in lookup tables. NamedCompletionData info = null; foreach (NamedObjectCollection <NamedCompletionData> lookupTable in lookupTables) { if (lookupTable.TryGet <NamedCompletionData>(text, out info)) { break; } } // Show tooltip if lookup was successful and description for the symbol is available. if (info != null && !string.IsNullOrEmpty(info.Description as string)) { // TODO: Use s better tooltip style. _toolTip = new ToolTip { Content = info.Description, Placement = PlacementMode.Mouse, IsOpen = true, }; } } }
SimpleSegment GetWordAtMousePosition(MouseEventArgs e) { TextView textView = textArea.TextView; if (textView == null) { return(SimpleSegment.Invalid); } Point pos = e.GetPosition(textView); if (pos.Y < 0) { pos.Y = 0; } if (pos.Y > textView.ActualHeight) { pos.Y = textView.ActualHeight; } pos += textView.ScrollOffset; VisualLine line = textView.GetVisualLineFromVisualTop(pos.Y); if (line != null) { int visualColumn = line.GetVisualColumn(pos, textArea.Selection.EnableVirtualSpace); int wordStartVC = line.GetNextCaretPosition(visualColumn + 1, LogicalDirection.Backward, CaretPositioningMode.WordStartOrSymbol, textArea.Selection.EnableVirtualSpace); if (wordStartVC == -1) { wordStartVC = 0; } int wordEndVC = line.GetNextCaretPosition(wordStartVC, LogicalDirection.Forward, CaretPositioningMode.WordBorderOrSymbol, textArea.Selection.EnableVirtualSpace); if (wordEndVC == -1) { wordEndVC = line.VisualLength; } int relOffset = line.FirstDocumentLine.Offset; int wordStartOffset = line.GetRelativeOffset(wordStartVC) + relOffset; int wordEndOffset = line.GetRelativeOffset(wordEndVC) + relOffset; return(new SimpleSegment(wordStartOffset, wordEndOffset - wordStartOffset)); } else { return(SimpleSegment.Invalid); } }
/// <summary> /// Validates the visual column of the caret using the specified visual line. /// The visual line must contain the caret offset. /// </summary> void RevalidateVisualColumn(VisualLine visualLine) { if (visualLine == null) { throw new ArgumentNullException("visualLine"); } // mark column as validated visualColumnValid = true; int caretOffset = textView.Document.GetOffset(position); int firstDocumentLineOffset = visualLine.FirstDocumentLine.Offset; if (position.VisualColumn < 0) { position.VisualColumn = visualLine.GetVisualColumn(caretOffset - firstDocumentLineOffset); } else { int offsetFromVisualColumn = visualLine.GetRelativeOffset(position.VisualColumn); offsetFromVisualColumn += firstDocumentLineOffset; if (offsetFromVisualColumn != caretOffset) { position.VisualColumn = visualLine.GetVisualColumn(caretOffset - firstDocumentLineOffset); } else { if (position.VisualColumn > visualLine.VisualLength) { position.VisualColumn = visualLine.VisualLength; } } } // search possible caret positions int newVisualColumnForwards = visualLine.GetNextCaretPosition(position.VisualColumn - 1, LogicalDirection.Forward, CaretPositioningMode.Normal); // If position.VisualColumn was valid, we're done with validation. if (newVisualColumnForwards != position.VisualColumn) { // also search backwards so that we can pick the better match int newVisualColumnBackwards = visualLine.GetNextCaretPosition(position.VisualColumn + 1, LogicalDirection.Backward, CaretPositioningMode.Normal); if (newVisualColumnForwards < 0 && newVisualColumnBackwards < 0) { throw ThrowUtil.NoValidCaretPosition(); } // determine offsets for new visual column positions int newOffsetForwards; if (newVisualColumnForwards >= 0) { newOffsetForwards = visualLine.GetRelativeOffset(newVisualColumnForwards) + firstDocumentLineOffset; } else { newOffsetForwards = -1; } int newOffsetBackwards; if (newVisualColumnBackwards >= 0) { newOffsetBackwards = visualLine.GetRelativeOffset(newVisualColumnBackwards) + firstDocumentLineOffset; } else { newOffsetBackwards = -1; } int newVisualColumn, newOffset; // if there's only one valid position, use it if (newVisualColumnForwards < 0) { newVisualColumn = newVisualColumnBackwards; newOffset = newOffsetBackwards; } else if (newVisualColumnBackwards < 0) { newVisualColumn = newVisualColumnForwards; newOffset = newOffsetForwards; } else { // two valid positions: find the better match if (Math.Abs(newOffsetBackwards - caretOffset) < Math.Abs(newOffsetForwards - caretOffset)) { // backwards is better newVisualColumn = newVisualColumnBackwards; newOffset = newOffsetBackwards; } else { // forwards is better newVisualColumn = newVisualColumnForwards; newOffset = newOffsetForwards; } } this.Position = new TextViewPosition(textView.Document.GetLocation(newOffset), newVisualColumn); } }
static void MoveCaretUpDown(TextArea textArea, CaretMovementType direction, VisualLine visualLine, TextLine textLine, int caretVisualColumn) { // moving up/down happens using the desired visual X position double xPos = textArea.Caret.DesiredXPos; if (double.IsNaN(xPos)) { xPos = visualLine.GetTextLineVisualXPosition(textLine, caretVisualColumn); } // now find the TextLine+VisualLine where the caret will end up in VisualLine targetVisualLine = visualLine; TextLine targetLine; int textLineIndex = visualLine.TextLines.IndexOf(textLine); switch (direction) { case CaretMovementType.LineUp: { // Move up: move to the previous TextLine in the same visual line // or move to the last TextLine of the previous visual line int prevLineNumber = visualLine.FirstDocumentLine.LineNumber - 1; if (textLineIndex > 0) { targetLine = visualLine.TextLines[textLineIndex - 1]; } else if (prevLineNumber >= 1) { DocumentLine prevLine = textArea.Document.GetLineByNumber(prevLineNumber); targetVisualLine = textArea.TextView.GetOrConstructVisualLine(prevLine); targetLine = targetVisualLine.TextLines[targetVisualLine.TextLines.Count - 1]; } else { targetLine = null; } break; } case CaretMovementType.LineDown: { // Move down: move to the next TextLine in the same visual line // or move to the first TextLine of the next visual line int nextLineNumber = visualLine.LastDocumentLine.LineNumber + 1; if (textLineIndex < visualLine.TextLines.Count - 1) { targetLine = visualLine.TextLines[textLineIndex + 1]; } else if (nextLineNumber <= textArea.Document.LineCount) { DocumentLine nextLine = textArea.Document.GetLineByNumber(nextLineNumber); targetVisualLine = textArea.TextView.GetOrConstructVisualLine(nextLine); targetLine = targetVisualLine.TextLines[0]; } else { targetLine = null; } break; } case CaretMovementType.PageUp: case CaretMovementType.PageDown: { // Page up/down: find the target line using its visual position double yPos = visualLine.GetTextLineVisualYPosition(textLine, VisualYPosition.LineMiddle); if (direction == CaretMovementType.PageUp) { yPos -= textArea.TextView.RenderSize.Height; } else { yPos += textArea.TextView.RenderSize.Height; } DocumentLine newLine = textArea.TextView.GetDocumentLineByVisualTop(yPos); targetVisualLine = textArea.TextView.GetOrConstructVisualLine(newLine); targetLine = targetVisualLine.GetTextLineByVisualYPosition(yPos); break; } default: throw new NotSupportedException(direction.ToString()); } if (targetLine != null) { double yPos = targetVisualLine.GetTextLineVisualYPosition(targetLine, VisualYPosition.LineMiddle); int newVisualColumn = targetVisualLine.GetVisualColumn(new Point(xPos, yPos), textArea.Selection.EnableVirtualSpace); SetCaretPosition(textArea, targetVisualLine, targetLine, newVisualColumn, false); textArea.Caret.DesiredXPos = xPos; } }
static TextViewPosition GetUpDownCaretPosition(TextView textView, TextViewPosition caretPosition, CaretMovementType direction, VisualLine visualLine, TextLine textLine, bool enableVirtualSpace, ref double xPos) { // moving up/down happens using the desired visual X position if (double.IsNaN(xPos)) { xPos = visualLine.GetTextLineVisualXPosition(textLine, caretPosition.VisualColumn); } // now find the TextLine+VisualLine where the caret will end up in VisualLine targetVisualLine = visualLine; TextLine targetLine; int textLineIndex = visualLine.TextLines.IndexOf(textLine); switch (direction) { case CaretMovementType.LineUp: { // Move up: move to the previous TextLine in the same visual line // or move to the last TextLine of the previous visual line int prevLineNumber = visualLine.FirstDocumentLine.LineNumber - 1; if (textLineIndex > 0) { targetLine = visualLine.TextLines[textLineIndex - 1]; } else if (prevLineNumber >= 1) { DocumentLine prevLine = textView.Document.GetLineByNumber(prevLineNumber); targetVisualLine = textView.GetOrConstructVisualLine(prevLine); targetLine = targetVisualLine.TextLines[targetVisualLine.TextLines.Count - 1]; } else { targetLine = null; } break; } case CaretMovementType.LineDown: { // Move down: move to the next TextLine in the same visual line // or move to the first TextLine of the next visual line int nextLineNumber = visualLine.LastDocumentLine.LineNumber + 1; if (textLineIndex < visualLine.TextLines.Count - 1) { targetLine = visualLine.TextLines[textLineIndex + 1]; } else if (nextLineNumber <= textView.Document.LineCount) { DocumentLine nextLine = textView.Document.GetLineByNumber(nextLineNumber); targetVisualLine = textView.GetOrConstructVisualLine(nextLine); targetLine = targetVisualLine.TextLines[0]; } else { targetLine = null; } break; } case CaretMovementType.PageUp: case CaretMovementType.PageDown: { // Page up/down: find the target line using its visual position double yPos = visualLine.GetTextLineVisualYPosition(textLine, VisualYPosition.LineMiddle); if (direction == CaretMovementType.PageUp) { yPos -= textView.RenderSize.Height; } else { yPos += textView.RenderSize.Height; } DocumentLine newLine = textView.GetDocumentLineByVisualTop(yPos); targetVisualLine = textView.GetOrConstructVisualLine(newLine); targetLine = targetVisualLine.GetTextLineByVisualYPosition(yPos); break; } default: throw new NotSupportedException(direction.ToString()); } if (targetLine != null) { double yPos = targetVisualLine.GetTextLineVisualYPosition(targetLine, VisualYPosition.LineMiddle); int newVisualColumn = targetVisualLine.GetVisualColumn(new Point(xPos, yPos), enableVirtualSpace); // prevent wrapping to the next line; TODO: could 'IsAtEnd' help here? int targetLineStartCol = targetVisualLine.GetTextLineVisualStartColumn(targetLine); if (newVisualColumn >= targetLineStartCol + targetLine.Length) { if (newVisualColumn <= targetVisualLine.VisualLength) { newVisualColumn = targetLineStartCol + targetLine.Length - 1; } } return(targetVisualLine.GetTextViewPosition(newVisualColumn)); } else { return(caretPosition); } }