using System.Collections.Generic; using System.Diagnostics; using Boo.BooLangProject; using Boo.BooLangService.Document; using Boo.BooLangService.StringParsing; using BooLangService; using Microsoft.VisualStudio.Package; using Microsoft.VisualStudio.TextManager.Interop; namespace Boo.BooLangService { public class ParseRequestProcessor { private readonly LanguageService languageService; public ParseRequestProcessor(LanguageService languageService) { this.languageService = languageService; } /// /// /// /// /// Initially I thought it would be enough to just compile the documents and be done with it, but VS also wants a load of string /// manip doing. /// /// I figure we need to do a two stage Parse, the first part compiles the docs to build up the code DOM (so we can easily find members /// etc), and then the second part works on the current view's string content, allowing brace matching and what not. We can't use the /// compiled source, because the boo compiler alters it durin compilation (adds implied constructors etc... which screws up the line /// numbers). /// /// /// public AuthoringScope GetAuthoringScopeForRequest(ParseRequest request) { var compiledProject = GetCompiledProject(request); var viewSource = request.Text; // Autos: // Parse the code block at the given location to obtain any expressions that might be of interest in the Autos debugging window // (an expression is the name of variable or parameter that can be evaluated to produce a value). if (request.Reason == ParseReason.Autos) return GetAutos(request); // Check: // Parse the entire source file, checking for errors. This pass should also create lists of matching language pairs, triplets, // members, and methods. if (request.Reason == ParseReason.Check) return CheckForErrors(request); // CodeSpan: // Parse the section of code containing the specified location to find the extent of the statement. Used in validating breakpoints. if (request.Reason == ParseReason.CodeSpan) return FindStatementExtent(request); // CompleteWord: // Parse to get the partially completed word before the current position in order to show a list of possible completions (members, // arguments, methods). if (request.Reason == ParseReason.CompleteWord) return GetCompletionSuggestions(request); // DisplayMemberList: // Parse the separator and the possible name before it, to obtain a list of members to be shown in a member completion list. if (request.Reason == ParseReason.DisplayMemberList) return GetMemberList(request); // Goto: // Parse the identifier or expression at the specified location to obtain a possible URI of a file where the identifier is defined, // declared, or referenced. if (request.Reason == ParseReason.Goto) return GetGotoTarget(request); // HighlightBraces: // Parse to find the matching language pairs (such as "{" and "}" or "<" and ">") that enclose the given location so they and their // contents can be highlighted. if (request.Reason == ParseReason.HighlightBraces) return HighlightBraces(request, compiledProject); // MatchBraces: // Parse the language pair at the given location to finds its match. if (request.Reason == ParseReason.MatchBraces) return FindMatchingBrace(request); // MemberSelect: // Parse the separator character before the current location to obtain a list of members for the class. if (request.Reason == ParseReason.MemberSelect) return FindMembers(request); // MemberSelectAndHighlightBraces: // Parse the character at the current location to complete a member selection and to highlight the matching pair to the parsed // character (such as a ")" after a method name). if (request.Reason == ParseReason.MemberSelectAndHighlightBraces) return FindMembersAndHighlightBraces(request); // MethodTip: // Parse the method name before the current position to produce a list of all overloaded method signatures that match the method name. if (request.Reason == ParseReason.MethodTip) return GetMethodTip(request, compiledProject); // QuickInfo: // Parse the identifier or selection at the given location to obtain type information to be shown in an IntelliSense quick info tool tip. if (request.Reason == ParseReason.QuickInfo) return GetQuickInfo(request); return GetDefault(request, compiledProject); } private AuthoringScope GetDefault(ParseRequest request, CompiledProject compiledProject) { Debug.WriteLine("Default"); return new BooScope(compiledProject, (BooSource)languageService.GetSource(request.View), request.FileName); } private CompiledProject GetCompiledProject(ParseRequest request) { var project = GetProject(request); return project.GetCompiledProject(); } private AuthoringScope GetQuickInfo(ParseRequest request) { Debug.WriteLine("GetQuickInfo"); throw new System.NotImplementedException(); } private AuthoringScope FindMembersAndHighlightBraces(ParseRequest request) { Debug.WriteLine("FindMembersAndHighlightBraces"); throw new System.NotImplementedException(); } private AuthoringScope FindMembers(ParseRequest request) { Debug.WriteLine("FindMembers"); throw new System.NotImplementedException(); } private AuthoringScope FindMatchingBrace(ParseRequest request) { Debug.WriteLine("FindMatchingBrace"); throw new System.NotImplementedException(); } private AuthoringScope HighlightBraces(ParseRequest request, CompiledProject compiledProject) { Debug.WriteLine("HighlightBraces"); var source = languageService.GetSource(request.View); var indexOfOriginal = source.GetPositionOfLineIndex(request.Line, request.Col - 1); var bracketFinder = new BracketPairFinder(BracketPairType.FromChar(request.Text[indexOfOriginal])); var bracketPairs = bracketFinder.FindPairs(request.Text); int? partner = bracketPairs.FindPartnerIndex(indexOfOriginal); if (partner != null) { request.Sink.FoundMatchingBrace = true; int nextLine, nextCol; source.GetLineIndexOfPosition(partner.Value, out nextLine, out nextCol); request.Sink.MatchPair( new TextSpan { iStartLine = request.Line, iEndLine = request.Line, iStartIndex = request.Col - 1, iEndIndex = request.Col }, new TextSpan { iStartLine = nextLine, iEndLine = nextLine, iStartIndex = nextCol, iEndIndex = nextCol + 1 }, 0); } return GetDefault(request, compiledProject); } private AuthoringScope GetGotoTarget(ParseRequest request) { Debug.WriteLine("GetGotoTarget"); throw new System.NotImplementedException(); } private AuthoringScope GetMemberList(ParseRequest request) { Debug.WriteLine("GetMemberList"); throw new System.NotImplementedException(); } private AuthoringScope GetCompletionSuggestions(ParseRequest request) { Debug.WriteLine("GetCompletionSuggestions"); throw new System.NotImplementedException(); } private AuthoringScope FindStatementExtent(ParseRequest request) { Debug.WriteLine("FindStatementExtent"); throw new System.NotImplementedException(); } private AuthoringScope CheckForErrors(ParseRequest request) { Debug.WriteLine("CheckForErrors"); throw new System.NotImplementedException(); } private AuthoringScope GetAutos(ParseRequest request) { Debug.WriteLine("GetAutos"); throw new System.NotImplementedException(); } private AuthoringScope GetMethodTip(ParseRequest request, CompiledProject compiledProject) { Debug.WriteLine("GetMethodTip"); int col = request.Col; if (request.TokenInfo != null && (request.TokenInfo.Trigger & TokenTriggers.ParameterStart) == TokenTriggers.ParameterStart && request.Col == request.TokenInfo.StartIndex) { col++; } BooMethods methods = new BooMethods(); // add methods from parsed scope... methods.StartName = new TextSpan { iStartLine = request.Line, iEndLine = request.Line, iStartIndex = request.Col, iEndIndex = request.Col + 10 }; methods.StartParameters = new TextSpan { iStartLine = request.Line, iEndLine = request.Line, iStartIndex = request.Col + 11, iEndIndex = request.Col + 12 }; methods.NextParameters = new List { new TextSpan { iStartLine = request.Line, iEndLine = request.Line, iStartIndex = request.Col + 18, iEndIndex = request.Col + 19 } }; methods.EndParameters = new TextSpan { iStartLine = request.Line, iEndLine = request.Line, iStartIndex = request.Col + 24, iEndIndex = request.Col + 25 }; if (methods.StartName.iEndLine > 0) { request.Sink.StartName(methods.StartName, methods.GetName(0)); request.Sink.StartParameters(methods.StartParameters); foreach (var span in methods.NextParameters) request.Sink.NextParameter(span); request.Sink.EndParameters(methods.EndParameters); } else { TextSpan ts = new TextSpan(); ts.iStartIndex = request.Line; ts.iEndIndex = request.Line; ts.iStartIndex = request.Col - 1; ts.iEndIndex = request.Col + 1; request.Sink.StartName(ts, methods.GetName(0)); } return new BooScope(compiledProject, (BooSource)languageService.GetSource(request.View), request.FileName, methods); } private BooProjectSources GetProject(ParseRequest request) { BooProjectSources project = BooProjectSources.Find(request.FileName); if (project != null) project.Update(request); return project; } } }