@@ -23,10 +23,44 @@ export interface UsePathTabCompletionReturn {
2323 handleTabCompletion : ( ) => boolean
2424}
2525
26+ /**
27+ * Check if a path query represents an absolute path.
28+ * Supports POSIX paths (/...), tilde paths (~...), and Windows drive/UNC paths.
29+ */
30+ export function isAbsolutePath ( searchQuery : string ) : boolean {
31+ return (
32+ searchQuery . startsWith ( '/' ) ||
33+ searchQuery . startsWith ( '~' ) ||
34+ path . isAbsolute ( searchQuery ) ||
35+ path . win32 . isAbsolute ( searchQuery )
36+ )
37+ }
38+
39+ /**
40+ * Check if a completed path represents a full directory.
41+ * Matches trailing slash (/) or Windows backslash (\).
42+ */
43+ export function isCompleteDirectory ( completed : string ) : boolean {
44+ return completed . endsWith ( '/' ) || completed . endsWith ( '\\' )
45+ }
46+
47+ /**
48+ * Convert absolute completion back to relative path for display under current directory.
49+ */
50+ export function toRelativePath (
51+ completed : string ,
52+ currentPath : string ,
53+ ) : string | null {
54+ if ( completed . startsWith ( currentPath + path . sep ) ) {
55+ return completed . slice ( currentPath . length + 1 )
56+ }
57+ return null
58+ }
59+
2660/**
2761 * Hook for path tab completion.
28- * Handles both absolute (/, ~) and relative path completion.
29- * Always navigates to completed directories when completion ends with / .
62+ * Handles both absolute (/, ~, drive letters ) and relative path completion.
63+ * Always navigates to completed directories when completion ends with a directory separator .
3064 */
3165export function usePathTabCompletion ( {
3266 searchQuery,
@@ -36,12 +70,12 @@ export function usePathTabCompletion({
3670 expandPath,
3771} : UsePathTabCompletionOptions ) : UsePathTabCompletionReturn {
3872 const handleTabCompletion = useCallback ( ( ) : boolean => {
39- if ( searchQuery . startsWith ( '/' ) || searchQuery . startsWith ( '~' ) ) {
73+ if ( isAbsolutePath ( searchQuery ) ) {
4074 // Absolute path completion
4175 const completed = getPathCompletion ( searchQuery )
4276 if ( completed ) {
43- // If completion is a full directory (ends with /), navigate there and keep the path in input
44- if ( completed . endsWith ( '/' ) ) {
77+ // If completion is a full directory (ends with / or \ ), navigate there and keep the path in input
78+ if ( isCompleteDirectory ( completed ) ) {
4579 const dirPath = expandPath ( completed . slice ( 0 , - 1 ) )
4680 try {
4781 if ( existsSync ( dirPath ) && statSync ( dirPath ) . isDirectory ( ) ) {
@@ -60,8 +94,8 @@ export function usePathTabCompletion({
6094 const relativePath = path . join ( currentPath , searchQuery )
6195 const completed = getPathCompletion ( relativePath )
6296 if ( completed ) {
63- // If completion is a full directory (ends with /), navigate there and keep the path in input
64- if ( completed . endsWith ( '/' ) ) {
97+ // If completion is a full directory (ends with / or \ ), navigate there and keep the path in input
98+ if ( isCompleteDirectory ( completed ) ) {
6599 try {
66100 const dirPath = completed . slice ( 0 , - 1 )
67101 if ( existsSync ( dirPath ) && statSync ( dirPath ) . isDirectory ( ) ) {
@@ -74,8 +108,9 @@ export function usePathTabCompletion({
74108 }
75109 }
76110 // Convert back to relative path for display
77- if ( completed . startsWith ( currentPath + path . sep ) ) {
78- setSearchQuery ( completed . slice ( currentPath . length + 1 ) )
111+ const rel = toRelativePath ( completed , currentPath )
112+ if ( rel !== null ) {
113+ setSearchQuery ( rel )
79114 } else {
80115 setSearchQuery ( completed )
81116 }
0 commit comments