Skip to content

Add completion script for Visual Studio Code#24

Closed
Mellbourn wants to merge 6 commits intozsh-users:masterfrom
Mellbourn:completion-for-visual-studio-code
Closed

Add completion script for Visual Studio Code#24
Mellbourn wants to merge 6 commits intozsh-users:masterfrom
Mellbourn:completion-for-visual-studio-code

Conversation

@Mellbourn
Copy link
Contributor

@Mellbourn Mellbourn commented Apr 5, 2018

This script adds command line completion for the code command, which is used to start Visual Studio Code (https://code.visualstudio.com/). Code is ranked the most popular developer environment in the Stack Overflow Developer Survey 2018, so I think there is a strong case for including completion functionality directly in zsh.

This implementation gives completion for all documented parameters and has specialized completion for parameters that don't take filenames as parameters, for example --add only takes directories as arguments.
I have tested that it works well on macOS and Windows Subsystem for Linux (Ubuntu).

I suggested this script to the maintainers of Visual Studio Code, but they felt it was out of scope of the product itself, and suggested I provide the script externally (microsoft/vscode#47101). So it would be great if it could be added directly to zsh instead.

I have also submitted this completion script to the zsh-completions repository, but it was pointed out to me that it could be a better idea to have the completion directly in zsh. So if you accept this pull request, I can withdraw the pull request from zsh-completions, since it will be redundant there.

@danielshahaf
Copy link
Member

In --level and --locale, I suggest to move the example/default values to after the first colon.

In the helper function, ${${(f)"$(locale -a)"}%%.*} should be faster and split on newlines only (per POSIX). I think it would fit better as Type/_locales, though—doesn't that exist already?

Excuse brevity (touch keyboard).

Copy link
Member

@okapia okapia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. This looks good. I've added some comments on some fairly trivial things.

local -a locales
locales=($(locale -a | sed -e 's/\..*$//'))
_describe 'locale' locales
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is an _locales function already but it appears that code does its own thing. To get German, using de_DE doesn't work but de-DE does.

I can get an accurate list with:
/usr/share/code/resources/app/out/vs/code/node/cli.nls.*.js(:r:t:s/cli.nls.//)

It might even be better to simply list the current 9 possible locales.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. I hard coded the list of actual possibilities. That makes the list straightforward, and more accurate.


arguments=(
{-d,--diff}'[compare two files with each other]:file to compare:_files:file to compare with:_files'
{-a,--add}'[add folder(s) to the last active window]:folder:_directories'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The term "folder(s)" indicates that more than one directory can be specified. It appears that to do this, you need to specify -a more than once. By default, zsh excludes options that have already been used so we need a * at the start of the spec. So I'd suggest something like:

\*{-a,--add}'[add folder to the last active window]:folder:_directories'

Actually, I would also ditch the modern Windows term "folder" and stick with the traditional Unix term "directory", though that is less important.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I have added the asterisk. I changed to directory/directories. Wasn’t totally sure about how to handle the “(ies)” part. I chose “directory (or directories)”. Feel free to suggest a better wording.

{-a,--add}'[add folder(s) to the last active window]:folder:_directories'
{-g,--goto}'[open a file at the path on the specified]'
{-n,--new-window}'[force to open a new window]'
{-r,--reuse-window}'[force to open a file or folder in the last active window]'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these last two options mutually exclusive. If so, we can indicate to zsh that only one should be used. It is also usually the case that long and short option forms are mutually exclusive of each other. Furthermore, the English in these descriptions is not great. I know it comes from code's --help output but the word "force" when used as a verb like this should have an object. So, I'd suggest something like:

'(-n --new-window -r --reuse-window)'{-n,--new-window}'[open a new window]'

And similarly for -r.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I followed your advice regarding -r and -n. I have also made all long and short arguments exclusive

'--uninstall-extension[uninstalls an extension]:id or path:_files -g "*.vsix"'
'--enable-proposed-api[enables proposed api features for an extension]:extension id:'
'--verbose[print verbose output (implies --wait)]'
'--log[log level to use. Default is info]:level:(critical error warn info debug trace off)'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Usual zsh completion way to indicate defaults is with square brackets in the argument description. That ensures it is on screen when you need it, e.g:

'--log[specify log level to use]:level [info]:(critical error warn info debug trace off)'

I also add the word "specify" to the start of the description which is very common. In most cases, the first word of per-match descriptions will be a verb.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, changed the defaults to be in square brackets. Added "specify"

{-r,--reuse-window}'[force to open a file or folder in the last active window]'
{-w,--wait}'[wait for the files to be closed before]'
'--locale[the locale to use (e.g. en-US or zh-TW)]:locale:__code_locales'
'--user-data-dir[specifies the directory that user data is in]:directory:_directories'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd change the verb "specifies" to "specify". Similarly later, I'd change enables to enable, uploads to upload and (un)installs to (un)install. It is more consistent to use the same form for the verbs in descriptions and you have "print", "set" and "list" elsewhere. Usual zsh convention is this short verb form.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed lots of verb cases and used “specify” more

'--inspect-brk-extensions[allow debugging and profiling of extensions with the extension host being paused after start]'
'--disable-gpu[disable GPU hardware acceleration]'
'--upload-logs[uploads logs from current session to a secure endpoint]'
'--max-memory[max memory size for a window]:size (in Mbytes):'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

units in parentheses is a common convention anyway, the word "in" isn't needed.
Perhaps start the other description with "specify ", though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed “in”

'*:filename:_files'
)

_arguments $arguments
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can pass -s and -S to _arguments - short forms like -wn for -w -n are allowed and no options are allowed after --. So this can be:
_arguments -s -S $arguments

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added parameters. I had no idea about the -- trick.

Thank you for all your comments!
I made some further improvements:

  • --upload-logs can now complete the confirmation.
  • Corrected --wait description
  • Made it easier to end --goto parameter with a colon
  • Added an optional = to some options that can accept it (unclear to me exactly which do, but it is not all)

Please let me know if I got something wrong or there is anything else I should improve.

Make locales a fixed list
Allow multiple --add
Make exclusive arguments exclusive
Improve wording using "specify"
Improve word case
Add -s and -S
Add --upload-logs completion
Correct --wait description
Add optional "=" to commands thatn can accept it
Make it easier to end --goto parameter with a colon

arguments=(
'(-d --diff)'{-d,--diff}'[compare two files with each other]:file to compare:_files:file to compare with:_files'
'(-a --add)'\*{-a,--add}'[add specified directory (or directories) to the last active window.]:directory:_directories'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't want the (-a --add) exclusion as well as *.
The * prevents -a excluding -a (i.e. itself) which it does by default. The option can be repeated so you can mix -a and --add. So no exclusion is needed.

I wouldn't bother with the "(or directories)". The fact that the option can be repeated conveys the information that more than one directory can be added. Admittedly, _arguments doesn't make that as obvious as it might in completion listings but it'd be better to try to make it do so for all completions than to use convoluted wording in each one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. Removed (-a --add) exclusion and redundant pluralization.

arguments=(
'(-d --diff)'{-d,--diff}'[compare two files with each other]:file to compare:_files:file to compare with:_files'
'(-a --add)'\*{-a,--add}'[add specified directory (or directories) to the last active window.]:directory:_directories'
'(-g --goto)'{-g,--goto}'[open a file at the path on the specified line and character position]:file\:line[\:character]:_files -r \:'
Copy link
Member

@okapia okapia Apr 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unlike earlier, I don't have VS code available to check but I wouldn't be surprised if the -g option can also be repeated. Could be worth checking.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope. When I test, it seems to ignore the second -g

'--locale=[specify the locale to use]:locale (e.g. en-US or zh-TW):(de en en-US es fr it ja ko ru zh-CN zh-TW bg hu pt-br tr)'
'--user-data-dir[specify the directory that user data is in]:directory:_directories'
'(-v --version)'{-v,--version}'[print version]'
'(-h --help)'{-h,--help}'[print usage]'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't verify with code at the moment but it is common for options like -h and -V to not be applicable in combination with any other options. In which case the exclusion list can be just (- *)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Set exclusion list to (- *)

Maybe the obverse should be done too:
If any parameters have been added, disallow -v and -h?

'--list-extensions[list the installed extensions]'
'--show-versions[show versions of installed extensions, when using --list-extension]'
'--install-extension[specify extension to install]:id or path:_files -g "*.vsix"'
'--uninstall-extension[specify extension to uninstall]:id or path:_files -g "*.vsix"'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a very pedantic point but in completion, it is common to use the glob qualifier (-.) with _files -g.
So _files -g "*.vsix(-.)"
That only matters if you have something like a directory named with the extension.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Thanks again for your comments!

Copy link
Member

@okapia okapia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sourceforge's git seems to be broken at the moment otherwise I'd have probably tweaked this and pushed. So anyway, here's a couple more comments on the update. Again all fairly minor but it'd be good to get this done and the function can make it in before 5.5 gets released.

Maybe the obverse should be done too:
If any parameters have been added, disallow -v and -h?
Remove -a --add exclusion and redundant pluralization
Use the glob qualifier (-.) with _files -g
These additional display languages are on the VS Code Marketplace
@okapia
Copy link
Member

okapia commented Apr 7, 2018

Merged in 5e10acc

Thanks for the contribution and for your patience with the petty comments.

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 this pull request may close these issues.

3 participants