2
// HighlightPropertiesSemanticRule.cs
5
// Mike KrĆ¼ger <mkrueger@novell.com>
7
// Copyright (C) 2008 Novell, Inc (http://www.novell.com)
9
// Permission is hereby granted, free of charge, to any person obtaining
10
// a copy of this software and associated documentation files (the
11
// "Software"), to deal in the Software without restriction, including
12
// without limitation the rights to use, copy, modify, merge, publish,
13
// distribute, sublicense, and/or sell copies of the Software, and to
14
// permit persons to whom the Software is furnished to do so, subject to
15
// the following conditions:
17
// The above copyright notice and this permission notice shall be
18
// included in all copies or substantial portions of the Software.
20
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30
using System.Collections.Generic;
32
using Mono.TextEditor;
33
using Mono.TextEditor.Highlighting;
34
using MonoDevelop.Ide.Gui;
35
using MonoDevelop.Projects;
36
using MonoDevelop.Projects.Dom;
37
using MonoDevelop.Projects.Dom.Parser;
38
using MonoDevelop.Projects.Gui.Completion;
40
using ICSharpCode.NRefactory.Ast;
42
namespace MonoDevelop.CSharpBinding
44
class HighlightCSharpSemanticRule : SemanticRule
47
// Mono.TextEditor.Document document;
48
// MonoDevelop.Ide.Gui.Document doc;
50
// IResolver resolver;
51
// IExpressionFinder expressionFinder;
53
/* void Init (Mono.TextEditor.Document document)
56
// parser = ProjectDomService.GetParser (document.FileName, document.MimeType);
57
// expressionFinder = ProjectDomService.GetExpressionFinder (document.FileName);
61
ProjectDom GetParserContext (Mono.TextEditor.Document document)
63
Project project = IdeApp.ProjectOperations.CurrentSelectedProject;
65
return ProjectDomService.GetProjectDom (project);
66
return ProjectDom.Empty;
70
/* IMember GetLanguageItem (Mono.TextEditor.Document document, LineSegment line, int offset, string expression)
72
string txt = document.Text;
73
ExpressionResult expressionResult = new ExpressionResult (expression);
74
// ExpressionResult expressionResult = expressionFinder.FindFullExpression (txt, offset);
75
int lineNumber = document.OffsetToLineNumber (offset);
76
expressionResult.Region = new DomRegion (lineNumber, offset - line.Offset, lineNumber, offset + expression.Length - line.Offset);
77
expressionResult.ExpressionContext = ExpressionContext.IdentifierExpected;
79
resolver = new NRefactoryResolver (ctx, doc.CompilationUnit, doc.TextEditor, document.FileName);
80
ResolveResult result = resolver.Resolve (expressionResult, expressionResult.Region.Start);
82
if (result is MemberResolveResult)
83
return ((MemberResolveResult)result).ResolvedMember;
87
public override void Analyze (Mono.TextEditor.Document doc, LineSegment line, Chunk startChunk, int startOffset, int endOffset)
89
if (!MonoDevelop.Core.PropertyService.Get ("EnableSemanticHighlighting", false) || doc == null || line == null || startChunk == null)
91
ctx = GetParserContext (doc);
92
int lineNumber = doc.OffsetToLineNumber (line.Offset);
93
ParsedDocument parsedDocument = ProjectDomService.GetParsedDocument (ctx, doc.FileName);
94
if (parsedDocument == null || parsedDocument.CompilationUnit == null)
96
for (Chunk chunk = startChunk; chunk != null; chunk = chunk.Next) {
97
if (chunk.Style != "text")
99
for (int i = chunk.Offset; i < chunk.EndOffset; i++) {
100
char charBefore = i > 0 ? doc.GetCharAt (i - 1) : '}';
101
if (Char.IsLetter (doc.GetCharAt (i)) && !Char.IsLetterOrDigit (charBefore)) {
107
bool wasWhitespace = false;
109
int bracketCount = 0;
111
char ch = doc.GetCharAt (start);
112
if (wasWhitespace && IsNamePart(ch)) {
114
if (start < chunk.Offset)
115
start = Int32.MaxValue;
120
if (bracketCount < 0) {
125
wasWhitespace = false;
129
if (wasWhitespace && !wasDot)
133
wasWhitespace = false;
136
if (!IsNamePart(ch) && !Char.IsWhiteSpace (ch) && ch != '.') {
140
wasWhitespace = Char.IsWhiteSpace (ch);
141
wasDot = ch == '.' || wasDot && wasWhitespace;
146
int genericCount = 0;
147
wasWhitespace = false;
148
List<Segment> nameSegments = new List<Segment> ();
149
while (end < chunk.EndOffset) {
150
char ch = doc.GetCharAt (end);
151
if (wasWhitespace && IsNamePart(ch))
155
while (end < doc.Length) {
156
ch = doc.GetCharAt (end);
160
nameSegments.Add (new Segment (end, 1));
167
if (!IsNamePart(ch) && !Char.IsWhiteSpace (ch))
169
wasWhitespace = Char.IsWhiteSpace (ch);
174
string typeString = doc.GetTextBetween (start, end);
175
IReturnType returnType = NRefactoryResolver.ParseReturnType (new ExpressionResult (typeString));
177
int nameEndOffset = start;
178
for (; nameEndOffset < end; nameEndOffset++) {
179
char ch = doc.GetCharAt (nameEndOffset);
180
if (nameEndOffset >= i && ch == '<') {
185
nameSegments.Add (new Segment (i, nameEndOffset - i));
187
int column = i - line.Offset;
188
IType callingType = parsedDocument.CompilationUnit.GetTypeAt (lineNumber, column);
189
List<IReturnType> genericParams = null;
190
if (genericCount > 0) {
191
genericParams = new List<IReturnType> ();
192
for (int n = 0; n < genericCount; n++)
193
genericParams.Add (new DomReturnType ("A"));
196
IType type = ctx.SearchType (new SearchTypeRequest (parsedDocument.CompilationUnit, returnType, callingType));
198
nameSegments.ForEach (segment => HighlightSegment (startChunk, segment, "keyword.semantic.type"));
203
static void HighlightSegment (Chunk startChunk, Segment namePart, string style)
205
for (Chunk searchChunk = startChunk; searchChunk != null; searchChunk = searchChunk.Next) {
206
if (!searchChunk.Contains (namePart))
208
if (searchChunk.Length == namePart.Length) {
209
searchChunk.Style = style;
212
Chunk propertyChunk = new Chunk (namePart.Offset, namePart.Length, style);
213
propertyChunk.Next = searchChunk.Next;
214
searchChunk.Next = propertyChunk;
215
if (searchChunk.EndOffset - propertyChunk.EndOffset > 0) {
216
Chunk newChunk = new Chunk (propertyChunk.EndOffset, searchChunk.EndOffset - propertyChunk.EndOffset, searchChunk.Style);
217
newChunk.Next = propertyChunk.Next;
218
propertyChunk.Next = newChunk;
220
searchChunk.Length = namePart.Offset - searchChunk.Offset;
226
bool IsNamePart (char ch)
228
return Char.IsLetterOrDigit (ch) || ch == '_';