/// <summary>
 /// Clears the menu from the console
 /// </summary>
 /// <param name="notUsed"></param>
 public virtual void ClearMenu(RichCommandLineContext notUsed)
 {
     menuWiper.Wipe();
 }
 /// <summary>
 /// Writes the prompt message and takes over the console until the user makes a selection or cancels via the escape key.  This method
 /// never returns a NoOp result.
 /// </summary>
 /// <param name="parentContext">context about the parent reader that we are assisting </param>
 /// <returns>A selection or cancellation result, never a NoOp</returns>
 public virtual ContextAssistResult DrawMenu(RichCommandLineContext parentContext)
 {
     try
     {
         DoSearchInternal(parentContext, null, true);
         return ContextAssistResult.CreateInsertResult(parentContext, SelectedValue.RichDisplayText);
     }
     catch (OperationCanceledException)
     {
         return ContextAssistResult.Cancel;
     }
 }
 /// <summary>
 /// Always returns true.  When overrided in a derived class the derived class can provide custom logic to determine whether or not this assist provider
 /// can assist.
 /// </summary>
 /// <param name="parentContext">context about the parent reader that we may be assisting </param>
 /// <returns>Always returns true.  When overrided in a derived class the derived class can provide custom logic to determine whether or not this assist provider
 /// can assist.</returns>
 public virtual bool CanAssist(RichCommandLineContext parentContext)
 {
     return true;
 }
 private void _SearchReader_HandleKeyPressed(RichCommandLineContext searchReaderContext)
 {
     if(searchReaderContext.KeyPressed.Key == ConsoleKey.UpArrow || searchReaderContext.KeyPressed.Key == ConsoleKey.DownArrow)
     {
         return;
     }
     else
     {
         DoSearch(searchReaderContext.Buffer.ToNormalString());
     }
 }
 private void _SearchReader_HandleEnterKey(RichCommandLineContext searchReaderContext)
 {
     searchReaderContext.Intercept = true;
     if (latestResults.Count > 0)
     {
         SelectedValue = latestResults[selectedIndex];
         searchReaderContext.IsFinished = true;
     }
 }
        private void DoSearchInternal(RichCommandLineContext parentContext, IConsoleProvider standaloneConsole, bool allowCancel)
        {
            if(parentContext == null && standaloneConsole == null)
            {
                throw new ArgumentException("You must specify either parentContext or standaloneConsole");
            }
            else if(parentContext != null && standaloneConsole != null)
            {
                throw new ArgumentException("You cannot specify both parentContext and standaloneConsole, you must choose one or the other");
            }

            this.parentReaderContext = parentContext;
            this.console = parentContext != null ? parentContext.Console : standaloneConsole;
            this.menuWiper.Console = this.console;
            this.resultsWiper.Console = this.console;
            this.expireableAsyncRequestManager = new ExpireableAsyncRequestManager();
            SelectedValue = null;

            this.menuWiper.SetTopLeftFromConsole();

            if (allowCancel)
            {
                this.console.Write(new ConsoleString("Type to search. Use up/down/enter/escape to navigate/select/cancel: ", ConsoleColor.Cyan));
            }
            else
            {
                this.console.Write(new ConsoleString("Type to search. Use up/down/enter to navigate/select: ", ConsoleColor.Cyan));
            }

            this.resultsWiper.SetTopLeftFromConsole();
            this.resultsWiper.Left = 0;
            this.resultsWiper.Top += 2;

            this.searchReader = new RichTextCommandLineReader() { Console = this.console };
            this.searchReader.UnregisterHandler(ConsoleKey.UpArrow);
            this.searchReader.UnregisterHandler(ConsoleKey.DownArrow);
            this.searchReader.UnregisterHandler(ConsoleKey.Escape);
            this.searchReader.UnregisterHandler(ConsoleKey.Enter);

            this.searchReader.RegisterHandler(KeyHandler.FromAction((searchReaderContext) => { _MoveSelectedIndex(-1); searchReaderContext.Intercept = true; }, ConsoleKey.UpArrow));
            this.searchReader.RegisterHandler(KeyHandler.FromAction((_searchReaderContext) => { _searchReaderContext.Intercept = true; _MoveSelectedIndex(1); }, ConsoleKey.DownArrow));
            this.searchReader.RegisterHandler(KeyHandler.FromAction((searchReaderContext) =>
            {
                searchReaderContext.Intercept = true;
                if (allowCancel)
                {
                    throw new OperationCanceledException();
                }
            }, ConsoleKey.Escape));
            this.searchReader.RegisterHandler(KeyHandler.FromAction((searchReaderContext) => { _SearchReader_HandleEnterKey(searchReaderContext); }, ConsoleKey.Enter));
            this.searchReader.AfterReadKey += (searchReaderContext) => { _SearchReader_HandleKeyPressed(searchReaderContext); };

            try
            {
                this.DoSearch(string.Empty);
                this.searchReader.ReadLine();
            }
            finally
            {
                // This next lione makes sure that we ignore any in flight search calls that come back after we return control of the main
                // thread.  If we didn't do this then the results would get written to the screen even though the search assist code is no
                // longer running.
                this.expireableAsyncRequestManager.ExpireAll();
            }
        }
 /// <summary>
 /// This is not implemented because this assist provider always takes over the console during the draw menu.
 /// </summary>
 /// <param name="parentReaderContext">not implemented</param>
 /// <param name="keyPress">not implemented</param>
 /// <returns>not implemented</returns>
 public virtual ContextAssistResult OnKeyboardInput(RichCommandLineContext parentReaderContext, ConsoleKeyInfo keyPress)
 {
     throw new NotImplementedException();
 }