예제 #1
0
        /// <summary>
        /// Creates a new instance of the ConsoleServicePSHostUserInterface
        /// class with the given IConsoleHost implementation.
        /// </summary>
        /// <param name="powerShellContext">The PowerShellContext to use for executing commands.</param>
        /// <param name="logger">An ILogger implementation to use for this host.</param>
        public TerminalPSHostUserInterface(
            PowerShellContext powerShellContext,
            ILogger logger)
            : base(
                powerShellContext,
                new TerminalPSHostRawUserInterface(logger),
                logger)
        {
            this.consoleReadLine = new ConsoleReadLine(powerShellContext);

            // Set the output encoding to UTF-8 so that special
            // characters are written to the console correctly
            System.Console.OutputEncoding = System.Text.Encoding.UTF8;

            System.Console.CancelKeyPress +=
                (obj, args) =>
            {
                if (!this.IsNativeApplicationRunning)
                {
                    // We'll handle Ctrl+C
                    args.Cancel = true;
                    this.SendControlC();
                }
            };
        }
        private string ResolveFilePath(string filePath)
        {
            if (!IsPathInMemory(filePath))
            {
                if (filePath.StartsWith(@"file://"))
                {
                    // Client sent the path in URI format, extract the local path and trim
                    // any extraneous slashes
                    Uri fileUri = new Uri(filePath);
                    filePath = fileUri.LocalPath.TrimStart('/');
                }

                // Some clients send paths with UNIX-style slashes, replace those if necessary
                filePath = filePath.Replace('/', '\\');

                // Clients could specify paths with escaped space, [ and ] characters which .NET APIs
                // will not handle.  These paths will get appropriately escaped just before being passed
                // into the PowerShell engine.
                filePath = PowerShellContext.UnescapePath(filePath);

                // Get the absolute file path
                filePath = Path.GetFullPath(filePath);
            }

            Logger.Write(LogLevel.Verbose, "Resolved path: " + filePath);

            return(filePath);
        }
        /// <summary>
        /// Gets the CommandInfo instance for a command with a particular name.
        /// </summary>
        /// <param name="commandName">The name of the command.</param>
        /// <param name="powerShellContext">The PowerShellContext to use for running Get-Command.</param>
        /// <returns>A CommandInfo object with details about the specified command.</returns>
        public static async Task <CommandInfo> GetCommandInfo(
            string commandName,
            PowerShellContext powerShellContext)
        {
            Validate.IsNotNull(nameof(commandName), commandName);

            // Make sure the command's noun isn't blacklisted.  This is
            // currently necessary to make sure that Get-Command doesn't
            // load PackageManagement or PowerShellGet because they cause
            // a major slowdown in IntelliSense.
            var commandParts = commandName.Split('-');

            if (commandParts.Length == 2 && NounBlackList.Contains(commandParts[1]))
            {
                return(null);
            }

            PSCommand command = new PSCommand();

            command.AddCommand(@"Microsoft.PowerShell.Core\Get-Command");
            command.AddArgument(commandName);
            command.AddParameter("ErrorAction", "Ignore");

            return
                ((await powerShellContext
                  .ExecuteCommand <PSObject>(command, false, false))
                 .Select(o => o.BaseObject)
                 .OfType <CommandInfo>()
                 .FirstOrDefault());
        }
        /// <summary>
        /// Sets the list of breakpoints for the current debugging session.
        /// </summary>
        /// <param name="scriptFile">The ScriptFile in which breakpoints will be set.</param>
        /// <param name="lineNumbers">The line numbers at which breakpoints will be set.</param>
        /// <param name="clearExisting">If true, causes all existing breakpoints to be cleared before setting new ones.</param>
        /// <returns>An awaitable Task that will provide details about the breakpoints that were set.</returns>
        public async Task <BreakpointDetails[]> SetBreakpoints(
            ScriptFile scriptFile,
            int[] lineNumbers,
            bool clearExisting = true)
        {
            IEnumerable <Breakpoint> resultBreakpoints = null;

            if (clearExisting)
            {
                await this.ClearBreakpointsInFile(scriptFile);
            }

            if (lineNumbers.Length > 0)
            {
                // Fix for issue #123 - file paths that contain wildcard chars [ and ] need to
                // quoted and have those wildcard chars escaped.
                string escapedScriptPath = PowerShellContext.EscapeWildcardsInPath(scriptFile.FilePath);

                PSCommand psCommand = new PSCommand();
                psCommand.AddCommand("Set-PSBreakpoint");
                psCommand.AddParameter("Script", escapedScriptPath);
                psCommand.AddParameter("Line", lineNumbers.Length > 0 ? lineNumbers : null);

                resultBreakpoints =
                    await this.powerShellContext.ExecuteCommand <Breakpoint>(
                        psCommand);

                return
                    (resultBreakpoints
                     .Select(BreakpointDetails.Create)
                     .ToArray());
            }

            return(new BreakpointDetails[0]);
        }
        /// <summary>
        /// Initializes a new instance of the DebugService class and uses
        /// the given PowerShellContext for all future operations.
        /// </summary>
        /// <param name="powerShellContext">
        /// The PowerShellContext to use for all debugging operations.
        /// </param>
        public DebugService(PowerShellContext powerShellContext)
        {
            Validate.IsNotNull("powerShellContext", powerShellContext);

            this.powerShellContext = powerShellContext;
            this.powerShellContext.DebuggerStop      += this.OnDebuggerStop;
            this.powerShellContext.BreakpointUpdated += this.OnBreakpointUpdated;
        }
 public PipelineExecutionRequest(
     PowerShellContext powerShellContext,
     PSCommand psCommand,
     bool sendOutputToHost)
 {
     this.powerShellContext = powerShellContext;
     this.psCommand         = psCommand;
     this.sendOutputToHost  = sendOutputToHost;
 }
        /// <summary>
        /// Constructs an instance of the LanguageService class and uses
        /// the given Runspace to execute language service operations.
        /// </summary>
        /// <param name="powerShellContext">
        /// The PowerShellContext in which language service operations will be executed.
        /// </param>
        public LanguageService(PowerShellContext powerShellContext)
        {
            Validate.IsNotNull("powerShellContext", powerShellContext);

            this.powerShellContext = powerShellContext;

            this.CmdletToAliasDictionary = new Dictionary <String, List <String> >(StringComparer.OrdinalIgnoreCase);
            this.AliasToCmdletDictionary = new Dictionary <String, String>(StringComparer.OrdinalIgnoreCase);
        }
 /// <summary>
 /// Creates a new instance of the ConsoleServicePSHost class
 /// with the given IConsoleHost implementation.
 /// </summary>
 /// <param name="powerShellContext">
 /// An implementation of IHostSupportsInteractiveSession for runspace management.
 /// </param>
 /// <param name="hostDetails">
 /// Provides details about the host application.
 /// </param>
 /// <param name="hostUserInterface">
 /// The EditorServicesPSHostUserInterface implementation to use for this host.
 /// </param>
 /// <param name="logger">An ILogger implementation to use for this host.</param>
 public EditorServicesPSHost(
     PowerShellContext powerShellContext,
     HostDetails hostDetails,
     EditorServicesPSHostUserInterface hostUserInterface,
     ILogger logger)
 {
     this.Logger            = logger;
     this.hostDetails       = hostDetails;
     this.hostUserInterface = hostUserInterface;
     this.hostSupportsInteractiveSession = powerShellContext;
 }
예제 #9
0
        static internal async Task <SymbolDetails> CreateAsync(
            SymbolReference symbolReference,
            PowerShellContext powerShellContext)
        {
            SymbolDetails symbolDetails = new SymbolDetails();

            symbolDetails.SymbolReference = symbolReference;

            // If the symbol is a command, get its documentation
            if (symbolReference.SymbolType == SymbolType.Function)
            {
                CommandInfo commandInfo =
                    await CommandHelpers.GetCommandInfoAsync(
                        symbolReference.SymbolName,
                        powerShellContext);

                if (commandInfo != null)
                {
                    symbolDetails.Documentation =
                        await CommandHelpers.GetCommandSynopsisAsync(
                            commandInfo,
                            powerShellContext);

                    if (commandInfo.CommandType == CommandTypes.Application)
                    {
                        symbolDetails.DisplayString = "(application) " + symbolReference.SymbolName;
                    }
                    else
                    {
                        symbolDetails.DisplayString = "function " + symbolReference.SymbolName;
                    }
                }
                else
                {
                    // Command information can't be loaded.  This is likely due to
                    // the symbol being a function that is defined in a file that
                    // hasn't been loaded in the runspace yet.
                    symbolDetails.DisplayString = "function " + symbolReference.SymbolName;
                }
            }
            else if (symbolReference.SymbolType == SymbolType.Parameter)
            {
                // TODO: Get parameter help
                symbolDetails.DisplayString = "(parameter) " + symbolReference.SymbolName;
            }
            else if (symbolReference.SymbolType == SymbolType.Variable)
            {
                symbolDetails.DisplayString = symbolReference.SymbolName;
            }

            return(symbolDetails);
        }
        /// <summary>
        /// Starts a debug-only session using the provided IConsoleHost implementation
        /// for the ConsoleService.
        /// </summary>
        /// <param name="powerShellContext"></param>
        /// <param name="editorOperations">
        /// An IEditorOperations implementation used to interact with the editor.
        /// </param>
        public void StartDebugSession(
            PowerShellContext powerShellContext,
            IEditorOperations editorOperations)
        {
            this.PowerShellContext = powerShellContext;

            // Initialize all services
            this.RemoteFileManager = new RemoteFileManager(this.PowerShellContext, editorOperations, logger);
            this.DebugService      = new DebugService(this.PowerShellContext, this.RemoteFileManager, logger);

            // Create a workspace to contain open files
            this.Workspace = new Workspace(this.PowerShellContext.LocalPowerShellVersion.Version, this.logger);
        }
        /// <summary>
        /// Gets the CommandInfo instance for a command with a particular name.
        /// </summary>
        /// <param name="commandName">The name of the command.</param>
        /// <param name="powerShellContext">The PowerShellContext to use for running Get-Command.</param>
        /// <returns>A CommandInfo object with details about the specified command.</returns>
        public static async Task <CommandInfo> GetCommandInfo(
            string commandName,
            PowerShellContext powerShellContext)
        {
            PSCommand command = new PSCommand();

            command.AddCommand(@"Microsoft.PowerShell.Core\Get-Command");
            command.AddArgument(commandName);

            var results = await powerShellContext.ExecuteCommand <CommandInfo>(command, false, false);

            return(results.FirstOrDefault());
        }
예제 #12
0
        /// <summary>
        /// Creates a new instance of the ConsoleServicePSHostUserInterface
        /// class with the given IConsoleHost implementation.
        /// </summary>
        /// <param name="powerShellContext">The PowerShellContext to use for executing commands.</param>
        /// <param name="rawUserInterface">The PSHostRawUserInterface implementation to use for this host.</param>
        /// <param name="logger">An ILogger implementation to use for this host.</param>
        public EditorServicesPSHostUserInterface(
            PowerShellContext powerShellContext,
            PSHostRawUserInterface rawUserInterface,
            ILogger logger)
        {
            this.Logger            = logger;
            this.powerShellContext = powerShellContext;
            this.rawUserInterface  = rawUserInterface;

            this.powerShellContext.DebuggerStop           += PowerShellContext_DebuggerStop;
            this.powerShellContext.DebuggerResumed        += PowerShellContext_DebuggerResumed;
            this.powerShellContext.ExecutionStatusChanged += PowerShellContext_ExecutionStatusChanged;
        }
예제 #13
0
        /// <summary>
        /// Gets the CommandInfo instance for a command with a particular name.
        /// </summary>
        /// <param name="commandName">The name of the command.</param>
        /// <param name="powerShellContext">The PowerShellContext to use for running Get-Command.</param>
        /// <returns>A CommandInfo object with details about the specified command.</returns>
        public static async Task <CommandInfo> GetCommandInfo(
            string commandName,
            PowerShellContext powerShellContext)
        {
            PSCommand command = new PSCommand();

            command.AddCommand(@"Microsoft.PowerShell.Core\Get-Command");
            command.AddArgument(commandName);

            return
                ((await powerShellContext
                  .ExecuteCommand <PSObject>(command, false, false))
                 .Select(o => o.BaseObject)
                 .OfType <CommandInfo>()
                 .FirstOrDefault());
        }
예제 #14
0
        /// <summary>
        /// Starts the session using the provided IConsoleHost implementation
        /// for the ConsoleService.
        /// </summary>
        /// <param name="powerShellContext"></param>
        /// <param name="hostInput"></param>
        public void StartSession(
            PowerShellContext powerShellContext,
            IHostInput hostInput)
        {
            this.PowerShellContext = powerShellContext;
            this.HostInput         = hostInput;

            // Initialize all services
            this.LanguageService  = new LanguageService(this.PowerShellContext, this.logger);
            this.ExtensionService = new ExtensionService(this.PowerShellContext);
            this.TemplateService  = new TemplateService(this.PowerShellContext, this.logger);

            this.InstantiateAnalysisService();

            // Create a workspace to contain open files
            this.Workspace = new Workspace(this.PowerShellContext.LocalPowerShellVersion.Version, this.logger);
        }
        /// <summary>
        /// Constructs an instance of the LanguageService class and uses
        /// the given Runspace to execute language service operations.
        /// </summary>
        /// <param name="powerShellContext">
        /// The PowerShellContext in which language service operations will be executed.
        /// </param>
        /// <param name="logger">An ILogger implementation used for writing log messages.</param>
        public LanguageService(
            PowerShellContext powerShellContext,
            ILogger logger)
        {
            Validate.IsNotNull("powerShellContext", powerShellContext);

            this.powerShellContext = powerShellContext;
            this.logger            = logger;

            this.CmdletToAliasDictionary = new Dictionary <String, List <String> >(StringComparer.OrdinalIgnoreCase);
            this.AliasToCmdletDictionary = new Dictionary <String, String>(StringComparer.OrdinalIgnoreCase);
            this.documentSymbolProviders = new IDocumentSymbolProvider[]
            {
                new ScriptDocumentSymbolProvider(powerShellContext.LocalPowerShellVersion.Version),
                new PsdDocumentSymbolProvider(),
                new PesterDocumentSymbolProvider()
            };
        }
        /// <summary>
        /// Gets the command's "Synopsis" documentation section.
        /// </summary>
        /// <param name="commandInfo">The CommandInfo instance for the command.</param>
        /// <param name="powerShellContext">The PowerShellContext to use for getting command documentation.</param>
        /// <returns></returns>
        public static async Task <string> GetCommandSynopsis(
            CommandInfo commandInfo,
            PowerShellContext powerShellContext)
        {
            string synopsisString = string.Empty;

            PSObject helpObject = null;

            if (commandInfo != null &&
                (commandInfo.CommandType == CommandTypes.Cmdlet ||
                 commandInfo.CommandType == CommandTypes.Function ||
                 commandInfo.CommandType == CommandTypes.Filter))
            {
                PSCommand command = new PSCommand();
                command.AddCommand(@"Microsoft.PowerShell.Core\Get-Help");
                command.AddArgument(commandInfo);
                command.AddParameter("ErrorAction", "Ignore");

                var results = await powerShellContext.ExecuteCommand <PSObject>(command, false, false);

                helpObject = results.FirstOrDefault();

                if (helpObject != null)
                {
                    // Extract the synopsis string from the object
                    synopsisString =
                        (string)helpObject.Properties["synopsis"].Value ??
                        string.Empty;

                    // Ignore the placeholder value for this field
                    if (string.Equals(synopsisString, "SHORT DESCRIPTION", System.StringComparison.CurrentCultureIgnoreCase))
                    {
                        synopsisString = string.Empty;
                    }
                }
            }

            return(synopsisString);
        }
예제 #17
0
        internal string ResolveFilePath(string filePath)
        {
            if (!IsPathInMemory(filePath))
            {
                if (filePath.StartsWith(@"file://"))
                {
                    filePath = Workspace.UnescapeDriveColon(filePath);
                    // Client sent the path in URI format, extract the local path
                    filePath = new Uri(filePath).LocalPath;
                }

                // Clients could specify paths with escaped space, [ and ] characters which .NET APIs
                // will not handle.  These paths will get appropriately escaped just before being passed
                // into the PowerShell engine.
                filePath = PowerShellContext.UnescapeWildcardEscapedPath(filePath);

                // Get the absolute file path
                filePath = Path.GetFullPath(filePath);
            }

            this.logger.Write(LogLevel.Verbose, "Resolved path: " + filePath);

            return(filePath);
        }
 /// <summary>
 /// Initializes a new instance of the RunspaceHandle class using the
 /// given runspace.
 /// </summary>
 /// <param name="powerShellContext">The PowerShellContext instance which manages the runspace.</param>
 public RunspaceHandle(PowerShellContext powerShellContext)
     : this(powerShellContext, false)
 {
 }
예제 #19
0
 /// <summary>
 /// Initializes a new instance of the RunspaceHandle class using the
 /// given runspace.
 /// </summary>
 /// <param name="runspace">The runspace instance which is temporarily owned by this handle.</param>
 /// <param name="powerShellContext">The PowerShellContext instance which manages the runspace.</param>
 public RunspaceHandle(Runspace runspace, PowerShellContext powerShellContext)
 {
     this.Runspace          = runspace;
     this.powerShellContext = powerShellContext;
 }
 internal RunspaceHandle(PowerShellContext powerShellContext, bool isReadLine)
 {
     this.powerShellContext = powerShellContext;
     this.IsReadLine        = isReadLine;
 }
        /// <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="powerShellContext">
        /// The PowerShellContext to use for gathering completions.
        /// </param>
        /// <param name="logger">An ILogger implementation used for writing log messages.</param>
        /// <param name="cancellationToken">
        /// A CancellationToken to cancel completion requests.
        /// </param>
        /// <returns>
        /// A CommandCompletion instance that contains completions for the
        /// symbol at the given offset.
        /// </returns>
        static public async Task <CommandCompletion> GetCompletionsAsync(
            Ast scriptAst,
            Token[] currentTokens,
            int fileOffset,
            PowerShellContext powerShellContext,
            ILogger logger,
            CancellationToken cancellationToken)
        {
            if (!s_completionHandle.Wait(0))
            {
                return(null);
            }

            try
            {
                IScriptPosition cursorPosition = (IScriptPosition)s_extentCloneWithNewOffset.Invoke(
                    scriptAst.Extent.StartScriptPosition,
                    new object[] { fileOffset });

                logger.Write(
                    LogLevel.Verbose,
                    string.Format(
                        "Getting completions at offset {0} (line: {1}, column: {2})",
                        fileOffset,
                        cursorPosition.LineNumber,
                        cursorPosition.ColumnNumber));

                if (!powerShellContext.IsAvailable)
                {
                    return(null);
                }

                var stopwatch = new Stopwatch();

                // If the current runspace is out of process we can use
                // CommandCompletion.CompleteInput because PSReadLine won't be taking up the
                // main runspace.
                if (powerShellContext.IsCurrentRunspaceOutOfProcess())
                {
                    using (RunspaceHandle runspaceHandle = await powerShellContext.GetRunspaceHandleAsync(cancellationToken))
                        using (PowerShell powerShell = PowerShell.Create())
                        {
                            powerShell.Runspace = runspaceHandle.Runspace;
                            stopwatch.Start();
                            try
                            {
                                return(CommandCompletion.CompleteInput(
                                           scriptAst,
                                           currentTokens,
                                           cursorPosition,
                                           options: null,
                                           powershell: powerShell));
                            }
                            finally
                            {
                                stopwatch.Stop();
                                logger.Write(LogLevel.Verbose, $"IntelliSense completed in {stopwatch.ElapsedMilliseconds}ms.");
                            }
                        }
                }

                CommandCompletion commandCompletion = null;
                await powerShellContext.InvokeOnPipelineThreadAsync(
                    pwsh =>
                {
                    stopwatch.Start();
                    commandCompletion = CommandCompletion.CompleteInput(
                        scriptAst,
                        currentTokens,
                        cursorPosition,
                        options: null,
                        powershell: pwsh);
                });

                stopwatch.Stop();
                logger.Write(LogLevel.Verbose, $"IntelliSense completed in {stopwatch.ElapsedMilliseconds}ms.");

                return(commandCompletion);
            }
            finally
            {
                s_completionHandle.Release();
            }
        }
        /// <summary>
        /// Sets the list of line breakpoints for the current debugging session.
        /// </summary>
        /// <param name="scriptFile">The ScriptFile in which breakpoints will be set.</param>
        /// <param name="breakpoints">BreakpointDetails for each breakpoint that will be set.</param>
        /// <param name="clearExisting">If true, causes all existing breakpoints to be cleared before setting new ones.</param>
        /// <returns>An awaitable Task that will provide details about the breakpoints that were set.</returns>
        public async Task <BreakpointDetails[]> SetLineBreakpoints(
            ScriptFile scriptFile,
            BreakpointDetails[] breakpoints,
            bool clearExisting = true)
        {
            var resultBreakpointDetails = new List <BreakpointDetails>();

            if (clearExisting)
            {
                await this.ClearBreakpointsInFile(scriptFile);
            }

            if (breakpoints.Length > 0)
            {
                // Fix for issue #123 - file paths that contain wildcard chars [ and ] need to
                // quoted and have those wildcard chars escaped.
                string escapedScriptPath =
                    PowerShellContext.EscapePath(scriptFile.FilePath, escapeSpaces: false);

                foreach (BreakpointDetails breakpoint in breakpoints)
                {
                    PSCommand psCommand = new PSCommand();
                    psCommand.AddCommand(@"Microsoft.PowerShell.Utility\Set-PSBreakpoint");
                    psCommand.AddParameter("Script", escapedScriptPath);
                    psCommand.AddParameter("Line", breakpoint.LineNumber);

                    // Check if the user has specified the column number for the breakpoint.
                    if (breakpoint.ColumnNumber.HasValue)
                    {
                        // It bums me out that PowerShell will silently ignore a breakpoint
                        // where either the line or the column is invalid.  I'd rather have an
                        // error or warning message I could relay back to the client.
                        psCommand.AddParameter("Column", breakpoint.ColumnNumber.Value);
                    }

                    // Check if this is a "conditional" line breakpoint.
                    if (breakpoint.Condition != null)
                    {
                        ScriptBlock actionScriptBlock =
                            GetBreakpointActionScriptBlock(breakpoint);

                        // If there was a problem with the condition string,
                        // move onto the next breakpoint.
                        if (actionScriptBlock == null)
                        {
                            resultBreakpointDetails.Add(breakpoint);
                            continue;
                        }

                        psCommand.AddParameter("Action", actionScriptBlock);
                    }

                    IEnumerable <Breakpoint> configuredBreakpoints =
                        await this.powerShellContext.ExecuteCommand <Breakpoint>(psCommand);

                    // The order in which the breakpoints are returned is significant to the
                    // VSCode client and should match the order in which they are passed in.
                    resultBreakpointDetails.AddRange(
                        configuredBreakpoints.Select(BreakpointDetails.Create));
                }
            }

            return(resultBreakpointDetails.ToArray());
        }
예제 #23
0
        /// <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="powerShellContext">
        /// The PowerShellContext to use for gathering completions.
        /// </param>
        /// <param name="logger">An ILogger implementation used for writing log messages.</param>
        /// <param name="cancellationToken">
        /// A CancellationToken to cancel completion requests.
        /// </param>
        /// <returns>
        /// A CommandCompletion instance that contains completions for the
        /// symbol at the given offset.
        /// </returns>
        static public async Task <CommandCompletion> GetCompletions(
            Ast scriptAst,
            Token[] currentTokens,
            int fileOffset,
            PowerShellContext powerShellContext,
            ILogger logger,
            CancellationToken cancellationToken)
        {
            var type   = scriptAst.Extent.StartScriptPosition.GetType();
            var method =
#if CoreCLR
                type.GetMethod(
                    "CloneWithNewOffset",
                    BindingFlags.Instance | BindingFlags.NonPublic);
#else
                type.GetMethod(
                    "CloneWithNewOffset",
                    BindingFlags.Instance | BindingFlags.NonPublic,
                    null,
                    new[] { typeof(int) }, null);
#endif

            IScriptPosition cursorPosition =
                (IScriptPosition)method.Invoke(
                    scriptAst.Extent.StartScriptPosition,
                    new object[] { fileOffset });

            logger.Write(
                LogLevel.Verbose,
                string.Format(
                    "Getting completions at offset {0} (line: {1}, column: {2})",
                    fileOffset,
                    cursorPosition.LineNumber,
                    cursorPosition.ColumnNumber));

            CommandCompletion commandCompletion = null;
            if (powerShellContext.IsDebuggerStopped)
            {
                PSCommand command = new PSCommand();
                command.AddCommand("TabExpansion2");
                command.AddParameter("Ast", scriptAst);
                command.AddParameter("Tokens", currentTokens);
                command.AddParameter("PositionOfCursor", cursorPosition);
                command.AddParameter("Options", null);

                PSObject outputObject =
                    (await powerShellContext.ExecuteCommand <PSObject>(command, false, false))
                    .FirstOrDefault();

                if (outputObject != null)
                {
                    ErrorRecord errorRecord = outputObject.BaseObject as ErrorRecord;
                    if (errorRecord != null)
                    {
                        logger.WriteException(
                            "Encountered an error while invoking TabExpansion2 in the debugger",
                            errorRecord.Exception);
                    }
                    else
                    {
                        commandCompletion = outputObject.BaseObject as CommandCompletion;
                    }
                }
            }
            else if (powerShellContext.CurrentRunspace.Runspace.RunspaceAvailability ==
                     RunspaceAvailability.Available)
            {
                using (RunspaceHandle runspaceHandle = await powerShellContext.GetRunspaceHandle(cancellationToken))
                    using (PowerShell powerShell = PowerShell.Create())
                    {
                        powerShell.Runspace = runspaceHandle.Runspace;

                        Stopwatch stopwatch = new Stopwatch();
                        stopwatch.Start();

                        commandCompletion =
                            CommandCompletion.CompleteInput(
                                scriptAst,
                                currentTokens,
                                cursorPosition,
                                null,
                                powerShell);

                        stopwatch.Stop();

                        logger.Write(LogLevel.Verbose, $"IntelliSense completed in {stopwatch.ElapsedMilliseconds}ms.");
                    }
            }

            return(commandCompletion);
        }
예제 #24
0
 /// <summary>
 /// Initializes a new instance of the RunspaceHandle class using the
 /// given runspace.
 /// </summary>
 /// <param name="powerShellContext">The PowerShellContext instance which manages the runspace.</param>
 public RunspaceHandle(PowerShellContext powerShellContext)
 {
     this.powerShellContext = powerShellContext;
 }