Finish settings TODO cleanup
This commit is contained in:
15
CHANGELOG.md
15
CHANGELOG.md
@@ -6,6 +6,21 @@ loosely follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Auto-summarization settings now save as soon as a changed row is
|
||||||
|
applied, including cadence/provider/toggle changes and model edits,
|
||||||
|
without requiring a separate save step.
|
||||||
|
- Auto-summarization setting rows now visually separate grey labels
|
||||||
|
from regular-colour values.
|
||||||
|
- The active-thread summary in the tab bar is now constrained to the
|
||||||
|
active tab's width instead of spanning the whole top row.
|
||||||
|
- Sidebar summary text now wraps from the full summary text instead of
|
||||||
|
using an ellipsized single-line value.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Removed the redundant "Back to Settings" row from the
|
||||||
|
Agents / Auto-summarization settings screen.
|
||||||
|
|
||||||
## [0.0.6] - 2026-05-15
|
## [0.0.6] - 2026-05-15
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|||||||
@@ -1,61 +0,0 @@
|
|||||||
claude + new │ Processes
|
|
||||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━───────│ ─────────────────────────
|
|
||||||
- abc1234 if no tag exists yet
|
|
||||||
|
|
||||||
4. Wire version into the release workflow
|
|
||||||
|
|
||||||
Update .gitea/workflows/release.yml lines 31-35 to inject the pushed tag:
|
|
||||||
|
|
||||||
go build -trimpath \
|
|
||||||
-ldflags="-s -w -X main.version=${{ github.ref_name }}" \
|
|
||||||
-o dist/patterm-${{ github.ref_name }}-linux-amd64 \
|
|
||||||
./cmd/patterm
|
|
||||||
|
|
||||||
github.ref_name is the tag name (e.g. v0.0.1) because the workflow only
|
|
||||||
triggers on tags: ['v*'].
|
|
||||||
|
|
||||||
5. Update inline doc comment
|
|
||||||
|
|
||||||
cmd/patterm/main.go header comment (lines 5-11) — add the --version form
|
|
||||||
to the usage block. SPEC.md/CLAUDE.md already use --, no change needed there.
|
|
||||||
|
|
||||||
Out of scope
|
|
||||||
|
|
||||||
- Surfacing version in MCP whoami (the hardcoded "version": "0.1.0" in
|
|
||||||
internal/mcp/protocol.go:27 is the MCP protocol version, not the patterm
|
|
||||||
binary version — leave it).
|
|
||||||
- Renaming any existing flags.
|
|
||||||
- Adding short forms like -p for --project.
|
|
||||||
|
|
||||||
Critical files
|
|
||||||
|
|
||||||
- cmd/patterm/main.go — import swap, --version wiring, version var, header comment
|
|
||||||
- cmd/patterm/debug_harness.go — import swap
|
|
||||||
- Makefile lines 38-39 — VERSION var + ldflags
|
|
||||||
- .gitea/workflows/release.yml lines 31-35 — ldflags
|
|
||||||
- go.mod / go.sum — add github.com/spf13/pflag
|
|
||||||
|
|
||||||
Verification
|
|
||||||
|
|
||||||
1. go build -o ./bin/patterm ./cmd/patterm (without Makefile) → still builds, version reports dev.
|
|
||||||
2. make patterm → ./bin/patterm --version prints patterm v0.0.1 (commit <sha>, built <date>).
|
|
||||||
3. ./bin/patterm -h → help text shows --project string and --version lines.
|
|
||||||
4. ./bin/patterm -project /tmp → pflag rejects with usage error (confirms -- is enforced).
|
|
||||||
5. ./bin/patterm --project /tmp → starts normally.
|
|
||||||
6. ./bin/patterm mcp-stdio --socket /tmp/s --identity x → existing path still works (will fail to connect, but should parse flags fine).
|
|
||||||
7. ./bin/patterm debug-harness --scenario internal/harness/scenarios/spawn_process_via_palette.json → harness still runs.
|
|
||||||
8. go test ./... and go test ./internal/harness/... — both green.
|
|
||||||
9. Push a temporary tag locally and inspect git describe output; confirm release workflow's ${{ github.ref_name }} substitution matches the tag.
|
|
||||||
╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
|
|
||||||
|
|
||||||
Claude has written up a plan and is ready to execute. Would you like to proceed?
|
|
||||||
|
|
||||||
❯ 1. Yes, and use auto mode
|
|
||||||
2. Yes, manually approve edits
|
|
||||||
3. No, refine with Ultraplan on Claude Code on the web
|
|
||||||
4. Tell Claude what to change
|
|
||||||
shift+tab to approve with this feedback
|
|
||||||
|
|
||||||
ctrl-g to edit in VS Code · ~/.claude/plans/flags-in-this-project-vectorized-gosling.md
|
|
||||||
|
|
||||||
claude · you have control Ctrl-A/D · tabs · Ctrl-W/S · tree · Ctrl-K · palette
|
|
||||||
@@ -505,7 +505,18 @@ func (st *uiState) dbgf(format string, args ...any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (st *uiState) activeSummaryText(width int) string {
|
func (st *uiState) activeSummaryText(width int) string {
|
||||||
if width <= 0 || st.summaries == nil {
|
text := st.activeSummaryRaw()
|
||||||
|
if text == "" || width <= 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if visibleLen(text) > width {
|
||||||
|
text = clipRunes(text, width-1) + "…"
|
||||||
|
}
|
||||||
|
return text
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *uiState) activeSummaryRaw() string {
|
||||||
|
if st.summaries == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
st.settingsMu.Lock()
|
st.settingsMu.Lock()
|
||||||
@@ -525,9 +536,6 @@ func (st *uiState) activeSummaryText(width int) string {
|
|||||||
if text == "" {
|
if text == "" {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
if visibleLen(text) > width {
|
|
||||||
text = clipRunes(text, width-1) + "…"
|
|
||||||
}
|
|
||||||
return text
|
return text
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1626,6 +1634,11 @@ func (st *uiState) processStdin(chunk []byte) {
|
|||||||
adv = 1
|
adv = 1
|
||||||
}
|
}
|
||||||
i += adv
|
i += adv
|
||||||
|
if action.kind == "settings-save" {
|
||||||
|
st.applySettingsAction(action)
|
||||||
|
st.renderPaletteLocked()
|
||||||
|
continue
|
||||||
|
}
|
||||||
if done {
|
if done {
|
||||||
a := action
|
a := action
|
||||||
pendingAction = &a
|
pendingAction = &a
|
||||||
|
|||||||
@@ -1277,8 +1277,11 @@ func (p *paletteState) handleSettingsTextInput(chunk []byte, i int) (paletteActi
|
|||||||
}
|
}
|
||||||
switch b {
|
switch b {
|
||||||
case '\r', '\n':
|
case '\r', '\n':
|
||||||
p.applySettingsInput()
|
changed := p.applySettingsInput()
|
||||||
p.mode = paletteModeAutoSummary
|
p.mode = paletteModeAutoSummary
|
||||||
|
if changed {
|
||||||
|
return p.settingsAction("settings-save"), false, 1
|
||||||
|
}
|
||||||
case 0x7f, 0x08:
|
case 0x7f, 0x08:
|
||||||
if len(p.settingsInput.value) > 0 {
|
if len(p.settingsInput.value) > 0 {
|
||||||
p.settingsInput.value = p.settingsInput.value[:len(p.settingsInput.value)-1]
|
p.settingsInput.value = p.settingsInput.value[:len(p.settingsInput.value)-1]
|
||||||
@@ -1310,7 +1313,6 @@ func autoSummaryRows() []autoSummaryRow {
|
|||||||
{key: "run_now", label: "Summarize current top-level agent now"},
|
{key: "run_now", label: "Summarize current top-level agent now"},
|
||||||
{key: "save", label: "Save settings"},
|
{key: "save", label: "Save settings"},
|
||||||
{key: "cancel", label: "Cancel"},
|
{key: "cancel", label: "Cancel"},
|
||||||
{key: "back", label: "Back to Settings"},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1322,6 +1324,8 @@ func (p *paletteState) activateAutoSummaryRow() (paletteAction, bool, int) {
|
|||||||
switch rows[p.cursor].key {
|
switch rows[p.cursor].key {
|
||||||
case "enabled":
|
case "enabled":
|
||||||
p.settings.AutoSummary.Enabled = !p.settings.AutoSummary.Enabled
|
p.settings.AutoSummary.Enabled = !p.settings.AutoSummary.Enabled
|
||||||
|
p.settings.normalize()
|
||||||
|
return p.settingsAction("settings-save"), false, 1
|
||||||
case "provider":
|
case "provider":
|
||||||
switch p.settings.AutoSummary.Provider {
|
switch p.settings.AutoSummary.Provider {
|
||||||
case "codex":
|
case "codex":
|
||||||
@@ -1331,6 +1335,8 @@ func (p *paletteState) activateAutoSummaryRow() (paletteAction, bool, int) {
|
|||||||
default:
|
default:
|
||||||
p.settings.AutoSummary.Provider = "codex"
|
p.settings.AutoSummary.Provider = "codex"
|
||||||
}
|
}
|
||||||
|
p.settings.normalize()
|
||||||
|
return p.settingsAction("settings-save"), false, 1
|
||||||
case "codex_model", "opencode_model", "claude_model":
|
case "codex_model", "opencode_model", "claude_model":
|
||||||
provider := strings.TrimSuffix(rows[p.cursor].key, "_model")
|
provider := strings.TrimSuffix(rows[p.cursor].key, "_model")
|
||||||
p.settingsInput = &settingsInputForm{
|
p.settingsInput = &settingsInputForm{
|
||||||
@@ -1349,6 +1355,8 @@ func (p *paletteState) activateAutoSummaryRow() (paletteAction, bool, int) {
|
|||||||
default:
|
default:
|
||||||
p.settings.AutoSummary.Cadence = "15s"
|
p.settings.AutoSummary.Cadence = "15s"
|
||||||
}
|
}
|
||||||
|
p.settings.normalize()
|
||||||
|
return p.settingsAction("settings-save"), false, 1
|
||||||
case "test":
|
case "test":
|
||||||
return p.settingsAction("settings-test"), true, 1
|
return p.settingsAction("settings-test"), true, 1
|
||||||
case "run_now":
|
case "run_now":
|
||||||
@@ -1357,36 +1365,36 @@ func (p *paletteState) activateAutoSummaryRow() (paletteAction, bool, int) {
|
|||||||
return p.settingsAction("settings-close"), true, 1
|
return p.settingsAction("settings-close"), true, 1
|
||||||
case "cancel":
|
case "cancel":
|
||||||
return paletteAction{kind: "cancel"}, true, 1
|
return paletteAction{kind: "cancel"}, true, 1
|
||||||
case "back":
|
|
||||||
p.mode = paletteModeSettings
|
|
||||||
p.cursor = 0
|
|
||||||
p.query = nil
|
|
||||||
p.rebuildSettings()
|
|
||||||
}
|
}
|
||||||
p.settings.normalize()
|
p.settings.normalize()
|
||||||
return paletteAction{}, false, 1
|
return paletteAction{}, false, 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *paletteState) applySettingsInput() {
|
func (p *paletteState) applySettingsInput() bool {
|
||||||
if p.settingsInput == nil {
|
if p.settingsInput == nil {
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
val := strings.TrimSpace(string(p.settingsInput.value))
|
val := strings.TrimSpace(string(p.settingsInput.value))
|
||||||
if val == "" {
|
if val == "" {
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
if p.settings.AutoSummary.Models == nil {
|
if p.settings.AutoSummary.Models == nil {
|
||||||
p.settings.AutoSummary.Models = defaultSummaryModels()
|
p.settings.AutoSummary.Models = defaultSummaryModels()
|
||||||
}
|
}
|
||||||
|
changed := false
|
||||||
switch p.settingsInput.field {
|
switch p.settingsInput.field {
|
||||||
case "codex_model":
|
case "codex_model":
|
||||||
|
changed = p.settings.AutoSummary.Models["codex"] != val
|
||||||
p.settings.AutoSummary.Models["codex"] = val
|
p.settings.AutoSummary.Models["codex"] = val
|
||||||
case "opencode_model":
|
case "opencode_model":
|
||||||
|
changed = p.settings.AutoSummary.Models["opencode"] != val
|
||||||
p.settings.AutoSummary.Models["opencode"] = val
|
p.settings.AutoSummary.Models["opencode"] = val
|
||||||
case "claude_model":
|
case "claude_model":
|
||||||
|
changed = p.settings.AutoSummary.Models["claude"] != val
|
||||||
p.settings.AutoSummary.Models["claude"] = val
|
p.settings.AutoSummary.Models["claude"] = val
|
||||||
}
|
}
|
||||||
p.settings.normalize()
|
p.settings.normalize()
|
||||||
|
return changed
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *paletteState) settingsCloseAction() paletteAction {
|
func (p *paletteState) settingsCloseAction() paletteAction {
|
||||||
@@ -1473,7 +1481,7 @@ func (p *paletteState) renderAutoSummary(out writeFlusher, cols, rows int) {
|
|||||||
moveTo(&b, row, leftPad)
|
moveTo(&b, row, leftPad)
|
||||||
b.WriteString(styleBorder + "├" + strings.Repeat("─", width-2) + "┤" + styleReset)
|
b.WriteString(styleBorder + "├" + strings.Repeat("─", width-2) + "┤" + styleReset)
|
||||||
row++
|
row++
|
||||||
footer := styleHint + "↵ edit/toggle · cadence 15s/30s/1m · save row commits · esc cancel" + styleReset
|
footer := styleHint + "↵ edit/toggle · changes save when applied · esc cancel" + styleReset
|
||||||
if visibleLen(footer) > content {
|
if visibleLen(footer) > content {
|
||||||
footer = clipRunes(footer, content-1) + "…"
|
footer = clipRunes(footer, content-1) + "…"
|
||||||
}
|
}
|
||||||
@@ -1503,7 +1511,7 @@ func (p *paletteState) autoSummaryDisplayRows() []string {
|
|||||||
var out []string
|
var out []string
|
||||||
for _, row := range autoSummaryRows() {
|
for _, row := range autoSummaryRows() {
|
||||||
if v, ok := values[row.key]; ok {
|
if v, ok := values[row.key]; ok {
|
||||||
out = append(out, row.label+": "+v)
|
out = append(out, styleHint+row.label+":"+styleReset+" "+v)
|
||||||
} else {
|
} else {
|
||||||
out = append(out, row.label)
|
out = append(out, row.label)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -356,20 +356,71 @@ func TestAutoSummaryCadenceCyclesSoloValues(t *testing.T) {
|
|||||||
if p.settings.AutoSummary.Cadence != "1m" {
|
if p.settings.AutoSummary.Cadence != "1m" {
|
||||||
t.Fatalf("initial cadence = %q", p.settings.AutoSummary.Cadence)
|
t.Fatalf("initial cadence = %q", p.settings.AutoSummary.Cadence)
|
||||||
}
|
}
|
||||||
p.activateAutoSummaryRow()
|
action, done, _ := p.activateAutoSummaryRow()
|
||||||
|
if done || action.kind != "settings-save" {
|
||||||
|
t.Fatalf("first cycle action = %+v done=%v, want settings-save without close", action, done)
|
||||||
|
}
|
||||||
if p.settings.AutoSummary.Cadence != "15s" {
|
if p.settings.AutoSummary.Cadence != "15s" {
|
||||||
t.Fatalf("first cycle cadence = %q", p.settings.AutoSummary.Cadence)
|
t.Fatalf("first cycle cadence = %q", p.settings.AutoSummary.Cadence)
|
||||||
}
|
}
|
||||||
p.activateAutoSummaryRow()
|
action, done, _ = p.activateAutoSummaryRow()
|
||||||
|
if done || action.kind != "settings-save" {
|
||||||
|
t.Fatalf("second cycle action = %+v done=%v, want settings-save without close", action, done)
|
||||||
|
}
|
||||||
if p.settings.AutoSummary.Cadence != "30s" {
|
if p.settings.AutoSummary.Cadence != "30s" {
|
||||||
t.Fatalf("second cycle cadence = %q", p.settings.AutoSummary.Cadence)
|
t.Fatalf("second cycle cadence = %q", p.settings.AutoSummary.Cadence)
|
||||||
}
|
}
|
||||||
p.activateAutoSummaryRow()
|
action, done, _ = p.activateAutoSummaryRow()
|
||||||
|
if done || action.kind != "settings-save" {
|
||||||
|
t.Fatalf("third cycle action = %+v done=%v, want settings-save without close", action, done)
|
||||||
|
}
|
||||||
if p.settings.AutoSummary.Cadence != "1m" {
|
if p.settings.AutoSummary.Cadence != "1m" {
|
||||||
t.Fatalf("third cycle cadence = %q", p.settings.AutoSummary.Cadence)
|
t.Fatalf("third cycle cadence = %q", p.settings.AutoSummary.Cadence)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAutoSummaryScreenOmitsBackRow(t *testing.T) {
|
||||||
|
for _, row := range autoSummaryRows() {
|
||||||
|
if row.label == "Back to Settings" {
|
||||||
|
t.Fatal("auto-summary settings should not show Back to Settings")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAutoSummaryValueRowsStyleLabelAndValueSeparately(t *testing.T) {
|
||||||
|
p := newPalette(nil, "", "", preset.Set{}, defaultSettings())
|
||||||
|
rows := p.autoSummaryDisplayRows()
|
||||||
|
for _, row := range rows {
|
||||||
|
if strings.Contains(row, "Cadence:") {
|
||||||
|
if !strings.HasPrefix(row, styleHint+"Cadence:"+styleReset+" ") {
|
||||||
|
t.Fatalf("cadence row styling = %q", row)
|
||||||
|
}
|
||||||
|
if strings.Contains(strings.TrimPrefix(row, styleHint+"Cadence:"+styleReset+" "), styleHint) {
|
||||||
|
t.Fatalf("cadence value should use regular text styling: %q", row)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.Fatal("missing cadence display row")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAutoSummaryTextInputSavesWhenSubmitted(t *testing.T) {
|
||||||
|
p := newPalette(nil, "", "", preset.Set{}, defaultSettings())
|
||||||
|
p.mode = paletteModeSettingsInput
|
||||||
|
p.settingsInput = &settingsInputForm{
|
||||||
|
title: "codex model",
|
||||||
|
field: "codex_model",
|
||||||
|
value: []rune("custom-model"),
|
||||||
|
}
|
||||||
|
action, done, _ := p.handleSettingsTextInput([]byte{'\r'}, 0)
|
||||||
|
if done || action.kind != "settings-save" {
|
||||||
|
t.Fatalf("submit action = %+v done=%v, want settings-save without close", action, done)
|
||||||
|
}
|
||||||
|
if got := p.settings.AutoSummary.modelFor("codex"); got != "custom-model" {
|
||||||
|
t.Fatalf("codex model = %q", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestPaletteFormCtrlRTogglesRelaunchFromCommandField(t *testing.T) {
|
func TestPaletteFormCtrlRTogglesRelaunchFromCommandField(t *testing.T) {
|
||||||
p := newPalette(nil, "", "", preset.Set{})
|
p := newPalette(nil, "", "", preset.Set{})
|
||||||
p.mode = paletteModeSpawnForm
|
p.mode = paletteModeSpawnForm
|
||||||
|
|||||||
@@ -331,7 +331,7 @@ func (st *uiState) drawSidebar() {
|
|||||||
write(prefix + openStyle + nameCell + styleReset + suffix)
|
write(prefix + openStyle + nameCell + styleReset + suffix)
|
||||||
}
|
}
|
||||||
|
|
||||||
if summary := st.activeSummaryText(width - 4); summary != "" && row+2 <= maxRow {
|
if summary := st.activeSummaryRaw(); summary != "" && row+2 <= maxRow {
|
||||||
write("")
|
write("")
|
||||||
for _, line := range wrapSidebarSummary(summary, width-4) {
|
for _, line := range wrapSidebarSummary(summary, width-4) {
|
||||||
if row > maxRow {
|
if row > maxRow {
|
||||||
@@ -417,7 +417,13 @@ func wrapSidebarSummary(s string, width int) []string {
|
|||||||
out = append(out, cur)
|
out = append(out, cur)
|
||||||
cur = ""
|
cur = ""
|
||||||
}
|
}
|
||||||
out = append(out, clipRunes(word, width-1)+"…")
|
for visibleLen(word) > width {
|
||||||
|
out = append(out, clipRunes(word, width))
|
||||||
|
word = string([]rune(word)[width:])
|
||||||
|
}
|
||||||
|
if word != "" {
|
||||||
|
cur = word
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if cur == "" {
|
if cur == "" {
|
||||||
|
|||||||
@@ -42,8 +42,13 @@ func TestWrapSidebarSummaryKeepsWordBoundaries(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
long := wrapSidebarSummary("supercalifragilistic short", 8)
|
long := wrapSidebarSummary("supercalifragilistic short", 8)
|
||||||
if len(long) == 0 || !strings.HasSuffix(long[0], "…") {
|
if len(long) == 0 || strings.Contains(strings.Join(long, ""), "…") {
|
||||||
t.Fatalf("long word should clip with ellipsis: %#v", long)
|
t.Fatalf("long word should wrap without ellipsis: %#v", long)
|
||||||
|
}
|
||||||
|
for _, line := range long {
|
||||||
|
if visibleLen(line) > 8 {
|
||||||
|
t.Fatalf("line %q exceeds width", line)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ func (st *uiState) drawTabBar() {
|
|||||||
label string
|
label string
|
||||||
active bool
|
active bool
|
||||||
}
|
}
|
||||||
|
activeTab := -1
|
||||||
|
|
||||||
// Reserve space at the right edge for "+ new". If there are too
|
// Reserve space at the right edge for "+ new". If there are too
|
||||||
// many tabs to fit even at minTabWidth, drop tabs from the right
|
// many tabs to fit even at minTabWidth, drop tabs from the right
|
||||||
@@ -134,6 +135,9 @@ func (st *uiState) drawTabBar() {
|
|||||||
label: label,
|
label: label,
|
||||||
active: c.ID == focus,
|
active: c.ID == focus,
|
||||||
})
|
})
|
||||||
|
if tabs[len(tabs)-1].active {
|
||||||
|
activeTab = len(tabs) - 1
|
||||||
|
}
|
||||||
col += w
|
col += w
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -195,8 +199,12 @@ func (st *uiState) drawTabBar() {
|
|||||||
hintCol, styleBorder, strings.Repeat("─", newHintW), styleReset)
|
hintCol, styleBorder, strings.Repeat("─", newHintW), styleReset)
|
||||||
}
|
}
|
||||||
|
|
||||||
if summary := st.activeSummaryText(width - 2); summary != "" {
|
if activeTab >= 0 {
|
||||||
fmt.Fprintf(&b, "\x1b[2;1H %s%s%s", styleDim, summary, styleReset)
|
tab := tabs[activeTab]
|
||||||
|
summaryWidth := tab.width - 2
|
||||||
|
if summary := st.activeSummaryText(summaryWidth); summary != "" {
|
||||||
|
fmt.Fprintf(&b, "\x1b[2;%dH %s%s%s", tab.startCol, styleDim, summary, styleReset)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
frame := b.String()
|
frame := b.String()
|
||||||
|
|||||||
Reference in New Issue
Block a user