Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.NRefactory/5.5.0/NRefactory.CSharp-5.5.0/Completion/ICompletionContextProvider.cs @ 13401

Last change on this file since 13401 was 11700, checked in by jkarder, 10 years ago

#2077: created branch and added first version

File size: 7.0 KB
Line 
1//
2// IMemberProvider.cs
3// 
4// Author:
5//       Mike Krüger <mkrueger@xamarin.com>
6//
7// Copyright (c) 2012 Xamarin Inc.
8//
9// Permission is hereby granted, free of charge, to any person obtaining a copy
10// of this software and associated documentation files (the "Software"), to deal
11// in the Software without restriction, including without limitation the rights
12// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13// copies of the Software, and to permit persons to whom the Software is
14// furnished to do so, subject to the following conditions:
15//
16// The above copyright notice and this permission notice shall be included in
17// all copies or substantial portions of the Software.
18//
19// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25// THE SOFTWARE.
26using System;
27using System.Collections.Generic;
28using ICSharpCode.NRefactory.TypeSystem;
29using ICSharpCode.NRefactory.Editor;
30using ICSharpCode.NRefactory.CSharp.TypeSystem;
31using System.Linq;
32using ICSharpCode.NRefactory.CSharp.Resolver;
33
34namespace ICSharpCode.NRefactory.CSharp.Completion
35{
36  public interface ICompletionContextProvider
37  {
38    IList<string> ConditionalSymbols {
39      get;
40    }
41
42    void GetCurrentMembers (int offset, out IUnresolvedTypeDefinition currentType, out IUnresolvedMember currentMember);
43
44    Tuple<string, TextLocation> GetMemberTextToCaret(int caretOffset, IUnresolvedTypeDefinition currentType, IUnresolvedMember currentMember);
45
46    CSharpAstResolver GetResolver (CSharpResolver resolver, AstNode rootNode);
47  }
48
49  public class DefaultCompletionContextProvider : ICompletionContextProvider
50  {
51    readonly IDocument document;
52    readonly CSharpUnresolvedFile unresolvedFile;
53    readonly List<string> symbols = new List<string> ();
54
55    public IList<string> ConditionalSymbols {
56      get {
57        return symbols;
58      }
59    }
60
61    public DefaultCompletionContextProvider (IDocument document, CSharpUnresolvedFile unresolvedFile)
62    {
63      if (document == null)
64        throw new ArgumentNullException("document");
65      if (unresolvedFile == null)
66        throw new ArgumentNullException("unresolvedFile");
67      this.document = document;
68      this.unresolvedFile = unresolvedFile;
69    }
70
71    public void AddSymbol (string sym)
72    {
73      symbols.Add (sym);
74    }
75    public void GetCurrentMembers(int offset, out IUnresolvedTypeDefinition currentType, out IUnresolvedMember currentMember)
76    {
77      //var document = engine.document;
78      var location = document.GetLocation(offset);
79     
80      currentType = null;
81     
82      foreach (var type in unresolvedFile.TopLevelTypeDefinitions) {
83        if (type.Region.Begin < location)
84          currentType = type;
85      }
86      currentType = FindInnerType (currentType, location);
87     
88      // location is beyond last reported end region, now we need to check, if the end region changed
89      if (currentType != null && currentType.Region.End < location) {
90        if (!IsInsideType (currentType, location))
91          currentType = null;
92      }
93      currentMember = null;
94      if (currentType != null) {
95        foreach (var member in currentType.Members) {
96          if (member.Region.Begin < location && (currentMember == null || currentMember.Region.Begin < member.Region.Begin))
97            currentMember = member;
98        }
99      }
100     
101      // location is beyond last reported end region, now we need to check, if the end region changed
102      // NOTE: Enums are a special case, there the "last" field needs to be treated as current member
103      if (currentMember != null && currentMember.Region.End < location && currentType.Kind != TypeKind.Enum) {
104        if (!IsInsideType (currentMember, location))
105          currentMember = null;
106      }/*
107      var stack = GetBracketStack (engine.GetMemberTextToCaret ().Item1);
108      if (stack.Count == 0)
109        currentMember = null;*/
110    }
111
112    IUnresolvedTypeDefinition FindInnerType (IUnresolvedTypeDefinition parent, TextLocation location)
113    {
114      if (parent == null)
115        return null;
116      var currentType = parent;
117      foreach (var type in parent.NestedTypes) {
118        if (type.Region.Begin < location  && location < type.Region.End)
119          currentType = FindInnerType (type, location);
120      }
121     
122      return currentType;
123    }
124   
125    bool IsInsideType (IUnresolvedEntity currentType, TextLocation location)
126    {
127      if (currentType.Region.IsEmpty)
128        return false;
129      int startOffset = document.GetOffset (currentType.Region.Begin);
130      int endOffset = document.GetOffset (location);
131      //bool foundEndBracket = false;
132   
133      var bracketStack = new Stack<char> ();
134   
135      bool isInString = false, isInChar = false;
136      bool isInLineComment = false, isInBlockComment = false;
137     
138      for (int i = startOffset; i < endOffset; i++) {
139        char ch = document.GetCharAt (i);
140        switch (ch) {
141          case '(':
142          case '[':
143          case '{':
144            if (!isInString && !isInChar && !isInLineComment && !isInBlockComment)
145              bracketStack.Push (ch);
146            break;
147          case ')':
148          case ']':
149          case '}':
150            if (!isInString && !isInChar && !isInLineComment && !isInBlockComment)
151            if (bracketStack.Count > 0)
152              bracketStack.Pop ();
153            break;
154          case '/':
155            if (isInBlockComment) {
156              if (i > 0 && document.GetCharAt (i - 1) == '*')
157                isInBlockComment = false;
158            } else if (!isInString && !isInChar && i + 1 < document.TextLength) {
159              char nextChar = document.GetCharAt (i + 1);
160              if (nextChar == '/')
161                isInLineComment = true;
162              if (!isInLineComment && nextChar == '*')
163                isInBlockComment = true;
164            }
165            break;
166          case '"':
167            if (!(isInChar || isInLineComment || isInBlockComment))
168              isInString = !isInString;
169            break;
170          case '\'':
171            if (!(isInString || isInLineComment || isInBlockComment))
172              isInChar = !isInChar;
173            break;
174          default :     
175            if (NewLine.IsNewLine(ch)) {
176              isInLineComment = false;
177            }
178            break;
179          }
180        }
181      return bracketStack.Any (t => t == '{');
182    }
183 
184    public Tuple<string, TextLocation> GetMemberTextToCaret(int caretOffset, IUnresolvedTypeDefinition currentType, IUnresolvedMember currentMember)
185    {
186      int startOffset;
187      if (currentMember != null && currentType != null && currentType.Kind != TypeKind.Enum) {
188        startOffset = document.GetOffset(currentMember.Region.Begin);
189      } else if (currentType != null) {
190        startOffset = document.GetOffset(currentType.Region.Begin);
191      } else {
192        startOffset = 0;
193      }
194      while (startOffset > 0) {
195        char ch = document.GetCharAt(startOffset - 1);
196        if (ch != ' ' && ch != '\t') {
197          break;
198        }
199        --startOffset;
200      }
201
202      return Tuple.Create (document.GetText (startOffset, caretOffset - startOffset), document.GetLocation (startOffset));
203    }
204
205
206    public CSharpAstResolver GetResolver (CSharpResolver resolver, AstNode rootNode)
207    {
208      return new CSharpAstResolver (resolver, rootNode, unresolvedFile);
209    }
210
211
212  }
213}
214
Note: See TracBrowser for help on using the repository browser.