// btw. I hate source code duplication ... but this time I don't care !!!! float MeasurePrintingHeight(Graphics g, LineSegment line, float maxWidth) { float xPos = 0; float yPos = 0; float fontHeight = Font.GetHeight(g); _currentTabIndent = 0; FontContainer fontContainer = TextEditorProperties.FontContainer; foreach (TextWord word in line.Words) { switch (word.Type) { case TextWordType.Space: Advance(ref xPos, ref yPos, maxWidth, _primaryTextArea.TextArea.TextView.SpaceWidth, fontHeight); break; case TextWordType.Tab: Advance(ref xPos, ref yPos, maxWidth, TabIndent * _primaryTextArea.TextArea.TextView.ColumnWidth, fontHeight); break; case TextWordType.Word: SizeF drawingSize = g.MeasureString(word.Word, word.GetFont(fontContainer), new SizeF(maxWidth, fontHeight * 100), _printingStringFormat); Advance(ref xPos, ref yPos, maxWidth, drawingSize.Width, fontHeight); break; } } return yPos + fontHeight; }
void DrawLine(Graphics g, LineSegment line, float yPos, RectangleF margin) { float xPos = 0; float fontHeight = Font.GetHeight(g); _currentTabIndent = 0; FontContainer fontContainer = TextEditorProperties.FontContainer; foreach (TextWord word in line.Words) { switch (word.Type) { case TextWordType.Space: Advance(ref xPos, ref yPos, margin.Width, _primaryTextArea.TextArea.TextView.SpaceWidth, fontHeight); break; case TextWordType.Tab: Advance(ref xPos, ref yPos, margin.Width, TabIndent * _primaryTextArea.TextArea.TextView.ColumnWidth, fontHeight); break; case TextWordType.Word: g.DrawString(word.Word, word.GetFont(fontContainer), BrushRegistry.GetBrush(word.Color), xPos + margin.X, yPos); SizeF drawingSize = g.MeasureString(word.Word, word.GetFont(fontContainer), new SizeF(margin.Width, fontHeight * 100), _printingStringFormat); Advance(ref xPos, ref yPos, margin.Width, drawingSize.Width, fontHeight); break; } } }
/// <summary> /// Initializes a new instance of the <see cref="TextWord"/> class. /// </summary> /// <param name="document">The document.</param> /// <param name="line">The line.</param> /// <param name="offset">The offset.</param> /// <param name="length">The length.</param> /// <param name="color">The color.</param> /// <param name="hasDefaultColor">if set to <c>true</c> [has default color].</param> public TextWord(IDocument document, LineSegment line, int offset, int length, HighlightColor color, bool hasDefaultColor) { Debug.Assert(document != null); Debug.Assert(line != null); Debug.Assert(color != null); _document = document; _line = line; _offset = offset; _length = length; _color = color; _hasDefaultColor = hasDefaultColor; }
/// <summary> /// Replaces the text in a line. /// If only whitespace at the beginning and end of the line was changed, this method /// only adjusts the whitespace and doesn't replace the other text. /// </summary> public static void SmartReplaceLine(IDocument document, LineSegment line, string newLineText) { if (document == null) throw new ArgumentNullException("document"); if (line == null) throw new ArgumentNullException("line"); if (newLineText == null) throw new ArgumentNullException("newLineText"); string newLineTextTrim = newLineText.Trim(_whitespaceChars); string oldLineText = document.GetText(line); if (oldLineText == newLineText) return; int pos = oldLineText.IndexOf(newLineTextTrim); if (newLineTextTrim.Length > 0 && pos >= 0) { document.UndoStack.StartUndoGroup(); try { // find whitespace at beginning int startWhitespaceLength = 0; while (startWhitespaceLength < newLineText.Length) { char c = newLineText[startWhitespaceLength]; if (c != ' ' && c != '\t') break; startWhitespaceLength++; } // find whitespace at end int endWhitespaceLength = newLineText.Length - newLineTextTrim.Length - startWhitespaceLength; // replace whitespace sections int lineOffset = line.Offset; document.Replace(lineOffset + pos + newLineTextTrim.Length, line.Length - pos - newLineTextTrim.Length, newLineText.Substring(newLineText.Length - endWhitespaceLength)); document.Replace(lineOffset, pos, newLineText.Substring(0, startWhitespaceLength)); } finally { document.UndoStack.EndUndoGroup(); } } else { document.Replace(line.Offset, line.Length, newLineText); } }
/// <summary> /// Get the object that was inserted under the keyword. /// </summary> /// <value>The object that was inserted under the keyword.</value> /// <remarks> /// <para> /// The keyword is taken from an <see cref="IDocument"/> at a given location /// (line, offset in line, length). /// </para> /// <para> /// Returns null, if no such keyword exists. /// </para> /// </remarks> public object this[IDocument document, LineSegment line, int offsetInLine, int lengthOfWord] { get { if (lengthOfWord == 0) return null; Node next = root; int wordOffset = line.Offset + offsetInLine; if (casesensitive) { for (int i = 0; i < lengthOfWord; ++i) { int index = ((int) document.GetCharAt(wordOffset + i)) % 256; next = next.leaf[index]; if (next == null) return null; if (next.color != null && TextUtilities.RegionMatches(document, wordOffset, lengthOfWord, next.word)) return next.color; } } else { for (int i = 0; i < lengthOfWord; ++i) { int index = ((int) Char.ToUpper(document.GetCharAt(wordOffset + i))) % 256; next = next.leaf[index]; if (next == null) return null; if (next.color != null && TextUtilities.RegionMatches(document, casesensitive, wordOffset, lengthOfWord, next.word)) return next.color; } } return null; } }
/// <summary> /// Get the object that was inserted under the keyword. /// </summary> /// <value>The object that was inserted under the keyword.</value> /// <remarks> /// <para> /// The keyword is taken from an <see cref="IDocument"/> at a given location /// (line, offset in line, length). /// </para> /// <para> /// Returns <c>null</c>, if no such keyword exists. /// </para> /// </remarks> public object this[IDocument document, LineSegment line, int offsetInLine, int lengthOfWord] { get { if (lengthOfWord == 0) return null; Node next = _root; int wordOffset = line.Offset + offsetInLine; if (_caseSensitive) { for (int i = 0; i < lengthOfWord; ++i) { int index = document.GetCharAt(wordOffset + i) % 256; next = next[index]; if (next == null) return null; if (next.Color != null && TextHelper.CompareSegment(document, wordOffset, lengthOfWord, next.Word)) return next.Color; } } else { for (int i = 0; i < lengthOfWord; ++i) { int index = Char.ToUpper(document.GetCharAt(wordOffset + i)) % 256; next = next[index]; if (next == null) return null; if (next.Color != null && TextHelper.CompareSegment(document, wordOffset, lengthOfWord, next.Word, _caseSensitive)) return next.Color; } } return null; } }
public bool Next() { if (_lineDirty) { _document.Replace(_line.Offset, _line.Length, _text); _lineDirty = false; ++_changedLines; } ++_lineNumber; if (_lineNumber > _maxLine) return false; _line = _document.GetLineSegment(_lineNumber); _text = _document.GetText(_line); return true; }
/// <summary> /// Marks the tokens. Used internally, do not call. /// </summary> /// <param name="document">The document.</param> /// <remarks> /// Used internally, do not call. /// </remarks> public virtual void MarkTokens(IDocument document) { if (Rules.Count == 0) { return; } int lineNumber = 0; while (lineNumber < document.TotalNumberOfLines) { LineSegment previousLine = (lineNumber > 0 ? document.GetLineSegment(lineNumber - 1) : null); if (lineNumber >= document.LineSegmentCollection.Count) { // may be, if the last line ends with a delimiter break; // then the last line is not in the collection :) } _currentSpanStack = ((previousLine != null && previousLine.HighlightSpanStack != null) ? previousLine.HighlightSpanStack.Clone() : null); if (_currentSpanStack != null) { while (!_currentSpanStack.IsEmpty && _currentSpanStack.Peek().StopEOL) { _currentSpanStack.Pop(); } if (_currentSpanStack.IsEmpty) _currentSpanStack = null; } _currentLine = document.LineSegmentCollection[lineNumber]; if (_currentLine.Length == -1) { // happens when buffer is empty ! return; } List<TextWord> words = ParseLine(document); // Alex: clear old words if (_currentLine.Words != null) { _currentLine.Words.Clear(); } _currentLine.Words = words; _currentLine.HighlightSpanStack = (_currentSpanStack == null || _currentSpanStack.IsEmpty) ? null : _currentSpanStack; ++lineNumber; } document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.WholeTextArea)); document.CommitUpdate(); _currentLine = null; }
/// <summary> /// Marks the tokens in a line. /// </summary> /// <param name="document">The document.</param> /// <param name="lineNumber">The line number.</param> /// <param name="spanChanged"><c>true</c> span has changed.</param> /// <returns><c>true</c> if the line has been parsed successfully and the next line can be parsed.</returns> bool MarkTokensInLine(IDocument document, int lineNumber, ref bool spanChanged) { bool processNextLine = false; LineSegment previousLine = (lineNumber > 0 ? document.GetLineSegment(lineNumber - 1) : null); _currentSpanStack = ((previousLine != null && previousLine.HighlightSpanStack != null) ? previousLine.HighlightSpanStack.Clone() : null); if (_currentSpanStack != null) { while (!_currentSpanStack.IsEmpty && _currentSpanStack.Peek().StopEOL) { _currentSpanStack.Pop(); } if (_currentSpanStack.IsEmpty) { _currentSpanStack = null; } } _currentLine = document.LineSegmentCollection[lineNumber]; if (_currentLine.Length == -1) { // happens when buffer is empty ! return false; } List<TextWord> words = ParseLine(document); if (_currentSpanStack != null && _currentSpanStack.IsEmpty) { _currentSpanStack = null; } // Check if the span state has changed, if so we must re-render the next line // This check may seem utterly complicated but I didn't want to introduce any function calls // or allocations here for perfomance reasons. if (_currentLine.HighlightSpanStack != _currentSpanStack) { if (_currentLine.HighlightSpanStack == null) { processNextLine = false; foreach (Span sp in _currentSpanStack) { if (!sp.StopEOL) { spanChanged = true; processNextLine = true; break; } } } else if (_currentSpanStack == null) { processNextLine = false; foreach (Span sp in _currentLine.HighlightSpanStack) { if (!sp.StopEOL) { spanChanged = true; processNextLine = true; break; } } } else { SpanStack.Enumerator e1 = _currentSpanStack.GetEnumerator(); SpanStack.Enumerator e2 = _currentLine.HighlightSpanStack.GetEnumerator(); bool done = false; while (!done) { bool blockSpanIn1 = false; while (e1.MoveNext()) { if (!e1.Current.StopEOL) { blockSpanIn1 = true; break; } } bool blockSpanIn2 = false; while (e2.MoveNext()) { if (!e2.Current.StopEOL) { blockSpanIn2 = true; break; } } if (blockSpanIn1 || blockSpanIn2) { if (blockSpanIn1 && blockSpanIn2) { if (e1.Current != e2.Current) { done = true; processNextLine = true; spanChanged = true; } } else { spanChanged = true; done = true; processNextLine = true; } } else { done = true; processNextLine = false; } } } } else { processNextLine = false; } // Alex: remove old words if (_currentLine.Words != null) _currentLine.Words.Clear(); _currentLine.Words = words; _currentLine.HighlightSpanStack = (_currentSpanStack != null && !_currentSpanStack.IsEmpty) ? _currentSpanStack : null; return processNextLine; }
void SetSegmentLength(LineSegment segment, int newTotalLength) { int delta = newTotalLength - segment.TotalLength; if (delta != 0) { lineCollection.SetSegmentLength(segment, newTotalLength); OnLineLengthChanged(new LineLengthChangeEventArgs(document, segment, delta)); } }
/// <summary> /// get the string, which matches the regular expression expr, /// in string s2 at index /// </summary> static string GetRegString(LineSegment lineSegment, char[] expr, int index, IDocument document) { int j = 0; StringBuilder regexpr = new StringBuilder(); for (int i = 0; i < expr.Length; ++i, ++j) { if (index + j >= lineSegment.Length) break; switch (expr[i]) { case '@': // "special" meaning ++i; switch (expr[i]) { case '!': // don't match the following expression StringBuilder whatmatch = new StringBuilder(); ++i; while (i < expr.Length && expr[i] != '@') { whatmatch.Append(expr[i++]); } break; case '@': // matches @ regexpr.Append(document.GetCharAt(lineSegment.Offset + index + j)); break; } break; default: if (expr[i] != document.GetCharAt(lineSegment.Offset + index + j)) { return regexpr.ToString(); } regexpr.Append(document.GetCharAt(lineSegment.Offset + index + j)); break; } } return regexpr.ToString(); }
/// <summary> /// returns true, if the get the string s2 at index matches the expression expr /// </summary> static bool MatchExpr(LineSegment lineSegment, char[] expr, int index, IDocument document, bool ignoreCase, bool isSingleWord) { for (int i = 0, j = 0; i < expr.Length; ++i, ++j) { switch (expr[i]) { case '@': // "special" meaning ++i; if (i == expr.Length) throw new HighlightingDefinitionInvalidException("Unexpected end of @ sequence, use @@ to look for a single @."); switch (expr[i]) { case 'C': // match whitespace or punctuation if (index + j == lineSegment.Offset || index + j >= lineSegment.Offset + lineSegment.Length) { // nothing (EOL or SOL) } else { char ch = document.GetCharAt(lineSegment.Offset + index + j); if (!Char.IsWhiteSpace(ch) && !Char.IsPunctuation(ch)) { return false; } } break; case '!': // don't match the following expression { StringBuilder whatmatch = new StringBuilder(); ++i; while (i < expr.Length && expr[i] != '@') { whatmatch.Append(expr[i++]); } if (lineSegment.Offset + index + j + whatmatch.Length < document.TextLength) { int k = 0; for (; k < whatmatch.Length; ++k) { char docChar = ignoreCase ? Char.ToUpperInvariant(document.GetCharAt(lineSegment.Offset + index + j + k)) : document.GetCharAt(lineSegment.Offset + index + j + k); char spanChar = ignoreCase ? Char.ToUpperInvariant(whatmatch[k]) : whatmatch[k]; if (docChar != spanChar) { break; } } if (k >= whatmatch.Length) { return false; } } // --j; break; } case '-': // don't match the expression before { StringBuilder whatmatch = new StringBuilder(); ++i; while (i < expr.Length && expr[i] != '@') { whatmatch.Append(expr[i++]); } if (index - whatmatch.Length >= 0) { int k = 0; for (; k < whatmatch.Length; ++k) { char docChar = ignoreCase ? Char.ToUpperInvariant(document.GetCharAt(lineSegment.Offset + index - whatmatch.Length + k)) : document.GetCharAt(lineSegment.Offset + index - whatmatch.Length + k); char spanChar = ignoreCase ? Char.ToUpperInvariant(whatmatch[k]) : whatmatch[k]; if (docChar != spanChar) break; } if (k >= whatmatch.Length) { return false; } } // --j; break; } case '@': // matches @ if (index + j >= lineSegment.Length || '@' != document.GetCharAt(lineSegment.Offset + index + j)) { return false; } break; } break; default: { if (index + j >= lineSegment.Length) { return false; } char docChar = ignoreCase ? Char.ToUpperInvariant(document.GetCharAt(lineSegment.Offset + index + j)) : document.GetCharAt(lineSegment.Offset + index + j); char spanChar = ignoreCase ? Char.ToUpperInvariant(expr[i]) : expr[i]; if (docChar != spanChar) { return false; } break; } } } if (isSingleWord) { int length = expr.Length; if (index + length < lineSegment.Length) { char ch = document.GetCharAt(lineSegment.Offset + index + length); if (!Char.IsWhiteSpace(ch) && !Char.IsPunctuation(ch)) { return false; } } } return true; }
/// <summary> /// Counts the visual columns (fast version). /// </summary> /// <param name="line">The line.</param> /// <param name="logicalColumn">The logical column.</param> /// <returns>The number of visual columns.</returns> public int GetVisualColumnFast(LineSegment line, int logicalColumn) { int lineOffset = line.Offset; int tabIndent = Document.TextEditorProperties.TabIndent; int guessedColumn = 0; for (int i = 0; i < logicalColumn; ++i) { char ch = (i >= line.Length) ? ' ' : Document.GetCharAt(lineOffset + i); switch (ch) { case '\t': guessedColumn += tabIndent; guessedColumn = (guessedColumn / tabIndent) * tabIndent; break; default: ++guessedColumn; break; } } return guessedColumn; }
/// <summary> /// Splits the <see cref="TextAnchor"/>s of a line if a newline is inserted. /// </summary> /// <param name="followingLine">The following line.</param> internal void SplitTo(LineSegment followingLine) { // Is called after a newline was inserted into this line, splitting it into this and followingLine. if (_anchors != null) { List<TextAnchor> movedAnchors = null; foreach (TextAnchor anchor in _anchors) { if (anchor.MovementType == AnchorMovementType.BeforeInsertion ? anchor.ColumnNumber > Length : anchor.ColumnNumber >= Length) { anchor.Line = followingLine; followingLine.AddAnchor(anchor); anchor.ColumnNumber -= Length; if (movedAnchors == null) movedAnchors = new List<TextAnchor>(); movedAnchors.Add(anchor); } } if (movedAnchors != null) foreach (TextAnchor a in movedAnchors) _anchors.Remove(a); } }
/// <summary> /// Initializes a new instance of the <see cref="LineLengthChangedEventArgs"/> class. /// </summary> /// <param name="document">The document.</param> /// <param name="lineSegment">The line segment.</param> /// <param name="difference">The difference (new line length - old line length).</param> public LineLengthChangedEventArgs(IDocument document, LineSegment lineSegment, int difference) : base(document, lineSegment) { _difference = difference; }
internal TextAnchor(LineSegment lineSegment, int columnNumber) { _lineSegment = lineSegment; _columnNumber = columnNumber; }
/// <summary> /// Initializes a new instance of the <see cref="LineLengthChangeEventArgs"/> class. /// </summary> /// <param name="document">The document.</param> /// <param name="lineSegment">The line segment.</param> /// <param name="moved">The moved.</param> public LineLengthChangeEventArgs(IDocument document, LineSegment lineSegment, int moved) : base(document, lineSegment) { this.lengthDelta = moved; }
/// <summary> /// Gets the highlighting color for a certain position in the document. /// </summary> /// <param name="document">The document.</param> /// <param name="currentSegment">The current segment.</param> /// <param name="currentOffset">The current offset.</param> /// <param name="currentLength">Length of the current.</param> /// <returns>The highlighting color.</returns> public HighlightColor GetColor(IDocument document, LineSegment currentSegment, int currentOffset, int currentLength) { return GetColor(_defaultRuleSet, document, currentSegment, currentOffset, currentLength); }
/// <summary> /// Determines whether a line is empty or filled with whitespaces. /// </summary> /// <param name="document">The document.</param> /// <param name="line">The line.</param> /// <returns> /// <c>true</c> if line is empty of filled with whitespaces; otherwise, <c>false</c>. /// </returns> /// <remarks> /// Returns true, if the line lineNumber is empty or filled with whitespaces. /// </remarks> public static bool IsEmptyLine(IDocument document, LineSegment line) { for (int i = line.Offset; i < line.Offset + line.Length; ++i) { char ch = document.GetCharAt(i); if (!Char.IsWhiteSpace(ch)) return false; } return true; }
/// <summary> /// Adds the removed line. /// </summary> /// <param name="line">The line.</param> public void AddRemovedLine(LineSegment line) { if (_removedLines == null) _removedLines = new List<LineSegment>(); _removedLines.Add(line); }
/// <summary> /// Initializes a new instance of the <see cref="LineEventArgs"/> class. /// </summary> /// <param name="document">The document.</param> /// <param name="lineSegment">The line segment.</param> public LineEventArgs(IDocument document, LineSegment lineSegment) { _document = document; _lineSegment = lineSegment; }
/// <summary> /// Initializes a new instance of the <see cref="LineEventArgs"/> class. /// </summary> /// <param name="document">The document.</param> /// <param name="lineSegment">The line segment.</param> public LineEventArgs(IDocument document, LineSegment lineSegment) { this.document = document; this.lineSegment = lineSegment; }
/// <summary> /// Marks the tokens. /// </summary> /// <param name="document">The document.</param> /// <param name="inputLines">The input lines.</param> public virtual void MarkTokens(IDocument document, List<LineSegment> inputLines) { if (Rules.Count == 0) return; Dictionary<LineSegment, bool> processedLines = new Dictionary<LineSegment, bool>(); bool spanChanged = false; int documentLineSegmentCount = document.LineSegmentCollection.Count; foreach (LineSegment lineToProcess in inputLines) { if (!processedLines.ContainsKey(lineToProcess)) { int lineNumber = lineToProcess.LineNumber; bool processNextLine = true; if (lineNumber != -1) { while (processNextLine && lineNumber < documentLineSegmentCount) { processNextLine = MarkTokensInLine(document, lineNumber, ref spanChanged); processedLines[_currentLine] = true; ++lineNumber; } } } } if (spanChanged || inputLines.Count > 20) { // if the span was changed (more than inputLines lines had to be reevaluated) // or if there are many lines in inputLines, it's faster to update the whole // text area instead of many small segments document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.WholeTextArea)); } else { // document.Caret.ValidateCaretPos(); // document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.SingleLine, document.GetLineNumberForOffset(document.Caret.Offset))); foreach (LineSegment lineToProcess in inputLines) { document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.SingleLine, lineToProcess.LineNumber)); } } document.CommitUpdate(); _currentLine = null; }
internal void Delete(ref DeferredEventList deferredEventList) { // we cannot fire an event here because this method is called while the LineManager adjusts the // lineCollection, so an event handler could see inconsistent state _lineSegment = null; deferredEventList.AddDeletedAnchor(this); }
/// <summary> /// Gets the highlighting color for a certain position in the document. /// </summary> /// <param name="ruleSet">The rule set.</param> /// <param name="document">The document.</param> /// <param name="currentSegment">The current segment.</param> /// <param name="currentOffset">The current offset.</param> /// <param name="currentLength">Length of the current.</param> /// <returns></returns> protected virtual HighlightColor GetColor(HighlightRuleSet ruleSet, IDocument document, LineSegment currentSegment, int currentOffset, int currentLength) { if (ruleSet != null) { if (ruleSet.Reference != null) return ruleSet.Highlighter.GetColor(document, currentSegment, currentOffset, currentLength); else return (HighlightColor) ruleSet.KeyWords[document, currentSegment, currentOffset, currentLength]; } return null; }
int GetLogicalColumnInternal(Graphics g, LineSegment line, int start, int end, ref int drawingPos, int targetVisualPosX) { if (start == end) return end; Debug.Assert(start < end); Debug.Assert(drawingPos < targetVisualPosX); int tabIndent = Document.TextEditorProperties.TabIndent; FontContainer fontContainer = TextEditorProperties.FontContainer; List<TextWord> words = line.Words; if (words == null) return 0; int wordOffset = 0; for (int i = 0; i < words.Count; i++) { TextWord word = words[i]; if (wordOffset >= end) { return wordOffset; } if (wordOffset + word.Length >= start) { int newDrawingPos; switch (word.Type) { case TextWordType.Space: newDrawingPos = drawingPos + _spaceWidth; if (newDrawingPos >= targetVisualPosX) return IsNearerToAThanB(targetVisualPosX, drawingPos, newDrawingPos) ? wordOffset : wordOffset + 1; break; case TextWordType.Tab: // go to next tab position drawingPos = (drawingPos + MinTabWidth) / tabIndent / ColumnWidth * tabIndent * ColumnWidth; newDrawingPos = drawingPos + tabIndent * ColumnWidth; if (newDrawingPos >= targetVisualPosX) return IsNearerToAThanB(targetVisualPosX, drawingPos, newDrawingPos) ? wordOffset : wordOffset + 1; break; case TextWordType.Word: int wordStart = Math.Max(wordOffset, start); int wordLength = Math.Min(wordOffset + word.Length, end) - wordStart; string text = Document.GetText(line.Offset + wordStart, wordLength); Font font = word.GetFont(fontContainer) ?? fontContainer.RegularFont; newDrawingPos = drawingPos + MeasureStringWidth(g, text, font); if (newDrawingPos >= targetVisualPosX) { for (int j = 0; j < text.Length; j++) { newDrawingPos = drawingPos + MeasureStringWidth(g, text[j].ToString(), font); if (newDrawingPos >= targetVisualPosX) { if (IsNearerToAThanB(targetVisualPosX, drawingPos, newDrawingPos)) return wordStart + j; else return wordStart + j + 1; } drawingPos = newDrawingPos; } return wordStart + text.Length; } break; default: throw new NotSupportedException(); } drawingPos = newDrawingPos; } wordOffset += word.Length; } return wordOffset; }
/// <summary> /// Called when a line has been parsed. /// </summary> /// <param name="document">The document.</param> /// <param name="currentLine">The current line.</param> /// <param name="words">The words.</param> protected virtual void OnParsedLine(IDocument document, LineSegment currentLine, List<TextWord> words) { }
/// <summary> /// Merges the <see cref="TextAnchor"/>s of two lines, if a newline is deleted. /// </summary> /// <param name="deletedLine">The deleted line.</param> /// <param name="firstLineLength">The length of the first line.</param> internal void MergedWith(LineSegment deletedLine, int firstLineLength) { // Is called after another line's content is appended to this line because the newline in between // was deleted. // The DefaultLineManager will call Deleted() on the deletedLine after the MergedWith call. // firstLineLength: the length of the line before the merge. if (deletedLine._anchors != null) { foreach (TextAnchor anchor in deletedLine._anchors) { anchor.Line = this; AddAnchor(anchor); anchor.ColumnNumber += firstLineLength; } deletedLine._anchors = null; } }
/// <summary> /// get the string, which matches the regular expression expr, /// in string s2 at index /// </summary> static string GetRegString(LineSegment lineSegment, char[] expr, int index, IDocument document) { int j = 0; StringBuilder regexpr = new StringBuilder(); for (int i = 0; i < expr.Length; ++i, ++j) { if (index + j >= lineSegment.Length) break; switch (expr[i]) { case '@': // "special" meaning ++i; if (i == expr.Length) throw new HighlightingDefinitionInvalidException("Unexpected end of @ sequence, use @@ to look for a single @."); switch (expr[i]) { case '!': // don't match the following expression StringBuilder whatmatch = new StringBuilder(); ++i; while (i < expr.Length && expr[i] != '@') { whatmatch.Append(expr[i++]); } break; case '@': // matches @ regexpr.Append(document.GetCharAt(lineSegment.Offset + index + j)); break; } break; default: if (expr[i] != document.GetCharAt(lineSegment.Offset + index + j)) { return regexpr.ToString(); } regexpr.Append(document.GetCharAt(lineSegment.Offset + index + j)); break; } } return regexpr.ToString(); }
/// <summary> /// returns true, if the get the string s2 at index matches the expression expr /// </summary> static bool MatchExpr(LineSegment lineSegment, char[] expr, int index, IDocument document, bool ignoreCase) { return MatchExpr(lineSegment, expr, index, document, ignoreCase, false); }