fix(tui): truncate project picker paths (#39678)
This commit is contained in:
parent
cba5ba03e3
commit
ce7a7e4e23
3 changed files with 30 additions and 9 deletions
|
|
@ -8,6 +8,9 @@ import { abbreviateHome } from "../runtime"
|
||||||
import { useTuiPaths } from "../context/runtime"
|
import { useTuiPaths } from "../context/runtime"
|
||||||
import { useLocation } from "../context/location"
|
import { useLocation } from "../context/location"
|
||||||
import { useToast } from "../ui/toast"
|
import { useToast } from "../ui/toast"
|
||||||
|
import { useTerminalDimensions } from "@opentui/solid"
|
||||||
|
import { truncateFilePath } from "../ui/file-path"
|
||||||
|
import { stringWidth } from "../util/string-width"
|
||||||
|
|
||||||
export function DialogProject() {
|
export function DialogProject() {
|
||||||
const dialog = useDialog()
|
const dialog = useDialog()
|
||||||
|
|
@ -16,6 +19,7 @@ export function DialogProject() {
|
||||||
const paths = useTuiPaths()
|
const paths = useTuiPaths()
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const toast = useToast()
|
const toast = useToast()
|
||||||
|
const dimensions = useTerminalDimensions()
|
||||||
|
|
||||||
data.project.invalidate()
|
data.project.invalidate()
|
||||||
void data.project.sync().catch(toast.error)
|
void data.project.sync().catch(toast.error)
|
||||||
|
|
@ -36,12 +40,19 @@ export function DialogProject() {
|
||||||
if (b.id === current()?.id) return 1
|
if (b.id === current()?.id) return 1
|
||||||
return 0
|
return 0
|
||||||
})
|
})
|
||||||
.map((project) => ({
|
.map((project) => {
|
||||||
title: project.name ?? path.basename(project.canonical),
|
const title = project.name ?? path.basename(project.canonical)
|
||||||
description: abbreviateHome(project.canonical, paths.home),
|
const description = abbreviateHome(project.canonical, paths.home)
|
||||||
value: project.canonical,
|
// Dialog padding, the current marker, title padding, and the separating space use nine columns.
|
||||||
category: project.id === current()?.id ? "Current" : "Projects",
|
const width = Math.min(60, dimensions().width - 2) - 9 - stringWidth(title)
|
||||||
}))
|
return {
|
||||||
|
title,
|
||||||
|
description: truncateFilePath(description, width),
|
||||||
|
searchText: description,
|
||||||
|
value: project.canonical,
|
||||||
|
category: project.id === current()?.id ? "Current" : "Projects",
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -62,9 +62,14 @@ export function truncateFilePath(value: string, maxWidth: number) {
|
||||||
const separatorWidth = stringWidth(separator)
|
const separatorWidth = stringWidth(separator)
|
||||||
let width = stringWidth(prefix + basename)
|
let width = stringWidth(prefix + basename)
|
||||||
for (let index = segments.length - 2; index >= 0; index--) {
|
for (let index = segments.length - 2; index >= 0; index--) {
|
||||||
const next = stringWidth(segments[index]!) + separatorWidth
|
const segment = segments[index]!
|
||||||
if (width + next > maxWidth) break
|
const next = stringWidth(segment) + separatorWidth
|
||||||
selected.unshift(segments[index]!)
|
if (width + next > maxWidth) {
|
||||||
|
const available = maxWidth - width - separatorWidth
|
||||||
|
if (available > 1) selected.unshift(takeStart(segment, available - 1) + "…")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
selected.unshift(segment)
|
||||||
width += next
|
width += next
|
||||||
}
|
}
|
||||||
return prefix + selected.join(separator)
|
return prefix + selected.join(separator)
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,11 @@ describe("truncateFilePath", () => {
|
||||||
expect(truncateFilePath(path, 19)).toBe("…/dialog-select.tsx")
|
expect(truncateFilePath(path, 19)).toBe("…/dialog-select.tsx")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("uses remaining width for part of a long parent segment", () => {
|
||||||
|
const path = "/private/var/folders/run-17f048ec-dbb2-4b36-860c-98637bb51a8d/files"
|
||||||
|
expect(truncateFilePath(path, 40)).toBe("/…/run-17f048ec-dbb2-4b36-860c-98…/files")
|
||||||
|
})
|
||||||
|
|
||||||
test("preserves the extension when the basename must shrink", () => {
|
test("preserves the extension when the basename must shrink", () => {
|
||||||
expect(truncateFilePath(path, 16)).toBe("…/dialog-se….tsx")
|
expect(truncateFilePath(path, 16)).toBe("…/dialog-se….tsx")
|
||||||
expect(truncateFilePath("dialog-select.tsx", 12)).toBe("dialog-….tsx")
|
expect(truncateFilePath("dialog-select.tsx", 12)).toBe("dialog-….tsx")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue