Compare commits

...

4 Commits

7 changed files with 165 additions and 7 deletions

View File

@ -3,7 +3,6 @@ import { MakerSquirrel } from "@electron-forge/maker-squirrel";
import { MakerZIP } from "@electron-forge/maker-zip"; import { MakerZIP } from "@electron-forge/maker-zip";
import { MakerDeb } from "@electron-forge/maker-deb"; import { MakerDeb } from "@electron-forge/maker-deb";
import { MakerRpm } from "@electron-forge/maker-rpm"; import { MakerRpm } from "@electron-forge/maker-rpm";
import { MakerFlatpak } from "@electron-forge/maker-flatpak";
import { VitePlugin } from "@electron-forge/plugin-vite"; import { VitePlugin } from "@electron-forge/plugin-vite";
import { FusesPlugin } from "@electron-forge/plugin-fuses"; import { FusesPlugin } from "@electron-forge/plugin-fuses";
import { FuseV1Options, FuseVersion } from "@electron/fuses"; import { FuseV1Options, FuseVersion } from "@electron/fuses";
@ -22,8 +21,8 @@ const config: ForgeConfig = {
makers: [ makers: [
new MakerSquirrel({}), new MakerSquirrel({}),
new MakerZIP({}), new MakerZIP({}),
new MakerRpm({ options: { icon: "res/icon.png", categories: ["Development"] } }), new MakerRpm({ options: { icon: "res/icon.png", categories: ["Development"], name: "miller-ide" } }),
new MakerDeb({ options: { icon: "res/icon.png", categories: ["Development"] } }), new MakerDeb({ options: { icon: "res/icon.png", categories: ["Development"], name: "miller-ide" } }),
], ],
plugins: [ plugins: [
new VitePlugin({ new VitePlugin({

View File

@ -1,7 +1,7 @@
{ {
"name": "miller", "name": "miller",
"productName": "miller", "productName": "miller",
"version": "0.2.4", "version": "0.2.5",
"description": "Column-based code editor", "description": "Column-based code editor",
"main": ".vite/build/main.js", "main": ".vite/build/main.js",
"scripts": { "scripts": {

View File

@ -51,7 +51,7 @@ const fixedHeightEditor = EditorView.theme({
minHeight: "1em", minHeight: "1em",
resize: "horizontal", resize: "horizontal",
overflow: "auto", overflow: "auto",
width: "768px", width: "864px",
minWidth: "8em", minWidth: "8em",
flex: "none", flex: "none",
fontSize: "16px", fontSize: "16px",
@ -184,7 +184,7 @@ export class Editor extends Displayable {
} catch (err) { } catch (err) {
console.warn("Failed to apply LSP extension:", err); console.warn("Failed to apply LSP extension:", err);
} }
}); }).catch((err) => console.warn("Failed to create LSP extension:",err));
}); });
van.derive(() => { van.derive(() => {

View File

@ -7,6 +7,8 @@ import * as u from "./utils";
import { Editor } from "./editor"; import { Editor } from "./editor";
import { Terminal } from "./terminal"; import { Terminal } from "./terminal";
import { Displayable } from "./displayable"; import { Displayable } from "./displayable";
import { QuickOpen } from "./quickopen";
import { toggleSidebar } from "./renderer";
const EditorWrapper = ( const EditorWrapper = (
editor: State<Displayable>, editor: State<Displayable>,
@ -135,6 +137,15 @@ function shortcutHandler(e: KeyboardEvent) {
addTerminal(); addTerminal();
} }
e.preventDefault(); e.preventDefault();
} else if (e.key === "p" && e.ctrlKey) {
if (e.type === "keydown") {
QuickOpen.open();
}
e.preventDefault();
} else if (e.key === "b" && e.ctrlKey) {
if (e.type === "keydown") {
toggleSidebar();
}
} }
} }

View File

@ -57,7 +57,7 @@ window.electronAPI.onFsEvent(async (ev: { event: string; path: string }) => {
// Read latest contents from disk // Read latest contents from disk
const data = await window.electronAPI const data = await window.electronAPI
.readFile(ev.path) .readFile(ev.path)
.catch(() => null); .catch((): any => null);
if (!data) return; if (!data) return;
if (ev.event === "unlink") { if (ev.event === "unlink") {
openFile.knownDiskContent.val = null; openFile.knownDiskContent.val = null;
@ -125,3 +125,19 @@ const FsItemView = (tree: FolderTree): HTMLElement => {
return folder; return folder;
}; };
function allFilesFromTree(t: FolderTree): string[] {
if (t.type == "directory") {
return t.children.flatMap(allFilesFromTree);
} else if (t.type == "file") {
return [t.path];
}
}
export const allFiles = van.derive(() => {
if (folderTreeState.val) {
return allFilesFromTree(folderTreeState.val);
} else {
return [];
}
})

119
src/app/quickopen.ts Normal file
View File

@ -0,0 +1,119 @@
import van, { State } from "vanjs-core";
import { OpenFile } from "./filestate";
import { addEditor } from "./editorgrid";
import { allFiles } from "./foldernav";
const v = van.tags;
export const QuickOpen = (() => {
const isOpen = van.state(false);
const query = van.state("");
const files = van.state([]);
const filteredFiles = van.derive(() => {
if (!query.val) return files.val.slice(0, 100);
return files.val.filter(f => f.toLowerCase().includes(query.val.toLowerCase())).slice(0, 100);
});
const selectedIndex = van.state(0);
// Update selectedIndex when filteredFiles changes
van.derive(() => {
filteredFiles.val; // track dependency
selectedIndex.val = 0;
});
const close = () => {
isOpen.val = false;
query.val = "";
selectedIndex.val = 0;
};
const openSelectedFile = async () => {
const path = filteredFiles.val[selectedIndex.val];
if (path) {
const file = await OpenFile.openFile(path);
if (file) {
addEditor(file);
}
}
close();
};
const handleKeyDown = (e: KeyboardEvent) => {
if (!isOpen.val) return;
if (e.key === "Escape") {
close();
e.preventDefault();
} else if (e.key === "Enter") {
openSelectedFile();
e.preventDefault();
} else if (e.key === "ArrowDown") {
selectedIndex.val = (selectedIndex.val + 1) % filteredFiles.val.length;
e.preventDefault();
} else if (e.key === "ArrowUp") {
selectedIndex.val = (selectedIndex.val - 1 + filteredFiles.val.length) % filteredFiles.val.length;
e.preventDefault();
}
};
const open = async () => {
query.val = "";
files.val = allFiles.val;
console.log("setting allfiles to ", allFiles.val);
isOpen.val = true;
// Focus the input after the DOM is updated
setTimeout(() => {
const input = document.getElementById("quick-open-input") as HTMLInputElement;
input?.focus();
}, 0);
};
document.addEventListener("keydown", handleKeyDown, { capture: true });
const modal = v.div(
{
class: () => isOpen.val ? "fixed inset-0 z-50 flex items-start justify-center pt-20 bg-black bg-opacity-50" : "hidden",
onclick: (e: MouseEvent) => {
if ((e.target as HTMLElement).id === "quick-open-overlay") {
close();
}
}
},
v.div(
{
id: "quick-open-overlay",
class: "bg-white dark:bg-gray-800 w-1/2 max-w-2xl rounded shadow-lg overflow-hidden flex flex-col",
},
v.input(
{
id: "quick-open-input",
class: "w-full p-4 text-lg border-b dark:border-gray-700 dark:bg-gray-800 dark:text-white outline-none",
placeholder: "Quick Open...",
value: query,
oninput: (e: any) => (query.val = e.target.value),
},
),
v.div(
{ class: "max-h-96 overflow-y-auto" },
() => v.ul(
filteredFiles.val.map((path, i) => v.div(
{
class: () => `p-2 cursor-pointer hover:bg-blue-100 dark:hover:bg-blue-900 ${selectedIndex.val === i ? "bg-blue-200 dark:bg-blue-800" : ""}`,
onclick: () => {
selectedIndex.val = filteredFiles.val.indexOf(path);
openSelectedFile();
},
},
path
)
))
)
)
);
return {
dom: modal,
open,
};
})();

View File

@ -6,6 +6,7 @@ const v = van.tags;
import { FolderTreeView } from "./foldernav"; import { FolderTreeView } from "./foldernav";
import { EditorTabs, addTab, addEditor } from "./editorgrid"; import { EditorTabs, addTab, addEditor } from "./editorgrid";
import { QuickOpen } from "./quickopen";
import * as u from "./utils"; import * as u from "./utils";
import { OpenFile } from "./filestate"; import { OpenFile } from "./filestate";
@ -14,17 +15,29 @@ function newFile() {
addEditor(file); addEditor(file);
} }
export function toggleSidebar() {
if (sidebar.val == "none") {
sidebar.val = "tree";
} else if (sidebar.val == "tree") {
sidebar.val = "none";
}
}
export const sidebar = van.state<"tree" | "none">("tree");
const app = v.div( const app = v.div(
{ class: "h-screen max-h-screen w-screen max-w-screen flex" }, { class: "h-screen max-h-screen w-screen max-w-screen flex" },
v.aside( v.aside(
{ {
class: "flex-none resize-x overflow-x-hidden overflow-y-scroll w-3xs min-w-32", class: "flex-none resize-x overflow-x-hidden overflow-y-scroll w-3xs min-w-32",
hidden: () => sidebar.val != "tree",
}, },
u.InlineButton(addTab, "Add Tab", "+Tab"), u.InlineButton(addTab, "Add Tab", "+Tab"),
u.InlineButton(newFile, "Add Editor", "+File"), u.InlineButton(newFile, "Add Editor", "+File"),
FolderTreeView, FolderTreeView,
), ),
EditorTabs, EditorTabs,
QuickOpen.dom,
); );
van.add(document.body, app); van.add(document.body, app);