@@ -28,39 +28,104 @@ interface OpenFileOptions {
2828
2929export async function openFile ( filePath : string , options : OpenFileOptions = { } ) {
3030 try {
31- // Get workspace root
3231 const workspaceRoot = getWorkspacePath ( )
32+ const homeDir = os . homedir ( )
33+ const originalFilePathForError = filePath // Keep original for error messages
3334
34- // If path starts with ./, resolve it relative to workspace root if available
35- // Otherwise, use the path as provided without modification
36- const fullPath = filePath . startsWith ( "./" )
37- ? workspaceRoot
38- ? path . join ( workspaceRoot , filePath . slice ( 2 ) )
39- : filePath
40- : filePath
35+ const attemptPaths : string [ ] = [ ]
4136
42- const uri = vscode . Uri . file ( fullPath )
37+ if ( filePath . startsWith ( "./" ) ) {
38+ const relativePart = filePath . slice ( 2 )
39+ if ( workspaceRoot ) {
40+ attemptPaths . push ( path . join ( workspaceRoot , relativePart ) )
41+ }
42+ if ( homeDir ) {
43+ const homePath = path . join ( homeDir , relativePart )
44+ // Add home path if it's different from what might have been added via workspaceRoot
45+ // (e.g. if workspaceRoot itself is the home directory)
46+ if ( ! attemptPaths . includes ( homePath ) ) {
47+ attemptPaths . push ( homePath )
48+ }
49+ }
50+ // If no workspace and no home, or if paths were identical.
51+ if ( attemptPaths . length === 0 ) {
52+ attemptPaths . push ( filePath ) // Try the original relative path as a last resort
53+ }
54+ } else {
55+ attemptPaths . push ( filePath ) // Assumed absolute or directly resolvable
56+ }
4357
44- // Check if file exists
45- try {
46- await vscode . workspace . fs . stat ( uri )
47- } catch {
48- // File doesn't exist
49- if ( ! options . create ) {
50- throw new Error ( "File does not exist" )
58+ let fileStat : vscode . FileStat | undefined
59+ let successfulUri : vscode . Uri | undefined
60+
61+ for ( const p of attemptPaths ) {
62+ try {
63+ const tempUri = vscode . Uri . file ( p )
64+ fileStat = await vscode . workspace . fs . stat ( tempUri )
65+ successfulUri = tempUri // Path found
66+ break // Exit loop once a path is successfully stated
67+ } catch ( e ) {
68+ // Stat failed for this path, continue to the next one
5169 }
70+ }
5271
53- // Create with provided content or empty string
54- const content = options . content || ""
55- await vscode . workspace . fs . writeFile ( uri , Buffer . from ( content , "utf8" ) )
72+ let uriToProcess : vscode . Uri
73+
74+ if ( fileStat && successfulUri ) {
75+ // Path was found
76+ if ( fileStat . type === vscode . FileType . Directory ) {
77+ await vscode . commands . executeCommand ( "revealInExplorer" , successfulUri )
78+ // Attempt to expand the revealed directory in the explorer.
79+ // This requires the explorer to have focus and the item to be selected.
80+ // A slight delay might sometimes be needed for focus to shift,
81+ // but often it works immediately after revealInExplorer.
82+ try {
83+ await vscode . commands . executeCommand ( "list.expand" )
84+ } catch ( expandError ) {
85+ // Log or handle if expansion specifically fails, though often not critical
86+ console . warn ( "Could not expand directory in explorer:" , expandError )
87+ }
88+ return // Done for directories
89+ }
90+ uriToProcess = successfulUri // It's an existing file
91+ } else {
92+ // Path was not found in any attempted locations. Consider creation.
93+ if (
94+ options . create &&
95+ ! ( originalFilePathForError . endsWith ( "/" ) || originalFilePathForError . endsWith ( "\\" ) )
96+ ) {
97+ let pathToCreateAt : string
98+ if ( originalFilePathForError . startsWith ( "./" ) ) {
99+ const relativePart = originalFilePathForError . slice ( 2 )
100+ if ( workspaceRoot ) {
101+ pathToCreateAt = path . join ( workspaceRoot , relativePart )
102+ } else if ( homeDir ) {
103+ pathToCreateAt = path . join ( homeDir , relativePart )
104+ } else {
105+ pathToCreateAt = originalFilePathForError // Fallback: use original relative path
106+ }
107+ } else {
108+ pathToCreateAt = originalFilePathForError // Absolute path
109+ }
110+
111+ uriToProcess = vscode . Uri . file ( pathToCreateAt )
112+ const contentToCreate = options . content || ""
113+ await vscode . workspace . fs . writeFile ( uriToProcess , Buffer . from ( contentToCreate , "utf8" ) )
114+ // File is now created, uriToProcess points to it.
115+ } else {
116+ // Not creating, or it's a directory-like path that doesn't exist.
117+ throw new Error ( `Path does not exist: ${ originalFilePathForError } ` )
118+ }
56119 }
57120
121+ // At this point, uriToProcess points to an existing file or a newly created file.
58122 // Check if the document is already open in a tab group that's not in the active editor's column
59123 try {
60124 for ( const group of vscode . window . tabGroups . all ) {
61125 const existingTab = group . tabs . find (
62126 ( tab ) =>
63- tab . input instanceof vscode . TabInputText && arePathsEqual ( tab . input . uri . fsPath , uri . fsPath ) ,
127+ tab . input instanceof vscode . TabInputText &&
128+ arePathsEqual ( tab . input . uri . fsPath , uriToProcess . fsPath ) ,
64129 )
65130 if ( existingTab ) {
66131 const activeColumn = vscode . window . activeTextEditor ?. viewColumn
@@ -75,7 +140,7 @@ export async function openFile(filePath: string, options: OpenFileOptions = {})
75140 }
76141 } catch { } // not essential, sometimes tab operations fail
77142
78- const document = await vscode . workspace . openTextDocument ( uri )
143+ const document = await vscode . workspace . openTextDocument ( uriToProcess )
79144 const selection =
80145 options . line !== undefined
81146 ? new vscode . Selection ( Math . max ( options . line - 1 , 0 ) , 0 , Math . max ( options . line - 1 , 0 ) , 0 )
0 commit comments