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/mohsin/.local/bin |
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 Selection Runner Script (Zed-Specific)
This script is different from the VS Code version because it reads from $ZED_SELECTED_TEXT instead of the clipboard.
mkdir -p ~/.local/bin
nano ~/.local/bin/stata_run_selection_zed.sh
Paste:
#!/usr/bin/env bash
set -euo pipefail
# ---------------------------------------------------------------
# stata_run_selection_zed.sh
# Run selected Stata code from Zed editor in Stata GUI
#
# Reads the selection from Zed's $ZED_SELECTED_TEXT env var,
# writes it to a temp .do file, and sends it to Stata.
#
# Safe for: backticks, globals, block comments, macros — all
# Stata syntax survives because the env var is never shell-parsed.
# ---------------------------------------------------------------
STATA_BIN="/usr/local/stata19/xstata-mp"
STATA_WMCLASS="Xstata-mp"
EDITOR_WMCLASS="zed"
TMPDO="/tmp/stata_selection_run.do"
# Read selected text from Zed's environment variable
if [[ -z "${ZED_SELECTED_TEXT:-}" ]]; then
echo "No text selected in Zed — nothing to run." >&2
exit 1
fi
# Write selection to temp do-file (printf %s does NOT interpret
# backticks, $, or escape sequences in the variable value)
printf '%s\n' "$ZED_SELECTED_TEXT" > "$TMPDO"
# Verify file is non-empty
if [[ ! -s "$TMPDO" ]]; then
echo "Temp do-file is empty after write — aborting." >&2
exit 1
fi
# 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
# Wait for Stata to fully initialize before sending input
sleep 4
fi
# Put the do command (not the raw code) on the clipboard
printf 'do "%s"\n' "$TMPDO" | xclip -selection clipboard
# Focus Stata and run
wmctrl -xa "${STATA_WMCLASS}"
sleep 0.3
xdotool key --clearmodifiers ctrl+v Return
# Return focus to Zed (uncomment below to enable)
# sleep 0.5
# wmctrl -xa "${EDITOR_WMCLASS}"
Make executable:
chmod +x ~/.local/bin/stata_run_selection_zed.sh
Verify:
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.sh",
"args": ["$ZED_FILE"],
"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
}
]
What each setting does
| Setting | Value | Purpose |
|---|---|---|
command | Full script path | No ~ — Zed tasks run in a login shell but full paths are safer |
args | ["$ZED_FILE"] | Passes the current file’s absolute path as argument 1 |
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 |
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 (labeled “Zorin OS on Xorg” on Zorin OS, “Ubuntu on Xorg” on standard Ubuntu — look for “Xorg” in the name) |
| 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.sh "$ZED_FILE" runs
├─→ 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 /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 /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 (shared with VS Code) | ~/.local/bin/stata_run_do.sh |
| Selection runner (Zed-specific) | ~/.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 | Same stata_run_do.sh (shared) |
Troubleshooting
| Problem | Cause | Fix |
|---|---|---|
| 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 (look for “Xorg” in the session name — “Zorin OS on Xorg” on Zorin, “Ubuntu on Xorg” on Ubuntu) |
| 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 stata_run_do.sh for whole-file runs. The selection scripts are separate (stata_run_selection.sh for VS Code, stata_run_selection_zed.sh for Zed) and do not interfere with each other.
Q: Why a separate script instead of reusing the VS Code selection script?
A: The VS Code script reads from the X11 clipboard (because VS Code copies there first). The Zed script reads from the $ZED_SELECTED_TEXT environment variable. Different input source, same output: a temp .do file 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 selection script
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 whole-file runner (affects VS Code too):
rm -f ~/.local/bin/stata_run_do.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 scripts are on PATH
which stata_run_do.sh
# Expected: /home/mohsin/.local/bin/stata_run_do.sh
which stata_run_selection_zed.sh
# Expected: /home/mohsin/.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 Stata integration guide Built on the tested Zorin OS 18.1 Pro setup · Zed 0.231.2 · April 2026
Discussion