Fix review findings in project-folder terminal command

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Vaclav Tvrdik
2026-09-06 11:09:05 +02:00
parent 430af419c0
commit 23644cbdf5
3 changed files with 26 additions and 16 deletions

View File

@@ -331,7 +331,9 @@ replaces both together.
**Plugin settings** (`vterm.sublime-settings`, read through the cached `settings()` **Plugin settings** (`vterm.sublime-settings`, read through the cached `settings()`
handle): `auto_close`, `scrollback_history_size`, `honor_erase_scrollback`, `min_columns`, handle): `auto_close`, `scrollback_history_size`, `honor_erase_scrollback`, `min_columns`,
`max_columns`, `theme`, `ansi_colors`, `debug`. `honor_erase_scrollback` is off, so ED 3 `max_columns`, `theme`, `ansi_colors`, `terminal`, `parameters`, `debug`. `terminal` and
`parameters` name the external terminal spawned by *vterm: Open Terminal in Project
Folder* (`%CWD%` in `parameters` becomes the project folder). `honor_erase_scrollback` is off, so ED 3
blanks the screen without dropping the scrollback: pi and Claude Code repaint by erasing blanks the screen without dropping the scrollback: pi and Claude Code repaint by erasing
saved lines, which would take the history with them (`cmd+shift+k` still empties the tab). Changing `theme` fires `SchemeManager.reload`, which rebuilds the saved lines, which would take the history with them (`cmd+shift+k` still empties the tab). Changing `theme` fires `SchemeManager.reload`, which rebuilds the
palette and restyles open terminals in place. palette and restyles open terminals in place.

View File

@@ -23,12 +23,12 @@
// External terminal for "vterm: Open Terminal in Project Folder". // External terminal for "vterm: Open Terminal in Project Folder".
// %CWD% in parameters is replaced with the project folder. // %CWD% in parameters is replaced with the project folder.
"terminal": "/opt/homebrew/bin/kitty",
"parameters": ["-d", "%CWD%"],
// Apple Terminal instead of kitty:
// "terminal": "/usr/bin/open", // "terminal": "/usr/bin/open",
// "parameters": ["-a", "Terminal", "%CWD%"], // "parameters": ["-a", "Terminal", "%CWD%"],
// kitty instead of Apple Terminal:
"terminal": "/opt/homebrew/bin/kitty",
"parameters": ["-d", "%CWD%"],
"debug": false "debug": false
} }

View File

@@ -67,15 +67,16 @@ class VtermOpenTerminalProjectFolderCommand(sublime_plugin.WindowCommand):
def run(self): def run(self):
"""Resolve the folder, substitute %CWD%, spawn the configured terminal.""" """Resolve the folder, substitute %CWD%, spawn the configured terminal."""
folders = self.window.folders()
if not folders:
return
cwd = folders[0]
view = self.window.active_view() view = self.window.active_view()
if view and view.file_name(): if view and view.file_name():
path = view.file_name() path = view.file_name()
folders = [f for f in self.window.folders() if path.find(f + os.sep) == 0] matches = [f for f in folders if path.find(f.rstrip(os.sep) + os.sep) == 0]
cwd = folders[0] if folders else os.path.dirname(path) if matches:
elif self.window.folders(): cwd = max(matches, key=len)
cwd = self.window.folders()[0]
else:
return
s = settings() s = settings()
terminal = s.get("terminal") terminal = s.get("terminal")
@@ -83,12 +84,19 @@ class VtermOpenTerminalProjectFolderCommand(sublime_plugin.WindowCommand):
sublime.error_message('vterm: set "terminal" in vterm.sublime-settings') sublime.error_message('vterm: set "terminal" in vterm.sublime-settings')
return return
parameters = [p.replace("%CWD%", cwd) for p in s.get("parameters", [])] parameters = s.get("parameters", [])
if not isinstance(parameters, list) or not all(isinstance(p, str) for p in parameters):
sublime.error_message('vterm: "parameters" must be a list of strings')
return
parameters = [p.replace("%CWD%", cwd) for p in parameters]
try: try:
subprocess.Popen([terminal] + parameters, cwd=cwd) subprocess.Popen(
[terminal] + parameters, cwd=cwd, start_new_session=True,
stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
)
except OSError: except OSError:
LOG.exception("failed to start external terminal: terminal=%s", terminal) LOG.exception("failed to start external terminal: terminal=%s", terminal)
sublime.error_message(f"vterm: could not start {terminal}") sublime.error_message("vterm: could not start {}".format(terminal))
def is_visible(self): def is_visible(self):
"""Hide the palette entry when there is no project folder.""" """Hide the palette entry when there is no project folder."""
@@ -201,7 +209,7 @@ class VtermSelectThemeCommand(sublime_plugin.WindowCommand):
items = [["No theme", "follow the Sublime color scheme"]] items = [["No theme", "follow the Sublime color scheme"]]
for name in self.choices[1:]: for name in self.choices[1:]:
theme = THEMES[name] theme = THEMES[name]
items.append([name, f"{theme["foreground"]} on {theme["background"]}"]) items.append([name, "{} on {}".format(theme["foreground"], theme["background"])])
current = self.choices.index(self.original) if self.original in self.choices else 0 current = self.choices.index(self.original) if self.original in self.choices else 0
self.window.show_quick_panel(items, self._done, selected_index=current, on_highlight=self._preview) self.window.show_quick_panel(items, self._done, selected_index=current, on_highlight=self._preview)
@@ -262,7 +270,7 @@ class VtermCleanupCommand(sublime_plugin.TextCommand):
terminal.process.isalive() terminal.process.isalive()
exitstatus = terminal.process.exitstatus exitstatus = terminal.process.exitstatus
if exitstatus is not None: if exitstatus is not None:
view.run_command("append", {"characters": f"\n[process exited with code {exitstatus}]"}) view.run_command("append", {"characters": "\n[process exited with code {}]".format(exitstatus)})
view.sel().clear() view.sel().clear()