Skip to content

Commit 109ad45

Browse files
committed
feat: add acode cli
1 parent 83264c4 commit 109ad45

File tree

3 files changed

+163
-0
lines changed

3 files changed

+163
-0
lines changed

src/components/terminal/terminal.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,42 @@ export default class TerminalComponent {
120120

121121
// Handle copy/paste keybindings
122122
this.setupCopyPasteHandlers();
123+
124+
// Handle custom OSC 7777 for acode CLI commands
125+
this.setupOscHandler();
126+
}
127+
128+
/**
129+
* Setup custom OSC handler for acode CLI integration
130+
* OSC 7777 format: \e]7777;command;arg1;arg2;...\a
131+
*/
132+
setupOscHandler() {
133+
// Register custom OSC handler for ID 7777
134+
this.terminal.parser.registerOscHandler(7777, (data) => {
135+
const parts = data.split(";");
136+
const command = parts[0];
137+
138+
switch (command) {
139+
case "open":
140+
this.handleOscOpen(parts[1], parts[2]);
141+
break;
142+
default:
143+
console.warn("Unknown OSC 7777 command:", command);
144+
}
145+
return true;
146+
});
147+
}
148+
149+
/**
150+
* Handle OSC open command from acode CLI
151+
* @param {string} type - "file" or "folder"
152+
* @param {string} path - Path to open
153+
*/
154+
handleOscOpen(type, path) {
155+
if (!path) return;
156+
157+
// Emit event for the app to handle
158+
this.onOscOpen?.(type, path);
123159
}
124160

125161
/**

src/components/terminal/terminalManager.js

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import "@xterm/xterm/css/xterm.css";
99
import quickTools from "components/quickTools";
1010
import toast from "components/toast";
1111
import confirm from "dialogs/confirm";
12+
import openFile from "lib/openFile";
13+
import openFolder from "lib/openFolder";
1214
import appSettings from "lib/settings";
1315
import helpers from "utils/helpers";
1416

@@ -577,6 +579,30 @@ class TerminalManager {
577579
toast(message);
578580
};
579581

582+
// Handle acode CLI open commands (OSC 7777)
583+
terminalComponent.onOscOpen = async (type, path) => {
584+
if (!path) return;
585+
586+
// Convert proot path
587+
const fileUri = this.convertProotPath(path);
588+
// Extract folder/file name from path
589+
const name = path.split("/").filter(Boolean).pop() || "folder";
590+
591+
try {
592+
if (type === "folder") {
593+
// Open folder in sidebar
594+
await openFolder(fileUri, { name, saveState: true, listFiles: true });
595+
toast(`Opened folder: ${name}`);
596+
} else {
597+
// Open file in editor
598+
await openFile(fileUri, { render: true });
599+
}
600+
} catch (error) {
601+
console.error("Failed to open from terminal:", error);
602+
toast(`Failed to open: ${path}`);
603+
}
604+
};
605+
580606
// Store references for cleanup
581607
terminalFile._terminalId = terminalId;
582608
terminalFile.terminalComponent = terminalComponent;
@@ -791,6 +817,43 @@ class TerminalManager {
791817
});
792818
}
793819

820+
/**
821+
* Convert proot internal path to app-accessible path
822+
* @param {string} prootPath - Path from inside proot environment
823+
* @returns {string} App filesystem path
824+
*/
825+
convertProotPath(prootPath) {
826+
if (!prootPath) return prootPath;
827+
828+
const packageName = window.BuildInfo?.packageName || "com.foxdebug.acode";
829+
const dataDir = `/data/user/0/${packageName}`;
830+
const alpineRoot = `${dataDir}/files/alpine`;
831+
832+
let convertedPath;
833+
834+
if (prootPath.startsWith("/public")) {
835+
// /public -> /data/user/0/com.foxdebug.acode/files/public
836+
convertedPath = `file://${dataDir}/files${prootPath}`;
837+
} else if (prootPath.startsWith("/sdcard")) {
838+
// /sdcard
839+
convertedPath = `file://${prootPath}`;
840+
} else if (prootPath.startsWith("/storage")) {
841+
// /storage
842+
convertedPath = `file://${prootPath}`;
843+
} else if (prootPath.startsWith("/data")) {
844+
// /data
845+
convertedPath = `file://${prootPath}`;
846+
} else if (prootPath.startsWith("/")) {
847+
// Everything else is relative to alpine root
848+
convertedPath = `file://${alpineRoot}${prootPath}`;
849+
} else {
850+
convertedPath = prootPath;
851+
}
852+
853+
//console.log(`Path conversion: ${prootPath} -> ${convertedPath}`);
854+
return convertedPath;
855+
}
856+
794857
shouldConfirmTerminalClose() {
795858
const settings = appSettings?.value?.terminalSettings;
796859
if (settings && settings.confirmTabClose === false) {

src/plugins/terminal/scripts/init-alpine.sh

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,70 @@ Working with packages:
6565
EOF
6666
fi
6767

68+
# Create acode CLI tool
69+
if [ ! -e "$PREFIX/alpine/usr/local/bin/acode" ]; then
70+
mkdir -p "$PREFIX/alpine/usr/local/bin"
71+
cat <<'ACODE_CLI' > "$PREFIX/alpine/usr/local/bin/acode"
72+
#!/bin/bash
73+
# acode - Open files/folders in Acode editor
74+
# Uses OSC escape sequences to communicate with the Acode terminal
75+
76+
usage() {
77+
echo "Usage: acode [file/folder...]"
78+
echo ""
79+
echo "Open files or folders in Acode editor."
80+
echo ""
81+
echo "Examples:"
82+
echo " acode file.txt # Open a file"
83+
echo " acode . # Open current folder"
84+
echo " acode ~/project # Open a folder"
85+
echo " acode -h, --help # Show this help"
86+
}
87+
88+
get_abs_path() {
89+
local path="$1"
90+
if [[ "$path" == /* ]]; then
91+
realpath "$path" 2>/dev/null || echo "$path"
92+
else
93+
realpath "$path" 2>/dev/null || echo "$(pwd)/$path"
94+
fi
95+
}
96+
97+
open_in_acode() {
98+
local path=$(get_abs_path "$1")
99+
local type="file"
100+
[[ -d "$path" ]] && type="folder"
101+
102+
# Send OSC 7777 escape sequence: \e]7777;cmd;type;path\a
103+
# The terminal component will intercept and handle this
104+
printf '\e]7777;open;%s;%s\a' "$type" "$path"
105+
}
106+
107+
if [[ $# -eq 0 ]]; then
108+
open_in_acode "."
109+
exit 0
110+
fi
111+
112+
for arg in "$@"; do
113+
case "$arg" in
114+
-h|--help)
115+
usage
116+
exit 0
117+
;;
118+
*)
119+
if [[ -e "$arg" ]]; then
120+
open_in_acode "$arg"
121+
else
122+
echo "Error: '$arg' does not exist" >&2
123+
exit 1
124+
fi
125+
;;
126+
esac
127+
done
128+
ACODE_CLI
129+
chmod +x "$PREFIX/alpine/usr/local/bin/acode"
130+
fi
131+
68132
# Create initrc if it doesn't exist
69133
#initrc runs in bash so we can use bash features
70134
if [ ! -e "$PREFIX/alpine/initrc" ]; then

0 commit comments

Comments
 (0)