int FindWordStart(Document.Document document, int offset) { LineSegment line = document.GetLineSegmentForOffset(offset); if (offset > 0 && Char.IsWhiteSpace(document.GetCharAt(offset - 1)) && Char.IsWhiteSpace(document.GetCharAt(offset))) { while (offset > line.Offset && Char.IsWhiteSpace(document.GetCharAt(offset - 1))) { --offset; } } else if (IsSelectableChar(document.GetCharAt(offset)) || (offset > 0 && Char.IsWhiteSpace(document.GetCharAt(offset)) && IsSelectableChar(document.GetCharAt(offset - 1)))) { while (offset > line.Offset && IsSelectableChar(document.GetCharAt(offset - 1))) { --offset; } } else { if (offset > 0 && !Char.IsWhiteSpace(document.GetCharAt(offset - 1)) && !IsSelectableChar(document.GetCharAt(offset - 1))) { return(Math.Max(0, offset - 1)); } } return(offset); }
// go back to the start of the word we are on // if we are already at the start of a word or if we are in whitespace, then go back // to the start of the previous word public static int FindPrevWordStart(Document document, int offset) { int originalOffset = offset; if (offset > 0) { LineSegment line = document.GetLineSegmentForOffset(offset); CharacterType t = GetCharacterType(document.GetCharAt(offset - 1)); while (offset > line.Offset && GetCharacterType(document.GetCharAt(offset - 1)) == t) { --offset; } // if we were in whitespace, and now we're at the end of a word or operator, go back to the beginning of it if (t == CharacterType.WhiteSpace && offset > line.Offset) { t = GetCharacterType(document.GetCharAt(offset - 1)); while (offset > line.Offset && GetCharacterType(document.GetCharAt(offset - 1)) == t) { --offset; } } } return(offset); }
/// <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, Document 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 Exception("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()); }
/// Interface implementation. public List <FoldMarker> GenerateFoldMarkers(Document document /*, string fileName, object parseInformation*/) { List <FoldMarker> foldMarkers = new List <FoldMarker>(); Stack <int> startOffsets = new Stack <int>(); int lastNewLineOffset = 0; char openingBrace = '{'; char closingBrace = '}'; for (int i = 0; i < document.TextLength; i++) { char c = document.GetCharAt(i); if (c == openingBrace) { startOffsets.Push(i); } else if (c == closingBrace && startOffsets.Count > 0) { int startOffset = startOffsets.Pop(); // don't fold if opening and closing brace are on the same line if (startOffset < lastNewLineOffset) { foldMarkers.Add(new FoldMarker(document, startOffset, i + 1 - startOffset, "{...}", false)); } } else if (c == '\n' || c == '\r') { lastNewLineOffset = i + 1; } } return(foldMarkers); }
public List <FoldMarker> GenerateFoldMarkersRegion(Document document, string fileName, object parseInformation) { List <FoldMarker> foldMarkers = new List <FoldMarker>(); Stack <int> startLines = new Stack <int>(); // Create foldmarkers for the whole document, enumerate through every line. for (int i = 0; i < document.TotalNumberOfLines; i++) { LineSegment seg = document.GetLineSegment(i); int offs = 0; int end = document.TextLength; char c; for (offs = seg.Offset; offs < end && ((c = document.GetCharAt(offs)) == ' ' || c == '\t'); offs++) { } if (offs == end) { break; } int spaceCount = offs - seg.Offset; // now offs points to the first non-whitespace char on the line if (document.GetCharAt(offs) == '#') { string text = document.GetText(offs, seg.Length - spaceCount); if (text.StartsWith("#region")) { startLines.Push(i); } if (text.StartsWith("#endregion") && startLines.Count > 0) { // Add a new FoldMarker to the list. int start = startLines.Pop(); foldMarkers.Add(new FoldMarker(document, start, document.GetLineSegment(start).Length, i, spaceCount + "#endregion".Length)); } } } return(foldMarkers); }
public static int GetFirstNonWSChar(Document document, int offset) { while (offset < document.TextLength && Char.IsWhiteSpace(document.GetCharAt(offset))) { ++offset; } return(offset); }
public virtual int SearchBracketForward(Document document, int offset, char openBracket, char closingBracket) { int brackets = 1; // try "quick find" - find the matching bracket if there is no string/comment in the way for (int i = offset; i < document.TextLength; ++i) { char ch = document.GetCharAt(i); if (ch == openBracket) { ++brackets; } else if (ch == closingBracket) { --brackets; if (brackets == 0) { return(i); } } else if (ch == '"') { break; } else if (ch == '\'') { break; } else if (ch == '/' && i > 0) { if (document.GetCharAt(i - 1) == '/') { break; } } else if (ch == '*' && i > 0) { if (document.GetCharAt(i - 1) == '/') { break; } } } return(-1); }
int FindNext(Document.Document document, int offset, char ch) { LineSegment line = document.GetLineSegmentForOffset(offset); int endPos = line.Offset + line.Length; while (offset < endPos && document.GetCharAt(offset) != ch) { ++offset; } return(offset); }
public static int FindWordEnd(Document document, int offset) { LineSegment line = document.GetLineSegmentForOffset(offset); int endPos = line.Offset + line.Length; while (offset < endPos && IsLetterDigitOrUnderscore(document.GetCharAt(offset))) { ++offset; } return(offset); }
public static int FindWordStart(Document document, int offset) { LineSegment line = document.GetLineSegmentForOffset(offset); int lineOffset = line.Offset; while (offset > lineOffset && IsLetterDigitOrUnderscore(document.GetCharAt(offset - 1))) { --offset; } return(offset); }
/// <remarks> /// Returns true, if the line lineNumber is empty or filled with whitespaces. /// </remarks> public static bool IsEmptyLine(Document 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); }
// go forward to the start of the next word // if the cursor is at the start or in the middle of a word we move to the end of the word // and then past any whitespace that follows it // if the cursor is at the start or in the middle of some whitespace we move to the start of the // next word public static int FindNextWordStart(Document document, int offset) { int originalOffset = offset; LineSegment line = document.GetLineSegmentForOffset(offset); int endPos = line.Offset + line.Length; // lets go to the end of the word, whitespace or operator CharacterType t = GetCharacterType(document.GetCharAt(offset)); while (offset < endPos && GetCharacterType(document.GetCharAt(offset)) == t) { ++offset; } // now we're at the end of the word, lets find the start of the next one by skipping whitespace while (offset < endPos && GetCharacterType(document.GetCharAt(offset)) == CharacterType.WhiteSpace) { ++offset; } return(offset); }
public static string GetWordAt(Document document, int offset) { if (offset < 0 || offset >= document.TextLength - 1 || !IsWordPart(document.GetCharAt(offset))) { return(String.Empty); } int startOffset = offset; int endOffset = offset; while (startOffset > 0 && IsWordPart(document.GetCharAt(startOffset - 1))) { --startOffset; } while (endOffset < document.TextLength - 1 && IsWordPart(document.GetCharAt(endOffset + 1))) { ++endOffset; } //Debug.Assert(endOffset >= startOffset); return(document.GetText(startOffset, endOffset - startOffset + 1)); }
int FindWordEnd(Document.Document document, int offset) { LineSegment line = document.GetLineSegmentForOffset(offset); if (line.Length == 0) { return(offset); } int endPos = line.Offset + line.Length; offset = Math.Min(offset, endPos - 1); if (IsSelectableChar(document.GetCharAt(offset))) { while (offset < endPos && IsSelectableChar(document.GetCharAt(offset))) { ++offset; } } else if (Char.IsWhiteSpace(document.GetCharAt(offset))) { if (offset > 0 && Char.IsWhiteSpace(document.GetCharAt(offset - 1))) { while (offset < endPos && Char.IsWhiteSpace(document.GetCharAt(offset))) { ++offset; } } } else { return(Math.Max(0, offset + 1)); } return(offset); }
public Highlight GetHighlight(Document.Document document, int offset) { int searchOffset; if (Shared.TEP.BracketMatchingStyle == BracketMatchingStyle.After) { searchOffset = offset; } else { searchOffset = offset + 1; } char word = document.GetCharAt(Math.Max(0, Math.Min(document.TextLength - 1, searchOffset))); TextLocation endP = document.OffsetToPosition(searchOffset); if (word == OpenTag) { if (searchOffset < document.TextLength) { int bracketOffset = TextUtilities.SearchBracketForward(document, searchOffset + 1, OpenTag, ClosingTag); if (bracketOffset >= 0) { TextLocation p = document.OffsetToPosition(bracketOffset); return(new Highlight(p, endP)); } } } else if (word == ClosingTag) { if (searchOffset > 0) { int bracketOffset = TextUtilities.SearchBracketBackward(document, searchOffset - 1, OpenTag, ClosingTag); if (bracketOffset >= 0) { TextLocation p = document.OffsetToPosition(bracketOffset); return(new Highlight(p, endP)); } } } return(null); }
int GetLevel(Document document, int offset) { int level = 0; int spaces = 0; for (int i = offset; i < document.TextLength; ++i) { char c = document.GetCharAt(i); if (c == '\t' || (c == ' ' && ++spaces == 4)) { spaces = 0; ++level; } else { break; } } return(level); }
/// <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, Document document, bool ignoreCase) { for (int i = 0, j = 0; i < expr.Length; ++i, ++j) { switch (expr[i]) { case '@': // "special" meaning ++i; if (i == expr.Length) { throw new Exception("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; } } } return(true); }
List <TextWord> ParseLine(Document document) { List <TextWord> words = new List <TextWord>(); HighlightColor markNext = null; _currentOffset = 0; _currentLength = 0; UpdateSpanStateVariables(); int currentLineLength = _currentLine.Length; int currentLineOffset = _currentLine.Offset; for (int i = 0; i < currentLineLength; ++i) { char ch = document.GetCharAt(currentLineOffset + i); switch (ch) { case '\n': case '\r': PushCurWord(document, ref markNext, words); ++_currentOffset; break; case ' ': PushCurWord(document, ref markNext, words); if (_activeSpan != null && _activeSpan.Color.HasBackground) { words.Add(new SpaceTextWord(_activeSpan.Color)); } else { words.Add(TextWord.Space); } ++_currentOffset; break; case '\t': PushCurWord(document, ref markNext, words); if (_activeSpan != null && _activeSpan.Color.HasBackground) { words.Add(new TabTextWord(_activeSpan.Color)); } else { words.Add(TextWord.Tab); } ++_currentOffset; break; default: { // handle escape characters char escapeCharacter = '\0'; if (_activeSpan != null && _activeSpan.EscapeCharacter != '\0') { escapeCharacter = _activeSpan.EscapeCharacter; } else if (_activeRuleSet != null) { escapeCharacter = _activeRuleSet.EscapeCharacter; } if (escapeCharacter != '\0' && escapeCharacter == ch) { // we found the escape character if (_activeSpan != null && _activeSpan.End != null && _activeSpan.End.Length == 1 && escapeCharacter == _activeSpan.End[0]) { // the escape character is a end-doubling escape character // it may count as escape only when the next character is the escape, too if (i + 1 < currentLineLength) { if (document.GetCharAt(currentLineOffset + i + 1) == escapeCharacter) { _currentLength += 2; PushCurWord(document, ref markNext, words); ++i; continue; } } } else { // this is a normal \-style escape ++_currentLength; if (i + 1 < currentLineLength) { ++_currentLength; } PushCurWord(document, ref markNext, words); ++i; continue; } } // highlight digits if (!_inSpan && (Char.IsDigit(ch) || (ch == '.' && i + 1 < currentLineLength && Char.IsDigit(document.GetCharAt(currentLineOffset + i + 1)))) && _currentLength == 0) { bool ishex = false; bool isfloatingpoint = false; if (ch == '0' && i + 1 < currentLineLength && Char.ToUpper(document.GetCharAt(currentLineOffset + i + 1)) == 'X') // hex digits { const string hex = "0123456789ABCDEF"; ++_currentLength; ++i; // skip 'x' ++_currentLength; ishex = true; while (i + 1 < currentLineLength && hex.IndexOf(Char.ToUpper(document.GetCharAt(currentLineOffset + i + 1))) != -1) { ++i; ++_currentLength; } } else { ++_currentLength; while (i + 1 < currentLineLength && Char.IsDigit(document.GetCharAt(currentLineOffset + i + 1))) { ++i; ++_currentLength; } } if (!ishex && i + 1 < currentLineLength && document.GetCharAt(currentLineOffset + i + 1) == '.') { isfloatingpoint = true; ++i; ++_currentLength; while (i + 1 < currentLineLength && Char.IsDigit(document.GetCharAt(currentLineOffset + i + 1))) { ++i; ++_currentLength; } } if (i + 1 < currentLineLength && Char.ToUpper(document.GetCharAt(currentLineOffset + i + 1)) == 'E') { isfloatingpoint = true; ++i; ++_currentLength; if (i + 1 < currentLineLength && (document.GetCharAt(currentLineOffset + i + 1) == '+' || document.GetCharAt(_currentLine.Offset + i + 1) == '-')) { ++i; ++_currentLength; } while (i + 1 < _currentLine.Length && Char.IsDigit(document.GetCharAt(currentLineOffset + i + 1))) { ++i; ++_currentLength; } } if (i + 1 < _currentLine.Length) { char nextch = Char.ToUpper(document.GetCharAt(currentLineOffset + i + 1)); if (nextch == 'F' || nextch == 'M' || nextch == 'D') { isfloatingpoint = true; ++i; ++_currentLength; } } if (!isfloatingpoint) { bool isunsigned = false; if (i + 1 < currentLineLength && Char.ToUpper(document.GetCharAt(currentLineOffset + i + 1)) == 'U') { ++i; ++_currentLength; isunsigned = true; } if (i + 1 < currentLineLength && Char.ToUpper(document.GetCharAt(currentLineOffset + i + 1)) == 'L') { ++i; ++_currentLength; if (!isunsigned && i + 1 < currentLineLength && Char.ToUpper(document.GetCharAt(currentLineOffset + i + 1)) == 'U') { ++i; ++_currentLength; } } } words.Add(new TextWord(document, _currentLine, _currentOffset, _currentLength, DigitColor, false)); _currentOffset += _currentLength; _currentLength = 0; continue; } // Check for SPAN ENDs if (_inSpan) { if (_activeSpan.End != null && _activeSpan.End.Length > 0) { if (MatchExpr(_currentLine, _activeSpan.End, i, document, _activeSpan.IgnoreCase)) { PushCurWord(document, ref markNext, words); string regex = GetRegString(_currentLine, _activeSpan.End, i, document); _currentLength += regex.Length; words.Add(new TextWord(document, _currentLine, _currentOffset, _currentLength, _activeSpan.EndColor, false)); _currentOffset += _currentLength; _currentLength = 0; i += regex.Length - 1; _currentSpanStack.Pop(); UpdateSpanStateVariables(); continue; } } } // check for SPAN BEGIN if (_activeRuleSet != null) { foreach (Span span in _activeRuleSet.Spans) { if ((!span.IsBeginSingleWord || _currentLength == 0) && (!span.IsBeginStartOfLine.HasValue || span.IsBeginStartOfLine.Value == (_currentLength == 0 && words.TrueForAll(delegate(TextWord textWord) { return(textWord.Type != TextWordType.Word); }))) && MatchExpr(_currentLine, span.Begin, i, document, _activeRuleSet.IgnoreCase)) { PushCurWord(document, ref markNext, words); string regex = GetRegString(_currentLine, span.Begin, i, document); if (!OverrideSpan(regex, document, words, span, ref i)) { _currentLength += regex.Length; words.Add(new TextWord(document, _currentLine, _currentOffset, _currentLength, span.BeginColor, false)); _currentOffset += _currentLength; _currentLength = 0; i += regex.Length - 1; if (_currentSpanStack == null) { _currentSpanStack = new SpanStack(); } _currentSpanStack.Push(span); span.IgnoreCase = _activeRuleSet.IgnoreCase; UpdateSpanStateVariables(); } goto skip; } } } // check if the char is a delimiter if (_activeRuleSet != null && ch < 256 && _activeRuleSet.Delimiters[ch]) { PushCurWord(document, ref markNext, words); if (_currentOffset + _currentLength + 1 < _currentLine.Length) { ++_currentLength; PushCurWord(document, ref markNext, words); goto skip; } } ++_currentLength; skip : continue; } } } PushCurWord(document, ref markNext, words); OnParsedLine(document, _currentLine, words); return(words); }
/// <remarks> /// This method returns the expression before a specified offset. /// That method is used in code completion to determine the expression given /// to the parser for type resolve. /// </remarks> public static string GetExpressionBeforeOffset(TextArea textArea, int initialOffset) { Document document = textArea.Document; int offset = initialOffset; while (offset - 1 > 0) { switch (document.GetCharAt(offset - 1)) { case '\n': case '\r': case '}': goto done; // offset = SearchBracketBackward(document, offset - 2, '{','}'); // break; case ']': offset = SearchBracketBackward(document, offset - 2, '[', ']'); break; case ')': offset = SearchBracketBackward(document, offset - 2, '(', ')'); break; case '.': --offset; break; case '"': if (offset < initialOffset - 1) { return(null); } return("\"\""); case '\'': if (offset < initialOffset - 1) { return(null); } return("'a'"); case '>': if (document.GetCharAt(offset - 2) == '-') { offset -= 2; break; } goto done; default: if (Char.IsWhiteSpace(document.GetCharAt(offset - 1))) { --offset; break; } int start = offset - 1; if (!IsLetterDigitOrUnderscore(document.GetCharAt(start))) { goto done; } while (start > 0 && IsLetterDigitOrUnderscore(document.GetCharAt(start - 1))) { --start; } string word = document.GetText(start, offset - start).Trim(); switch (word) { case "ref": case "out": case "in": case "return": case "throw": case "case": goto done; } if (word.Length > 0 && !IsLetterDigitOrUnderscore(word[0])) { goto done; } offset = start; break; } } done: //// simple exit fails when : is inside comment line or any other character //// we have to check if we got several ids in resulting line, which usually happens when //// id. is typed on next line after comment one //// Would be better if lexer would parse properly such expressions. However this will cause //// modifications in this area too - to get full comment line and remove it afterwards if (offset < 0) { return(string.Empty); } string resText = document.GetText(offset, textArea.Caret.Offset - offset).Trim(); int pos = resText.LastIndexOf('\n'); if (pos >= 0) { offset += pos + 1; //// whitespaces and tabs, which might be inside, will be skipped by trim below } string expression = document.GetText(offset, textArea.Caret.Offset - offset).Trim(); return(expression); }