Stata 19 MP with Zed Editor
Run Stata 19 MP from Zed editor on Linux using task automation — an alternative to the VS Code workflow.
Overview
This guide wires the Zed editor to Stata 19 MP so Ctrl+Enter runs the whole do-file and Shift+Enter runs the current selection in the Stata GUI — the same workflow as the VS Code setup, but with no extension required. Zed passes selected text to tasks as a real environment variable, which sidesteps the shell-interpolation problems that make the VS Code approach heavier.
What This Guide Does NOT Cover
Installation of Stata, desktop integration, file icons, or the Wayland resize fix. Those are all in the VS Code complete guide — Parts 1 through 4 apply identically to Zed.
Prerequisites
Before starting this guide, you must have:
| Requirement | How to verify |
|---|---|
| Stata 19 MP installed | ls /usr/local/stata19/xstata-mp |
| Xorg session (not Wayland) | echo $XDG_SESSION_TYPE → must print x11 |
wmctrl, xdotool, xclip installed | which wmctrl xdotool xclip |
| Zed editor installed | zed --version |
stata_run_do.sh from VS Code guide | which stata_run_do.sh |
~/.local/bin on PATH | echo $PATH should include $HOME/.local/bin (run echo $HOME to confirm your home path) |
If any of these are missing, complete Parts 1–5 of the VS Code complete guide first. The whole-file runner script (stata_run_do.sh) is shared between both editors.
Architecture: How It Works
VS Code approach (for comparison)
VS Code cannot safely pass selected text to a shell script because ${selectedText} is shell-interpolated. The workaround requires:
- The multi-command extension to chain two VS Code actions
- Action 1: Copy selection to clipboard internally
- Action 2: Run a task that reads the clipboard via
xclip
Zed approach (simpler)
Zed sets $ZED_SELECTED_TEXT as a real environment variable before running the task. The script reads this variable — bash never shell-interprets its contents. This means:
- No extension required — Zed handles it natively
- No clipboard manipulation for selection — the text goes directly from Zed to the script via the environment
- Backticks (
`c(os)'), dollar signs ($main), block comments (/* ... */) — all survive intact
The whole-file workflow is identical to VS Code: the script copies do "/path/to/file.do" to the clipboard, focuses Stata, pastes, and presses Enter.
Part 1 — Create the Zed-Specific Runner Scripts
Zed sets $ZED_FILE and $ZED_SELECTED_TEXT as environment variables when running tasks. Both scripts read these directly — no argument passing needed. This avoids all quoting issues with file paths that contain spaces.
Whole-file runner (Zed-specific wrapper)
The shared stata_run_do.sh (used by VS Code) expects the path as a command-line argument. Zed’s task system doesn’t pass arguments reliably for paths with spaces. This wrapper reads $ZED_FILE from the environment instead:
mkdir -p ~/.local/bin
nano ~/.local/bin/stata_run_do_zed.sh
Paste:
#!/usr/bin/env bash
set -euo pipefail
# Wrapper script for Zed - handles $ZED_FILE directly
STATA_BIN="/usr/local/stata19/xstata-mp"
STATA_WMCLASS="Xstata-mp"
EDITOR_WMCLASS="zed"
# Zed sets $ZED_FILE as environment variable
DOFILE="${ZED_FILE:-}"
if [[ -z "$DOFILE" ]]; then
echo "Error: ZED_FILE is not set" >&2
exit 2
fi
# Make path absolute and resolve symlinks
DOFILE="$(readlink -f "$DOFILE")"
# Verify file exists
if [[ ! -f "$DOFILE" ]]; then
echo "Error: File not found: $DOFILE" >&2
exit 1
fi
# Put the Stata do command on clipboard — quoted to preserve spaces
printf 'do "%s"\n' "$DOFILE" | xclip -selection clipboard
# Launch Stata GUI if not already running
if ! wmctrl -x -l | grep -qi "${STATA_WMCLASS}"; then
"${STATA_BIN}" >/dev/null 2>&1 &
for i in {1..50}; do
wmctrl -x -l | grep -qi "${STATA_WMCLASS}" && break
sleep 0.2
done
sleep 4
fi
# Focus Stata, paste and run
wmctrl -xa "${STATA_WMCLASS}"
sleep 0.3
xdotool key --clearmodifiers ctrl+v Return
# Return focus to editor (uncomment below to enable)
# sleep 0.5
# wmctrl -xa "${EDITOR_WMCLASS}"
Make executable:
chmod +x ~/.local/bin/stata_run_do_zed.sh
Selection runner (Zed-specific)
This script reads from $ZED_SELECTED_TEXT instead of the clipboard:
nano ~/.local/bin/stata_run_selection_zed.sh
Paste:
#!/usr/bin/env bash
set -euo pipefail
STATA_BIN="/usr/local/stata19/xstata-mp"
STATA_WMCLASS="Xstata-mp"
EDITOR_WMCLASS="zed"
TMPDO="/tmp/stata_selection_run.do"
if [[ -z "${ZED_SELECTED_TEXT:-}" ]]; then
echo "No text selected in Zed — nothing to run." >&2
exit 1
fi
printf '%s\n' "$ZED_SELECTED_TEXT" > "$TMPDO"
if [[ ! -s "$TMPDO" ]]; then
echo "Temp do-file is empty after write — aborting." >&2
exit 1
fi
if ! wmctrl -x -l | grep -qi "${STATA_WMCLASS}"; then
"${STATA_BIN}" >/dev/null 2>&1 &
for i in {1..50}; do
wmctrl -x -l | grep -qi "${STATA_WMCLASS}" && break
sleep 0.2
done
sleep 4
fi
printf 'do "%s"\n' "$TMPDO" | xclip -selection clipboard
wmctrl -xa "${STATA_WMCLASS}"
sleep 0.3
xdotool key --clearmodifiers ctrl+v Return
# sleep 0.5
# wmctrl -xa "${EDITOR_WMCLASS}"
Make executable:
chmod +x ~/.local/bin/stata_run_selection_zed.sh
Verify both scripts:
which stata_run_do_zed.sh
# Should print: /home/mohsin/.local/bin/stata_run_do_zed.sh
which stata_run_selection_zed.sh
# Should print: /home/mohsin/.local/bin/stata_run_selection_zed.sh
Why printf '%s\n' "$ZED_SELECTED_TEXT" is safe
When bash expands "$ZED_SELECTED_TEXT", it performs a single-pass parameter expansion. The resulting string is treated as literal text — bash does not re-interpret backticks, dollar signs, or any other special characters inside the value. Combined with printf '%s' (which does not process escape sequences in its arguments), this guarantees that every byte of your Stata code reaches the temp file exactly as written.
Part 2 — Create Global Zed Tasks
Zed tasks can be project-local (.zed/tasks.json) or global (~/.config/zed/tasks.json). Global is better here — you want Stata integration in every project.
nano ~/.config/zed/tasks.json
Paste:
[
{
"label": "Run do-file in Stata GUI",
"command": "/home/mohsin/.local/bin/stata_run_do_zed.sh",
"reveal": "never",
"hide": "never",
"use_new_terminal": false,
"allow_concurrent_runs": false,
"save": "current",
"show_summary": false,
"show_command": false
},
{
"label": "Run selection in Stata GUI",
"command": "/home/mohsin/.local/bin/stata_run_selection_zed.sh",
"reveal": "never",
"hide": "never",
"use_new_terminal": false,
"allow_concurrent_runs": false,
"save": "none",
"show_summary": false,
"show_command": false
}
]
Why a Zed-specific wrapper script? Zed sets
$ZED_FILEas an environment variable when running tasks. The wrapper script (stata_run_do_zed.sh) reads this variable directly — no argument passing needed. This avoids all quoting issues with file paths that contain spaces (e.g.,/media/mohsin/bigd/Dropbox/Env CC/Block PEDL-MRG 2024/...). The originalstata_run_do.sh(shared with VS Code) expects the path as a command-line argument, which Zed’s task system doesn’t handle reliably for paths with spaces.
What each setting does
| Setting | Value | Purpose |
|---|---|---|
command | Full script path | Zed-specific wrappers read $ZED_FILE and $ZED_SELECTED_TEXT directly from the environment — no argument passing needed |
reveal | "never" | Do not show Zed’s terminal panel (output goes to Stata GUI) |
save | "current" / "none" | Auto-save current file before whole-file run; skip for selection |
show_summary | false | Suppress task summary line in terminal output |
show_command | false | Suppress command echo in terminal output |
allow_concurrent_runs | false | Wait for previous Stata run to finish before starting another |
Replace
/home/mohsinwith your actual home directory path. Runecho $HOMEin a terminal to get the correct value. The full path is used instead of~because Zed tasks do not always expand the tilde reliably.
Note: The “Run selection in Stata GUI” task uses
$ZED_SELECTED_TEXTimplicitly — Zed sets it as an environment variable that the script reads. It does not appear inargsbecause passing it as an argument would expose it to shell interpretation.
Part 3 — Set Keybindings
nano ~/.config/zed/keymap.json
Paste:
[
{
"context": "Editor && extension == do",
"bindings": {
"ctrl-enter": ["task::Spawn", { "task_name": "Run do-file in Stata GUI" }],
"shift-enter": ["task::Spawn", { "task_name": "Run selection in Stata GUI" }]
}
}
]
What the context does
"context": "Editor && extension == do" means these keybindings are only active when editing a .do file. In all other file types — .tex, .md, .py — Ctrl+Enter and Shift+Enter retain their default Zed behaviour. This scoping is more precise than the VS Code setup, where the keybindings were global.
Daily Usage
| Step | Action |
|---|---|
| 1 | Log in → gear icon → your X11/Xorg session (Cinnamon on Xorg on Mint, Zorin on Xorg on Zorin — Mint defaults to X11) |
| 2 | Open Stata GUI once at the start of your session |
| 3 | Open your .do file in Zed |
| 4 | Ctrl+Enter — runs the entire file in Stata GUI |
| 5 | Select any lines → Shift+Enter — runs selection in Stata GUI |
Tip: For a single line, use Ctrl+L to select the entire line first, then Shift+Enter.
Tip: Leave Stata open for your entire session. The first run after boot may take ~4 seconds while Stata initializes. Every subsequent run is near-instant.
How It Works End to End
Ctrl+Enter (Run Whole File)
Ctrl+Enter pressed in .do file
─→ Zed auto-saves the file (save: "current")
└─→ Zed spawns task: "Run do-file in Stata GUI"
└─→ stata_run_do_zed.sh runs
├─→ Reads $ZED_FILE from environment (no argument passing)
├─→ Puts do "/path/to/file.do" on clipboard
├─→ Launches Stata if not running (waits ~4s)
├─→ Focuses Stata window via wmctrl
├─→ Pastes + Enter via xdotool
└─→ Stata executes the do-file
Shift+Enter (Run Selection)
Shift+Enter pressed with text selected in .do file
└─→ Zed spawns task: "Run selection in Stata GUI"
└─→ stata_run_selection_zed.sh runs
├─→ Reads $ZED_SELECTED_TEXT (environment variable)
│ No clipboard involved — no shell interpretation
├─→ Writes raw bytes to /tmp/stata_selection_run.do
│ Comments Supported
│ Globals ($) Supported
│ Backticks Supported
│ Block comments Supported
│ Macros Supported
├─→ Puts do "/tmp/stata_selection_run.do" on clipboard
├─→ Launches Stata if not running
├─→ Focuses Stata window
├─→ Pastes + Enter
└─→ Stata runs the temp do-file
Running from Terminal or AI Agent
The same stata_run_do.sh script works in all contexts:
# From terminal
stata_run_do.sh /media/mohsin/mmh/Dropbox/Projects/rwh_wp/5_do/Clean/00_run.do
# From AI agent (always use full path — no ~)
/home/mohsin/.local/bin/stata_run_do.sh /media/mohsin/mmh/Dropbox/Projects/rwh_wp/5_do/Clean/00_run.do
Keybinding Reference
| Keybinding | Context | Action |
|---|---|---|
| Ctrl+Enter | .do files only | Run the entire file in Stata GUI |
| Shift+Enter | .do files only | Run the selected text in Stata GUI |
| Ctrl+L | Any editor | Select current line (use before Shift+Enter for a single line) |
| Ctrl+Shift+P | Anywhere | Command palette (search “task” to see/run tasks manually) |
File Locations Reference
| File | Path |
|---|---|
| Stata binary | /usr/local/stata19/xstata-mp |
| Whole-file runner (VS Code) | ~/.local/bin/stata_run_do.sh |
| Whole-file runner (Zed) | ~/.local/bin/stata_run_do_zed.sh |
| Selection runner (VS Code) | ~/.local/bin/stata_run_selection.sh |
| Selection runner (Zed) | ~/.local/bin/stata_run_selection_zed.sh |
| Selection temp do-file | /tmp/stata_selection_run.do |
| Zed global tasks | ~/.config/zed/tasks.json |
| Zed keybindings | ~/.config/zed/keymap.json |
| Zed settings | ~/.config/zed/settings.json |
Differences from VS Code Guide
| Aspect | VS Code | Zed |
|---|---|---|
| Extension required | Yes — ryuta46.multi-command | No — native task variables |
| How selection reaches the script | Clipboard (copy action → xclip reads) | Environment variable ($ZED_SELECTED_TEXT) |
| Keybinding scope | Global (all file types) | Scoped to .do files via extension == do |
| Config files | .vscode/tasks.json + keybindings.json + settings.json | tasks.json + keymap.json (both in ~/.config/zed/) |
| Task output visibility | Terminal panel (can configure reveal) | Hidden by default ("reveal": "never") |
| Auto-save before run | Not built in | Built in ("save": "current") |
| Selection runner script | stata_run_selection.sh (reads clipboard) | stata_run_selection_zed.sh (reads env var) |
| Whole-file runner script | stata_run_do.sh (expects path as $1 argument) | stata_run_do_zed.sh (reads $ZED_FILE from environment — handles spaces in paths) |
Troubleshooting
| Problem | Cause | Fix |
|---|---|---|
| Stata says “file not found” with truncated path | Using stata_run_do.sh (VS Code script) instead of stata_run_do_zed.sh | Use the Zed-specific wrapper: ~/.local/bin/stata_run_do_zed.sh reads $ZED_FILE from environment |
| Ctrl+Enter does nothing | Keybinding not loaded | Restart Zed: Ctrl+Shift+P → “zed: reload” |
Ctrl+Enter works in .py but not .do | Context mismatch | Check keymap.json has extension == do |
| Shift+Enter says “No text selected” | Nothing highlighted | Select text first (Ctrl+L for a line) |
| Shift+Enter does nothing at all | Task not found | Check tasks.json label matches exactly: "Run selection in Stata GUI" |
| Stata flashes open then closes | Not enough init time | Increase sleep 4 to sleep 6 in both scripts |
| Terminal panel keeps appearing | reveal setting wrong | Set "reveal": "never" in tasks.json |
| Script not found | Not on PATH | Verify: which stata_run_selection_zed.sh |
| wmctrl/xdotool fail silently | Wayland session | Log out → gear → your X11/Xorg session (Cinnamon on Xorg on Mint, Zorin on Xorg on Zorin — Mint defaults to X11) |
| Focus does not return to Zed | Return lines commented | Uncomment last 2 lines in the script |
| Old task keeps rerunning | Zed caches last task for task::Rerun | Use task::Spawn (not Rerun) via the keybinding |
FAQ
Q: Can I use both VS Code and Zed with Stata? A: Yes. They share the same underlying Stata automation pattern but use different wrapper scripts:
- VS Code uses
stata_run_do.sh(path as argument) andstata_run_selection.sh(reads clipboard) - Zed uses
stata_run_do_zed.sh(reads$ZED_FILEfrom environment) andstata_run_selection_zed.sh(reads$ZED_SELECTED_TEXT)
The scripts do not interfere with each other.
Q: Why separate scripts instead of reusing the VS Code ones? A: Two reasons:
- Whole-file: VS Code’s
stata_run_do.shexpects the path as a command-line argument ($1). Zed’s task system doesn’t pass arguments reliably for paths with spaces. The Zed wrapper reads$ZED_FILEfrom the environment instead. - Selection: VS Code’s script reads from the X11 clipboard (because VS Code copies there first). The Zed script reads from the
$ZED_SELECTED_TEXTenvironment variable. Different input source, same output: a temp.dofile sent to Stata.
Q: What if my selection is very large? A: Environment variables have a size limit (typically 128 KB to 2 MB on Linux). Normal Stata do-file selections will never hit this. If you need to run a 500-line block, use Ctrl+Enter to run the whole file instead.
Q: Will Shift+Enter work if nothing is selected? A: No. The script exits with an error message. Zed may also filter the task from its task picker when no text is selected. Always select text first.
Q: Can I make these keybindings work in ALL file types, not just .do?
A: Yes. Remove the context restriction:
[
{
"bindings": {
"ctrl-enter": ["task::Spawn", { "task_name": "Run do-file in Stata GUI" }],
"shift-enter": ["task::Spawn", { "task_name": "Run selection in Stata GUI" }]
}
}
]
But this will override Shift+Enter in every file type, which is usually not desirable.
Q: After running, should focus stay on Stata or return to Zed? A: Personal preference. By default, focus stays on Stata so you can immediately read output. To auto-return to Zed, uncomment these two lines at the bottom of both scripts:
# sleep 0.5
# wmctrl -xa "${EDITOR_WMCLASS}"
In the Zed-specific script, EDITOR_WMCLASS is already set to "zed".
Complete Removal
To remove only the Zed-specific Stata integration (without affecting VS Code or Stata itself):
# Remove Zed-specific scripts
rm -f ~/.local/bin/stata_run_do_zed.sh
rm -f ~/.local/bin/stata_run_selection_zed.sh
# Remove Zed task and keybinding configs
rm -f ~/.config/zed/tasks.json
rm -f ~/.config/zed/keymap.json
To also remove the shared VS Code scripts (affects VS Code too):
rm -f ~/.local/bin/stata_run_do.sh
rm -f ~/.local/bin/stata_run_selection.sh
Quick Verification Checklist
# 1. Confirm Xorg session
echo $XDG_SESSION_TYPE
# Expected: x11
# 2. Confirm Stata binary exists
ls /usr/local/stata19/xstata-mp
# 3. Confirm both Zed scripts are on PATH
which stata_run_do_zed.sh
# Expected: /home/YOUR_USERNAME/.local/bin/stata_run_do_zed.sh
which stata_run_selection_zed.sh
# Expected: /home/YOUR_USERNAME/.local/bin/stata_run_selection_zed.sh
# 4. Confirm Zed tasks exist
cat ~/.config/zed/tasks.json
# Expected: two task definitions
# 5. Confirm Zed keybindings exist
cat ~/.config/zed/keymap.json
# Expected: ctrl-enter and shift-enter bindings
# 6. Open a .do file in Zed, press Ctrl+Enter
# Expected: Stata opens and runs the file
# 7. Select lines including block comments, press Shift+Enter
# Expected: runs correctly in Stata with no r(199) errors
All seven passing means everything is correctly configured.
Companion guide to stata19-complete-guide.md and the Antigravity IDE Stata integration guide Tested on Linux Mint 22.3 Cinnamon (also Zorin OS 18.1 Pro) · ThinkPad L14 Gen 2 (i5-1135G7, 16GB, Iris Xe) · Zed 1.3.6 · May 2026
Discussion