fix(editor): keep long file paths distinguishable (#21631)

* fix(editor): keep filename visible in long paths

* fix(review): keep diff filenames visible

* fix(review): prevent path metadata overlap
This commit is contained in:
Neil
2026-09-19 15:43:45 -07:00
committed by GitHub
parent cef4416115
commit 844e9df98f
5 changed files with 62 additions and 15 deletions
+20 -3
View File
@@ -1094,14 +1094,18 @@ html.native-shell .app-layout {
.editor-header-text {
min-width: 0;
flex: 1;
overflow: hidden;
}
.editor-header-path {
display: block;
display: flex;
align-items: center;
min-width: 0;
flex: 0 1 auto;
flex: 1 1 auto;
padding: 0;
max-width: 100%;
width: 100%;
overflow: hidden;
border: none;
background: transparent;
color: var(--muted-foreground);
@@ -1116,9 +1120,21 @@ html.native-shell .app-layout {
Consolas,
monospace;
white-space: nowrap;
text-align: left;
}
.path-display-prefix,
.editor-header-path-prefix {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
text-align: left;
white-space: nowrap;
}
.path-display-file,
.editor-header-path-file {
flex: 0 0 auto;
white-space: nowrap;
}
.editor-header-path:hover,
@@ -1140,6 +1156,7 @@ html.native-shell .app-layout {
align-items: center;
gap: 8px;
min-width: 0;
overflow: hidden;
}
.editor-header-copy-toast {
@@ -1,6 +1,7 @@
import { ChevronDown, ChevronRight, ExternalLink, Eye } from 'lucide-react'
import type { MouseEvent, ReactElement, ReactNode } from 'react'
import { translate } from '@/i18n/i18n'
import { splitPathForDisplay } from './editor-path-display'
export function DiffSectionHeader({
path,
@@ -25,16 +26,17 @@ export function DiffSectionHeader({
onOpenPreview?: (event: MouseEvent) => void
trailingContent?: ReactNode
}): ReactElement {
const displayPath = splitPathForDisplay(path)
return (
<div
className="sticky top-0 z-10 bg-background flex items-center w-full px-3 py-1.5 text-left text-xs hover:bg-accent transition-colors group cursor-pointer"
onClick={onToggle}
>
<span className="min-w-0 flex-1 truncate text-muted-foreground">
<span className="flex min-w-0 flex-1 items-center text-muted-foreground">
<span
role="button"
tabIndex={0}
className="cursor-copy hover:underline"
className="flex min-w-0 flex-1 cursor-copy overflow-hidden hover:underline"
onMouseDown={(event) => {
event.preventDefault()
event.stopPropagation()
@@ -60,16 +62,19 @@ export function DiffSectionHeader({
}}
title={translate('auto.components.editor.DiffSectionHeader.8915726e93', 'Copy path')}
>
{path}
<span className="path-display-prefix">{displayPath.prefix}</span>
<span className="path-display-file">{displayPath.fileName}</span>
</span>
<span className="flex shrink-0 items-center">
{dirty && <span className="font-medium ml-1">M</span>}
{(added > 0 || removed > 0) && (
<span className="tabular-nums ml-2">
{added > 0 && <span className="text-green-600 dark:text-green-500">+{added}</span>}
{added > 0 && removed > 0 && <span> </span>}
{removed > 0 && <span className="text-red-500">-{removed}</span>}
</span>
)}
</span>
{dirty && <span className="font-medium ml-1">M</span>}
{(added > 0 || removed > 0) && (
<span className="tabular-nums ml-2">
{added > 0 && <span className="text-green-600 dark:text-green-500">+{added}</span>}
{added > 0 && removed > 0 && <span> </span>}
{removed > 0 && <span className="text-red-500">-{removed}</span>}
</span>
)}
</span>
<div className="flex items-center gap-1 shrink-0 ml-2">
{trailingContent}
@@ -15,6 +15,7 @@ import type { OpenFile } from '@/store/slices/editor'
import { CLOSE_ALL_CONTEXT_MENUS_EVENT } from '../tab-bar/SortableTab'
import { useEditorHeaderFileRename } from './editor-header-file-rename'
import { getEditorHeaderCopyState } from './editor-header'
import { splitPathForDisplay } from './editor-path-display'
const isMac = navigator.userAgent.includes('Mac')
const isLinux = navigator.userAgent.includes('Linux')
@@ -55,6 +56,7 @@ export function EditorPanelHeaderPath({
const [pathMenuPoint, setPathMenuPoint] = useState({ x: 0, y: 0 })
const skipMenuFocusRestoreRef = useRef(false)
const headerCopyState = getEditorHeaderCopyState(activeFile)
const displayPath = splitPathForDisplay(headerCopyState.pathLabel)
const canCopyHeaderPath = headerCopyState.copyText !== null
const isVirtualEditorTab = activeFile.mode === 'check-details'
const markdownPreviewShortcutLabel = useShortcutLabel('editor.markdownPreview')
@@ -124,7 +126,8 @@ export function EditorPanelHeaderPath({
disabled={!canCopyHeaderPath}
title={headerCopyState.pathTitle}
>
{headerCopyState.pathLabel}
<span className="editor-header-path-prefix">{displayPath.prefix}</span>
<span className="editor-header-path-file">{displayPath.fileName}</span>
</button>
)}
<span
@@ -0,0 +1,12 @@
import { describe, expect, it } from 'vitest'
import { splitPathForDisplay } from './editor-path-display'
describe('splitPathForDisplay', () => {
it.each([
['/repo/src/file.ts', { prefix: '/repo/src/', fileName: 'file.ts' }],
['C:\\repo\\src\\file.ts', { prefix: 'C:\\repo\\src\\', fileName: 'file.ts' }],
['file.ts', { prefix: '', fileName: 'file.ts' }]
])('keeps the final filename separate for %s', (path, expected) => {
expect(splitPathForDisplay(path)).toEqual(expected)
})
})
@@ -0,0 +1,10 @@
export function splitPathForDisplay(path: string): { prefix: string; fileName: string } {
const separatorIndex = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\'))
if (separatorIndex < 0) {
return { prefix: '', fileName: path }
}
return {
prefix: path.slice(0, separatorIndex + 1),
fileName: path.slice(separatorIndex + 1)
}
}