Tasks
Gram supports ways to spawn (and rerun) commands using its integrated terminal to output the results. These commands can read a limited subset of Gram state (such as a path to the file currently being edited or selected text).
[
{
"label": "Example task",
"command": "for i in {1..5}; do echo \"Hello $i/5\"; sleep 1; done",
//"args": [],
// Env overrides for the command, will be appended to the terminal's environment from the settings.
"env": { "foo": "bar" },
// Current working directory to spawn the command into, defaults to current project root.
//"cwd": "/path/to/working/directory",
// Whether to use a new terminal tab or reuse the existing one to spawn the process, defaults to `false`.
"use_new_terminal": false,
// Whether to allow multiple instances of the same task to be run, or rather wait for the existing ones to finish, defaults to `false`.
"allow_concurrent_runs": false,
// What to do with the terminal pane and tab, after the command was started:
// * `always` — always show the task's pane, and focus the corresponding tab in it (default)
// * `no_focus` — always show the task's pane, add the task's tab in it, but don't focus it
// * `never` — do not alter focus, but still add/reuse the task's tab in its pane
"reveal": "always",
// What to do with the terminal pane and tab, after the command has finished:
// * `never` — Do nothing when the command finishes (default)
// * `always` — always hide the terminal tab, hide the pane also if it was the last tab in it
// * `on_success` — hide the terminal tab on task success only, otherwise behaves similar to `always`
"hide": "never",
// Which shell to use when running a task inside the terminal.
// May take 3 values:
// 1. (default) Use the system's default terminal configuration in /etc/passwd
// "shell": "system"
// 2. A program:
// "shell": {
// "program": "sh"
// }
// 3. A program with arguments:
// "shell": {
// "with_arguments": {
// "program": "/bin/bash",
// "args": ["--login"]
// }
// }
"shell": "system",
// Whether to show the task line in the output of the spawned task, defaults to `true`.
"show_summary": true,
// Whether to show the command line in the output of the spawned task, defaults to `true`.
"show_command": true,
// Which edited buffers to save before running the task:
// * `none` — don't save any buffers (default)
// * `all` — save all edited buffers
// * `current` — save current buffer only
"save": "none",
// Represents the tags for inline runnable indicators, or spawning multiple tasks at once.
// "tags": []
}
]
There are two actions that drive the workflow of using tasks: task: spawn and
task: rerun. task: spawn opens a modal with all available tasks in the
current file. task: rerun reruns the most recently spawned task. You can also
rerun tasks from the task modal.
By default, rerunning tasks reuses the same terminal (due to the
"use_new_terminal": false default) but waits for the previous task to finish
before starting (due to the "allow_concurrent_runs": false default).
Keep "use_new_terminal": false and set "allow_concurrent_runs": true to
allow cancelling previous tasks on rerun.
Task templates
Tasks can be defined:
- in the global
tasks.jsoncfile; such tasks are available in all Gram projects you work on. This file is usually located in~/.config/gram/tasks.json. You can edit them by using thegram: open tasksaction. - in the worktree-specific (local)
.gram/tasks.jsoncfile; such tasks are available only when working on a project with that worktree included. You can edit worktree-specific tasks by using thegram: open project tasksaction. - on the fly with oneshot tasks. These tasks are project-specific and do not persist across sessions.
- by language extension.
Variables
Gram tasks act just like your shell; that also means that you can reference
environmental variables via sh-esque $VAR_NAME syntax. A couple of additional
environmental variables are set for your convenience. These variables allow you
to pull information from the current editor and use it in your tasks. The
following variables are available:
GRAM_COLUMN: current line columnGRAM_ROW: current line rowGRAM_FILE: absolute path of the currently opened file (e.g./Users/my-user/path/to/project/src/main.rs)GRAM_FILENAME: filename of the currently opened file (e.g.main.rs)GRAM_DIRNAME: absolute path of the currently opened file with file name stripped (e.g./Users/my-user/path/to/project/src)GRAM_RELATIVE_FILE: path of the currently opened file, relative toGRAM_WORKTREE_ROOT(e.g.src/main.rs)GRAM_RELATIVE_DIR: path of the currently opened file's directory, relative toGRAM_WORKTREE_ROOT(e.g.src)GRAM_STEM: stem (filename without extension) of the currently opened file (e.g.main)GRAM_SYMBOL: currently selected symbol; should match the last symbol shown in a symbol breadcrumb (e.g.mod tests > fn test_task_contexts)GRAM_SELECTED_TEXT: currently selected textGRAM_WORKTREE_ROOT: absolute path to the root of the current worktree. (e.g./Users/my-user/path/to/project)GRAM_CUSTOM_RUST_PACKAGE: (Rust-specific) name of the parent package of $GRAM_FILE source file.
To use a variable in a task, prefix it with a dollar sign ($):
{
"label": "echo current file's path",
"command": "echo $GRAM_FILE",
}
You can also use verbose syntax that allows specifying a default if a given
variable is not available: ${GRAM_FILE:default_value}
These environmental variables can also be used in tasks' cwd, args, and
label fields.
Variable Quoting
When working with paths containing spaces or other special characters, please ensure variables are properly escaped.
For example, instead of this (which will fail if the path has a space):
{
"label": "stat current file",
"command": "stat $GRAM_FILE",
}
Provide the following:
{
"label": "stat current file",
"command": "stat",
"args": ["$GRAM_FILE"],
}
Or explicitly include escaped quotes like so:
{
"label": "stat current file",
"command": "stat \"$GRAM_FILE\"",
}
Task filtering based on variables
Task definitions with variables which are not present at the moment the task list is determined are filtered out. For example, the following task will appear in the spawn modal only if there is a text selection:
{
"label": "selected text",
"command": "echo \"$GRAM_SELECTED_TEXT\"",
}
Set default values to such variables to have such tasks always displayed:
{
"label": "selected text with default",
"command": "echo \"${GRAM_SELECTED_TEXT:no text selected}\"",
}
Oneshot tasks
The same task modal opened via task: spawn supports arbitrary bash-like
command execution: type a command inside the modal text field, and use
opt-enter to spawn it.
The task modal persists these ad-hoc commands for the duration of the session,
task: rerun will also rerun such tasks if they were the last ones spawned.
You can also adjust the currently selected task in a modal (tab is the default
key binding). Doing so will put its command into a prompt that can then be
edited & spawned as a oneshot task.
Ephemeral tasks
You can use the cmd modifier when spawning a task via a modal; tasks spawned
this way will not have their usage count increased (thus, they will not be
respawned with task: rerun and they won't have a high rank in the task modal).
The intended use of ephemeral tasks is to stay in the flow with continuous
task: rerun usage.
More task rerun control
By default, tasks capture their variables into a context once, and this "resolved task" is being rerun always.
This can be controlled with the "reevaluate_context" argument to the task:
setting it to true will force the task to be reevaluated before each run.
{
"context": "Workspace",
"bindings": {
"alt-t": ["task::Rerun", { "reevaluate_context": true }],
},
}
Custom keybindings for tasks
You can define your own keybindings for your tasks via an additional argument to
task::Spawn. If you wanted to bind the aforementioned
echo current file's path task to alt-g, you would add the following snippet
in your keymap.json file:
{
"context": "Workspace",
"bindings": {
"alt-g": ["task::Spawn", { "task_name": "echo current file's path" }],
},
}
Note that these tasks can also have a 'target' specified to control where the spawned task should show up. This could be useful for launching a terminal application that you want to use in the center area:
// In tasks.jsonc
{
"label": "start lazygit",
"command": "lazygit -p $GRAM_WORKTREE_ROOT"
}
// In keymap.jsonc
{
"context": "Workspace",
"bindings": {
"alt-g": [
"task::Spawn",
{ "task_name": "start lazygit", "reveal_target": "center" },
],
},
}
Binding runnable tags to task templates
Gram supports overriding the default action for inline runnable indicators via
workspace-local and global tasks.jsonc file with the following precedence
hierarchy:
- Workspace
tasks.jsonc - Global
tasks.jsonc - Language-provided tag bindings (default).
To tag a task, add the runnable tag name to the tags field on the task
template:
{
"label": "echo current file's path",
"command": "echo $GRAM_FILE",
"tags": ["rust-test"],
}
In doing so, you can change which task is shown in the runnables indicator.
Keybindings to run tasks bound to runnables
When you have a task definition that is bound to the runnable, you can quickly
run it using Code Actions that you
can trigger either via editor: Toggle Code Actions command or by the
cmd-./ctrl-. shortcut. Your task will be the first in the dropdown. The task
will run immediately if there are no additional Code Actions for this line.