commit 9ff869a28cf991084fe89aa309fd1203f774f692
parent 3527c57c6cc2944fa42c4a67f46552eeb33ccd14
Author: Damian Myrda <damian@prime8.dev>
Date: Thu, 22 Oct 2026 00:39:17 +0000
titles: show the full path, no … collapsing
Diffstat:
4 files changed, 12 insertions(+), 56 deletions(-)
diff --git a/internal/tui/shell_test.go b/internal/tui/shell_test.go
@@ -222,20 +222,17 @@ func TestShellUsesSessionUser(t *testing.T) {
}
}
-func TestWindowTitleIsShort(t *testing.T) {
+func TestWindowTitleIsFull(t *testing.T) {
m := testModel(t, 120, 40)
m.activateTab(tabExperience)
if got := m.windowTitle(); got != "prime8:~/experience" {
t.Errorf("experience title = %q", got)
}
m.activateTab(tabProjects)
- want := "prime8:…/" + m.selectedProject().ID
+ want := "prime8:~/projects/" + m.selectedProject().ID
if got := m.windowTitle(); got != want {
t.Errorf("project title = %q, want %q", got, want)
}
- if n := len([]rune(m.windowTitle())); n > 20 {
- t.Errorf("title too long: %d", n)
- }
}
func TestProjectsSharedBorderIsAccent(t *testing.T) {
diff --git a/internal/utils/title.go b/internal/utils/title.go
@@ -1,31 +1,9 @@
package utils
-import "strings"
-
-// MaxWindowTitle is the longest window/tab title we set, in runes, so it
-// fits terminal and browser tabs without being cut.
-const MaxWindowTitle = 20
-
const windowTitleHost = "prime8:"
// WindowTitle is the terminal/browser title for a shell-style path such as
-// "~/projects/mos": "prime8:<path>", collapsed to "prime8:…/<last segment>"
-// (and truncated with … if still too long) when it would exceed
-// MaxWindowTitle runes.
+// "~/projects/mos": "prime8:<path>", always in full.
func WindowTitle(path string) string {
- full := windowTitleHost + path
- if runeLen(full) <= MaxWindowTitle {
- return full
- }
- seg := path
- if i := strings.LastIndex(strings.TrimRight(path, "/"), "/"); i >= 0 {
- seg = strings.TrimRight(path, "/")[i+1:]
- }
- short := []rune(windowTitleHost + "…/" + seg)
- if len(short) > MaxWindowTitle {
- short = append(short[:MaxWindowTitle-1], '…')
- }
- return string(short)
+ return windowTitleHost + path
}
-
-func runeLen(s string) int { return len([]rune(s)) }
diff --git a/internal/utils/title_test.go b/internal/utils/title_test.go
@@ -1,27 +1,16 @@
package utils
-import (
- "testing"
- "unicode/utf8"
-)
+import "testing"
func TestWindowTitle(t *testing.T) {
for in, want := range map[string]string{
- "~": "prime8:~",
- "~/projects": "prime8:~/projects",
- "~/experience": "prime8:~/experience",
- "~/projects/mos": "prime8:…/mos",
- "~/projects/janitor": "prime8:…/janitor",
- "~/projects/summarizer": "prime8:…/summarizer",
- "~/experience/hark": "prime8:…/hark",
- "~/projects/a-very-long-project-name": "prime8:…/a-very-lon…",
+ "~": "prime8:~",
+ "~/projects": "prime8:~/projects",
+ "~/projects/janitor": "prime8:~/projects/janitor",
+ "~/experience/hark": "prime8:~/experience/hark",
} {
- got := WindowTitle(in)
- if got != want {
+ if got := WindowTitle(in); got != want {
t.Errorf("WindowTitle(%q) = %q, want %q", in, got, want)
}
- if n := utf8.RuneCountInString(got); n > MaxWindowTitle {
- t.Errorf("WindowTitle(%q) is %d runes", in, n)
- }
}
}
diff --git a/internal/web/scripts/modules/header.js b/internal/web/scripts/modules/header.js
@@ -115,17 +115,9 @@ export function initHeader() {
setActiveTabUI(currentFromPath(order, fallback));
}
-// Same rules as utils.WindowTitle: "prime8:~/projects", collapsed to
-// "prime8:…/<last segment>" past 20 characters so browser tabs don't cut it.
-const MAX_TITLE = 20;
-
+// Same as utils.WindowTitle: "prime8:~/projects/janitor", always in full.
export function windowTitle(path) {
- const full = `prime8:${path}`;
- if ([...full].length <= MAX_TITLE) return full;
- const trimmed = path.replace(/\/+$/, "");
- const seg = trimmed.slice(trimmed.lastIndexOf("/") + 1);
- const short = [...`prime8:…/${seg}`];
- return short.length > MAX_TITLE ? short.slice(0, MAX_TITLE - 1).join("") + "…" : short.join("");
+ return `prime8:${path}`;
}
export function updateAppTitle() {