/// <summary> /// Get the parameters to a specified function defined in a file in the include /// cache. /// </summary> /// <param name="function"> /// The name of the function for which to find parameters. /// </param> /// <returns> /// A list of the function's parameters or null if the function could not be /// found. /// </returns> public List <string> GetParametersFromIncludeCache(string function) { string fileName = null; IEnumerable <IncludeCacheEntry> entries = _includeCache.Values.Where( x => x.Functions.Any(y => y.Equals(function, StringComparison.CurrentCultureIgnoreCase)) || x.Macros.Any(y => y.Equals(function, StringComparison.CurrentCultureIgnoreCase))); foreach (IncludeCacheEntry entry in entries) { fileName = entry.FileName; break; } if (fileName != null) { try { string[] includeLines = File.ReadAllLines(fileName); return(CMakeParsing.ParseForParameterNames(includeLines, function)); } catch (IOException) { // Just ignore any errors. } } return(null); }
private void UpdateIncludeCacheItem(string include) { string curFileDir = Path.GetDirectoryName(GetFilePath()); string path = null; bool needUpdate = true; if (_includeCache.ContainsKey(include) && File.Exists(_includeCache[include].FileName)) { path = _includeCache[include].FileName; needUpdate = (File.GetLastWriteTime(path) != _includeCache[include].TimeStamp); } else { path = Path.Combine(curFileDir, include + ".cmake"); if (!File.Exists(path)) { path = Path.Combine(CMakePath.FindCMakeModules(), include + ".cmake"); if (!File.Exists(path)) { path = null; } } } if (path != null && needUpdate) { try { string[] includeLines = File.ReadAllLines(path); bool rootRef = _includeCache.ContainsKey(include) && _includeCache[include].RootRef; _includeCache[include] = new IncludeCacheEntry() { FileName = path, TimeStamp = File.GetLastWriteTime(path), RootRef = rootRef, Variables = CMakeParsing.ParseForVariables(includeLines), EnvVariables = CMakeParsing.ParseForEnvVariables( includeLines), CacheVariables = CMakeParsing.ParseForCacheVariables( includeLines), Functions = CMakeParsing.ParseForFunctionNames(includeLines, false), Macros = CMakeParsing.ParseForFunctionNames(includeLines, true), Dependencies = CMakeParsing.ParseForIncludes(includeLines) }; foreach (string dependency in _includeCache[include].Dependencies) { UpdateIncludeCacheItem(dependency); } } catch (IOException) { // Just ignore any errors. } } }
private static CMakeItemDeclarations CreateCacheVariableDeclarations( CMakeCommandId id, ParseRequest req, Source source, List <string> priorParameters) { List <string> vars = CMakeParsing.ParseForCacheVariables(source.GetLines()); return(new CMakeVariableDeclarations(vars, CMakeVariableType.CacheVariable)); }
private static CMakeItemDeclarations CreateTargetDeclarations(CMakeCommandId id, ParseRequest req, Source source, List <string> priorParameters) { List <string> targets = CMakeParsing.ParseForTargetNames(source.GetLines()); CMakeItemDeclarations decls = new CMakeItemDeclarations(); decls.AddItems(targets, CMakeItemDeclarations.ItemType.Target); decls.ExcludeItems(priorParameters); return(decls); }
private static CMakeItemDeclarations CreateInstalledFileDeclarations( CMakeCommandId id, ParseRequest req, Source source, List <string> priorParameters) { List <string> installedFiles = CMakeParsing.ParseForInstalledFiles( source.GetLines()); CMakeItemDeclarations decls = new CMakeItemDeclarations(); decls.AddItems(installedFiles, CMakeItemDeclarations.ItemType.SourceFile); decls.ExcludeItems(priorParameters); return(decls); }
/// <summary> /// Update the include cache with information on the files referenced by the /// specified lines. /// </summary> /// <param name="lines">A collection of lines.</param> public void BuildIncludeCache(IEnumerable <string> lines) { foreach (IncludeCacheEntry entry in _includeCache.Values) { entry.RootRef = false; } List <string> includes = CMakeParsing.ParseForIncludes(lines); foreach (string include in includes) { UpdateIncludeCacheItem(include); if (_includeCache.ContainsKey(include)) { _includeCache[include].RootRef = true; } } }
public override int FormatSpan(IVsTextLines buffer, TextSpan[] ts) { foreach (TextSpan span in ts) { // Set the indentation of each line in the snippet to match the first // line. LanguagePreferences prefs = Source.LanguageService.Preferences; char indentChar = prefs.InsertTabs ? '\t' : ' '; int level = CMakeParsing.GetIndentationLevel( Source.GetLine(span.iStartLine), indentChar); for (int i = span.iStartLine + 1; i <= span.iEndLine; ++i) { Source.SetText(i, 0, i, 0, new string(indentChar, level)); } } return(VSConstants.S_OK); }
public override bool HandleSmartIndent() { // If the line contains an outer opening parenthesis, intent by one level. // If the line contains an outer closing parenthesis, unindent to match the // level of the corresponding opening parenthesis. In all other cases, // match the indentation level of the previous line. LanguagePreferences prefs = Source.LanguageService.Preferences; char indentChar = prefs.InsertTabs ? '\t' : ' '; int line; int col; TextView.GetCaretPos(out line, out col); List <string> lines = Source.GetLines().ToList(); int prevLine = CMakeParsing.GetLastNonEmptyLine(lines, line - 1); int level = CMakeParsing.GetIndentationLevel(lines[prevLine], indentChar); int lineToMatch; if (CMakeParsing.ShouldIndent(lines, prevLine)) { level += prefs.InsertTabs ? 1 : prefs.IndentSize; } else if (CMakeParsing.ShouldUnindent(lines, prevLine, out lineToMatch)) { if (lineToMatch < 0) { level = 0; } else { level = CMakeParsing.GetIndentationLevel(lines[lineToMatch], indentChar); } } int oldIndentLen = 0; while (oldIndentLen < lines[line].Length && lines[line][oldIndentLen] == indentChar) { oldIndentLen++; } Source.SetText(line, 0, line, oldIndentLen, new string(indentChar, level)); TextView.PositionCaretForEditing(line, level); return(true); }
public override string GetDataTipText(int line, int col, out TextSpan span) { CMakeParsing.TokenData tokenData; if (_lines != null && CMakeParsing.ParseForToken(_lines, line, col, out tokenData) && !tokenData.InParens) { if (tokenData.TokenInfo.Token == (int)CMakeToken.Keyword) { // Get a Quick Info tip for the command at the cursor. span = tokenData.TokenInfo.ToTextSpan(line); string lineText = _lines.ToList()[line]; string tokenText = lineText.ExtractToken(tokenData.TokenInfo); CMakeCommandId id = CMakeKeywords.GetCommandId(tokenText); if (CMakeSubcommandMethods.HasSubcommands(id)) { // Parse to get the subcommand, if there is one. CMakeParsing.ParameterInfoResult result = CMakeParsing.ParseForParameterInfo(_lines, line, -1, true); return(CMakeSubcommandMethods.GetSubcommandQuickInfoTip(id, result.SubcommandName)); } return(CMakeMethods.GetCommandQuickInfoTip(id)); } else if (tokenData.TokenInfo.Token == (int)CMakeToken.Identifier) { // Get a Quick Info tip for the function called at the cursor, if // there is one. string lineText = _lines.ToList()[line]; string tokenText = lineText.ExtractToken(tokenData.TokenInfo); List <string> parameters = CMakeParsing.ParseForParameterNames(_lines, tokenText); if (parameters != null) { span = tokenData.TokenInfo.ToTextSpan(line); return(string.Format("{0}({1})", tokenText, string.Join(" ", parameters))); } } } span = new TextSpan(); return(null); }
public override string Goto(VSConstants.VSStd97CmdID cmd, IVsTextView textView, int line, int col, out TextSpan span) { if (_lines != null && (cmd == VSConstants.VSStd97CmdID.GotoDefn || cmd == VSConstants.VSStd97CmdID.GotoDecl)) { // Parse for any identifier that may be at the cursor. If the is one, // find the variable or function definition for that identifier and jump // to it. bool isVariable = false; string identifier = CMakeParsing.ParseForIdentifier(_lines, line, col, out isVariable); if (identifier != null) { if (isVariable) { if (CMakeParsing.ParseForVariableDefinition(_lines, identifier, out span)) { span.iEndIndex++; return(_fileName); } } else { if (CMakeParsing.ParseForFunctionDefinition(_lines, identifier, out span)) { span.iEndIndex++; return(_fileName); } } } } span = new TextSpan(); return(null); }
public override AuthoringScope ParseSource(ParseRequest req) { CMakeAuthoringScope scope = new CMakeAuthoringScope(); if (!CMakeSource.IsCMakeFile(req.FileName)) { // Don't do IntelliSense parsing for ordinary text files. return(scope); } CMakeSource source = (CMakeSource)GetSource(req.FileName); if (req.Sink.HiddenRegions) { req.Sink.ProcessHiddenRegions = true; List <TextSpan> regions = CMakeParsing.ParseForFunctionBodies( source.GetLines()); foreach (TextSpan textSpan in regions) { req.Sink.AddHiddenRegion(textSpan); } } if (req.Sink.BraceMatching) { List <CMakeParsing.SpanPair> pairs = null; switch ((CMakeToken)req.TokenInfo.Token) { case CMakeToken.OpenParen: case CMakeToken.CloseParen: pairs = CMakeParsing.ParseForParens(source.GetLines()); break; case CMakeToken.VariableStart: case CMakeToken.VariableStartEnv: case CMakeToken.VariableStartCache: case CMakeToken.VariableStartSetEnv: case CMakeToken.VariableEnd: pairs = CMakeParsing.ParseForVariableBraces(source.GetLines(), req.Line); break; case CMakeToken.GeneratorStart: case CMakeToken.GeneratorEnd: pairs = CMakeParsing.ParseForGeneratorBraces(source.GetLines(), req.Line); break; } if (pairs != null) { foreach (CMakeParsing.SpanPair pair in pairs) { req.Sink.MatchPair(pair.First, pair.Second, 0); } } } if (req.Reason == ParseReason.MemberSelect || req.Reason == ParseReason.MemberSelectAndHighlightBraces || req.Reason == ParseReason.CompleteWord) { // Set an appropriate declarations object depending on the token that // triggered member selection. CMakeToken token = (CMakeToken)req.TokenInfo.Token; if (token == CMakeToken.String) { // If the token is a string and the user has began to reference a // variable inside the string, treat the string as if it was the // appropriate type of variable start token and display member // selection for variables. string line = source.GetLine(req.Line); string tokenText = line.ExtractToken(req.TokenInfo); if (tokenText.EndsWith("${")) { token = CMakeToken.VariableStart; } else if (tokenText.EndsWith("$ENV{")) { token = CMakeToken.VariableStartEnv; } else if (tokenText.EndsWith("$CACHE{")) { token = CMakeToken.VariableStartCache; } } if (token == CMakeToken.VariableStart) { List <string> vars = CMakeParsing.ParseForVariables( source.GetLines(), req.Line); CMakeVariableDeclarations decls = new CMakeVariableDeclarations(vars, CMakeVariableType.Variable); decls.AddItems(source.GetIncludeCacheVariables(), CMakeItemDeclarations.ItemType.Variable); string functionName = CMakeParsing.ParseForCurrentFunction( source.GetLines(), req.Line); if (functionName != null) { List <string> paramNames = CMakeParsing.ParseForParameterNames( source.GetLines(), functionName); paramNames.Add("ARGN"); decls.AddItems(paramNames, CMakeItemDeclarations.ItemType.Variable); } scope.SetDeclarations(decls); } else if (token == CMakeToken.VariableStartEnv) { List <string> vars = CMakeParsing.ParseForEnvVariables( source.GetLines()); CMakeVariableDeclarations decls = new CMakeVariableDeclarations(vars, CMakeVariableType.EnvVariable); decls.AddItems(source.GetIncludeCacheEnvVariables(), CMakeItemDeclarations.ItemType.Variable); scope.SetDeclarations(decls); } else if (token == CMakeToken.VariableStartCache) { List <string> vars = CMakeParsing.ParseForCacheVariables( source.GetLines()); CMakeVariableDeclarations decls = new CMakeVariableDeclarations(vars, CMakeVariableType.CacheVariable); decls.AddItems(source.GetIncludeCacheCacheVariables(), CMakeItemDeclarations.ItemType.Variable); scope.SetDeclarations(decls); } else if (token == CMakeToken.Identifier) { CMakeParsing.TokenData tokenData; CMakeParsing.ParseForToken(source.GetLines(), req.Line, req.TokenInfo.StartIndex, out tokenData); if (!tokenData.InParens) { CMakeItemDeclarations decls = new CMakeItemDeclarations(); IEnumerable <string> commands = CMakeKeywords.GetAllCommands( CMakePackage.Instance.CMakeOptionPage.ShowDeprecated); if (!CMakePackage.Instance.CMakeOptionPage.CommandsLower) { commands = commands.Select(x => x.ToUpper()); } decls.AddItems(commands, CMakeItemDeclarations.ItemType.Command); decls.AddItems( CMakeParsing.ParseForFunctionNames(source.GetLines(), false), CMakeItemDeclarations.ItemType.Function); decls.AddItems( CMakeParsing.ParseForFunctionNames(source.GetLines(), true), CMakeItemDeclarations.ItemType.Macro); decls.AddItems(source.GetIncludeCacheFunctions(), CMakeItemDeclarations.ItemType.Function); decls.AddItems(source.GetIncludeCacheMacros(), CMakeItemDeclarations.ItemType.Macro); scope.SetDeclarations(decls); } else { Declarations decls = CMakeDeclarationsFactory.CreateDeclarations( tokenData.Command, req, source, tokenData.ParameterIndex > 0 ? tokenData.PriorParameters : null); scope.SetDeclarations(decls); } } else if (token == CMakeToken.OpenParen) { CMakeCommandId id = CMakeParsing.ParseForTriggerCommandId( source.GetLines(), req.Line, req.TokenInfo.StartIndex); Declarations decls = CMakeDeclarationsFactory.CreateDeclarations( id, req, source); scope.SetDeclarations(decls); } else if (token == CMakeToken.WhiteSpace) { CMakeParsing.TokenData tokenData; CMakeParsing.ParseForToken(source.GetLines(), req.Line, req.TokenInfo.StartIndex, out tokenData); Declarations decls = CMakeDeclarationsFactory.CreateDeclarations( tokenData.Command, req, source, tokenData.ParameterIndex > 0 ? tokenData.PriorParameters : null); scope.SetDeclarations(decls); } else if (token == CMakeToken.GeneratorStart) { scope.SetDeclarations(new CMakeGeneratorDeclarations()); } } else if (req.Reason == ParseReason.MethodTip) { CMakeParsing.ParameterInfoResult result = CMakeParsing.ParseForParameterInfo(source.GetLines(), req.Line, req.TokenInfo.EndIndex); if (result.CommandName != null && result.CommandSpan.HasValue) { if (result.SubcommandName == null) { req.Sink.StartName(result.CommandSpan.Value, result.CommandName); } else { req.Sink.StartName(result.CommandSpan.Value, result.CommandSpan + "(" + result.SubcommandName); } if (result.BeginSpan.HasValue) { req.Sink.StartParameters(result.BeginSpan.Value); } foreach (TextSpan span in result.SeparatorSpans) { req.Sink.NextParameter(span); } if (result.EndSpan.HasValue) { req.Sink.EndParameters(result.EndSpan.Value); } CMakeCommandId id = CMakeKeywords.GetCommandId(result.CommandName); if (id == CMakeCommandId.Unspecified) { // If it's a user-defined function or macro, parse to try to find // its parameters. List <string> parameters = CMakeParsing.ParseForParameterNames( source.GetLines(), result.CommandName); if (parameters == null) { parameters = source.GetParametersFromIncludeCache( result.CommandName); } if (parameters != null) { scope.SetMethods(new CMakeUserMethods(result.CommandName, parameters)); } } else { scope.SetMethods(CMakeMethods.GetCommandParameters(id, result.SubcommandName)); } } } else if (req.Reason == ParseReason.Goto) { scope.SetLines(source.GetLines()); scope.SetFileName(req.FileName); } else if (req.Reason == ParseReason.QuickInfo) { scope.SetLines(source.GetLines()); } else if (req.Reason == ParseReason.Check) { foreach (ParseForErrorMethod method in _parseForErrorMethods) { List <CMakeErrorInfo> info = method(source.GetLines()); foreach (CMakeErrorInfo item in info) { CMakeError err = item.ErrorCode; if (_errorStrings.ContainsKey(err) && (!_enabledMethods.ContainsKey(err) || _enabledMethods[err]())) { req.Sink.AddError(req.FileName, _errorStrings[err], item.Span, item.Warning ? Severity.Warning : Severity.Error); } } } if (CMakePackage.Instance.CMakeOptionPage.ParseIncludedFiles) { source.BuildIncludeCache(source.GetLines()); source.UpdateIncludeCache(); source.PruneIncludeCache(); } else { source.ClearIncludeCache(); } } return(scope); }
private void DoContextHelp() { // Open CMake help for the command, standard variables, or standard module // at the caret. int line; int col; CMakeParsing.TokenData tokenData; if (TextView != null && TextView.GetCaretPos(out line, out col) == VSConstants.S_OK && CMakeParsing.ParseForToken(Source.GetLines(), line, col, out tokenData)) { string text = Source.GetText(tokenData.TokenInfo.ToTextSpan(line)); string[] htmlFiles = null; switch ((CMakeToken)tokenData.TokenInfo.Token) { case CMakeToken.Keyword: if (!tokenData.InParens) { if (CMakeKeywords.IsDeprecated(CMakeKeywords.GetCommandId(text))) { htmlFiles = new string[] { "html\\command\\" + text.ToLower() + ".html", "cmake-compatcommands.html#command:" + text.ToLower() }; } else { htmlFiles = new string[] { "html\\command\\" + text.ToLower() + ".html", "cmake-commands.html#command:" + text.ToLower() }; } } break; case CMakeToken.Variable: if (CMakeVariableDeclarations.IsStandardVariable(text, CMakeVariableType.Variable)) { htmlFiles = new string[] { "html\\variable\\" + text + ".html", "cmake-variables.html#variable:" + text }; } break; case CMakeToken.Identifier: if (tokenData.Command == CMakeCommandId.Include) { htmlFiles = new string[] { "html\\module\\" + text + ".html", "cmake-modules.html#module:" + text }; } else if (tokenData.Command == CMakeCommandId.FindPackage) { htmlFiles = new string[] { "html\\module\\Find" + text + ".html", "cmake-modules.html#module:Find" + text }; } break; } if (htmlFiles != null) { CMakePackage.Instance.OpenCMakeHelpPage(htmlFiles); } } }
private string GetCurrentTokenFileName(out string extraSearchPath) { // Obtain the name of the file referenced by the current token if there is // one or null otherwise. int line; int col; extraSearchPath = null; if (TextView == null || TextView.GetCaretPos(out line, out col) != VSConstants.S_OK) { return(null); } TokenInfo tokenInfo = Source.GetTokenInfo(line, col); if (tokenInfo == null || (tokenInfo.Token != (int)CMakeToken.FileName && tokenInfo.Token != (int)CMakeToken.Identifier)) { return(null); } string text = Source.GetText(tokenInfo.ToTextSpan(line)); if (string.IsNullOrEmpty(text)) { return(null); } // If the string specifies a file name with an extension, just return it // regardless or where it is found. if (tokenInfo.Token == (int)CMakeToken.FileName && text.IndexOf('.') >= 0) { return(text); } // An identifier or path may reference a file if appears as a parameter to // one of certain commands, such as INCLUDE or FIND_PACKAGE. Parse to find // the command to which the token is a parameter, if any, and handle it // accordingly. CMakeParsing.TokenData tokenData; if (!CMakeParsing.ParseForToken(Source.GetLines(), line, col, out tokenData) || !tokenData.InParens) { return(null); } switch (tokenData.Command) { case CMakeCommandId.Include: if (tokenData.ParameterIndex == 0) { extraSearchPath = CMakePath.FindCMakeModules(); return(string.Format("{0}.cmake", Source.GetText(tokenInfo.ToTextSpan(line)))); } break; case CMakeCommandId.FindPackage: if (tokenData.ParameterIndex == 0) { extraSearchPath = CMakePath.FindCMakeModules(); return(string.Format("Find{0}.cmake", Source.GetText(tokenInfo.ToTextSpan(line)))); } break; case CMakeCommandId.AddSubdirectory: if (tokenData.ParameterIndex == 0) { return(Path.Combine(Source.GetText(tokenInfo.ToTextSpan(line)), "CMakeLists.txt")); } break; } return(null); }