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.
Run Do-Files and Selections from Zed — No Extensions Required
What This Guide Achieves
| Feature | Status |
|---|---|
Ctrl+Enter in Zed runs the whole .do file in Stata GUI | Yes |
| Shift+Enter in Zed runs selected line(s) or chunk in Stata GUI | Yes |
| Comments, globals, backticks, block comments all work in selection | Yes |
| Stata launches automatically if not already open | Yes |
| No Zed extension required | Yes |
Keybindings scoped to .do files only (won’t interfere elsewhere) | Yes |
| File is auto-saved before running whole file | Yes |
| Terminal panel stays hidden (no visual noise) | Yes |
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