code icon indicating copy to clipboard operation
code copied to clipboard

Snippets plugin: initial version

Open igordsm opened this issue 2 years ago • 12 comments

Fix #36

I'm proposing an initial version for a Snippets plugin. Basic editing works for placeholders and it's already useful on its own. The following features are implemented.

  • language specific snippets
  • placeholder for tabstops inside the snippet
  • placeholder for cursor after editing all placeholders
  • blocks interactive completion during placeholder editing
  • cancel placeholder editing after 500ms without pressing any key

It does not have (yet) support for default values or variables. I'm opening this PR to get some input on the following decisions:

  • Should we use a format shared by other editors? Sublime and TextMate are very popular and maybe adding support for importing their files directly would be interesting. VScode also has a specific JSON format for snippets and support Sublime and TextMate "snippet language".
  • Should we ship any snippets? Should we update them only when Code releases?
  • Where are snippets stored? I'm currently using XDG_USER_DATA_DIR (or something like that)/code/snippets/snippets.json, but if we ship snippets then this will change.
  • Do we want to support user snippets if we opt for shipping snippets?

A basic version with no snippets shipped and only user snippets supported already works. The snippets.json shows how to create snippets. The only problem with the current code is that it does not maintain indentation, so snippets for code might produce invalid code for some languages. There is relevent a discussion in #1098 that proposes moving part of the indentation plugins to the main code.

igordsm avatar Oct 06 '21 14:10 igordsm

Just a few preliminary code style comments. I'll have a more detailed look later. Probably best not to try and pack too much functionality into one PR. Choosing and inserting a few builtin (Vala) snippets is probably enough for a first step.

jeremypw avatar Oct 06 '21 16:10 jeremypw

@jeremypw Thank you for the quick and extensive review. I'll work on these points as soon as I can.

igordsm avatar Oct 06 '21 16:10 igordsm

I feel like this is ready for review now. A set of vala snippets is shipped with the plugin. You can see it in action below

snippets

Some noteworthy changes:

  1. moved some functions from the preserve indent plugin to Scratch.Utils. They are probably useful in other plugins/features as well
  2. the timeout to cancel an edition is 1 second
  3. snippets.json is installed to PLUGINDIR/snippets/snippets.json

igordsm avatar Oct 18 '21 23:10 igordsm

Merged master. I'm available to iterate on this, just let me know. We can also talk on slack about it if sync communication is better.

igordsm avatar Oct 28 '21 15:10 igordsm

This is shaping up as a useful addition though -thanks for working on it!

jeremypw avatar Nov 03 '21 19:11 jeremypw

@jeremypw From my poking around it seems like Word Completion does not play well with other completion providers. It seems to assume that it's the only completion provider and invalidates the context when it doesn't have proposals. I can send another PR that "fixes" this before this one is accepted. What do you think about that?

I used standard GtkSourceView widgets. I believe it's expected that the user understands how to use it. Honestly, I was always selecting with the arrows and it took me a while to realize that I could use Alt+2 for the second option. Same for Alt+D for details.

I added details to each snippet, so at least it's easier to know what they will do.

image

igordsm avatar Nov 07 '21 18:11 igordsm

@igordsm Using the builtin SourceCompletion UI is fine for now although it looks rather ugly (to me). More of a problem is how different completion plugins are going to work together. There are potentially three: this one, the existing word-completion plugin and the proposed GVLS plugin. Is there a way of making all these work together or are we going to have to make them mutually exclusive?

jeremypw avatar Nov 10 '21 10:11 jeremypw

I'm working on making the word completion plugin play nice with others. It assumed that it was the only one and did lots of strange things. As soon as I can test it together with snippets I'll send a draft PR. I'm convinced that completions providers can work together without problems.

On Wed, Nov 10, 2021 at 5:31 AM Jeremy Wootten @.***> wrote:

@igordsm https://github.com/igordsm Using the builtin SourceCompletion UI is fine for now although it looks rather ugly (to me). More of a problem is how different completion plugins are going to work together. There are potentially three: this one, the existing word-completion plugin and the proposed GVLS plugin. Is there a way of making all these work together or are we going to have to make them mutually exclusive?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/elementary/code/pull/1113#issuecomment-964997443, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABWCBR5DELZ43B2QYDB5JLULJCWVANCNFSM5FOW33AA . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

-- Igor Montagner http://igormontagner.blogspot.com/

igordsm avatar Nov 10 '21 19:11 igordsm

I'm working on making the word completion plugin play nice with others. It assumed that it was the only one and did lots of strange things. As soon as I can test it together with snippets I'll send a draft PR. I'm convinced that completions providers can work together without problems. On Wed, Nov 10, 2021 at 5:31 AM Jeremy Wootten @.***> wrote: @igordsm https://github.com/igordsm Using the builtin SourceCompletion UI is fine for now although it looks rather ugly (to me). More of a problem is how different completion plugins are going to work together. There are potentially three: this one, the existing word-completion plugin and the proposed GVLS plugin. Is there a way of making all these work together or are we going to have to make them mutually exclusive? — You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub <#1113 (comment)>, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABWCBR5DELZ43B2QYDB5JLULJCWVANCNFSM5FOW33AA . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub. -- Igor Montagner http://igormontagner.blogspot.com/

You should consider that GVls plugin and potentially others use async completion fill, that means you should consider to add proposals and pass false to add_proprosals() when your plugin is still in the works and true when it finish so make the others create its own proposals. Look at GVls's code.

I propose you to add you snippets to GVls so it can provide context snippets as completions using Microsoft LSP specification for snippets. This will help to avoid the problems above.

Also is possible to add a word index in GVls for an specific buffer and provide completion proposals for words, that may is useful and will fix the issue with current plugin requiring to deactivate it.

esodan avatar Nov 21 '21 03:11 esodan

I can't help thinking that we should not get too tied into GVLs at this stage - is it not possible to write a more generalized LSP client plugin that could use any LSP compliant server and keep the server code more at arm's length? I need for one need to find time to do a lot more work on understanding language servers in general and GVLs in particular.

I take the point that we need to consider how to make synchronous and asynchronous completion processes work together at some point. Not sure it should block release of this plugin as we do not have a working VLS plugin implementation yet.

jeremypw avatar Nov 21 '21 12:11 jeremypw

I can't help thinking that we should not get too tied into GVLs at this stage - is it not possible to write a more generalized LSP client plugin that could use any LSP compliant server and keep the server code more at arm's length? I need for one need to find time to do a lot more work on understanding language servers in general and GVLs in particular.

GVls provides a generic LSP client and a Server Manager to easy connect to any out there.

May you want to create a Vala snipped library so I can integrate it into GVls so that will be transparent for you. Your library could be used to write snippets plugins to any Vala editors or any thing out there.

I can help you to create your library if you want, so we can share work and help you to avoid understand how GVls or any other LSP client/server works.

I take the point that we need to consider how to make synchronous and asynchronous completion processes work together at some point. Not sure it should block release of this plugin as we do not have a working VLS plugin implementation yet.

As I've explained before, you should consider add_proprosals() to consider that async work on in the middle you (or both) work to write a snippets library for Vala, so any like GVls can add proposals and avoid conflicts with multiple completion providers.

GVls plugin in working, more integration to code will help to provide generic LSP client, that that is another history.

esodan avatar Nov 26 '21 17:11 esodan

    public class CodeUnit : Object {
        public struct TextUnit {
            int64 start;
            int64 end;
        }

        private ArrayList<TextUnit?> m_text_units;

        public string trigger { get ;set; }
        public string database { get; set; default = "SQL"; }
        public string category { get ;set; default = ""; }
        public string description { get ;set; default = ""; }
        public string text { get; set; default = ""; }
        public ArrayList<TextUnit?> placeholders { get { return m_text_units; }}

        construct {
            m_text_units = new ArrayList<TextUnit?>();
        }
    }

I'm implementing the same thing with GtkSourceView5, I use the class above to represent the snippet.

taozuhong avatar Aug 16 '23 14:08 taozuhong