internal static IEnumerable<char> GetTextWithoutCommentsAndStrings (Mono.TextEditor.TextDocument doc, int start, int end) { bool isInString = false, isInChar = false; bool isInLineComment = false, isInBlockComment = false; int escaping = 0; for (int pos = start; pos < end; pos++) { char ch = doc.GetCharAt (pos); switch (ch) { case '\r': case '\n': isInLineComment = false; break; case '/': if (isInBlockComment) { if (pos > 0 && doc.GetCharAt (pos - 1) == '*') isInBlockComment = false; } else if (!isInString && !isInChar && pos + 1 < doc.TextLength) { char nextChar = doc.GetCharAt (pos + 1); if (nextChar == '/') isInLineComment = true; if (!isInLineComment && nextChar == '*') isInBlockComment = true; } break; case '"': if (!(isInChar || isInLineComment || isInBlockComment)) if (!isInString || escaping != 1) isInString = !isInString; break; case '\'': if (!(isInString || isInLineComment || isInBlockComment)) if (!isInChar || escaping != 1) isInChar = !isInChar; break; case '\\': if (escaping != 1) escaping = 2; break; default : if (!(isInString || isInChar || isInLineComment || isInBlockComment)) yield return ch; break; } escaping--; } }
static IEnumerable<KeyValuePair <char, int>> GetTextWithoutCommentsAndStrings (Mono.TextEditor.Document doc, int start, int end) { bool isInString = false, isInChar = false; bool isInLineComment = false, isInBlockComment = false; for (int pos = start; pos < end; pos++) { char ch = doc.GetCharAt (pos); switch (ch) { case '\r': case '\n': isInLineComment = false; break; case '/': if (isInBlockComment) { if (pos > 0 && doc.GetCharAt (pos - 1) == '*') isInBlockComment = false; } else if (!isInString && !isInChar && pos + 1 < doc.Length) { char nextChar = doc.GetCharAt (pos + 1); if (nextChar == '/') isInLineComment = true; if (!isInLineComment && nextChar == '*') isInBlockComment = true; } break; case '"': if (!(isInChar || isInLineComment || isInBlockComment)) isInString = !isInString; break; case '\'': if (!(isInString || isInLineComment || isInBlockComment)) isInChar = !isInChar; break; default : if (!(isInString || isInChar || isInLineComment || isInBlockComment)) yield return new KeyValuePair<char, int> (ch, pos); break; } } }
static void CheckLine (Mono.TextEditor.Document doc, Mono.TextEditor.LineSegment line, out bool isBlank, out bool isBracket) { isBlank = true; isBracket = false; for (int i = 0; i < line.Length; i++) { char c = doc.GetCharAt (line.Offset + i); if (c == '{') { isBracket = true; isBlank = false; } else if (!Char.IsWhiteSpace (c)) { isBlank = false; if (isBracket) { isBracket = false; break; } } } }
public MonoDevelop.Projects.Dom.ResolveResult GetLanguageItem (ProjectDom dom, Mono.TextEditor.TextEditorData data, int offset) { if (offset < 0) return null; string fileName = data.Document.FileName; IParser parser = ProjectDomService.GetParser (fileName); if (parser == null) return null; MonoDevelop.Ide.Gui.Document doc = IdeApp.Workbench.ActiveDocument; if (doc == null) return null; IResolver resolver = parser.CreateResolver (dom, doc, fileName); if (resolver == null) return null; var expressionFinder = new NewCSharpExpressionFinder (dom); int wordEnd = Math.Min (offset, data.Length - 1); if (data.GetCharAt (wordEnd) == '@') wordEnd++; while (wordEnd < data.Length && (Char.IsLetterOrDigit (data.GetCharAt (wordEnd)) || data.GetCharAt (wordEnd) == '_')) wordEnd++; while (wordEnd < data.Length - 1 && Char.IsWhiteSpace (data.GetCharAt (wordEnd))) wordEnd++; /* is checked at the end. int saveEnd = wordEnd; if (wordEnd < data.Length && data.GetCharAt (wordEnd) == '<') { int matchingBracket = data.Document.GetMatchingBracketOffset (wordEnd); if (matchingBracket > 0) wordEnd = matchingBracket; while (wordEnd < data.Length - 1 && Char.IsWhiteSpace (data.GetCharAt (wordEnd))) wordEnd++; } bool wasMethodCall = false; if (data.GetCharAt (wordEnd) == '(') { int matchingBracket = data.Document.GetMatchingBracketOffset (wordEnd); if (matchingBracket > 0) { wordEnd = matchingBracket; wasMethodCall = true; } } if (!wasMethodCall) wordEnd = saveEnd;*/ ExpressionResult expressionResult = expressionFinder.FindExpression (data, wordEnd); if (expressionResult == null) return null; ResolveResult resolveResult; DocumentLocation loc = data.Document.OffsetToLocation (offset); string savedExpression = null; // special handling for 'var' "keyword" if (expressionResult.ExpressionContext == ExpressionContext.IdentifierExpected && expressionResult.Expression != null && expressionResult.Expression.Trim () == "var") { int endOffset = data.Document.LocationToOffset (expressionResult.Region.End.Line, expressionResult.Region.End.Column); StringBuilder identifer = new StringBuilder (); for (int i = endOffset; i >= 0 && i < data.Document.Length; i++) { char ch = data.Document.GetCharAt (i); if (Char.IsWhiteSpace (ch)) continue; if (ch == '=') break; if (Char.IsLetterOrDigit (ch) || ch =='_') { identifer.Append (ch); continue; } identifer.Length = 0; break; } if (identifer.Length > 0) { expressionResult.Expression = identifer.ToString (); resolveResult = resolver.Resolve (expressionResult, new DomLocation (loc.Line, loc.Column)); if (resolveResult != null) { resolveResult = new MemberResolveResult (dom.GetType (resolveResult.ResolvedType)); resolveResult.ResolvedExpression = expressionResult; return resolveResult; } } } if (expressionResult.ExpressionContext == ExpressionContext.Attribute) { savedExpression = expressionResult.Expression; expressionResult.Expression = expressionResult.Expression.Trim () + "Attribute"; expressionResult.ExpressionContext = ExpressionContext.ObjectCreation; } resolveResult = resolver.Resolve (expressionResult, new DomLocation (loc.Line, loc.Column)); if (savedExpression != null && resolveResult == null) { expressionResult.Expression = savedExpression; resolveResult = resolver.Resolve (expressionResult, new DomLocation (loc.Line, loc.Column)); } // Search for possible generic parameters. // if (this.resolveResult == null || this.resolveResult.ResolvedType == null || String.IsNullOrEmpty (this.resolveResult.ResolvedType.Name)) { if (!expressionResult.Region.IsEmpty) { int j = data.Document.LocationToOffset (expressionResult.Region.End.Line, expressionResult.Region.End.Column); int bracket = 0; for (int i = j; i >= 0 && i < data.Document.Length; i++) { char ch = data.Document.GetCharAt (i); if (Char.IsWhiteSpace (ch)) continue; if (ch == '<') { bracket++; } else if (ch == '>') { bracket--; if (bracket == 0) { expressionResult.Expression += data.Document.GetTextBetween (j, i + 1); expressionResult.ExpressionContext = ExpressionContext.ObjectCreation; resolveResult = resolver.Resolve (expressionResult, new DomLocation (loc.Line, loc.Column)); break; } } else { if (bracket == 0) break; } } } // To resolve method overloads the full expression must be parsed. // ex.: Overload (1)/ Overload("one") - parsing "Overload" gives just a MethodResolveResult // and for constructor initializers it's tried too to to resolve constructor overloads. if (resolveResult is ThisResolveResult || resolveResult is BaseResolveResult || resolveResult is MethodResolveResult && ((MethodResolveResult)resolveResult).Methods.Count > 1) { // put the search offset at the end of the invocation to be able to find the full expression // the resolver finds it itself if spaces are between the method name and the argument opening parentheses. while (wordEnd < data.Length - 1 && Char.IsWhiteSpace (data.GetCharAt (wordEnd))) wordEnd++; if (data.GetCharAt (wordEnd) == '(') { int matchingBracket = data.Document.GetMatchingBracketOffset (wordEnd); if (matchingBracket > 0) wordEnd = matchingBracket; } //Console.WriteLine (expressionFinder.FindFullExpression (txt, wordEnd)); ResolveResult possibleResult = resolver.Resolve (expressionFinder.FindFullExpression (data, wordEnd), new DomLocation (loc.Line, loc.Column)) ?? resolveResult; //Console.WriteLine ("possi:" + resolver.Resolve (expressionFinder.FindFullExpression (txt, wordEnd), new DomLocation (loc.Line, loc.Column))); if (possibleResult is MethodResolveResult) resolveResult = possibleResult; } return resolveResult; }
public MonoDevelop.Projects.Dom.ResolveResult GetLanguageItem (ProjectDom dom, Mono.TextEditor.TextEditorData data, int offset, string expression) { string fileName = data.Document.FileName; MonoDevelop.Ide.Gui.Document doc = IdeApp.Workbench.ActiveDocument; if (doc == null) return null; IParser parser = ProjectDomService.GetParser (fileName); if (parser == null) return null; IResolver resolver = parser.CreateResolver (dom, doc, fileName); IExpressionFinder expressionFinder = parser.CreateExpressionFinder (dom); if (resolver == null || expressionFinder == null) return null; int wordEnd = offset; while (wordEnd < data.Length && (Char.IsLetterOrDigit (data.GetCharAt (wordEnd)) || data.GetCharAt (wordEnd) == '_')) wordEnd++; ExpressionResult expressionResult = new ExpressionResult (expression); expressionResult.ExpressionContext = ExpressionContext.MethodBody; DocumentLocation loc = data.Document.OffsetToLocation (offset); string savedExpression = null; ResolveResult resolveResult; if (expressionResult.ExpressionContext == ExpressionContext.Attribute) { savedExpression = expressionResult.Expression; expressionResult.Expression += "Attribute"; expressionResult.ExpressionContext = ExpressionContext.ObjectCreation; } resolveResult = resolver.Resolve (expressionResult, new DomLocation (loc.Line, loc.Column)); if (savedExpression != null && resolveResult == null) { expressionResult.Expression = savedExpression; resolveResult = resolver.Resolve (expressionResult, new DomLocation (loc.Line, loc.Column)); } if (expressionResult.Region.End.IsEmpty) return resolveResult; // Search for possible generic parameters. // if (this.resolveResult == null || this.resolveResult.ResolvedType == null || String.IsNullOrEmpty (this.resolveResult.ResolvedType.Name)) { int j = data.Document.LocationToOffset (expressionResult.Region.End.Line, expressionResult.Region.End.Column); int bracket = 0; for (int i = j; i >= 0 && i < data.Document.Length; i++) { char ch = data.Document.GetCharAt (i); if (Char.IsWhiteSpace (ch)) continue; if (ch == '<') { bracket++; } else if (ch == '>') { bracket--; if (bracket == 0) { expressionResult.Expression += data.Document.GetTextBetween (j, i + 1); expressionResult.ExpressionContext = ExpressionContext.ObjectCreation; resolveResult = resolver.Resolve (expressionResult, new DomLocation (loc.Line, loc.Column)) ?? resolveResult; break; } } else { if (bracket == 0) break; } } // } // To resolve method overloads the full expression must be parsed. // ex.: Overload (1)/ Overload("one") - parsing "Overload" gives just a MethodResolveResult if (resolveResult is MethodResolveResult) resolveResult = resolver.Resolve (expressionFinder.FindFullExpression (data, wordEnd), new DomLocation (loc.Line, loc.Column)) ?? resolveResult; return resolveResult; }
static bool IsBlankLine(Mono.TextEditor.TextDocument doc, Mono.TextEditor.DocumentLine line) { for (int i = 0; i < line.Length; i++) { if (!Char.IsWhiteSpace (doc.GetCharAt (line.Offset + i))) return false; } return true; }
// string expression; /* IMember GetLanguageItem (Mono.TextEditor.Document document, LineSegment line, int offset, string expression) { string txt = document.Text; ExpressionResult expressionResult = new ExpressionResult (expression); // ExpressionResult expressionResult = expressionFinder.FindFullExpression (txt, offset); int lineNumber = document.OffsetToLineNumber (offset); expressionResult.Region = new DomRegion (lineNumber, offset - line.Offset, lineNumber, offset + expression.Length - line.Offset); expressionResult.ExpressionContext = ExpressionContext.IdentifierExpected; resolver = new NRefactoryResolver (ctx, doc.CompilationUnit, doc.TextEditor, document.FileName); ResolveResult result = resolver.Resolve (expressionResult, expressionResult.Region.Start); if (result is MemberResolveResult) return ((MemberResolveResult)result).ResolvedMember; return null; }*/ public override void Analyze (Mono.TextEditor.Document doc, LineSegment line, Chunk startChunk, int startOffset, int endOffset) { if (!MonoDevelop.Core.PropertyService.Get ("EnableSemanticHighlighting", false) || doc == null || line == null || startChunk == null) return; ctx = GetParserContext (doc); int lineNumber = doc.OffsetToLineNumber (line.Offset); ParsedDocument parsedDocument = ProjectDomService.GetParsedDocument (ctx, doc.FileName); ICompilationUnit unit = parsedDocument != null ? parsedDocument.CompilationUnit : null; if (unit == null) return; for (Chunk chunk = startChunk; chunk != null; chunk = chunk.Next) { if (chunk.Style != "text") continue; for (int i = chunk.Offset; i < chunk.EndOffset; i++) { char charBefore = i > 0 ? doc.GetCharAt (i - 1) : '}'; if (Char.IsLetter (doc.GetCharAt (i)) && !Char.IsLetterOrDigit (charBefore)) { } else { continue; } int start = i; bool wasWhitespace = false; bool wasDot = false; int bracketCount = 0; while (start > 0) { char ch = doc.GetCharAt (start); if (ch == '\n' || ch == '\r') break; if (wasWhitespace && IsNamePart(ch)) { start++; if (start < chunk.Offset) start = Int32.MaxValue; break; } if (ch == '<') { bracketCount--; if (bracketCount < 0) { start++; break; } start--; wasWhitespace = false; continue; } if (ch == '>') { if (wasWhitespace && !wasDot) break; bracketCount++; start--; wasWhitespace = false; continue; } if (!IsNamePart(ch) && !Char.IsWhiteSpace (ch) && ch != '.') { start++; break; } wasWhitespace = Char.IsWhiteSpace (ch); wasDot = ch == '.' || wasDot && wasWhitespace; start--; } int end = i; int genericCount = 0; wasWhitespace = false; List<Segment> nameSegments = new List<Segment> (); while (end < chunk.EndOffset) { char ch = doc.GetCharAt (end); if (wasWhitespace && IsNamePart(ch)) break; if (ch == '<') { genericCount = 1; while (end < doc.Length) { ch = doc.GetCharAt (end); if (ch == ',') genericCount++; if (ch == '>') { nameSegments.Add (new Segment (end, 1)); break; } end++; } break; } if (!IsNamePart(ch) && !Char.IsWhiteSpace (ch)) break; wasWhitespace = Char.IsWhiteSpace (ch); end++; } if (start >= end) continue; string typeString = doc.GetTextBetween (start, end); IReturnType returnType = NRefactoryResolver.ParseReturnType (new ExpressionResult (typeString)); int nameEndOffset = start; for (; nameEndOffset < end; nameEndOffset++) { char ch = doc.GetCharAt (nameEndOffset); if (nameEndOffset >= i && ch == '<') { nameEndOffset++; break; } } nameSegments.Add (new Segment (i, nameEndOffset - i)); int column = i - line.Offset; IType callingType = unit.GetTypeAt (lineNumber, column); List<IReturnType> genericParams = null; if (genericCount > 0) { genericParams = new List<IReturnType> (); for (int n = 0; n < genericCount; n++) genericParams.Add (new DomReturnType ("A")); } IType type = null; if (ctx != null) type = ctx.SearchType ((MonoDevelop.Projects.Dom.INode)callingType ?? unit, returnType); if (type == null && unit != null && returnType != null) type = unit.GetType (returnType.FullName, returnType.GenericArguments.Count); if (ctx != null && type == null && returnType != null) { returnType.Name += "Attribute"; type = ctx.SearchType ((MonoDevelop.Projects.Dom.INode)callingType ?? unit, returnType); } if (type != null) nameSegments.ForEach (segment => HighlightSegment (startChunk, segment, "keyword.semantic.type")); } } }