private static void ToClassificationInfo(Token token, int start, int length, ICollection<ClassificationInfo> classificationInfo) { if (token != null && length > 0) { classificationInfo.Add(new ClassificationInfo(start, length, GetClassificationType(token))); } }
private static List <System.Management.Automation.Language.Token> GetCommentBlock(System.Management.Automation.Language.Token[] tokens, ref int startIndex) { List <System.Management.Automation.Language.Token> list = new List <System.Management.Automation.Language.Token>(); int num = 0x7fffffff; for (int i = startIndex; i < tokens.Length; i++) { System.Management.Automation.Language.Token item = tokens[i]; if (item.Extent.StartLineNumber > num) { startIndex = i; return(list); } if (item.Kind == TokenKind.Comment) { list.Add(item); num = item.Extent.EndLineNumber + 1; } else if (item.Kind != TokenKind.NewLine) { startIndex = i; return(list); } } return(list); }
internal ErrorStatementAst(IScriptExtent extent, Token kind, IEnumerable<KeyValuePair<string, Tuple<Token, Ast>>> flags, IEnumerable<Ast> conditions, IEnumerable<Ast> bodies) : base(extent) { if (kind == null) { throw PSTraceSource.NewArgumentNullException("kind"); } this.Kind = kind; if ((flags != null) && flags.Any<KeyValuePair<string, Tuple<Token, Ast>>>()) { this.Flags = new Dictionary<string, Tuple<Token, Ast>>(StringComparer.OrdinalIgnoreCase); foreach (KeyValuePair<string, Tuple<Token, Ast>> pair in flags) { if (!this.Flags.ContainsKey(pair.Key)) { this.Flags.Add(pair.Key, pair.Value); if (pair.Value.Item2 != null) { base.SetParent(pair.Value.Item2); } } } } if ((conditions != null) && conditions.Any<Ast>()) { this.Conditions = new ReadOnlyCollection<Ast>(conditions.ToArray<Ast>()); base.SetParents(conditions); } if ((bodies != null) && bodies.Any<Ast>()) { this.Bodies = new ReadOnlyCollection<Ast>(bodies.ToArray<Ast>()); base.SetParents(bodies); } }
internal CompletionAnalysis(Ast ast, Token[] tokens, IScriptPosition cursorPosition, Hashtable options) { _ast = ast; _tokens = tokens; _cursorPosition = cursorPosition; _options = options; }
private static List<string> GetSingleAstRequiredModules(Ast ast, Token[] tokens) { List<string> modules = new List<string>(); List<string> resources = new List<string>(); var imports = tokens.Where(token => String.Compare(token.Text, "Import-DscResource", StringComparison.OrdinalIgnoreCase) == 0); // // Create a function with the same name as Import-DscResource keyword and use powershell // argument function binding to emulate Import-DscResource argument binding. // InitialSessionState initialSessionState = InitialSessionState.Create(); SessionStateFunctionEntry importDscResourcefunctionEntry = new SessionStateFunctionEntry( "Import-DscResource", @"param($Name, $ModuleName) if ($ModuleName) { foreach ($m in $ModuleName) { $global:modules.Add($m) } } else { foreach ($n in $Name) { $global:resources.Add($n) } } "); initialSessionState.Commands.Add(importDscResourcefunctionEntry); initialSessionState.LanguageMode = PSLanguageMode.RestrictedLanguage; var moduleVarEntry = new SessionStateVariableEntry("modules", modules, ""); var resourcesVarEntry = new SessionStateVariableEntry("resources", resources, ""); initialSessionState.Variables.Add(moduleVarEntry); initialSessionState.Variables.Add(resourcesVarEntry); using (System.Management.Automation.PowerShell powerShell = System.Management.Automation.PowerShell.Create(initialSessionState)) { foreach (var import in imports) { int startOffset = import.Extent.StartOffset; var asts = ast.FindAll(a => IsCandidateForImportDscResourceAst(a, startOffset), true); int longestLen = -1; Ast longestCandidate = null; foreach (var candidatAst in asts) { int curLen = candidatAst.Extent.EndOffset - candidatAst.Extent.StartOffset; if (curLen > longestLen) { longestCandidate = candidatAst; longestLen = curLen; } } // longestCandidate should contain AST for import-dscresource, like "Import-DSCResource -Module x -Name y". if (longestCandidate != null) { string importText = longestCandidate.Extent.Text; // We invoke-command "importText" here. Script injection is prevented: // We checked that file represents a valid AST without errors. powerShell.AddScript(importText); powerShell.Invoke(); powerShell.Commands.Clear(); } } } modules.AddRange(resources.Select(GetModuleNameForDscResource)); return modules; }
private static List <System.Management.Automation.Language.Token> GetPrecedingCommentBlock(System.Management.Automation.Language.Token[] tokens, int tokenIndex, int proximity) { List <System.Management.Automation.Language.Token> list = new List <System.Management.Automation.Language.Token>(); int num = tokens[tokenIndex].Extent.StartLineNumber - proximity; for (int i = tokenIndex - 1; i >= 0; i--) { System.Management.Automation.Language.Token item = tokens[i]; if (item.Extent.EndLineNumber < num) { break; } if (item.Kind == TokenKind.Comment) { list.Add(item); num = item.Extent.StartLineNumber - 1; } else if (item.Kind != TokenKind.NewLine) { break; } } list.Reverse(); return(list); }
/// <summary> /// Retrieve completion suggestions /// </summary> /// <param name="completionWord">Word to complete</param> /// <param name="content">Script that we're working with</param> /// <param name="lineContent">Content of the current line</param> /// <param name="line">Line object from AvaloneEdit</param> /// <param name="runbookToken">Token containing the name of the runbook (if not runbook, null)</param> /// <param name="position">Caret offset</param> /// <param name="triggerChar">Not used</param> /// <param name="triggerTag">Counter</param> public void GetCompletionData(string completionWord, string content, string lineContent, DocumentLine line, Token runbookToken, int position, char? triggerChar, long triggerTag) { if (_requestTrigger != 0 && triggerTag <= _requestTrigger) return; DismissGetCompletionResults(); ProcessCompletion(content, triggerChar, completionWord, runbookToken, position, triggerTag); }
/// <summary> /// Get the state of the buffer - the ast, tokens, errors, and position of the cursor /// </summary> public static void GetBufferState(out Ast ast, out Token[] tokens, out ParseError[] parseErrors, out int cursor) { _singleton.ParseInput(); ast = _singleton._ast; tokens = _singleton._tokens; parseErrors = _singleton._parseErrors; cursor = _singleton._current; }
internal ExpandableStringExpressionAst(Token token, string value, string formatString, IEnumerable<ExpressionAst> nestedExpressions) : base(token.Extent) { this.FormatExpression = formatString; this.Value = value; this.StringConstantType = StringConstantExpressionAst.MapTokenKindToStringContantKind(token); this.NestedExpressions = new ReadOnlyCollection<ExpressionAst>(nestedExpressions.ToArray<ExpressionAst>()); base.SetParents((IEnumerable<Ast>) this.NestedExpressions); }
/// <summary> /// Gets called when the window looses focus. If the inspector window is open, we want to close it at this point. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void OnLostFocus(object sender, RoutedEventArgs e) { if (_objectInspector == null) return; _objectInspector?.Close(); _currentToken = null; }
private void AddSpanForToken(Token token, int spanStart, List<ClassificationInfo> classificationInfo) { var stringExpandableToken = token as StringExpandableToken; if (stringExpandableToken != null && stringExpandableToken.NestedTokens != null) { AddSpansForStringToken(stringExpandableToken, spanStart, classificationInfo); } ToClassificationInfo(token, token.Extent.StartOffset + spanStart, token.Extent.EndOffset - token.Extent.StartOffset, classificationInfo); }
/// <summary> /// Parse input from the specified file. /// </summary> /// <param name="fileName">The name of the file to parse.</param> /// <param name="tokens">Returns the tokens from parsing the script.</param> /// <param name="errors">Returns errors, if any, discovered while parsing the script.</param> /// <returns>The <see cref="ScriptBlockAst"/> that represents the input script file.</returns> public static ScriptBlockAst ParseFile(string fileName, out Token[] tokens, out ParseError[] errors) { const string scriptSchemaExtension = ".schema.psm1"; var parseDscResource = false; // If the file has the 'schema.psm1' extension, then it is a 'DSC module file' however we don't actually load the // module at parse time so we can't use the normal mechanisms to bind the module name for configuration commands. // As an alternative, we extract the base name of the module file and use that as the module name for any keywords exported by this file. var parser = new Parser(); if (!string.IsNullOrEmpty(fileName) && fileName.Length > scriptSchemaExtension.Length && fileName.EndsWith(scriptSchemaExtension, StringComparison.OrdinalIgnoreCase)) { parser._keywordModuleName = Path.GetFileName(fileName.Substring(0, fileName.Length - scriptSchemaExtension.Length)); parseDscResource = true; } string scriptContents; try { var esi = new ExternalScriptInfo(fileName, fileName); scriptContents = esi.ScriptContents; } catch (Exception e) { var emptyExtent = new EmptyScriptExtent(); var errorMsg = string.Format(CultureInfo.CurrentCulture, ParserStrings.FileReadError, e.Message); errors = new[] { new ParseError(emptyExtent, "FileReadError", errorMsg) }; tokens = Utils.EmptyArray<Token>(); return new ScriptBlockAst(emptyExtent, null, new StatementBlockAst(emptyExtent, null, null), false); } var tokenList = new List<Token>(); ScriptBlockAst result; try { if (!parseDscResource) { DynamicKeyword.Push(); } result = parser.Parse(fileName, scriptContents, tokenList, out errors, ParseMode.Default); } catch (Exception e) { throw new ParseException(ParserStrings.UnrecoverableParserError, e); } finally { if (!parseDscResource) { DynamicKeyword.Pop(); } } tokens = tokenList.ToArray(); return result; }
internal ErrorStatementAst(IScriptExtent extent, Token kind, IEnumerable<Ast> nestedAsts = null) : base(extent) { if (kind == null) { throw PSTraceSource.NewArgumentNullException("kind"); } this.Kind = kind; if ((nestedAsts != null) && nestedAsts.Any<Ast>()) { this.NestedAst = new ReadOnlyCollection<Ast>(nestedAsts.ToArray<Ast>()); base.SetParents(this.NestedAst); } }
internal PSToken(Token token) { Type = GetPSTokenType(token); _extent = token.Extent; if (token is StringToken) { _content = ((StringToken)token).Value; } else if (token is VariableToken) { _content = ((VariableToken)token).VariablePath.ToString(); } }
public BlockStatementAst(IScriptExtent extent, Token kind, StatementBlockAst body) : base(extent) { if ((kind == null) || (body == null)) { throw PSTraceSource.NewArgumentNullException((kind == null) ? "kind" : "body"); } if ((kind.Kind != TokenKind.Sequence) && (kind.Kind != TokenKind.Parallel)) { throw PSTraceSource.NewArgumentException("kind"); } this.Kind = kind; this.Body = body; base.SetParent(body); }
/// <summary> /// Get the abstract syntax tree, tokens and the cursor position. /// </summary> /// <param name="script">The active script.</param> /// <param name="caretPosition">The caret position.</param> /// <param name="ast">The AST to get.</param> /// <param name="tokens">The tokens to get.</param> /// <param name="cursorPosition">The cursor position to get.</param> public static void GetCommandCompletionParameters(string script, int caretPosition, out Ast ast, out Token[] tokens, out IScriptPosition cursorPosition) { ParseError[] array; ast = Tokenize(script, out tokens, out array); if (ast != null) { //HACK: Clone with a new offset using private method... var type = ast.Extent.StartScriptPosition.GetType(); var method = type.GetMethod("CloneWithNewOffset", BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { typeof(int) }, null); cursorPosition = (IScriptPosition)method.Invoke(ast.Extent.StartScriptPosition, new object[] { caretPosition }); return; } cursorPosition = null; }
/// <summary> /// Map a V3 token to a V2 PSTokenType /// </summary> /// <param name="token">The V3 token</param> /// <returns>The V2 PSTokenType</returns> public static PSTokenType GetPSTokenType(Token token) { if ((token.TokenFlags & TokenFlags.CommandName) != 0) { return PSTokenType.Command; } if ((token.TokenFlags & TokenFlags.MemberName) != 0) { return PSTokenType.Member; } if ((token.TokenFlags & TokenFlags.AttributeName) != 0) { return PSTokenType.Attribute; } if ((token.TokenFlags & TokenFlags.TypeName) != 0) { return PSTokenType.Type; } return s_tokenKindMapping[(int)token.Kind]; }
internal static System.Management.Automation.Language.StringConstantType MapTokenKindToStringContantKind(Token token) { switch (token.Kind) { case TokenKind.Generic: return System.Management.Automation.Language.StringConstantType.BareWord; case TokenKind.StringLiteral: return System.Management.Automation.Language.StringConstantType.SingleQuoted; case TokenKind.StringExpandable: return System.Management.Automation.Language.StringConstantType.DoubleQuoted; case TokenKind.HereStringLiteral: return System.Management.Automation.Language.StringConstantType.SingleQuotedHereString; case TokenKind.HereStringExpandable: return System.Management.Automation.Language.StringConstantType.DoubleQuotedHereString; } throw PSTraceSource.NewInvalidOperationException(); }
/// <summary> /// Gets completions for the symbol found in the Ast at /// the given file offset. /// </summary> /// <param name="scriptAst"> /// The Ast which will be traversed to find a completable symbol. /// </param> /// <param name="currentTokens"> /// The array of tokens corresponding to the scriptAst parameter. /// </param> /// <param name="fileOffset"> /// The 1-based file offset at which a symbol will be located. /// </param> /// <param name="runspace"> /// The Runspace to use for gathering completions. /// </param> /// <returns> /// A CommandCompletion instance that contains completions for the /// symbol at the given offset. /// </returns> static public CommandCompletion GetCompletions( Ast scriptAst, Token[] currentTokens, int fileOffset, Runspace runspace) { var type = scriptAst.Extent.StartScriptPosition.GetType(); var method = type.GetMethod( "CloneWithNewOffset", BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { typeof(int) }, null); IScriptPosition cursorPosition = (IScriptPosition)method.Invoke( scriptAst.Extent.StartScriptPosition, new object[] { fileOffset }); CommandCompletion commandCompletion = null; if (runspace.RunspaceAvailability == RunspaceAvailability.Available) { using (System.Management.Automation.PowerShell powerShell = System.Management.Automation.PowerShell.Create()) { powerShell.Runspace = runspace; commandCompletion = CommandCompletion.CompleteInput( scriptAst, currentTokens, cursorPosition, null, powerShell); } } return commandCompletion; }
private static bool CompleteAgainstStatementFlags(Ast scriptAst, Ast lastAst, Token token, out TokenKind kind) { Func<Ast, bool> predicate = null; kind = TokenKind.Unknown; ErrorStatementAst ast = lastAst as ErrorStatementAst; if (((ast != null) && (ast.Kind != null)) && (ast.Kind.Kind == TokenKind.Switch)) { kind = TokenKind.Switch; return true; } ScriptBlockAst ast2 = scriptAst as ScriptBlockAst; if (((token != null) && (token.Kind == TokenKind.Minus)) && (ast2 != null)) { Tuple<Token, Ast> tuple; if (predicate == null) { predicate = a => IsCursorBeforeExtent(token.Extent.StartScriptPosition, a.Extent); } Ast parent = AstSearcher.FindAll(ast2, predicate, true).LastOrDefault<Ast>(); ast = null; while (parent != null) { ast = parent as ErrorStatementAst; if (ast != null) { break; } parent = parent.Parent; } if ((((ast != null) && (ast.Kind != null)) && ((ast.Kind.Kind == TokenKind.Switch) && (ast.Flags != null))) && (ast.Flags.TryGetValue("--%", out tuple) && IsTokenTheSame(tuple.Item1, token))) { kind = TokenKind.Switch; return true; } } return false; }
private static bool CompleteAgainstSwitchFile(Ast lastAst, Token tokenBeforeCursor) { Tuple<Token, Ast> tuple; ErrorStatementAst ast = lastAst as ErrorStatementAst; if ((((ast != null) && (ast.Flags != null)) && ((ast.Kind != null) && (tokenBeforeCursor != null))) && (ast.Kind.Kind.Equals(TokenKind.Switch) && ast.Flags.TryGetValue("file", out tuple))) { return (tuple.Item1.Extent.EndOffset == tokenBeforeCursor.Extent.EndOffset); } if (!(lastAst.Parent is CommandExpressionAst)) { return false; } PipelineAst parent = lastAst.Parent.Parent as PipelineAst; if (parent == null) { return false; } ast = parent.Parent as ErrorStatementAst; if (((ast == null) || (ast.Kind == null)) || (ast.Flags == null)) { return false; } return ((ast.Kind.Kind.Equals(TokenKind.Switch) && ast.Flags.TryGetValue("file", out tuple)) && (tuple.Item2 == parent)); }
public static IEnumerable<DiagnosticRecord> Analyze(ScriptBlockAst scriptBlock, Token[] tokens) { return ScriptAnalyzer.Instance.AnalyzeSyntaxTree(scriptBlock, tokens, string.Empty); }
/// <summary> /// Tokonize the script and get the needed data. /// </summary> /// <param name="script">The active script.</param> /// <param name="tokens">The tokens to get.</param> /// <param name="errors">The parse errors to get.</param> /// <returns></returns> public static Ast Tokenize(string script, out Token[] tokens, out ParseError[] errors) { Ast result; try { Ast ast = System.Management.Automation.Language.Parser.ParseInput(script, out tokens, out errors); result = ast; } catch (RuntimeException ex) { var parseError = new ParseError(null, ex.ErrorRecord.FullyQualifiedErrorId, ex.Message); errors = new[] { parseError }; tokens = new Token[0]; result = null; } return result; }
private void ReallyRender() { var text = ParseInput(); int statusLineCount = GetStatusLineCount(); int j = _initialX + (_bufferWidth * Options.ExtraPromptLineCount); var backgroundColor = _initialBackgroundColor; var foregroundColor = _initialForegroundColor; bool afterLastToken = false; int totalBytes = j; int bufferWidth = _console.BufferWidth; var tokenStack = new Stack<SavedTokenState>(); tokenStack.Push(new SavedTokenState { Tokens = _tokens, Index = 0, BackgroundColor = _initialBackgroundColor, ForegroundColor = _initialForegroundColor }); int bufferLineCount; try { _console.StartRender(); bufferLineCount = ConvertOffsetToCoordinates(text.Length).Y - _initialY + 1 + statusLineCount; if (_consoleBuffer.Length != bufferLineCount * bufferWidth) { var newBuffer = new CHAR_INFO[bufferLineCount * bufferWidth]; Array.Copy(_consoleBuffer, newBuffer, _initialX + (Options.ExtraPromptLineCount * _bufferWidth)); if (_consoleBuffer.Length > bufferLineCount * bufferWidth) { int consoleBufferOffset = ConvertOffsetToConsoleBufferOffset(text.Length, _initialX + (Options.ExtraPromptLineCount * _bufferWidth)); // Need to erase the extra lines that we won't draw again for (int i = consoleBufferOffset; i < _consoleBuffer.Length; i++) { _consoleBuffer[i] = _space; } _console.WriteBufferLines(_consoleBuffer, ref _initialY); } _consoleBuffer = newBuffer; } for (int i = 0; i < text.Length; i++) { totalBytes = totalBytes % bufferWidth; if (!afterLastToken) { // Figure out the color of the character - if it's in a token, // use the tokens color otherwise use the initial color. var state = tokenStack.Peek(); var token = state.Tokens[state.Index]; if (i == token.Extent.EndOffset) { if (token == state.Tokens[state.Tokens.Length - 1]) { tokenStack.Pop(); if (tokenStack.Count == 0) { afterLastToken = true; token = null; foregroundColor = _initialForegroundColor; backgroundColor = _initialBackgroundColor; } else { state = tokenStack.Peek(); } } if (!afterLastToken) { foregroundColor = state.ForegroundColor; backgroundColor = state.BackgroundColor; token = state.Tokens[++state.Index]; } } if (!afterLastToken && i == token.Extent.StartOffset) { GetTokenColors(token, out foregroundColor, out backgroundColor); var stringToken = token as StringExpandableToken; if (stringToken != null) { // We might have nested tokens. if (stringToken.NestedTokens != null && stringToken.NestedTokens.Any()) { var tokens = new Token[stringToken.NestedTokens.Count + 1]; stringToken.NestedTokens.CopyTo(tokens, 0); // NestedTokens doesn't have an "EOS" token, so we use // the string literal token for that purpose. tokens[tokens.Length - 1] = stringToken; tokenStack.Push(new SavedTokenState { Tokens = tokens, Index = 0, BackgroundColor = backgroundColor, ForegroundColor = foregroundColor }); if (i == tokens[0].Extent.StartOffset) { GetTokenColors(tokens[0], out foregroundColor, out backgroundColor); } } } } } var charToRender = text[i]; if (charToRender == '\n') { while ((j % bufferWidth) != 0) { _consoleBuffer[j++] = _space; } for (int k = 0; k < Options.ContinuationPrompt.Length; k++, j++) { _consoleBuffer[j].UnicodeChar = Options.ContinuationPrompt[k]; _consoleBuffer[j].ForegroundColor = Options.ContinuationPromptForegroundColor; _consoleBuffer[j].BackgroundColor = Options.ContinuationPromptBackgroundColor; } } else { int size = LengthInBufferCells(charToRender); totalBytes += size; //if there is no enough space for the character at the edge, fill in spaces at the end and //put the character to next line. int filling = totalBytes > bufferWidth ? (totalBytes - bufferWidth) % size : 0; for (int f = 0; f < filling; f++) { _consoleBuffer[j++] = _space; totalBytes++; } if (char.IsControl(charToRender)) { _consoleBuffer[j].UnicodeChar = '^'; MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor); _consoleBuffer[j].UnicodeChar = (char)('@' + charToRender); MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor); } else if (size > 1) { _consoleBuffer[j].UnicodeChar = charToRender; _consoleBuffer[j].Attributes = (ushort)(_consoleBuffer[j].Attributes | (uint)CHAR_INFO_Attributes.COMMON_LVB_LEADING_BYTE); MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor); _consoleBuffer[j].UnicodeChar = charToRender; _consoleBuffer[j].Attributes = (ushort)(_consoleBuffer[j].Attributes | (uint)CHAR_INFO_Attributes.COMMON_LVB_TRAILING_BYTE); MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor); } else { _consoleBuffer[j].UnicodeChar = charToRender; MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor); } } } } finally { _console.EndRender(); } for (; j < (_consoleBuffer.Length - (statusLineCount * _bufferWidth)); j++) { _consoleBuffer[j] = _space; } if (_statusLinePrompt != null) { foregroundColor = _statusIsErrorMessage ? Options.ErrorForegroundColor : _console.ForegroundColor; backgroundColor = _statusIsErrorMessage ? Options.ErrorBackgroundColor : _console.BackgroundColor; for (int i = 0; i < _statusLinePrompt.Length; i++, j++) { _consoleBuffer[j].UnicodeChar = _statusLinePrompt[i]; _consoleBuffer[j].ForegroundColor = foregroundColor; _consoleBuffer[j].BackgroundColor = backgroundColor; } for (int i = 0; i < _statusBuffer.Length; i++, j++) { _consoleBuffer[j].UnicodeChar = _statusBuffer[i]; _consoleBuffer[j].ForegroundColor = foregroundColor; _consoleBuffer[j].BackgroundColor = backgroundColor; } for (; j < _consoleBuffer.Length; j++) { _consoleBuffer[j] = _space; } } bool rendered = false; if (_parseErrors.Length > 0) { int promptChar = _initialX - 1 + (_bufferWidth * Options.ExtraPromptLineCount); while (promptChar >= 0) { var c = (char)_consoleBuffer[promptChar].UnicodeChar; if (char.IsWhiteSpace(c)) { promptChar -= 1; continue; } ConsoleColor prevColor = _consoleBuffer[promptChar].ForegroundColor; _consoleBuffer[promptChar].ForegroundColor = ConsoleColor.Red; _console.WriteBufferLines(_consoleBuffer, ref _initialY); rendered = true; _consoleBuffer[promptChar].ForegroundColor = prevColor; break; } } if (!rendered) { _console.WriteBufferLines(_consoleBuffer, ref _initialY); } PlaceCursor(); if ((_initialY + bufferLineCount) > (_console.WindowTop + _console.WindowHeight)) { _console.WindowTop = _initialY + bufferLineCount - _console.WindowHeight; } _lastRenderTime.Restart(); }
private void ReallyRender() { _renderForDemoNeeded = false; var text = ParseInput(); int statusLineCount = GetStatusLineCount(); int bufferLineCount = ConvertOffsetToCoordinates(text.Length).Y - _initialY + 1 + _demoWindowLineCount + statusLineCount; int bufferWidth = Console.BufferWidth; if (_consoleBuffer.Length != bufferLineCount * bufferWidth) { var newBuffer = new CHAR_INFO[bufferLineCount * bufferWidth]; Array.Copy(_consoleBuffer, newBuffer, _initialX + (Options.ExtraPromptLineCount * _bufferWidth)); if (_consoleBuffer.Length > bufferLineCount * bufferWidth) { // Need to erase the extra lines that we won't draw again for (int i = bufferLineCount * bufferWidth; i < _consoleBuffer.Length; i++) { _consoleBuffer[i] = _space; } WriteBufferLines(_consoleBuffer, ref _initialY); } _consoleBuffer = newBuffer; } var tokenStack = new Stack<SavedTokenState>(); tokenStack.Push(new SavedTokenState { Tokens = _tokens, Index = 0, BackgroundColor = _initialBackgroundColor, ForegroundColor = _initialForegroundColor }); int j = _initialX + (_bufferWidth * Options.ExtraPromptLineCount); var backgroundColor = _initialBackgroundColor; var foregroundColor = _initialForegroundColor; for (int i = 0; i < text.Length; i++) { // Figure out the color of the character - if it's in a token, // use the tokens color otherwise use the initial color. var state = tokenStack.Peek(); var token = state.Tokens[state.Index]; if (i == token.Extent.EndOffset) { if (token == state.Tokens[state.Tokens.Length - 1]) { tokenStack.Pop(); state = tokenStack.Peek(); } foregroundColor = state.ForegroundColor; backgroundColor = state.BackgroundColor; token = state.Tokens[++state.Index]; } if (i == token.Extent.StartOffset) { GetTokenColors(token, out foregroundColor, out backgroundColor); var stringToken = token as StringExpandableToken; if (stringToken != null) { // We might have nested tokens. if (stringToken.NestedTokens != null && stringToken.NestedTokens.Any()) { var tokens = new Token[stringToken.NestedTokens.Count + 1]; stringToken.NestedTokens.CopyTo(tokens, 0); // NestedTokens doesn't have an "EOS" token, so we use // the string literal token for that purpose. tokens[tokens.Length - 1] = stringToken; tokenStack.Push(new SavedTokenState { Tokens = tokens, Index = 0, BackgroundColor = backgroundColor, ForegroundColor = foregroundColor }); } } } if (text[i] == '\n') { while ((j % bufferWidth) != 0) { _consoleBuffer[j++] = _space; } for (int k = 0; k < Options.ContinuationPrompt.Length; k++, j++) { _consoleBuffer[j].UnicodeChar = Options.ContinuationPrompt[k]; _consoleBuffer[j].ForegroundColor = Options.ContinuationPromptForegroundColor; _consoleBuffer[j].BackgroundColor = Options.ContinuationPromptBackgroundColor; } } else if (char.IsControl(text[i])) { _consoleBuffer[j].UnicodeChar = '^'; MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor); _consoleBuffer[j].UnicodeChar = (char)('@' + text[i]); MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor); } else { _consoleBuffer[j].UnicodeChar = text[i]; MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor); } } for (; j < (_consoleBuffer.Length - ((statusLineCount + _demoWindowLineCount) * _bufferWidth)); j++) { _consoleBuffer[j] = _space; } if (_statusLinePrompt != null) { for (int i = 0; i < _statusLinePrompt.Length; i++, j++) { _consoleBuffer[j].UnicodeChar = _statusLinePrompt[i]; _consoleBuffer[j].ForegroundColor = Console.ForegroundColor; _consoleBuffer[j].BackgroundColor = Console.BackgroundColor; } for (int i = 0; i < _statusBuffer.Length; i++, j++) { _consoleBuffer[j].UnicodeChar = _statusBuffer[i]; _consoleBuffer[j].ForegroundColor = Console.ForegroundColor; _consoleBuffer[j].BackgroundColor = Console.BackgroundColor; } for (; j < (_consoleBuffer.Length - (_demoWindowLineCount * _bufferWidth)); j++) { _consoleBuffer[j] = _space; } } if (_demoMode) { RenderDemoWindow(j); } bool rendered = false; if (_parseErrors.Length > 0) { int promptChar = _initialX - 1 + (_bufferWidth * Options.ExtraPromptLineCount); while (promptChar >= 0) { if (char.IsSymbol((char)_consoleBuffer[promptChar].UnicodeChar)) { ConsoleColor prevColor = _consoleBuffer[promptChar].ForegroundColor; _consoleBuffer[promptChar].ForegroundColor = ConsoleColor.Red; WriteBufferLines(_consoleBuffer, ref _initialY); rendered = true; _consoleBuffer[promptChar].ForegroundColor = prevColor; break; } promptChar -= 1; } } if (!rendered) { WriteBufferLines(_consoleBuffer, ref _initialY); } PlaceCursor(); if ((_initialY + bufferLineCount + (_demoMode ? 1 : 0)) > (Console.WindowTop + Console.WindowHeight)) { Console.WindowTop = _initialY + bufferLineCount + (_demoMode ? 1 : 0) - Console.WindowHeight; } _lastRenderTime.Restart(); }
private static bool IsTokenTheSame(Token x, Token y) { if (x.Kind == y.Kind && x.TokenFlags == y.TokenFlags && x.Extent.StartLineNumber == y.Extent.StartLineNumber && x.Extent.StartColumnNumber == y.Extent.StartColumnNumber && x.Extent.EndLineNumber == y.Extent.EndLineNumber && x.Extent.EndColumnNumber == y.Extent.EndColumnNumber) { return true; } return false; }
private static bool CompleteAgainstStatementFlags(Ast scriptAst, Ast lastAst, Token token, out TokenKind kind) { kind = TokenKind.Unknown; // Handle "switch -f<tab>" var errorStatement = lastAst as ErrorStatementAst; if (errorStatement != null && errorStatement.Kind != null) { switch (errorStatement.Kind.Kind) { case TokenKind.Switch: kind = TokenKind.Switch; return true; default: break; } } // Handle "switch -<tab>". Skip cases like "switch ($a) {} -<tab> " var scriptBlockAst = scriptAst as ScriptBlockAst; if (token != null && token.Kind == TokenKind.Minus && scriptBlockAst != null) { var asts = AstSearcher.FindAll(scriptBlockAst, ast => IsCursorAfterExtent(token.Extent.StartScriptPosition, ast.Extent), searchNestedScriptBlocks: true); Ast last = asts.LastOrDefault(); errorStatement = null; while (last != null) { errorStatement = last as ErrorStatementAst; if (errorStatement != null) { break; } last = last.Parent; } if (errorStatement != null && errorStatement.Kind != null) { switch (errorStatement.Kind.Kind) { case TokenKind.Switch: Tuple<Token, Ast> value; if (errorStatement.Flags != null && errorStatement.Flags.TryGetValue(Parser.VERBATIM_ARGUMENT, out value)) { if (IsTokenTheSame(value.Item1, token)) { kind = TokenKind.Switch; return true; } } break; default: break; } } } return false; }
/// <summary> /// Split the text in the comment token into multiple lines, appending commentLines. /// </summary> /// <param name="comment">A single line or multiline comment token</param> /// <param name="commentLines"></param> private static void CollectCommentText(Token comment, List<string> commentLines) { string text = comment.Text; CollectCommentText(text, commentLines); }
private static void CollectCommentText(System.Management.Automation.Language.Token comment, List <string> commentLines) { CollectCommentText(comment.Text, commentLines); }
private void GetTokenColors(Token token, out ConsoleColor foregroundColor, out ConsoleColor backgroundColor) { switch (token.Kind) { case TokenKind.Comment: foregroundColor = _options.CommentForegroundColor; backgroundColor = _options.CommentBackgroundColor; return; case TokenKind.Parameter: foregroundColor = _options.ParameterForegroundColor; backgroundColor = _options.ParameterBackgroundColor; return; case TokenKind.Variable: case TokenKind.SplattedVariable: foregroundColor = _options.VariableForegroundColor; backgroundColor = _options.VariableBackgroundColor; return; case TokenKind.StringExpandable: case TokenKind.StringLiteral: case TokenKind.HereStringExpandable: case TokenKind.HereStringLiteral: foregroundColor = _options.StringForegroundColor; backgroundColor = _options.StringBackgroundColor; return; case TokenKind.Number: foregroundColor = _options.NumberForegroundColor; backgroundColor = _options.NumberBackgroundColor; return; } if ((token.TokenFlags & TokenFlags.CommandName) != 0) { foregroundColor = _options.CommandForegroundColor; backgroundColor = _options.CommandBackgroundColor; return; } if ((token.TokenFlags & TokenFlags.Keyword) != 0) { foregroundColor = _options.KeywordForegroundColor; backgroundColor = _options.KeywordBackgroundColor; return; } if ((token.TokenFlags & (TokenFlags.BinaryOperator | TokenFlags.UnaryOperator | TokenFlags.AssignmentOperator)) != 0) { foregroundColor = _options.OperatorForegroundColor; backgroundColor = _options.OperatorBackgroundColor; return; } if ((token.TokenFlags & TokenFlags.TypeName) != 0) { foregroundColor = _options.TypeForegroundColor; backgroundColor = _options.TypeBackgroundColor; return; } if ((token.TokenFlags & TokenFlags.MemberName) != 0) { foregroundColor = _options.MemberForegroundColor; backgroundColor = _options.MemberBackgroundColor; return; } foregroundColor = _options.DefaultTokenForegroundColor; backgroundColor = _options.DefaultTokenBackgroundColor; }
static bool OffsetWithinToken(int offset, Token token) { return offset < token.Extent.EndOffset && offset >= token.Extent.StartOffset; }
private static bool IsInterestingToken(Token token) { return token.Kind != TokenKind.NewLine && token.Kind != TokenKind.EndOfInput; }
private static List<string> GetRequiredModulesFromAst(Ast ast, Token[] tokens) { List<string> modules = new List<string>(); // We use System.Management.Automation.Language.Parser to extract required modules from ast, // but format of ast is a bit tricky and have changed in time. // // There are two place where 'Import-DscResource' keyword can appear: // 1) // Configuration Foo { // Import-DscResource .... # outside node // Node Bar {...} // } // 2) // Configuration Foo { // Node Bar { // Import-DscResource .... # inside node // ... // } // } // // The old version of System.Management.Automation.Language.Parser produces slightly different AST for the first case. // In new version, Configuration corresponds to ConfigurationDefinitionAst. // In old version is's a generic CommandAst with specific commandElements which capture top-level Imports (case 1). // In new version all imports correspond to their own CommandAsts, same for case 2 in old version. // Old version, case 1: IEnumerable<CommandAst> legacyConfigurationAsts = ast.FindAll(IsLegacyAstConfiguration, true).Select(x => (CommandAst)x); foreach (var legacyConfigurationAst in legacyConfigurationAsts) { // Note: these two sequences are translated to same AST: // // Import-DscResource -Module xComputerManagement; Import-DscResource -Name xComputer // Import-DscResource -Module xComputerManagement -Name xComputer // // We cannot distinguish different imports => cannot ignore resource names for imports with specified modules. // So we process everything: ModuleDefinition and ResourceDefinition. // Example: Import-DscResource -Module xPSDesiredStateConfiguration modules.AddRange(GetLegacyTopLevelParametersFromAst(legacyConfigurationAst, "ModuleDefinition")); // Example: Import-DscResource -Name MSFT_xComputer modules.AddRange(GetLegacyTopLevelParametersFromAst(legacyConfigurationAst, "ResourceDefinition").Select(GetModuleNameForDscResource)); } // Both cases in new version and 2nd case in old version: modules.AddRange(GetSingleAstRequiredModules(ast, tokens)); return modules.Distinct().ToList(); }