PowerShell / PowerShellEditorServices

A common platform for PowerShell development support in any editor or application!
MIT License
634 stars 217 forks source link

Can you provide an example of the intellisense of the avalonedit and PowerShell Editor? #1017

Closed tylike closed 5 years ago

tylike commented 5 years ago

hi, I want to use avalonedit and PowerShellEditor Services to implement the intellisense function, It looks like I need to call the ScriptFile.ApplyChange method, but I don't know how to do, can you provide a small example?

using ICSharpCode.AvalonEdit;
using ICSharpCode.AvalonEdit.CodeCompletion;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.AvalonEdit.Folding;
using ICSharpCode.AvalonEdit.Highlighting;
using Microsoft.PowerShell.EditorServices;
using System;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Management.Automation;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Media;
using System.Xml;

namespace PowerShellEditor
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            path = @"E:\test.ps1";
            this.context = new PowerShellContext();
            this.workspace = new Workspace(this.context.PowerShellVersion);
            this.language = new LanguageService(this.context);
            file = workspace.GetFile(path);

            CreateEditor();
            Editor.Text = File.ReadAllText(path);
        }
        string path;
        PowerShellContext context;
        Workspace workspace;
        LanguageService language;
        ScriptFile file;
        public TextEditor Editor { get; set; }
        private void CreateEditor()
        {
            Editor = new TextEditor();

            Editor.TextArea.TextEntering += TextArea_TextEntering;
            Editor.TextArea.TextEntered += TextArea_TextEntered;
            Editor.ShowLineNumbers = true;

            Editor.FontFamily = new System.Windows.Media.FontFamily("Consolas");
            Editor.FontSize = 12;
            //Editor.SyntaxHighlighting.MainRuleSet.Rules

            Editor.TextArea.IndentationStrategy =
                new ICSharpCode.AvalonEdit.Indentation.CSharp.CSharpIndentationStrategy(Editor.Options);
            var foldingManager = FoldingManager.Install(Editor.TextArea);
            var foldingStrategy = new BraceFoldingStrategy();

            this.elementHost1.Child = Editor;
        }

        private string SetStatusBarText()
        {
            return "行:" + Editor.TextArea.Caret.Position.Line + " 列:" + Editor.TextArea.Caret.Position.Column;
        }

        private void TextArea_TextEntered(object sender, TextCompositionEventArgs e)
        {
            Debug.WriteLine("TextArea_TextEntered:" + e.Text);

            if (completionWindow == null)                
            {
                FileChange fc = new FileChange();
                //Here need call ApplyChange?
                file.ApplyChange(fc);
                // Open code completion after the user has pressed dot:
                completionWindow = new CompletionWindow(Editor.TextArea);
                completionWindow.Width = 300;
                var data = completionWindow.CompletionList.CompletionData;

                var list = language.GetCompletionsInFile(file, Editor.TextArea.Caret.Line, Editor.TextArea.Caret.Column).Result.Completions;

                foreach (var x in list.Select(x => new CompletionData(x.CompletionText, null, x.ToolTipText, x.CompletionType)))
                {
                    data.Add(x);
                }

                completionWindow.Show();
                completionWindow.Closed += delegate
                {
                    completionWindow = null;
                };
            }

            if (e.Text == "\n")
            {
                //this.Validated();
                this.OnValueChanged?.Invoke(this, null);
            }
        }

        private void TextArea_TextEntering(object sender, TextCompositionEventArgs e)
        {
            Debug.WriteLine("TextArea_TextEntering:" + e.Text);
            if (e.Text.Length > 0 && completionWindow != null)
            {
                if (!char.IsLetterOrDigit(e.Text[0]))
                {
                    completionWindow.CompletionList.RequestInsertion(e);
                }
            }
        }
        public event EventHandler OnValueChanged;
        CompletionWindow completionWindow;
    }

    public class CompletionData : ICompletionData
    {
        public CompletionType TokenType { get; set; }
        public CompletionData(string text, ImageSource bmp, string description, CompletionType tokenType)
        {
            this.Text = text;
            this.Image = bmp;
            this.Description = description;
            this.TokenType = tokenType;
        }

        public ImageSource Image
        {
            get;
        }

        public string Text { get; private set; }

        // Use this property if you want to show a fancy UIElement in the list.
        public object Content
        {
            get { return this.Text; }
        }

        public object Description { get; }

        public double Priority
        {
            get { return 1; }
        }

        public void Complete(TextArea textArea, ISegment completionSegment, EventArgs insertionRequestEventArgs)
        {
            textArea.Document.Replace(completionSegment, this.Text);
        }
    }

}

thank you!

TylerLeonhardt commented 5 years ago

@tylike does AvalonEdit support the language server protocol?

If so, I can give you an example - however we start PowerShell Editor Services from within a PowerShell session.

If not, then I would recommend using the PowerShell SDK or the Windows PowerShell reference assemblies to run the .NET API to complete input using the PowerShell engine. Here's how we do it in PowerShell Editor Services:

https://github.com/PowerShell/PowerShellEditorServices/blob/93587095ae957a634515ab4d4f8665f21a0fa9aa/src/PowerShellEditorServices/Language/AstOperations.cs#L99-L117

rjmholt commented 5 years ago

Yeah, ScriptFile.ApplyChange doesn't provide completions -- it changes the backend representation of the file being edited. Completions are handled elsewhere, but our project isn't going to be much use to you there; it's really geared to use the language server protocol, and if you don't use that I think you're going to have a lot of trouble getting good reuse out of it.

Instead, if the editor you're writing this for doesn't support the language server protocol, I'd recommend something like the PowerShell SDK's completions API.

tylike commented 5 years ago

Thank you very much, this is very helpful to me!