WrapCommand
A Command Wrapper providing an unified and easy to use interface regarding variable expansion.
Details
Installs
- Total 780
- Win 433
- Mac 228
- Linux 119
Nov 21 | Nov 20 | Nov 19 | Nov 18 | Nov 17 | Nov 16 | Nov 15 | Nov 14 | Nov 13 | Nov 12 | Nov 11 | Nov 10 | Nov 9 | Nov 8 | Nov 7 | Nov 6 | Nov 5 | Nov 4 | Nov 3 | Nov 2 | Nov 1 | Oct 31 | Oct 30 | Oct 29 | Oct 28 | Oct 27 | Oct 26 | Oct 25 | Oct 24 | Oct 23 | Oct 22 | Oct 21 | Oct 20 | Oct 19 | Oct 18 | Oct 17 | Oct 16 | Oct 15 | Oct 14 | Oct 13 | Oct 12 | Oct 11 | Oct 10 | Oct 9 | Oct 8 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Windows | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Mac | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Linux | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Readme
- Source
- bitbucket.org
Wrap Command
A Command Wrapper for providing an unified easy to use and powerful interface for Sublime Text 2 and Sublime Text 3 commands.
Example:
{ "command": "wrap_command", "args": { "command": "open_file": "args": {"file": "${input:File to open}"} } }
This will prompt user for input and then runs command open_file.
Motivation
While trying to setup build systems and configuring packages, I noticed that there are more or less powerful opportunities to specify arguments, depending on the package.
For example, I tried to setup a build system for a django app collection, where the build system runs the test:
manage.py test <APPLICATION NAME>
But this was only partly possible:
{ "selector": "source.python", "cmd": ["python", "manage.py", "test", "${file_path/.*[\\/\\\\]//}" ], "file_regex": "^[ ]*File \"(...*?)\", line ([0-9]*)", "working_dir": "${project_path:}/webapps" }
Problem is that this works only for files at application's root folder.
Solution
I created a new package WrapCommand providing command wrap_command. Problem above would be solved like this:
{ "selector": "source.python", // we wrap the default "exec" target with with "wrap_command" "target": "wrap_command", "wrap_command": "exec", // make sure we have wanted evaluation order "order": ["f", "django_site", "django_app"], // get normed filename "f": "${n:$file_path}", // get normed django-site (folder where manage..py is located) "django_site": "${n:${d:${back:$f;manage.py}}}", // extract django app name from filename "django_app": "${s:${django_site}/([^/]+).*;$1;$f}", "args": { "cmd": ["python", "manage.py", "test", "${django_app}"] "working_dir": "${django_site}", } "file_regex": "^[ ]*File \"(...*?)\", line ([0-9]*)" "name": "Run" }
I have to admit that it does not look nice, but it does the job. You will find output on console useful, while setting up such patterns.
I mostly do not use Build Systems, but rather commands in SublimeREPL, for easy debugging:
{ "command": "wrap_command", "caption": ":django manage test", "args": { "wrap_command": "repl_open", "order": ["f", "django_site", "django_app"], "f": "${n:$file_path}", "django_site": "${n:${d:${back:$f;manage.py}}}", "django_app": "${s:${django_site}/([^/]+).*;$1;$f}", "args": { "type": "subprocess", "encoding": "utf8", "cmd": ["python", "-i", "-u", "manage.py", "test", "${django_app}"], "cwd": "${django_site}", "syntax": "Packages/Python/Python.tmLanguage", "external_id": "python", "extend_env": {"PYTHONIOENCODING": "utf-8"} } } }
Settings
WrapCommand interpretes following settings:
Name | Type | Default | Description |
---|---|---|---|
wrap_command_debug | boolean | false | toggle debug logging to console helpfull to trace expansions. |
Options
- select
Select an argument set:
{ "select": "${ext:$file_name}" "foo": { "wrap_command": "echo", ... } "bar": { "wrap_command": "echo", ... } }
Please note, that first all arguments will be evaluated and only right before calling the command, the selection will be applied. You may override the wrap_command parameter in selected arguments.
Default is to select "args".
- wrap_command
- The command to run. This key may also be in arguments section. It will be removed from arguments passed to command to run.
- order
Variables specified in order are evaluated first, in given order.
You may specify the order of argument parsing (or only a part of it). This is useful, if you use named captures, you want to reuse later, or you use other argument's values. In following examples there is a platform independent path separator:
{ "order": ["sep"], // make sure $sep can be used in // other configs like args "sep": "(?:\\\\|/)", // file separator pattern "wrap_command": "exec" "args": { ... } }
- args
- The wrapped command's arguments.
- *
- Any other argument may be used for either name an argument set, which can be selected by select or to predefine a value. Each argument will be available as variable after processing.
Argument Expansion
Variables
First there are supported build system variables as specified in documentation for buildsystems.
$file_path | The directory of the current file, e. g., C:\Files. |
$file | The full path to the current file, e. g., C:\Files\Chapter1.txt. |
$file_name | The name portion of the current file, e. g., Chapter1.txt. |
$file_extension | The extension portion of the current file, e. g., txt. |
$file_base_name | The name only portion of the current file, e. g., Document. |
$packages | The full path to the Packages folder. |
$project | The full path to the current project file. |
$project_path | The directory of the current project file. |
$project_name | The name portion of the current project file. |
$project_extension | The extension portion of the current project file. |
$project_base_name | The name only portion of the current project file. |
Apart from these, there are following more variables available:
$installed_packages | what sublime.installed_packages() returns |
$settings_path | Directory of your Settings directory, where session files reside. |
$session_file | Full path of session file. |
$auto_session_file | Full path of auto session file. |
$session | dictionary of data stored in session |
$auto_session | dictionary of data stored in auto session |
$settings | dictionary of settings |
$project_buildsystems | list of buildsystems |
$project_folders | list of project folders |
$project_settings | dictionary of project settings. |
$env | dictionary of environment |
You probably noticed that there are also complex types available. You can access them like you usually access such data:
$session[dictionary]
will provide the path to your dictionary file, like specified in your settings.
So you can access cmd of first buildsystem of your project:
$project_buildsystems[0][cmd]
All of these values you can also access in ${} notation, which is:
${project_buildsystems[0][cmd]}
If a variable does not exist, you can provide a default:
${project_buildsystems[0][cmd]:Default}
Shortcuts
There are some shortcuts for easier Access:
$PB | $project_buildsystems |
$PS | $project_settings |
$PF | $project_folders |
$S | $settings |
Anonymous Regex Captures
All variables $0, $1, $2, ..., $9 are automatically expanded to \\1, \\2, etc., for having more convenient capture parameters. So instead:
{ "foo": "${s:f(oo);\\\\1}" }
You can write:
{ "foo": "${s:f(oo);$1}" }
List Interpolation
In commands you often are more interested in a list of values than only at a single string:
{ "cmd": [ "echo", "${project_folders}" ] }
Will expand to:
{ "cmd": [ "echo", "folder1/foo;folder2/bar" ] }
This is maybe not what you want. Consider list interpolation sigil "@":
{ "cmd": [ "echo", "@{project_folders}" ] }
In context of a list, this will expand to:
{ "cmd": [ "echo", "folder1/foo", "folder2/bar" ]}
Functions
Apart from variables, you can also evaluate little functions on these Variables. There may be more useful functions, but these shall be enough for now.
- basename, base, b
Get the basename of a file. Please note that here the extension of the file is included:
${b:foo/bar.txt} -> bar.txt
- Arguments:
- path of a file
- count
Count variables of a list or characters of a string:
${count:a;b;c} -> 3
- Argunents:
- any
- dirname, dir, d
Get directory part of a filename:
${d:foo/bar.txt} -> foo
- Arguments:
- path of a file
- escape, esc, e
Escape the given value (or values) for further processing. (";" and "" are escaped, such that you can use it further as arguments). This is useful for e.g. map function.
${e:foo;bar} -> foo;bar- Arguments:
- any
- Returns:
- string
- exists
Test if given file exists:
${exists:$packages/WrapCommand} -> true ${exists:does/not/exist} ->
If something does not exist, an empty string is returned.
- Arguments:
- path of file
- extension, ext
Return file's extension:
${ext:foo/bar.txt} -> txt
- Arguments:
- path of file
- filter
Filter some elements out of a list:
${filter:oo;foo;gloo;fue;glue} -> foo;gloo
- Arguments:
- pattern
- list to filter
- find
Return a list of files whose path match a regular expression:
${find:$packages;\\.sublime-commands$} -> sublime command files
Resulting list contains file paths relative to given root.
- Arguments:
- root where to start search
- pattern
- find_back, back
Return a list of files whose path match a regular expression. Difference to find is that the search is done backwards in path. It will be returned the first non-empty set of files in a parent directory.
Resulting list contains absolute path names.
- Arguments:
- root where to start
- pattern
- has
Check if a variable has an item:
${has:var[item]}
Please note that ${has:$var[item]} is something different.
- Arguments:
- An itemgetter
- if
If the first arguments evaluates to a true (non-empty) value, the second argument is returned, else third argument is returned if given or "":
${if:condition;then;else} -> then ${if:;then;else} -> else
- Arguments:
- Condition
- result for non-empty condition
- result for empty condition
- input, in
Get some user input:
${in:User Prompt} -> Open a user input ${in:User Prompt;default} -> Open a user input
- Arguments:
- caption of input
- default value (optional)
It is not possible to use ${in:foo} in a nested way:
${exists:${input:Filename}} THIS DOES NOT WORK AS EXPECTED, result will be the user's input
- join
Join all parts of list using the first parameter as joining string:
${join: ;first;second;third} -> first second third
- Arguments:
- Joining string
- any other args
- length, len
Return length of string:
${length:foo} -> 3
- Arguments:
- a string
- list
Create a list:
${list:first;second;third} -> Explicitely create a list
- Arguments:
- list items
- map
Map a function to multiple values:
${map:${e:s:/$;;$_};first/;second;third/}
This example will remove trailing slashes, if present. Please note that the first parameter will be evaluated by map for each following parameter, replacing $_ with parameter's value.
The escape function must be used, to have a nice way of writing this, otherwise you had to escape all ";" and "$".
The upper command is actually the same like:
${list:${s:/$;;first/};${s:/$;;second};${s:/$;;third/}}
If your mapping function only takes one parameter, you can omit the escaping:
${map:abspath;$_;first;second;third}
- Arguments:
- map function without "${}" around
- list to map
- match, m
Match a string. If match contains named captures, variable dictionary is updated with these captures for later use:
${m:f(?P<o>oo);foobar} -> foo ${m:f(?P<o>oo);foobar}$o -> foooo
Returns the matched string.
- Arguments:
- pattern
- string to match
- normpath, norm, n
Normalize a path:
${norm:foo//bar} -> foo/bar
- Arguments:
- pattern
- select, select
Open a Quick Panel for a user selection:
${sel:first;second;third} -> Open a panel and user can select between first, second, third ${sel:first\nmore info;second\n;third\nalso more info} -> Open a panel and user can select between first, second, third with displayed more info
- Arguments:
- values displayed in quick panel
It is not possible to use ${sel:foo} in a nested way:
${exists:${sel:Filename}} THIS DOES NOT WORK AS EXPECTED, result will be the user's input
Here the recommended usage for opening either "foo.txt" or "bar.txt":
{ "command": "wrap_command", "args": { "command": "open_file", "args": {"file": "${sel:foo.txt;bar.txt}"} } }
If you have to manipulate result you got from user:
{ "command": "wrap_command", "args": { "command": "open_file", "filename": "${sel:foo.txt;bar.txt}", "args": {"file": "${s:\\.txt;\\.cpp;${filename}}"} } }
- subst, s
Substitute matched patterns with value:
${s:foo;bar;foobar} -> barbar ${s:f(oo);bar\1;foobar} -> baroobar ${s:f(oo);bar$1;foobar} -> baroobar
Please note that in JSON context, you have to escape "\":
{ foo: "${s:f(oo);bar\\1;foobar}" }
- Arguments:
- pattern
- replacement
- string to process
Adding a custom function
In sublime text 2 context, this is pretty easy:
import expander @expander.modifier('my', 'funcs', 'names') def _myfunc(*args): return args
Changes
Added functions for collecting user input.