Skip to content

Commit cfbf398

Browse files
authored
Add Custom File Type Handler API (Acode-Foundation#1262)
* feat: Add Custom File Type Handler API * removed unwanted api
1 parent 4e9997c commit cfbf398

File tree

4 files changed

+144
-5
lines changed

4 files changed

+144
-5
lines changed

src/lib/acode.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import actionStack from "lib/actionStack";
2323
import commands from "lib/commands";
2424
import EditorFile from "lib/editorFile";
2525
import files from "lib/fileList";
26+
import fileTypeHandler from "lib/fileTypeHandler";
2627
import fonts from "lib/fonts";
2728
import NotificationManager from "lib/notificationManager";
2829
import openFolder from "lib/openFolder";
@@ -495,4 +496,23 @@ export default class Acode {
495496
type,
496497
});
497498
}
499+
500+
/**
501+
* Register a custom file type handler
502+
* @param {string} id Unique identifier for the handler
503+
* @param {Object} options Handler configuration
504+
* @param {string[]} options.extensions File extensions to handle (without dots)
505+
* @param {function} options.handleFile Function that handles the file opening
506+
*/
507+
registerFileHandler(id, options) {
508+
fileTypeHandler.registerFileHandler(id, options);
509+
}
510+
511+
/**
512+
* Unregister a file type handler
513+
* @param {string} id The handler id to remove
514+
*/
515+
unregisterFileHandler(id) {
516+
fileTypeHandler.unregisterFileHandler(id);
517+
}
498518
}

src/lib/fileTypeHandler.js

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/**
2+
* @typedef {Object} FileTypeHandler
3+
* @property {string} id - Unique identifier for the handler
4+
* @property {string[]} extensions - File extensions this handler supports (without dots)
5+
* @property {function} handleFile - Function that handles the file
6+
*/
7+
8+
/**
9+
* @typedef {Object} FileInfo
10+
* @property {string} name - File name
11+
* @property {string} uri - File URI
12+
* @property {Object} stats - File stats
13+
* @property {boolean} readOnly - Whether the file is read-only
14+
* @property {Object} options - Additional options passed during file open
15+
*/
16+
17+
class FileTypeHandlerRegistry {
18+
#handlers = new Map();
19+
20+
/**
21+
* Register a file type handler
22+
* @param {string} id - Unique identifier for the handler
23+
* @param {Object} options - Handler options
24+
* @param {string[]} options.extensions - File extensions to handle (without dots)
25+
* @param {function(FileInfo): Promise<void>} options.handleFile - Async function to handle the file
26+
* @throws {Error} If id is already registered or required options are missing
27+
*/
28+
registerFileHandler(id, { extensions, handleFile }) {
29+
if (this.#handlers.has(id)) {
30+
throw new Error(`Handler with id '${id}' is already registered`);
31+
}
32+
33+
if (!extensions?.length) {
34+
throw new Error("extensions array is required");
35+
}
36+
37+
if (typeof handleFile !== "function") {
38+
throw new Error("handleFile function is required");
39+
}
40+
41+
// Normalize extensions (remove dots if present, convert to lowercase)
42+
const normalizedExts = extensions.map((ext) =>
43+
ext.toLowerCase().replace(/^\./, ""),
44+
);
45+
46+
this.#handlers.set(id, {
47+
extensions: normalizedExts,
48+
handleFile,
49+
});
50+
}
51+
52+
/**
53+
* Unregister a file type handler
54+
* @param {string} id - The handler id to remove
55+
*/
56+
unregisterFileHandler(id) {
57+
this.#handlers.delete(id);
58+
}
59+
60+
/**
61+
* Get a file handler for a given filename
62+
* @param {string} filename
63+
* @returns {Object|null} The matching handler or null if none found
64+
*/
65+
getFileHandler(filename) {
66+
const ext = filename.split(".").pop().toLowerCase();
67+
68+
for (const [id, handler] of this.#handlers) {
69+
if (
70+
handler.extensions.includes(ext) ||
71+
handler.extensions.includes("*")
72+
) {
73+
return {
74+
id,
75+
...handler,
76+
};
77+
}
78+
}
79+
80+
return null;
81+
}
82+
83+
/**
84+
* Get all registered handlers
85+
* @returns {Map} Map of all registered handlers
86+
*/
87+
getHandlers() {
88+
return new Map(this.#handlers);
89+
}
90+
}
91+
92+
export const fileTypeHandler = new FileTypeHandlerRegistry();
93+
export default fileTypeHandler;

src/lib/openFile.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { reopenWithNewEncoding } from "palettes/changeEncoding";
77
import { decode } from "utils/encodings";
88
import helpers from "utils/helpers";
99
import EditorFile from "./editorFile";
10+
import fileTypeHandler from "./fileTypeHandler";
1011
import recents from "./recents";
1112
import appSettings from "./settings";
1213

@@ -97,6 +98,31 @@ export default async function openFile(file, options = {}) {
9798
});
9899
};
99100

101+
// Check for registered file handlers
102+
const customHandler = fileTypeHandler.getFileHandler(name);
103+
if (customHandler) {
104+
try {
105+
await customHandler.handleFile({
106+
name,
107+
uri,
108+
stats: fileInfo,
109+
readOnly,
110+
options: {
111+
cursorPos,
112+
render,
113+
onsave,
114+
encoding,
115+
mode,
116+
createEditor,
117+
},
118+
});
119+
return;
120+
} catch (error) {
121+
console.error(`File handler '${customHandler.id}' failed:`, error);
122+
// Continue with default handling if custom handler fails
123+
}
124+
}
125+
100126
if (text) {
101127
// If file is not opened and has unsaved text
102128
createEditor(true, text);

www/index.html

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -165,17 +165,17 @@
165165

166166
<title>Acode</title>
167167
<!--styles-->
168+
<link rel="stylesheet" href="./css/build/218.css">
169+
<link rel="stylesheet" href="./css/build/32.css">
170+
<link rel="stylesheet" href="./css/build/383.css">
171+
<link rel="stylesheet" href="./css/build/53.css">
172+
<link rel="stylesheet" href="./css/build/609.css">
168173
<link rel="stylesheet" href="./css/build/about.css">
169174
<link rel="stylesheet" href="./css/build/customTheme.css">
170175
<link rel="stylesheet" href="./css/build/donate.css">
171176
<link rel="stylesheet" href="./css/build/fileBrowser.css">
172177
<link rel="stylesheet" href="./css/build/main.css">
173178
<link rel="stylesheet" href="./css/build/plugins.css">
174-
<link rel="stylesheet" href="./css/build/src_pages_quickTools_quickTools_js.css">
175-
<link rel="stylesheet" href="./css/build/src_sidebarApps_extensions_index_js.css">
176-
<link rel="stylesheet" href="./css/build/src_sidebarApps_files_index_js.css">
177-
<link rel="stylesheet" href="./css/build/src_sidebarApps_notification_index_js.css">
178-
<link rel="stylesheet" href="./css/build/src_sidebarApps_searchInFiles_index_js.css">
179179
<link rel="stylesheet" href="./css/build/themeSetting.css">
180180
<!--styles_end-->
181181
</head>

0 commit comments

Comments
 (0)