Create Displayable interface, fix file save-as
This commit is contained in:
parent
55aac46630
commit
50ba297473
|
|
@ -1,9 +1,4 @@
|
||||||
import {
|
import { Transaction, Compartment, Extension } from "@codemirror/state";
|
||||||
Transaction,
|
|
||||||
StateEffect,
|
|
||||||
Compartment,
|
|
||||||
Extension,
|
|
||||||
} from "@codemirror/state";
|
|
||||||
import {
|
import {
|
||||||
EditorView,
|
EditorView,
|
||||||
keymap,
|
keymap,
|
||||||
|
|
@ -27,8 +22,10 @@ import {
|
||||||
} from "@codemirror/language";
|
} from "@codemirror/language";
|
||||||
import { languages } from "@codemirror/language-data";
|
import { languages } from "@codemirror/language-data";
|
||||||
import { highlightSelectionMatches, searchKeymap } from "@codemirror/search";
|
import { highlightSelectionMatches, searchKeymap } from "@codemirror/search";
|
||||||
|
import van from "vanjs-core";
|
||||||
|
|
||||||
import { OpenFile } from "./filestate";
|
import { OpenFile } from "./filestate";
|
||||||
|
import { Displayable } from "./editorgrid";
|
||||||
|
|
||||||
const fixedHeightEditor = EditorView.theme({
|
const fixedHeightEditor = EditorView.theme({
|
||||||
"&": {
|
"&": {
|
||||||
|
|
@ -44,12 +41,13 @@ const fixedHeightEditor = EditorView.theme({
|
||||||
".cm-scroller": { overflow: "auto scroll" },
|
".cm-scroller": { overflow: "auto scroll" },
|
||||||
});
|
});
|
||||||
|
|
||||||
export class Editor {
|
export class Editor implements Displayable {
|
||||||
view: EditorView;
|
view: EditorView;
|
||||||
file: OpenFile;
|
file: OpenFile;
|
||||||
deleteFn?: () => void;
|
deleteFn?: () => void;
|
||||||
|
|
||||||
private wordWrapCompartment = new Compartment();
|
private wordWrapCompartment = new Compartment();
|
||||||
|
private languageCompartment = new Compartment();
|
||||||
|
|
||||||
dispatch(tr: Transaction, inhibitSync = false) {
|
dispatch(tr: Transaction, inhibitSync = false) {
|
||||||
this.view.update([tr]);
|
this.view.update([tr]);
|
||||||
|
|
@ -95,6 +93,7 @@ export class Editor {
|
||||||
fixedHeightEditor,
|
fixedHeightEditor,
|
||||||
kmap,
|
kmap,
|
||||||
this.wordWrapCompartment.of(EditorView.lineWrapping),
|
this.wordWrapCompartment.of(EditorView.lineWrapping),
|
||||||
|
this.languageCompartment.of([]),
|
||||||
lineNumbers(),
|
lineNumbers(),
|
||||||
highlightSpecialChars(),
|
highlightSpecialChars(),
|
||||||
foldGutter(),
|
foldGutter(),
|
||||||
|
|
@ -113,12 +112,16 @@ export class Editor {
|
||||||
// lintKeymap,
|
// lintKeymap,
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
van.derive(() => {
|
||||||
LanguageDescription.matchFilename(languages, file.filePath.val)
|
LanguageDescription.matchFilename(languages, file.filePath.val)
|
||||||
?.load()
|
?.load()
|
||||||
.then((Lang) => {
|
.then((Lang) => {
|
||||||
const eff = StateEffect.appendConfig.of(Lang);
|
// const eff = StateEffect.appendConfig.of(Lang);
|
||||||
|
const eff = this.languageCompartment.reconfigure(Lang);
|
||||||
this.view.dispatch({ effects: [eff] });
|
this.view.dispatch({ effects: [eff] });
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
get dom() {
|
get dom() {
|
||||||
|
|
@ -130,9 +133,13 @@ export class Editor {
|
||||||
this.view.focus();
|
this.view.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
title(): string {
|
||||||
|
return this.file.filePath.val + (this.file.isDirty() ? "*" : "");
|
||||||
|
}
|
||||||
|
|
||||||
changeWidth(increment: number) {
|
changeWidth(increment: number) {
|
||||||
const w = parseInt(window.getComputedStyle(this.view.dom).width, 10);
|
const w = parseInt(window.getComputedStyle(this.view.dom).width, 10);
|
||||||
this.view.dom.style.width = (w + increment) + 'px';
|
this.view.dom.style.width = w + increment + "px";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,18 @@ import { OpenFile } from "./filestate";
|
||||||
import * as u from "./utils";
|
import * as u from "./utils";
|
||||||
import { Editor } from "./editor";
|
import { Editor } from "./editor";
|
||||||
|
|
||||||
const EditorWrapper = (editor: State<Editor>, del: () => void, k: number) => {
|
export interface Displayable {
|
||||||
|
setDeleteFunction(del: () => void): void;
|
||||||
|
title(): string;
|
||||||
|
close(): void;
|
||||||
|
dom: HTMLElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
const EditorWrapper = (
|
||||||
|
editor: State<Displayable>,
|
||||||
|
del: () => void,
|
||||||
|
k: number,
|
||||||
|
) => {
|
||||||
// Set the delete function on the editor when it's created
|
// Set the delete function on the editor when it's created
|
||||||
van.derive(() => {
|
van.derive(() => {
|
||||||
if (editor.val) {
|
if (editor.val) {
|
||||||
|
|
@ -18,12 +29,7 @@ const EditorWrapper = (editor: State<Editor>, del: () => void, k: number) => {
|
||||||
{ class: "flex flex-col" },
|
{ class: "flex flex-col" },
|
||||||
v.div(
|
v.div(
|
||||||
{ class: "flex" },
|
{ class: "flex" },
|
||||||
v.span(
|
v.span({ class: "mx-1 flex-1" }, () => editor.val.title()),
|
||||||
{ class: "mx-1 flex-1" },
|
|
||||||
() =>
|
|
||||||
editor.val.file.filePath.val +
|
|
||||||
(editor.val.file.isDirty() ? "*" : ""),
|
|
||||||
),
|
|
||||||
u.InlineButton(() => editor.val.close(), "Close", "❌"),
|
u.InlineButton(() => editor.val.close(), "Close", "❌"),
|
||||||
),
|
),
|
||||||
v.div({ class: "flex-auto h-4" }, editor.val.dom),
|
v.div({ class: "flex-auto h-4" }, editor.val.dom),
|
||||||
|
|
@ -55,6 +61,7 @@ const TabHeader = (tab: State<Editor[]>, del: () => void, k: number) =>
|
||||||
v.span({ class: "mx-1 flex-1" }, "Tab " + k),
|
v.span({ class: "mx-1 flex-1" }, "Tab " + k),
|
||||||
u.InlineButton(del, "Close", "❌"),
|
u.InlineButton(del, "Close", "❌"),
|
||||||
);
|
);
|
||||||
|
|
||||||
const EditorGrid = (tab: State<Editor[]>, del: () => void, k: number) => {
|
const EditorGrid = (tab: State<Editor[]>, del: () => void, k: number) => {
|
||||||
console.log("Rendering", tab.val, "with key", k);
|
console.log("Rendering", tab.val, "with key", k);
|
||||||
const main = v.main({
|
const main = v.main({
|
||||||
|
|
@ -64,12 +71,15 @@ const EditorGrid = (tab: State<Editor[]>, del: () => void, k: number) => {
|
||||||
vanX.list(main, tab.val, EditorWrapper);
|
vanX.list(main, tab.val, EditorWrapper);
|
||||||
return main;
|
return main;
|
||||||
};
|
};
|
||||||
|
|
||||||
const TabBar = v.div({ class: "flex-none flex" });
|
const TabBar = v.div({ class: "flex-none flex" });
|
||||||
|
|
||||||
export const EditorTabs = v.div(
|
export const EditorTabs = v.div(
|
||||||
{
|
{
|
||||||
class: "flex flex-col flex-auto min-w-4",
|
class: "flex flex-col flex-auto min-w-4",
|
||||||
},
|
},
|
||||||
TabBar,
|
TabBar,
|
||||||
);
|
);
|
||||||
|
|
||||||
vanX.list(TabBar, editors, TabHeader);
|
vanX.list(TabBar, editors, TabHeader);
|
||||||
vanX.list(EditorTabs, editors, EditorGrid);
|
vanX.list(EditorTabs, editors, EditorGrid);
|
||||||
|
|
|
||||||
|
|
@ -40,13 +40,14 @@ export class OpenFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
private setPath(path: string) {
|
private setPath(path: string) {
|
||||||
delete openFiles[this.filePath?.val];
|
delete openFiles[this.filePath.val];
|
||||||
this.filePath.val = path;
|
this.filePath.val = path;
|
||||||
openFiles[path] = this;
|
openFiles[path] = this;
|
||||||
|
// TODO: what if openFiles[path] already exists?
|
||||||
}
|
}
|
||||||
|
|
||||||
async saveFile() {
|
async saveFile() {
|
||||||
if (this.filePath) {
|
if (this.filePath.val) {
|
||||||
await window.electronAPI.saveFile(
|
await window.electronAPI.saveFile(
|
||||||
this.rootState.val.doc.toString(),
|
this.rootState.val.doc.toString(),
|
||||||
this.filePath.val,
|
this.filePath.val,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue