Compare commits

...
Author SHA1 Message Date
IanandClaude Opus 5.5 7adece54df fix(tui): suspend on ctrl+z
Bubble Tea's raw mode clears ISIG, so ctrl+z reached the TUI as a key and
was ignored instead of stopping the job. Return tea.Suspend for it on every
screen, and re-enable mouse tracking on resume, since Bubble Tea's restore
brings back the alt screen but not the mouse mode.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-28 17:49:09 -04:00
Yash Aslekar d6dd9dec26 fix(dev): make check-all non-mutating (#1360) 2026-09-27 17:47:20 -07:00
3 changed files with 48 additions and 3 deletions

No files matched your search

+11 -3
View File
@@ -1,4 +1,4 @@
.PHONY: help install dev-install format lint type-check security check-all clean pre-commit setup-dev dev viewer wheel tui-build tui-test tui-lint
.PHONY: help install dev-install format lint format-check lint-check type-check security check-all clean pre-commit setup-dev dev viewer wheel tui-build tui-test tui-lint
TUI_BINARY := build/sidecar/strix-tui$(if $(filter Windows_NT,$(OS)),.exe)
@@ -10,7 +10,9 @@ help:
@echo ""
@echo "Code Quality:"
@echo " format - Format code with ruff"
@echo " lint - Lint code with ruff"
@echo " lint - Lint code with ruff and apply fixes"
@echo " format-check - Check formatting without modifying files"
@echo " lint-check - Check lint without modifying files"
@echo " type-check - Run type checking with mypy and pyright"
@echo " security - Run security checks with bandit"
@echo " check-all - Run all code quality checks"
@@ -45,6 +47,12 @@ lint:
uv run ruff check . --fix
@echo "✅ Linting complete!"
format-check:
uv run ruff format --check .
lint-check:
uv run ruff check .
type-check:
@echo "🔍 Type checking with mypy..."
uv run mypy strix/
@@ -57,7 +65,7 @@ security:
uv run bandit -r strix/ -c pyproject.toml
@echo "✅ Security checks complete!"
check-all: format lint type-check security
check-all: format-check lint-check type-check security
@echo "✅ All code quality checks passed!"
pre-commit:
@@ -384,7 +384,16 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.vulnerabilityCopyError = msg.err.Error()
}
return m, nil
case tea.ResumeMsg:
// Suspend turns mouse tracking off with the rest of the terminal state,
// but the restore brings back only the alt screen, so turn it back on.
return m, tea.EnableMouseCellMotion
case tea.KeyMsg:
// Raw mode clears ISIG, so ctrl+z arrives as a key instead of SIGTSTP.
// Suspend on every screen, the way a shell job would.
if msg.Type == tea.KeyCtrlZ {
return m, tea.Suspend
}
if m.showSplash {
switch msg.String() {
case "ctrl+c", "ctrl+q", "q", "esc":
@@ -1439,3 +1439,31 @@ func TestNarrowTerminalKeepsTheFrameIntact(t *testing.T) {
}
}
}
func TestCtrlZSuspendsFromEveryScreen(t *testing.T) {
for name, prepare := range map[string]func(*Model){
"splash": func(m *Model) { m.showSplash = true },
"modal": func(m *Model) { m.showSplash = false; m.openModal(modalHelp) },
"main": func(m *Model) { m.showSplash = false },
} {
model := New(nil)
prepare(&model)
_, cmd := model.Update(tea.KeyMsg{Type: tea.KeyCtrlZ})
if cmd == nil {
t.Fatalf("%s: ctrl+z returned no command", name)
}
if _, ok := cmd().(tea.SuspendMsg); !ok {
t.Fatalf("%s: ctrl+z did not suspend", name)
}
}
}
func TestResumeReenablesMouse(t *testing.T) {
_, cmd := New(nil).Update(tea.ResumeMsg{})
if cmd == nil {
t.Fatal("resume returned no command")
}
if msg := cmd(); msg != tea.EnableMouseCellMotion() {
t.Fatalf("resume did not re-enable mouse tracking: %#v", msg)
}
}