//public SymbolDetails GetSymbolDetails() #endregion #region Private Fields /// <summary> /// Gets all aliases found in the runspace /// </summary> private async Task GetAliases() { if (!this.areAliasesLoaded) { RunspaceHandle runspaceHandle = await this.powerShellContext.GetRunspaceHandle(); CommandInvocationIntrinsics invokeCommand = runspaceHandle.Runspace.SessionStateProxy.InvokeCommand; IEnumerable <CommandInfo> aliases = invokeCommand.GetCommands("*", CommandTypes.Alias, true); runspaceHandle.Dispose(); foreach (AliasInfo aliasInfo in aliases) { if (!CmdletToAliasDictionary.ContainsKey(aliasInfo.Definition)) { CmdletToAliasDictionary.Add(aliasInfo.Definition, new List <String>() { aliasInfo.Name }); } else { CmdletToAliasDictionary[aliasInfo.Definition].Add(aliasInfo.Name); } AliasToCmdletDictionary.Add(aliasInfo.Name, aliasInfo.Definition); } this.areAliasesLoaded = true; } }
/// <summary> /// Gets completions for a statement contained in the given /// script file at the specified line and column position. /// </summary> /// <param name="scriptFile"> /// The script file in which completions will be gathered. /// </param> /// <param name="lineNumber"> /// The 1-based line number at which completions will be gathered. /// </param> /// <param name="columnNumber"> /// The 1-based column number at which completions will be gathered. /// </param> /// <returns> /// A CommandCompletion instance completions for the identified statement. /// </returns> public async Task <CompletionResults> GetCompletionsInFile( ScriptFile scriptFile, int lineNumber, int columnNumber) { Validate.IsNotNull("scriptFile", scriptFile); // Get the offset at the specified position. This method // will also validate the given position. int fileOffset = scriptFile.GetOffsetAtPosition( lineNumber, columnNumber); RunspaceHandle runspaceHandle = await this.powerShellContext.GetRunspaceHandle(); CompletionResults completionResults = AstOperations.GetCompletions( scriptFile.ScriptAst, scriptFile.ScriptTokens, fileOffset, runspaceHandle.Runspace); runspaceHandle.Dispose(); // save state of most recent completion mostRecentCompletions = completionResults; mostRecentRequestFile = scriptFile.Id; mostRecentRequestLine = lineNumber; mostRecentRequestOffest = columnNumber; return(completionResults); }
/// <summary> /// Finds the details of the symbol at the given script file location. /// </summary> /// <param name="scriptFile">The ScriptFile in which the symbol can be located.</param> /// <param name="lineNumber">The line number at which the symbol can be located.</param> /// <param name="columnNumber">The column number at which the symbol can be located.</param> /// <returns></returns> public async Task <SymbolDetails> FindSymbolDetailsAtLocation( ScriptFile scriptFile, int lineNumber, int columnNumber) { SymbolDetails symbolDetails = null; SymbolReference symbolReference = AstOperations.FindSymbolAtPosition( scriptFile.ScriptAst, lineNumber, columnNumber); if (symbolReference != null) { RunspaceHandle runspaceHandle = await this.powerShellContext.GetRunspaceHandle(); symbolReference.FilePath = scriptFile.FilePath; symbolDetails = new SymbolDetails(symbolReference, runspaceHandle.Runspace); runspaceHandle.Dispose(); } else { // TODO #21: Return Result<T> return(null); } return(symbolDetails); }
/// <summary> /// Finds the details of the symbol at the given script file location. /// </summary> /// <param name="scriptFile">The ScriptFile in which the symbol can be located.</param> /// <param name="lineNumber">The line number at which the symbol can be located.</param> /// <param name="columnNumber">The column number at which the symbol can be located.</param> /// <returns></returns> public async Task <SymbolDetails> FindSymbolDetailsAtLocation( ScriptFile scriptFile, int lineNumber, int columnNumber) { SymbolDetails symbolDetails = null; SymbolReference symbolReference = AstOperations.FindSymbolAtPosition( scriptFile.ScriptAst, lineNumber, columnNumber); if (symbolReference != null) { // Request a runspace handle with a short timeout RunspaceHandle runspaceHandle = await this.powerShellContext.GetRunspaceHandle( new CancellationTokenSource(DefaultWaitTimeoutMilliseconds).Token); symbolReference.FilePath = scriptFile.FilePath; symbolDetails = new SymbolDetails(symbolReference, runspaceHandle.Runspace); runspaceHandle.Dispose(); } else { // TODO #21: Return Result<T> return(null); } return(symbolDetails); }
/// <summary> /// Gets completions for a statement contained in the given /// script file at the specified line and column position. /// </summary> /// <param name="scriptFile"> /// The script file in which completions will be gathered. /// </param> /// <param name="lineNumber"> /// The 1-based line number at which completions will be gathered. /// </param> /// <param name="columnNumber"> /// The 1-based column number at which completions will be gathered. /// </param> /// <returns> /// A CommandCompletion instance completions for the identified statement. /// </returns> public async Task <CompletionResults> GetCompletionsInFile( ScriptFile scriptFile, int lineNumber, int columnNumber) { Validate.IsNotNull("scriptFile", scriptFile); // Get the offset at the specified position. This method // will also validate the given position. int fileOffset = scriptFile.GetOffsetAtPosition( lineNumber, columnNumber); RunspaceHandle runspaceHandle = await this.powerShellContext.GetRunspaceHandle( new CancellationTokenSource(DefaultWaitTimeoutMilliseconds).Token); CommandCompletion commandCompletion = AstOperations.GetCompletions( scriptFile.ScriptAst, scriptFile.ScriptTokens, fileOffset, runspaceHandle.Runspace); runspaceHandle.Dispose(); if (commandCompletion != null) { try { CompletionResults completionResults = CompletionResults.Create( scriptFile, commandCompletion); // save state of most recent completion mostRecentCompletions = completionResults; mostRecentRequestFile = scriptFile.Id; mostRecentRequestLine = lineNumber; mostRecentRequestOffest = columnNumber; return(completionResults); } catch (ArgumentException e) { // Bad completion results could return an invalid // replacement range, catch that here Logger.Write( LogLevel.Error, $"Caught exception while trying to create CompletionResults:\n\n{e.ToString()}"); } } // If all else fails, return empty results return(new CompletionResults()); }
/// <summary> /// Gets all aliases found in the runspace /// </summary> private async Task GetAliases() { if (_areAliasesLoaded) { return; } try { RunspaceHandle runspaceHandle = await _powerShellContext.GetRunspaceHandle( new CancellationTokenSource(DefaultWaitTimeoutMilliseconds).Token); CommandInvocationIntrinsics invokeCommand = runspaceHandle.Runspace.SessionStateProxy.InvokeCommand; IEnumerable <CommandInfo> aliases = invokeCommand.GetCommands("*", CommandTypes.Alias, true); runspaceHandle.Dispose(); foreach (AliasInfo aliasInfo in aliases) { if (!_cmdletToAliasDictionary.ContainsKey(aliasInfo.Definition)) { _cmdletToAliasDictionary.Add(aliasInfo.Definition, new List <String> { aliasInfo.Name }); } else { _cmdletToAliasDictionary[aliasInfo.Definition].Add(aliasInfo.Name); } _aliasToCmdletDictionary.Add(aliasInfo.Name, aliasInfo.Definition); } _areAliasesLoaded = true; } catch (PSNotSupportedException e) { _logger.Write( LogLevel.Warning, $"Caught PSNotSupportedException while attempting to get aliases from remote session:\n\n{e.ToString()}"); // Prevent the aliases from being fetched again - no point if the remote doesn't support InvokeCommand. _areAliasesLoaded = true; } catch (TaskCanceledException) { // The wait for a RunspaceHandle has timed out, skip aliases for now } }
/// <summary> /// Gets completions for a statement contained in the given /// script file at the specified line and column position. /// </summary> /// <param name="scriptFile"> /// The script file in which completions will be gathered. /// </param> /// <param name="lineNumber"> /// The 1-based line number at which completions will be gathered. /// </param> /// <param name="columnNumber"> /// The 1-based column number at which completions will be gathered. /// </param> /// <returns> /// A CommandCompletion instance completions for the identified statement. /// </returns> public async Task <CompletionResults> GetCompletionsInFile( ScriptFile scriptFile, int lineNumber, int columnNumber) { Validate.IsNotNull("scriptFile", scriptFile); // Get the offset at the specified position. This method // will also validate the given position. int fileOffset = scriptFile.GetOffsetAtPosition( lineNumber, columnNumber); RunspaceHandle runspaceHandle = await this.powerShellContext.GetRunspaceHandle( new CancellationTokenSource(DefaultWaitTimeoutMilliseconds).Token); CommandCompletion commandCompletion = AstOperations.GetCompletions( scriptFile.ScriptAst, scriptFile.ScriptTokens, fileOffset, runspaceHandle.Runspace); runspaceHandle.Dispose(); if (commandCompletion != null) { CompletionResults completionResults = CompletionResults.Create( scriptFile, commandCompletion); // save state of most recent completion mostRecentCompletions = completionResults; mostRecentRequestFile = scriptFile.Id; mostRecentRequestLine = lineNumber; mostRecentRequestOffest = columnNumber; return(completionResults); } else { return(new CompletionResults()); } }
/// <summary> /// Gets all aliases found in the runspace /// </summary> private async Task GetAliases() { if (!this.areAliasesLoaded) { try { RunspaceHandle runspaceHandle = await this.powerShellContext.GetRunspaceHandle( new CancellationTokenSource(DefaultWaitTimeoutMilliseconds).Token); CommandInvocationIntrinsics invokeCommand = runspaceHandle.Runspace.SessionStateProxy.InvokeCommand; IEnumerable <CommandInfo> aliases = invokeCommand.GetCommands("*", CommandTypes.Alias, true); runspaceHandle.Dispose(); foreach (AliasInfo aliasInfo in aliases) { if (!CmdletToAliasDictionary.ContainsKey(aliasInfo.Definition)) { CmdletToAliasDictionary.Add(aliasInfo.Definition, new List <String>() { aliasInfo.Name }); } else { CmdletToAliasDictionary[aliasInfo.Definition].Add(aliasInfo.Name); } AliasToCmdletDictionary.Add(aliasInfo.Name, aliasInfo.Definition); } this.areAliasesLoaded = true; } catch (TaskCanceledException) { // The wait for a RunspaceHandle has timed out, skip aliases for now } } }
/// <summary> /// Executes a PSCommand against the session's runspace and returns /// a collection of results of the expected type. /// </summary> /// <typeparam name="TResult">The expected result type.</typeparam> /// <param name="psCommand">The PSCommand to be executed.</param> /// <param name="sendOutputToHost"> /// If true, causes any output written during command execution to be written to the host. /// </param> /// <param name="sendErrorToHost"> /// If true, causes any errors encountered during command execution to be written to the host. /// </param> /// <returns> /// An awaitable Task which will provide results once the command /// execution completes. /// </returns> public async Task <IEnumerable <TResult> > ExecuteCommand <TResult>( PSCommand psCommand, bool sendOutputToHost = false, bool sendErrorToHost = true) { RunspaceHandle runspaceHandle = null; IEnumerable <TResult> executionResult = null; // If the debugger is active and the caller isn't on the pipeline // thread, send the command over to that thread to be executed. if (Thread.CurrentThread.ManagedThreadId != this.pipelineThreadId && this.pipelineExecutionTask != null) { Logger.Write(LogLevel.Verbose, "Passing command execution to pipeline thread."); PipelineExecutionRequest <TResult> executionRequest = new PipelineExecutionRequest <TResult>( this, psCommand, sendOutputToHost); // Send the pipeline execution request to the pipeline thread this.pipelineResultTask = new TaskCompletionSource <IPipelineExecutionRequest>(); this.pipelineExecutionTask.SetResult(executionRequest); await this.pipelineResultTask.Task; return(executionRequest.Results); } else { try { // Instruct PowerShell to send output and errors to the host if (sendOutputToHost) { psCommand.Commands[0].MergeMyResults( PipelineResultTypes.Error, PipelineResultTypes.Output); psCommand.Commands.Add( this.GetOutputCommand( endOfStatement: false)); } if (this.currentRunspace.RunspaceAvailability == RunspaceAvailability.AvailableForNestedCommand || this.debuggerStoppedTask != null) { Logger.Write( LogLevel.Verbose, string.Format( "Attempting to execute nested pipeline command(s):\r\n\r\n{0}", GetStringForPSCommand(psCommand))); executionResult = this.ExecuteCommandInDebugger <TResult>( psCommand, sendOutputToHost); } else { Logger.Write( LogLevel.Verbose, string.Format( "Attempting to execute command(s):\r\n\r\n{0}", GetStringForPSCommand(psCommand))); // Set the runspace runspaceHandle = await this.GetRunspaceHandle(); if (runspaceHandle.Runspace.RunspaceAvailability != RunspaceAvailability.AvailableForNestedCommand) { this.powerShell.Runspace = runspaceHandle.Runspace; } // Invoke the pipeline on a background thread // TODO: Use built-in async invocation! executionResult = await Task.Factory.StartNew <IEnumerable <TResult> >( () => { this.powerShell.Commands = psCommand; Collection <TResult> result = this.powerShell.Invoke <TResult>(); return(result); }, CancellationToken.None, // Might need a cancellation token TaskCreationOptions.None, TaskScheduler.Default ); if (this.powerShell.HadErrors) { string errorMessage = "Execution completed with errors:\r\n\r\n"; foreach (var error in this.powerShell.Streams.Error) { errorMessage += error.ToString() + "\r\n"; } Logger.Write(LogLevel.Error, errorMessage); } else { Logger.Write( LogLevel.Verbose, "Execution completed successfully."); } return(executionResult); } } catch (RuntimeException e) { Logger.Write( LogLevel.Error, "Runtime exception occurred while executing command:\r\n\r\n" + e.ToString()); if (sendErrorToHost) { // Write the error to the host this.WriteExceptionToHost(e); } } finally { // Get the new prompt before releasing the runspace handle if (sendOutputToHost) { // Write the prompt if (runspaceHandle != null) { this.WritePromptWithRunspace(runspaceHandle.Runspace); } else { this.WritePromptWithNestedPipeline(); } } // Dispose of the execution context if (runspaceHandle != null) { runspaceHandle.Dispose(); } } } return(executionResult); }