Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/lib/acode.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import actionStack from "lib/actionStack";
import commands from "lib/commands";
import EditorFile from "lib/editorFile";
import files from "lib/fileList";
import fileTypeHandler from "lib/fileTypeHandler";
import fonts from "lib/fonts";
import NotificationManager from "lib/notificationManager";
import openFolder from "lib/openFolder";
Expand Down Expand Up @@ -495,4 +496,23 @@ export default class Acode {
type,
});
}

/**
* Register a custom file type handler
* @param {string} id Unique identifier for the handler
* @param {Object} options Handler configuration
* @param {string[]} options.extensions File extensions to handle (without dots)
* @param {function} options.handleFile Function that handles the file opening
*/
registerFileHandler(id, options) {
fileTypeHandler.registerFileHandler(id, options);
}

/**
* Unregister a file type handler
* @param {string} id The handler id to remove
*/
unregisterFileHandler(id) {
fileTypeHandler.unregisterFileHandler(id);
}
}
93 changes: 93 additions & 0 deletions src/lib/fileTypeHandler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/**
* @typedef {Object} FileTypeHandler
* @property {string} id - Unique identifier for the handler
* @property {string[]} extensions - File extensions this handler supports (without dots)
* @property {function} handleFile - Function that handles the file
*/

/**
* @typedef {Object} FileInfo
* @property {string} name - File name
* @property {string} uri - File URI
* @property {Object} stats - File stats
* @property {boolean} readOnly - Whether the file is read-only
* @property {Object} options - Additional options passed during file open
*/

class FileTypeHandlerRegistry {
#handlers = new Map();

/**
* Register a file type handler
* @param {string} id - Unique identifier for the handler
* @param {Object} options - Handler options
* @param {string[]} options.extensions - File extensions to handle (without dots)
* @param {function(FileInfo): Promise<void>} options.handleFile - Async function to handle the file
* @throws {Error} If id is already registered or required options are missing
*/
registerFileHandler(id, { extensions, handleFile }) {
if (this.#handlers.has(id)) {
throw new Error(`Handler with id '${id}' is already registered`);
}

if (!extensions?.length) {
throw new Error("extensions array is required");
}

if (typeof handleFile !== "function") {
throw new Error("handleFile function is required");
}

// Normalize extensions (remove dots if present, convert to lowercase)
const normalizedExts = extensions.map((ext) =>
ext.toLowerCase().replace(/^\./, ""),
);

this.#handlers.set(id, {
extensions: normalizedExts,
handleFile,
});
}

/**
* Unregister a file type handler
* @param {string} id - The handler id to remove
*/
unregisterFileHandler(id) {
this.#handlers.delete(id);
}

/**
* Get a file handler for a given filename
* @param {string} filename
* @returns {Object|null} The matching handler or null if none found
*/
getFileHandler(filename) {
const ext = filename.split(".").pop().toLowerCase();

for (const [id, handler] of this.#handlers) {
if (
handler.extensions.includes(ext) ||
handler.extensions.includes("*")
) {
return {
id,
...handler,
};
}
}

return null;
}

/**
* Get all registered handlers
* @returns {Map} Map of all registered handlers
*/
getHandlers() {
return new Map(this.#handlers);
}
}

export const fileTypeHandler = new FileTypeHandlerRegistry();
export default fileTypeHandler;
26 changes: 26 additions & 0 deletions src/lib/openFile.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { reopenWithNewEncoding } from "palettes/changeEncoding";
import { decode } from "utils/encodings";
import helpers from "utils/helpers";
import EditorFile from "./editorFile";
import fileTypeHandler from "./fileTypeHandler";
import recents from "./recents";
import appSettings from "./settings";

Expand Down Expand Up @@ -97,6 +98,31 @@ export default async function openFile(file, options = {}) {
});
};

// Check for registered file handlers
const customHandler = fileTypeHandler.getFileHandler(name);
if (customHandler) {
try {
await customHandler.handleFile({
name,
uri,
stats: fileInfo,
readOnly,
options: {
cursorPos,
render,
onsave,
encoding,
mode,
createEditor,
},
});
return;
} catch (error) {
console.error(`File handler '${customHandler.id}' failed:`, error);
// Continue with default handling if custom handler fails
}
}

if (text) {
// If file is not opened and has unsaved text
createEditor(true, text);
Expand Down
10 changes: 5 additions & 5 deletions www/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -165,17 +165,17 @@

<title>Acode</title>
<!--styles-->
<link rel="stylesheet" href="./css/build/218.css">
<link rel="stylesheet" href="./css/build/32.css">
<link rel="stylesheet" href="./css/build/383.css">
<link rel="stylesheet" href="./css/build/53.css">
<link rel="stylesheet" href="./css/build/609.css">
<link rel="stylesheet" href="./css/build/about.css">
<link rel="stylesheet" href="./css/build/customTheme.css">
<link rel="stylesheet" href="./css/build/donate.css">
<link rel="stylesheet" href="./css/build/fileBrowser.css">
<link rel="stylesheet" href="./css/build/main.css">
<link rel="stylesheet" href="./css/build/plugins.css">
<link rel="stylesheet" href="./css/build/src_pages_quickTools_quickTools_js.css">
<link rel="stylesheet" href="./css/build/src_sidebarApps_extensions_index_js.css">
<link rel="stylesheet" href="./css/build/src_sidebarApps_files_index_js.css">
<link rel="stylesheet" href="./css/build/src_sidebarApps_notification_index_js.css">
<link rel="stylesheet" href="./css/build/src_sidebarApps_searchInFiles_index_js.css">
<link rel="stylesheet" href="./css/build/themeSetting.css">
<!--styles_end-->
</head>
Expand Down