@@ -75,7 +75,6 @@ import stripAnsi from "strip-ansi"
7575import { usePromptRef } from "../../context/prompt"
7676import { useExit } from "../../context/exit"
7777import { Filesystem } from "@/util/filesystem"
78- import { Global } from "@opencode-ai/core/global"
7978import { PermissionPrompt } from "./permission"
8079import { QuestionPrompt } from "./question"
8180import { DialogExportOptions } from "../../ui/dialog-export-options"
@@ -90,6 +89,7 @@ import { SessionRetry } from "@/session/retry"
9089import { getRevertDiffFiles } from "../../util/revert-diff"
9190import { useCommandPalette } from "../../context/command-palette"
9291import { useBindings , useCommandShortcut } from "../../keymap"
92+ import { PathFormatterProvider , usePathFormatter } from "../../context/path-format"
9393
9494addDefaultParsers ( parsers . parsers )
9595
@@ -1078,23 +1078,24 @@ export function Session() {
10781078 createEffect ( on ( ( ) => route . sessionID , toBottom ) )
10791079
10801080 return (
1081- < context . Provider
1082- value = { {
1083- get width ( ) {
1084- return contentWidth ( )
1085- } ,
1086- sessionID : route . sessionID ,
1087- conceal,
1088- showThinking,
1089- showTimestamps,
1090- showDetails,
1091- showGenericToolOutput,
1092- diffWrapMode,
1093- providers,
1094- sync,
1095- tui : tuiConfig ,
1096- } }
1097- >
1081+ < PathFormatterProvider path = { session ( ) ?. directory } >
1082+ < context . Provider
1083+ value = { {
1084+ get width ( ) {
1085+ return contentWidth ( )
1086+ } ,
1087+ sessionID : route . sessionID ,
1088+ conceal,
1089+ showThinking,
1090+ showTimestamps,
1091+ showDetails,
1092+ showGenericToolOutput,
1093+ diffWrapMode,
1094+ providers,
1095+ sync,
1096+ tui : tuiConfig ,
1097+ } }
1098+ >
10981099 < box flexDirection = "row" flexGrow = { 1 } minHeight = { 0 } >
10991100 < box flexGrow = { 1 } minHeight = { 0 } paddingBottom = { 1 } paddingLeft = { 2 } paddingRight = { 2 } gap = { 1 } >
11001101 < Show when = { session ( ) } >
@@ -1270,7 +1271,8 @@ export function Session() {
12701271 </ Switch >
12711272 </ Show >
12721273 </ box >
1273- </ context . Provider >
1274+ </ context . Provider >
1275+ </ PathFormatterProvider >
12741276 )
12751277}
12761278
@@ -1827,7 +1829,7 @@ function BlockTool(props: {
18271829
18281830function Shell ( props : ToolProps < typeof ShellTool > ) {
18291831 const { theme } = useTheme ( )
1830- const sync = useSync ( )
1832+ const pathFormatter = usePathFormatter ( )
18311833 const isRunning = createMemo ( ( ) => props . part . state . status === "running" )
18321834 const output = createMemo ( ( ) => stripAnsi ( props . metadata . output ?. trim ( ) ?? "" ) )
18331835 const [ expanded , setExpanded ] = createSignal ( false )
@@ -1841,18 +1843,7 @@ function Shell(props: ToolProps<typeof ShellTool>) {
18411843 const workdirDisplay = createMemo ( ( ) => {
18421844 const workdir = props . input . workdir
18431845 if ( ! workdir || workdir === "." ) return undefined
1844-
1845- const base = sync . path . directory
1846- if ( ! base ) return undefined
1847-
1848- const absolute = path . resolve ( base , workdir )
1849- if ( absolute === base ) return undefined
1850-
1851- const home = Global . Path . home
1852- if ( ! home ) return absolute
1853-
1854- const match = absolute === home || absolute . startsWith ( home + path . sep )
1855- return match ? absolute . replace ( home , "~" ) : absolute
1846+ return pathFormatter . format ( workdir )
18561847 } )
18571848
18581849 const title = createMemo ( ( ) => {
@@ -1894,6 +1885,7 @@ function Shell(props: ToolProps<typeof ShellTool>) {
18941885
18951886function Write ( props : ToolProps < typeof WriteTool > ) {
18961887 const { theme, syntax } = useTheme ( )
1888+ const pathFormatter = usePathFormatter ( )
18971889 const code = createMemo ( ( ) => {
18981890 if ( ! props . input . content ) return ""
18991891 return props . input . content
@@ -1902,7 +1894,7 @@ function Write(props: ToolProps<typeof WriteTool>) {
19021894 return (
19031895 < Switch >
19041896 < Match when = { props . metadata . diagnostics !== undefined } >
1905- < BlockTool title = { "# Wrote " + normalizePath ( props . input . filePath ! ) } part = { props . part } >
1897+ < BlockTool title = { "# Wrote " + pathFormatter . format ( props . input . filePath ) } part = { props . part } >
19061898 < line_number fg = { theme . textMuted } minWidth = { 3 } paddingRight = { 1 } >
19071899 < code
19081900 conceal = { false }
@@ -1917,17 +1909,18 @@ function Write(props: ToolProps<typeof WriteTool>) {
19171909 </ Match >
19181910 < Match when = { true } >
19191911 < InlineTool icon = "←" pending = "Preparing write..." complete = { props . input . filePath } part = { props . part } >
1920- Write { normalizePath ( props . input . filePath ! ) }
1912+ Write { pathFormatter . format ( props . input . filePath ) }
19211913 </ InlineTool >
19221914 </ Match >
19231915 </ Switch >
19241916 )
19251917}
19261918
19271919function Glob ( props : ToolProps < typeof GlobTool > ) {
1920+ const pathFormatter = usePathFormatter ( )
19281921 return (
19291922 < InlineTool icon = "✱" pending = "Finding files..." complete = { props . input . pattern } part = { props . part } >
1930- Glob "{ props . input . pattern } " < Show when = { props . input . path } > in { normalizePath ( props . input . path ) } </ Show >
1923+ Glob "{ props . input . pattern } " < Show when = { props . input . path } > in { pathFormatter . format ( props . input . path ) } </ Show >
19311924 < Show when = { props . metadata . count } >
19321925 ({ props . metadata . count } { props . metadata . count === 1 ? "match" : "matches" } )
19331926 </ Show >
@@ -1937,6 +1930,7 @@ function Glob(props: ToolProps<typeof GlobTool>) {
19371930
19381931function Read ( props : ToolProps < typeof ReadTool > ) {
19391932 const { theme } = useTheme ( )
1933+ const pathFormatter = usePathFormatter ( )
19401934 const isRunning = createMemo ( ( ) => props . part . state . status === "running" )
19411935 const loaded = createMemo ( ( ) => {
19421936 if ( props . part . state . status !== "completed" ) return [ ]
@@ -1954,13 +1948,13 @@ function Read(props: ToolProps<typeof ReadTool>) {
19541948 spinner = { isRunning ( ) }
19551949 part = { props . part }
19561950 >
1957- Read { normalizePath ( props . input . filePath ! ) } { input ( props . input , [ "filePath" ] ) }
1951+ Read { pathFormatter . format ( props . input . filePath ) } { input ( props . input , [ "filePath" ] ) }
19581952 </ InlineTool >
19591953 < For each = { loaded ( ) } >
19601954 { ( filepath ) => (
19611955 < box paddingLeft = { 3 } >
19621956 < text paddingLeft = { 3 } fg = { theme . textMuted } >
1963- ↳ Loaded { normalizePath ( filepath ) }
1957+ ↳ Loaded { pathFormatter . format ( filepath ) }
19641958 </ text >
19651959 </ box >
19661960 ) }
@@ -1970,9 +1964,10 @@ function Read(props: ToolProps<typeof ReadTool>) {
19701964}
19711965
19721966function Grep ( props : ToolProps < typeof GrepTool > ) {
1967+ const pathFormatter = usePathFormatter ( )
19731968 return (
19741969 < InlineTool icon = "✱" pending = "Searching content..." complete = { props . input . pattern } part = { props . part } >
1975- Grep "{ props . input . pattern } " < Show when = { props . input . path } > in { normalizePath ( props . input . path ) } </ Show >
1970+ Grep "{ props . input . pattern } " < Show when = { props . input . path } > in { pathFormatter . format ( props . input . path ) } </ Show >
19761971 < Show when = { props . metadata . matches } >
19771972 ({ props . metadata . matches } { props . metadata . matches === 1 ? "match" : "matches" } )
19781973 </ Show >
@@ -2071,6 +2066,7 @@ function Task(props: ToolProps<typeof TaskTool>) {
20712066function Edit ( props : ToolProps < typeof EditTool > ) {
20722067 const ctx = use ( )
20732068 const { theme, syntax } = useTheme ( )
2069+ const pathFormatter = usePathFormatter ( )
20742070
20752071 const view = createMemo ( ( ) => {
20762072 const diffStyle = ctx . tui . diff_style
@@ -2086,7 +2082,7 @@ function Edit(props: ToolProps<typeof EditTool>) {
20862082 return (
20872083 < Switch >
20882084 < Match when = { props . metadata . diff !== undefined } >
2089- < BlockTool title = { "← Edit " + normalizePath ( props . input . filePath ! ) } part = { props . part } >
2085+ < BlockTool title = { "← Edit " + pathFormatter . format ( props . input . filePath ) } part = { props . part } >
20902086 < box paddingLeft = { 1 } >
20912087 < diff
20922088 diff = { diffContent ( ) }
@@ -2113,7 +2109,7 @@ function Edit(props: ToolProps<typeof EditTool>) {
21132109 </ Match >
21142110 < Match when = { true } >
21152111 < InlineTool icon = "←" pending = "Preparing edit..." complete = { props . input . filePath } part = { props . part } >
2116- Edit { normalizePath ( props . input . filePath ! ) } { input ( { replaceAll : props . input . replaceAll } ) }
2112+ Edit { pathFormatter . format ( props . input . filePath ) } { input ( { replaceAll : props . input . replaceAll } ) }
21172113 </ InlineTool >
21182114 </ Match >
21192115 </ Switch >
@@ -2123,6 +2119,7 @@ function Edit(props: ToolProps<typeof EditTool>) {
21232119function ApplyPatch ( props : ToolProps < typeof ApplyPatchTool > ) {
21242120 const ctx = use ( )
21252121 const { theme, syntax } = useTheme ( )
2122+ const pathFormatter = usePathFormatter ( )
21262123
21272124 const files = createMemo ( ( ) => props . metadata . files ?? [ ] )
21282125
@@ -2161,7 +2158,7 @@ function ApplyPatch(props: ToolProps<typeof ApplyPatchTool>) {
21612158 function title ( file : { type : string ; relativePath : string ; filePath : string ; deletions : number } ) {
21622159 if ( file . type === "delete" ) return "# Deleted " + file . relativePath
21632160 if ( file . type === "add" ) return "# Created " + file . relativePath
2164- if ( file . type === "move" ) return "# Moved " + normalizePath ( file . filePath ) + " → " + file . relativePath
2161+ if ( file . type === "move" ) return "# Moved " + pathFormatter . format ( file . filePath ) + " → " + file . relativePath
21652162 return "← Patched " + file . relativePath
21662163 }
21672164
@@ -2281,20 +2278,6 @@ function Diagnostics(props: { diagnostics?: Record<string, Record<string, any>[]
22812278 )
22822279}
22832280
2284- function normalizePath ( input ?: string ) {
2285- if ( ! input ) return ""
2286-
2287- const cwd = process . cwd ( )
2288- const absolute = path . isAbsolute ( input ) ? input : path . resolve ( cwd , input )
2289- const relative = path . relative ( cwd , absolute )
2290-
2291- if ( ! relative ) return "."
2292- if ( ! relative . startsWith ( ".." ) ) return relative
2293-
2294- // outside cwd - use absolute
2295- return absolute
2296- }
2297-
22982281function input ( input : Record < string , any > , omit ?: string [ ] ) : string {
22992282 const primitives = Object . entries ( input ) . filter ( ( [ key , value ] ) => {
23002283 if ( omit ?. includes ( key ) ) return false
0 commit comments