Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: Add ability to load snippets from file or directory #4

Open
iilyak opened this issue Feb 17, 2022 · 9 comments · May be fixed by #8
Open

feature: Add ability to load snippets from file or directory #4

iilyak opened this issue Feb 17, 2022 · 9 comments · May be fixed by #8

Comments

@iilyak
Copy link

iilyak commented Feb 17, 2022

The https://github.com/asbjornh/vscode-module-templates extension supports loading templates from files using separate configuration field module-templates.templateFiles.

This extension could use similar approach as well. For example

"betterSnippets.customSnippets": [
        {
            "name": "foo",
            "snippetFile"

However ideally the configuration like follows would be perfect for my use case.

"betterSnippets.snippetsDir": [
    "./snippets"
]

cat ./snippets/cdb-debug.erl

---
name: cdb-debug
when:
  languages:
  - erlang
  locations:
  - fileStart
---
% Licensed under the Apache License, Version 2.0 (the "License"); you may not
% use this file except in compliance with the License. You may obtain a copy of
% the License at
%
%   http://www.apache.org/licenses/LICENSE-2.0
%
% Unless required by applicable law or agreed to in writing, software
% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
% License for the specific language governing permissions and limitations under
% the License.

-module(${TM_FILENAME_BASE}).

-export([
    help/0,
    help/1
]).

-export([
]).

help() ->
    [
        %% list of provided commands
        ${1:opened_files}
    ].

-spec help(Function :: atom()) -> ok.
%% erlfmt-ignore
help(${1:opened_files}) ->
    io:format("
    ${1:opened_files}
    --------------

    Returns ${2:[]}
    ---
    ", []);
help(Unknown) ->
    io:format("Unknown function: `~p`. Please try one of the following:~n", [Unknown]),
    [io:format("    - ~s~n", [Function]) || Function <- help()],
    io:format("    ---~n", []),
    ok.

-spec ${1:opened_files}() ->
    ${3:[]}.

${1:opened_files}() ->
    ${4:[]}.

As you can see all configuration is contained in the frontmatter of the snippet file.

@iilyak
Copy link
Author

iilyak commented Feb 17, 2022

JFYI the frontmatter based approach is implemented in Foam extension for markdown templates https://foambubble.github.io/foam/features/note-templates.

@zardoy
Copy link
Owner

zardoy commented Feb 17, 2022

Hey! Thank you so much for reporting this issue!

First of all, it would be possible soon to define snippets at workspace level (in .vscode/settings.json).

However, your idea would be extremely useful in cases when snippets are large or you want to track them in individual files.

Do we have some cross-IDE standard? Any extensions from other IDEs that implements something like this?


I think to implement this setting with the following default: ['.better-snippets'] (just like foam do). Ideas about default folder name are welcome!

Also about frontmatter. It is okay to use it in Markdown files, however, for other languages it would be much better to define metadata in comments at the start of file. For example we can have file .better-snippets/cdb-debug.erl:

% .snippet
% locations: fileStart

% Licensed under the Apache License, Version 2.0 (the "License"); you may not
% ...

Empty line is required as it used to denote end of metadata.

Also we can skip definining name and languages as they both can be derived from the file name.

It is much better to define metadata in comments, so we don't break:

  1. Syntax highlighting (especially important for github.com and other IDEs)
  2. Language server type-checking (e.g. important for TypeScript files)

Also, you can expect web support!

@zardoy
Copy link
Owner

zardoy commented Feb 17, 2022

"betterSnippets.customSnippets": [
    {
        "name": "foo",
        "snippetFile": "..."

This case won't be supported as this would make sense only in workspace-level configuration.

In case above and in betterSnippets.snippetsDir paths should not be absolute as in this case you lose:

  • benefit from settings sync
  • web support

That's why global snippets should always be defined in VSCode's settings.json. I'll make a sidebar panel for convenient snippet editing (each snippet you could edit in individual tab).

@iilyak
Copy link
Author

iilyak commented Feb 17, 2022

Do we have some cross-IDE standard? Any extensions from other IDEs that implements something like this?

I am not aware of cross-IDE standards.

Also about frontmatter. It is okay to use it in Markdown files, however, for other languages it would be much better to define metadata in comments at the start of file.

I thought the better-snippets extension would read a file. Split the file in two parts: metadata from frontmatter and snippet body. It would use snippet body and inject it into the currently opened file. The expanded result wouldn't have frontmatter and therefore language independent.

However I do agree the syntax highlighting would be broken.

@iilyak
Copy link
Author

iilyak commented Feb 17, 2022

That's why global snippets should always be defined in VSCode's settings.json. I'll make a sidebar panel for convenient snippet editing (each snippet you could edit in individual tab).

Would it be possible to have a project specific snippets? For example by checking existence of .vscode/.better_snippets directory? It would be nice if additional directories could be configured:

cat .vscode/settings.json
{
    "betterSnippets.snippetsDirs": [
        "../snippets/erlang",
        "../snippets/elixir",
        "../snippets/docs"
   ]
}

By default the "betterSnippets.snippetsDirs" would be ["./.better-snippets"].

@zardoy
Copy link
Owner

zardoy commented Feb 17, 2022

However I do agree the syntax highlighting would be broken.

Yes, that's why metadata will live in comments for now. As you said the file split in two parts: metadata and body.

Metadata is commented.
Body goes as is, but with snippet variables support.
Emptyline will be delimiter.
Look at example with .better-snippets/cdb-debug.erl from above (#4 (comment))

Would it be possible to have a project specific snippets?

Yes, it would be supported with this setting.

By default the "betterSnippets.snippetsDirs" would be ["./.better-snippets"].

Great! This will be configurable!

@iilyak
Copy link
Author

iilyak commented Feb 17, 2022

Yes, that's why metadata will live in comments for now. As you said the file split in two parts: metadata and body.

There is one problem with using comments. Most IDE use shebang presence to figure out which syntax to enable if file extension is not reliable. Which is the case for shell scripts. The shebang should be in the first line for this detection to work.

@zardoy
Copy link
Owner

zardoy commented Feb 19, 2022

Sorry for delayed response. I just started implementing this feature.

The shebang should be in the first line for this detection to work.

I see only two solutions:

  • let user define snippet metadata at any line of the file. For example:
#!/usr/bin/env bash

# .snippet
# locations: fileStart

if [[ "$OSTYPE" == "darwin"* ]]; then
# ...

The body of the snippet would look like:

#!/usr/bin/env bash

if [[ "$OSTYPE" == "darwin"* ]]; then
# ...

However, I don't like the ambiguity it introduces. For example snippet can have > 100 lines and since snippet metadata can be placed at any line, programmer can spend some time to find it. It can be just annoying.


  • Second solution would be to let define snippet in separate file. For example we have the same .better-snippets/cdb-debug.erl but with body only:
% ...
% License for the specific language governing permissions and limitations under
% the License.

-module(${TM_FILENAME_BASE}).
...

And second file .better-snippets/cdb-debug.snippet.json:

{
    "locations": ["fileStart"]
}

Supported formats would be: json, yaml, js. The last one would allow to run aribtrary code and will be disabled in trusted workspaces. I'm also thinking about support for toml and ts formats.

I more like the second solution and I'm currently planning to implement only it. WDYT?

@zardoy zardoy linked a pull request Feb 20, 2022 that will close this issue
6 tasks
@iilyak
Copy link
Author

iilyak commented Feb 22, 2022

second file .better-snippets/cdb-debug.snippet.json would work for my use case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants