Skip to content

Commit df320d5

Browse files
committed
feat: add "Open in Terminal" option to folder context menu
1 parent b82d3f7 commit df320d5

File tree

2 files changed

+76
-1
lines changed

2 files changed

+76
-1
lines changed

src/lang/en-us.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
"open file": "Open file",
6060
"open files and folders": "Open files and folders",
6161
"open folder": "Open folder",
62+
"open in terminal": "Open in Terminal",
6263
"open recent": "Open recent",
6364
"ok": "ok",
6465
"overwrite": "Overwrite",

src/lib/openFolder.js

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import sidebarApps from "sidebarApps";
33
import collapsableList from "components/collapsableList";
44
import FileTree from "components/fileTree";
55
import Sidebar from "components/sidebar";
6+
import { TerminalManager } from "components/terminal";
67
import tile from "components/tile";
78
import toast from "components/toast";
89
import alert from "dialogs/alert";
@@ -27,6 +28,39 @@ const isAcodeTerminalPublicSafUri = (value = "") =>
2728
const isTerminalSafUri = (value = "") =>
2829
isTermuxSafUri(value) || isAcodeTerminalPublicSafUri(value);
2930

31+
const getTerminalPaths = () => {
32+
const packageName = window.BuildInfo?.packageName || "com.foxdebug.acode";
33+
const dataDir = `/data/user/0/${packageName}`;
34+
const alpineRoot = `${dataDir}/files/alpine`;
35+
const publicDir = `${dataDir}/files/public`;
36+
return { alpineRoot, publicDir, dataDir };
37+
};
38+
39+
const isTerminalAccessiblePath = (url = "") => {
40+
if (isAcodeTerminalPublicSafUri(url)) return true;
41+
const { alpineRoot, publicDir } = getTerminalPaths();
42+
const cleanUrl = url.replace(/^file:\/\//, "");
43+
if (cleanUrl.startsWith(alpineRoot) || cleanUrl.startsWith(publicDir)) {
44+
return true;
45+
}
46+
return false;
47+
};
48+
49+
const convertToProotPath = (url = "") => {
50+
const { alpineRoot, publicDir } = getTerminalPaths();
51+
if (isAcodeTerminalPublicSafUri(url)) {
52+
return "/public";
53+
}
54+
const cleanUrl = url.replace(/^file:\/\//, "");
55+
if (cleanUrl.startsWith(publicDir)) {
56+
return cleanUrl.replace(publicDir, "/public");
57+
}
58+
if (cleanUrl.startsWith(alpineRoot)) {
59+
return cleanUrl.replace(alpineRoot, "") || "/";
60+
}
61+
return cleanUrl;
62+
};
63+
3064
/**
3165
* @typedef {import('../components/collapsableList').Collapsible} Collapsible
3266
*/
@@ -311,14 +345,34 @@ async function handleContextmenu(type, url, name, $target) {
311345
}
312346

313347
options.push(NEW_FILE, NEW_FOLDER, OPEN_FOLDER, INSERT_FILE);
348+
349+
if (isTerminalAccessiblePath(url)) {
350+
const OPEN_IN_TERMINAL = [
351+
"open-in-terminal",
352+
strings["open in terminal"] || "Open in Terminal",
353+
"licons terminal",
354+
];
355+
options.push(OPEN_IN_TERMINAL);
356+
}
314357
} else if (type === "root") {
315358
options = [];
316359

317360
if (clipBoard.url != null) {
318361
options.push(PASTE);
319362
}
320363

321-
options.push(NEW_FILE, NEW_FOLDER, INSERT_FILE, CLOSE_FOLDER);
364+
options.push(NEW_FILE, NEW_FOLDER, INSERT_FILE);
365+
366+
if (isTerminalAccessiblePath(url)) {
367+
const OPEN_IN_TERMINAL = [
368+
"open-in-terminal",
369+
strings["open in terminal"] || "Open in Terminal",
370+
"licons terminal",
371+
];
372+
options.push(OPEN_IN_TERMINAL);
373+
}
374+
375+
options.push(CLOSE_FOLDER);
322376
}
323377

324378
if (clipBoard.action) options.push(CANCEL);
@@ -378,6 +432,9 @@ function execOperation(type, action, url, $target, name) {
378432

379433
case "install-plugin":
380434
return installPlugin();
435+
436+
case "open-in-terminal":
437+
return openInTerminal();
381438
}
382439

383440
async function installPlugin() {
@@ -396,6 +453,23 @@ function execOperation(type, action, url, $target, name) {
396453
}
397454
}
398455

456+
async function openInTerminal() {
457+
try {
458+
const prootPath = convertToProotPath(url);
459+
const terminal = await TerminalManager.createTerminal({
460+
name: `Terminal - ${name}`,
461+
render: true,
462+
});
463+
if (terminal?.component) {
464+
terminal.component.write(`cd ${JSON.stringify(prootPath)}\n`);
465+
Sidebar.hide();
466+
}
467+
} catch (error) {
468+
console.error("Failed to open terminal:", error);
469+
toast(strings["error"] || "Error");
470+
}
471+
}
472+
399473
async function deleteFile() {
400474
const msg = strings["delete entry"].replace("{name}", name);
401475
const confirmation = await confirm(strings.warning, msg);

0 commit comments

Comments
 (0)