diff --git a/packages/local-open-targets/src/index.ts b/packages/local-open-targets/src/index.ts index ad73e9f01a..ba5ce125fe 100644 --- a/packages/local-open-targets/src/index.ts +++ b/packages/local-open-targets/src/index.ts @@ -369,6 +369,16 @@ function parseDesktopEntryValue(line: string): [string, string] | null { ]; } +const LINUX_WORKSPACE_APPLICATION_CATEGORIES = new Set([ + "FileManager", + "TerminalEmulator", + "TextEditor", +]); + +function parseDesktopEntryList(value: string | undefined): string[] { + return value?.split(";").filter(Boolean) ?? []; +} + function parseLinuxDesktopApplication( desktopFilePath: string, content: string, @@ -403,7 +413,14 @@ function parseLinuxDesktopApplication( const label = fields.get("Name"); const exec = fields.get("Exec"); - if (!label || !exec) { + const categories = parseDesktopEntryList(fields.get("Categories")); + if ( + !label || + !exec || + !categories.some((category) => + LINUX_WORKSPACE_APPLICATION_CATEGORIES.has(category), + ) + ) { return null; } diff --git a/packages/local-open-targets/test/workspace-open-targets.test.ts b/packages/local-open-targets/test/workspace-open-targets.test.ts index b7a6486bdb..4e435e5e94 100644 --- a/packages/local-open-targets/test/workspace-open-targets.test.ts +++ b/packages/local-open-targets/test/workspace-open-targets.test.ts @@ -234,6 +234,7 @@ describe("workspace open targets", () => { "[Desktop Entry]", "Type=Application", "Name=Mock Edit", + "Categories=Utility;TextEditor;", "Exec=mockedit --open %f", "", ].join("\n"), @@ -245,10 +246,41 @@ describe("workspace open targets", () => { "Type=Application", "Name=Hidden App", "NoDisplay=true", + "Categories=TextEditor;", "Exec=hidden %f", "", ].join("\n"), ); + await Promise.all( + [ + ["files", "Files", "FileManager"], + ["terminal", "Terminal", "TerminalEmulator"], + ].map(async ([id, name, category]) => + writeFile( + path.join(desktopDirectory, `${id}.desktop`), + [ + "[Desktop Entry]", + "Type=Application", + `Name=${name}`, + `Categories=System;${category};`, + `Exec=${id} %f`, + "", + ].join("\n"), + ), + ), + ); + await writeFile( + path.join(desktopDirectory, "unrelated.desktop"), + [ + "[Desktop Entry]", + "Type=Application", + "Name=Music Player", + "Categories=AudioVideo;Player;", + "MimeType=audio/mpeg;inode/directory;", + "Exec=music-player %f", + "", + ].join("\n"), + ); try { const targets = await listWorkspaceOpenTargetsWithRuntime( @@ -258,8 +290,12 @@ describe("workspace open targets", () => { }), ); - expect(targets).toEqual([ - { + expect(targets).toEqual( + [ + ["desktop-app:files", "Files"], + ["desktop-app:mockedit", "Mock Edit"], + ["desktop-app:terminal", "Terminal"], + ].map(([id, label]) => ({ capabilities: { openDirectory: true, openFile: true, @@ -267,11 +303,11 @@ describe("workspace open targets", () => { openFileAtLine: false, }, icon: { kind: "symbol", name: "app" }, - id: "desktop-app:mockedit", + id, kind: "native-app", - label: "Mock Edit", - }, - ]); + label, + })), + ); } finally { await rm(root, { force: true, recursive: true }); } @@ -472,6 +508,7 @@ describe("workspace open targets", () => { "[Desktop Entry]", "Type=Application", "Name=Mock Edit", + "Categories=TextEditor;", "Exec=mockedit --open %f", "", ].join("\n"),