@@ -24,21 +24,37 @@ async function getFileIcon() {
2424let cachedApps : DetectedApplication [ ] | null = null ;
2525let detectionPromise : Promise < DetectedApplication [ ] > | null = null ;
2626
27- const APP_PATHS : Record < string , string > = {
28- vscode : "/Applications/Visual Studio Code.app" ,
29- cursor : "/Applications/Cursor.app" ,
30- sublime : "/Applications/Sublime Text.app" ,
31- webstorm : "/Applications/WebStorm.app" ,
32- intellij : "/Applications/IntelliJ IDEA.app" ,
33- zed : "/Applications/Zed.app" ,
34- pycharm : "/Applications/PyCharm.app" ,
35- iterm : "/Applications/iTerm.app" ,
36- warp : "/Applications/Warp.app" ,
37- terminal : "/System/Applications/Utilities/Terminal.app" ,
38- alacritty : "/Applications/Alacritty.app" ,
39- kitty : "/Applications/kitty.app" ,
40- ghostty : "/Applications/Ghostty.app" ,
41- finder : "/System/Library/CoreServices/Finder.app" ,
27+ interface AppDefinition {
28+ path : string ;
29+ type : ExternalAppType ;
30+ }
31+
32+ const APP_DEFINITIONS : Record < string , AppDefinition > = {
33+ // Editors
34+ vscode : { path : "/Applications/Visual Studio Code.app" , type : "editor" } ,
35+ cursor : { path : "/Applications/Cursor.app" , type : "editor" } ,
36+ sublime : { path : "/Applications/Sublime Text.app" , type : "editor" } ,
37+ webstorm : { path : "/Applications/WebStorm.app" , type : "editor" } ,
38+ intellij : { path : "/Applications/IntelliJ IDEA.app" , type : "editor" } ,
39+ zed : { path : "/Applications/Zed.app" , type : "editor" } ,
40+ pycharm : { path : "/Applications/PyCharm.app" , type : "editor" } ,
41+
42+ // Terminals
43+ iterm : { path : "/Applications/iTerm.app" , type : "terminal" } ,
44+ warp : { path : "/Applications/Warp.app" , type : "terminal" } ,
45+ terminal : {
46+ path : "/System/Applications/Utilities/Terminal.app" ,
47+ type : "terminal" ,
48+ } ,
49+ alacritty : { path : "/Applications/Alacritty.app" , type : "terminal" } ,
50+ kitty : { path : "/Applications/kitty.app" , type : "terminal" } ,
51+ ghostty : { path : "/Applications/Ghostty.app" , type : "terminal" } ,
52+
53+ // File managers
54+ finder : {
55+ path : "/System/Library/CoreServices/Finder.app" ,
56+ type : "file-manager" ,
57+ } ,
4258} ;
4359
4460const DISPLAY_NAMES : Record < string , string > = {
@@ -129,8 +145,12 @@ async function checkApplication(
129145async function detectExternalApps ( ) : Promise < DetectedApplication [ ] > {
130146 const apps : DetectedApplication [ ] = [ ] ;
131147
132- for ( const [ id , appPath ] of Object . entries ( APP_PATHS ) ) {
133- const detected = await checkApplication ( id , appPath , "editor" ) ;
148+ for ( const [ id , definition ] of Object . entries ( APP_DEFINITIONS ) ) {
149+ const detected = await checkApplication (
150+ id ,
151+ definition . path ,
152+ definition . type ,
153+ ) ;
134154 if ( detected ) {
135155 apps . push ( detected ) ;
136156 }
@@ -180,11 +200,21 @@ export function registerExternalAppsIpc(): void {
180200 return { success : false , error : "Application not found" } ;
181201 }
182202
203+ let isFile = false ;
204+ try {
205+ const stat = await fs . stat ( targetPath ) ;
206+ isFile = stat . isFile ( ) ;
207+ } catch {
208+ // if stat fails, assume it is a path that does not exist yet
209+ isFile = false ;
210+ }
211+
183212 let command : string ;
184- if ( appToOpen . command . includes ( "open -a" ) ) {
185- command = `${ appToOpen . command } "${ targetPath } "` ;
213+ if ( appToOpen . id === "finder" && isFile ) {
214+ // for Finder with files, use -R to highlight the file in its parent folder
215+ command = `open -R "${ targetPath } "` ;
186216 } else {
187- command = `${ appToOpen . command } "${ targetPath } "` ;
217+ command = `open -a " ${ appToOpen . path } " "${ targetPath } "` ;
188218 }
189219
190220 await execAsync ( command ) ;
0 commit comments