static CMakeDeclarationsFactory() { // Display subcommands for all commands that have them. IEnumerable <CMakeCommandId> triggers = CMakeSubcommandMethods.GetMemberSelectionTriggers(); foreach (CMakeCommandId id in triggers) { _methods[id] = CreateSubcommandDeclarations; } }
/// <summary> /// Get a methods object containing the parameters for a given CMake command. /// </summary> /// <param name="id">The identifier of a CMake command.</param> /// <param name="subcommand">The name of a subcommand or null if none.</param> /// <returns> /// A methods object or null if there is no parameter information. /// </returns> public static Methods GetCommandParameters(CMakeCommandId id, string subcommand) { if (subcommand != null) { return(CMakeSubcommandMethods.GetSubcommandParameters(id, subcommand)); } if (!_parameters.ContainsKey(id)) { return(null); } return(new CMakeMethods(id)); }
private static CMakeItemDeclarations CreateSubcommandDeclarations( CMakeCommandId id, ParseRequest req, Source source, List <string> priorParameters) { IEnumerable <string> subcommands = CMakeSubcommandMethods.GetSubcommands(id); if (subcommands == null) { return(null); } CMakeItemDeclarations decls = new CMakeItemDeclarations(); decls.AddItems(subcommands, CMakeItemDeclarations.ItemType.Command); return(decls); }
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 void TestQuickInfoTips() { // Test ordinary commands. Assert.AreEqual("if(expression)", CMakeMethods.GetCommandQuickInfoTip(CMakeCommandId.If)); Assert.AreEqual("set(variable value)", CMakeMethods.GetCommandQuickInfoTip(CMakeCommandId.Set)); Assert.IsNull(CMakeMethods.GetCommandQuickInfoTip( CMakeCommandId.AddCustomCommand)); // Test subcommands. Assert.AreEqual("cmake_policy(PUSH)", CMakeSubcommandMethods.GetSubcommandQuickInfoTip( CMakeCommandId.CMakePolicy, "PUSH")); Assert.AreEqual("export(PACKAGE name)", CMakeSubcommandMethods.GetSubcommandQuickInfoTip( CMakeCommandId.Export, "PACKAGE")); Assert.AreEqual("file(READ filename variable)", CMakeSubcommandMethods.GetSubcommandQuickInfoTip( CMakeCommandId.File, "READ")); Assert.IsNull(CMakeSubcommandMethods.GetSubcommandQuickInfoTip( CMakeCommandId.Install, "CODE")); }
public bool ScanTokenAndProvideInfoAboutIt(TokenInfo tokenInfo, ref int state) { if (_textFile) { // Don't perform syntax highlighting if the file is an ordinary text // file. return(false); } if (GetStringFlag(state) && _offset < _source.Length) { // If the line begins inside a string token, begin by scanning the rest // of the string. ScanString(tokenInfo, ref state, false); _scannedNonWhitespace = true; _lastWhitespace = false; return(true); } bool bracketComment = GetBracketCommentFlag(state); bool bracketArgument = GetBracketArgumentFlag(state); if ((bracketComment || bracketArgument) && _offset < _source.Length) { // If the line begins inside a bracket comment token, begin by scanning // the rest of the bracket comment. ScanBracketCommentOrArgument(tokenInfo, bracketComment, ref state); _lastWhitespace = true; return(true); } bool originalScannedNonWhitespace = _scannedNonWhitespace; bool originalLastWhitespace = _lastWhitespace; int originalVariableDepth = GetVariableDepth(state); SetVariableDepth(ref state, 0); bool noSeparator = GetNoSeparatorFlag(state); SetNoSeparatorFlag(ref state, false); tokenInfo.Trigger = TokenTriggers.None; _lastWhitespace = false; while (_offset < _source.Length) { if (char.IsWhiteSpace(_source[_offset])) { // Scan a whitespace token. tokenInfo.StartIndex = _offset; while (_offset < _source.Length && char.IsWhiteSpace(_source[_offset])) { _offset++; } tokenInfo.EndIndex = _offset - 1; tokenInfo.Color = TokenColor.Text; tokenInfo.Token = (int)CMakeToken.WhiteSpace; CMakeCommandId id = GetLastCommand(state); if (InsideParens(state)) { if (!noSeparator) { if (CMakeSubcommandMethods.HasSubcommands(id)) { // The first whitespace token after a subcommand marks // the beginning of the parameters. The remaining // whitespace parameters separate consecutive parameters. if (GetSubcommandParmsFlag(state)) { if (GetNeedSubcommandFlag(state)) { SetNeedSubcommandFlag(ref state, false); tokenInfo.Trigger = TokenTriggers.ParameterStart; } else if (!originalLastWhitespace) { tokenInfo.Trigger = TokenTriggers.ParameterNext; } } } else if (id == CMakeCommandId.Unspecified || GetSeparatorCount(state) > 0) { if (!originalLastWhitespace) { SetSeparatorCount(ref state, GetSeparatorCount(state) - 1); tokenInfo.Trigger = TokenTriggers.ParameterNext; } } } if (CMakeKeywords.TriggersMemberSelection(id) || CMakeKeywords.TriggersMemberSelectionOnWhiteSpace(id)) { tokenInfo.Trigger |= TokenTriggers.MemberSelect; } } SetNoSeparatorFlag(ref state, true); _lastWhitespace = true; return(true); } else if (_source[_offset] == '#') { // Check if it's a bracket comment. If so, handle it specially. if (_offset + 1 < _source.Length && _source[_offset + 1] == '[') { int i = _offset + 2; while (i < _source.Length && _source[i] == '=') { i++; } if (i < _source.Length && _source[i] == '[') { SetBracketCommentFlag(ref state, true); ScanBracketCommentOrArgument(tokenInfo, true, ref state); _lastWhitespace = true; return(true); } } // Scan a comment token. tokenInfo.StartIndex = _offset; int endPos = _source.IndexOf('\n', _offset); if (endPos > _offset) { while (endPos < _source.Length - 1 && (_source[endPos + 1] == '\r' || _source[endPos + 1] == '\n')) { endPos++; } } else { endPos = _source.Length - 1; } tokenInfo.EndIndex = endPos; tokenInfo.Color = TokenColor.Comment; tokenInfo.Token = (int)CMakeToken.Comment; _offset = endPos + 1; SetNoSeparatorFlag(ref state, noSeparator); return(true); } // If we haven't returned by this point, the token is something other // than whitespace. Therefore, set the flag indicating that a // non-whitespace token has been scanned on the current line so that // any additional identifier characters at the end won't trigger member // selection. If you add any additional token, ensure that you handle // them after this point. _scannedNonWhitespace = true; if (_source[_offset] == '"') { // Scan a string token. ScanString(tokenInfo, ref state, true); return(true); } else if (_source[_offset] == '(') { // Scan an opening parenthesis. if (!InsideParens(state)) { CMakeCommandId id = GetLastCommand(state); if (CMakeKeywords.TriggersMemberSelection(id)) { tokenInfo.Trigger |= TokenTriggers.MemberSelect; SetNeedSubcommandFlag(ref state, true); SetNoSeparatorFlag(ref state, true); } else { tokenInfo.Trigger |= TokenTriggers.ParameterStart; SetNoSeparatorFlag(ref state, true); } } IncParenDepth(ref state); tokenInfo.StartIndex = _offset; tokenInfo.EndIndex = _offset; tokenInfo.Color = TokenColor.Text; tokenInfo.Token = (int)CMakeToken.OpenParen; tokenInfo.Trigger |= TokenTriggers.MatchBraces; _offset++; return(true); } else if (_source[_offset] == ')') { // Scan a closing parenthesis. DecParenDepth(ref state); if (GetParenDepth(state) == 0) { SetLastCommand(ref state, CMakeCommandId.Unspecified); SetSeparatorCount(ref state, 0); tokenInfo.Trigger = TokenTriggers.ParameterEnd; } tokenInfo.StartIndex = _offset; tokenInfo.EndIndex = _offset; tokenInfo.Color = TokenColor.Text; tokenInfo.Token = (int)CMakeToken.CloseParen; tokenInfo.Trigger |= TokenTriggers.MatchBraces; _offset++; return(true); } else if (char.IsLetter(_source[_offset]) || _source[_offset] == '_' || (originalVariableDepth == 0 && _source[_offset] == '\\')) { // Scan a keyword, identifier, or file name token. bool isFileName = false; bool isNumeric = false; tokenInfo.StartIndex = _offset; if (_source[_offset] == '\\' && _offset != _source.Length - 1) { // If the identifier starts with an escape sequence, skip over it. _offset++; isFileName = true; } while (_offset < _source.Length - 1) { char ch = _source[_offset + 1]; if (ch == '-') { // Variable names may contain hyphens but function names // can't. There classify an identifier with a hyphen in it // as a numeric identifier. isNumeric = true; } else if (originalVariableDepth == 0 && ScanFileNameChar()) { isFileName = true; } else if (!char.IsLetterOrDigit(ch) && ch != '_') { break; } _offset++; } tokenInfo.EndIndex = _offset; _offset++; CMakeCommandId id = GetLastCommand(state); string substr = _source.ExtractToken(tokenInfo); if (originalVariableDepth != 0) { // If we're inside curly braces following a dollar sign, treat // the identifier as a variable. tokenInfo.Color = TokenColor.Identifier; tokenInfo.Token = (int)CMakeToken.Variable; SetVariableDepth(ref state, originalVariableDepth); } else if ((id == CMakeCommandId.Set || id == CMakeCommandId.Unset) && substr.StartsWith("ENV{")) { // Inside a SET or UNSET command, ENV{ indicates an environment // variable. This token is case-sensitive. SetVariableDepth(ref state, originalVariableDepth + 1); tokenInfo.EndIndex = tokenInfo.StartIndex + 3; tokenInfo.Color = TokenColor.Identifier; tokenInfo.Token = (int)CMakeToken.VariableStartSetEnv; _offset = tokenInfo.EndIndex + 1; } else if (isNumeric) { tokenInfo.Color = TokenColor.Identifier; tokenInfo.Token = (int)CMakeToken.NumericIdentifier; } else if (isFileName) { // If we found characters that aren't valid in an identifier, // treat the token as a file name. tokenInfo.Color = TokenColor.Identifier; tokenInfo.Token = (int)CMakeToken.FileName; } else { // Check whether the string is a keyword or not. string tokenText = _source.ExtractToken(tokenInfo); bool isKeyword = false; if (!InsideParens(state)) { isKeyword = CMakeKeywords.IsCommand(tokenText); id = CMakeKeywords.GetCommandId(tokenText); SetLastCommand(ref state, id); SetSeparatorCount(ref state, CMakeMethods.GetParameterCount(id)); int count = GetSeparatorCount(state); if (count > 0) { SetSeparatorCount(ref state, count - 1); } } else { isKeyword = CMakeKeywords.IsKeyword(id, tokenText); if (isKeyword) { SetSubcommandParmsFlag(ref state, CMakeSubcommandMethods.HasSubcommandParameters( id, tokenText)); } } tokenInfo.Color = isKeyword ? TokenColor.Keyword : TokenColor.Identifier; tokenInfo.Token = isKeyword ? (int)CMakeToken.Keyword : (int)CMakeToken.Identifier; } if (tokenInfo.StartIndex == tokenInfo.EndIndex) { if (!InsideParens(state) && !originalScannedNonWhitespace) { // Trigger member selection if we're not inside parentheses. tokenInfo.Trigger |= TokenTriggers.MemberSelect; } else if (!originalScannedNonWhitespace || originalLastWhitespace) { // Always trigger member selection in response to certain // commands. if (CMakeKeywords.TriggersMemberSelection(id) || CMakeKeywords.TriggersMemberSelectionOnWhiteSpace(id)) { tokenInfo.Trigger |= TokenTriggers.MemberSelect; } } } return(true); } else if (char.IsDigit(_source[_offset]) || _source[_offset] == '-') { // Variable names can start with numbers or hyphens in CMake, but // function names can't. We'll call these tokens "numeric // identifiers" here and treat them accordingly when parsing. tokenInfo.StartIndex = _offset; bool isFileName = false; while (_offset < _source.Length - 1) { char ch = _source[_offset + 1]; if (originalVariableDepth == 0 && ScanFileNameChar()) { isFileName = true; } else if (!char.IsLetterOrDigit(ch) && ch != '_') { break; } _offset++; } tokenInfo.EndIndex = _offset; _offset++; tokenInfo.Color = TokenColor.Identifier; if (originalVariableDepth != 0) { tokenInfo.Token = (int)CMakeToken.Variable; SetVariableDepth(ref state, originalVariableDepth); } else if (isFileName) { tokenInfo.Token = (int)CMakeToken.FileName; } else { tokenInfo.Token = (int)CMakeToken.NumericIdentifier; } return(true); } else if (_source[_offset] == '$') { // Scan a variable start token. CMakeToken varToken = _varTokenMap.FirstOrDefault( x => _source.Substring(_offset).StartsWith(x.Value)).Key; tokenInfo.StartIndex = _offset; _offset++; if (varToken != CMakeToken.Unspecified) { if (varToken != CMakeToken.GeneratorStart) { SetVariableDepth(ref state, originalVariableDepth + 1); } tokenInfo.Token = (int)varToken; tokenInfo.Trigger = TokenTriggers.MemberSelect | TokenTriggers.MatchBraces; _offset += _varTokenMap[varToken].Length - 1; } tokenInfo.EndIndex = _offset - 1; tokenInfo.Color = TokenColor.Identifier; return(true); } else if (_source[_offset] == '}') { // Scan a variable end token. tokenInfo.StartIndex = _offset; tokenInfo.EndIndex = _offset; tokenInfo.Color = TokenColor.Identifier; tokenInfo.Token = (int)CMakeToken.VariableEnd; tokenInfo.Trigger = TokenTriggers.MatchBraces; SetVariableDepth(ref state, originalVariableDepth > 0 ? originalVariableDepth - 1 : 0); _offset++; return(true); } else if (_source[_offset] == '>') { // Scan a generator expression end token. tokenInfo.StartIndex = _offset; tokenInfo.EndIndex = _offset; tokenInfo.Color = TokenColor.Identifier; tokenInfo.Token = (int)CMakeToken.GeneratorEnd; tokenInfo.Trigger = TokenTriggers.MatchBraces; SetVariableDepth(ref state, originalVariableDepth > 0 ? originalVariableDepth - 1 : 0); _offset++; return(true); } else if (_source[_offset] == ':') { // Scan a colon. tokenInfo.StartIndex = _offset; tokenInfo.EndIndex = _offset; tokenInfo.Color = TokenColor.Identifier; tokenInfo.Token = (int)CMakeToken.Colon; _offset++; return(true); } else if (_source[_offset] == '[') { // Scan a bracket argument, if it is one. int i = _offset + 1; while (i < _source.Length && _source[i] == '=') { i++; } if (i < _source.Length && _source[i] == '[') { SetBracketArgumentFlag(ref state, true); ScanBracketCommentOrArgument(tokenInfo, false, ref state); _lastWhitespace = false; return(true); } } _offset++; } return(false); }