This commit is contained in:
Zef Hemel
2022-04-26 19:04:36 +02:00
parent cb2d3f8652
commit 76636dd9b1
41 changed files with 500 additions and 287 deletions
+1 -1
View File
@@ -10,7 +10,7 @@ export function StatusBar({ editorView }: { editorView?: EditorView }) {
readingTime = util.readingTime(wordCount);
}
return (
<div id="bottom">
<div id="status-bar">
<div className="inner">
{wordCount} words | {readingTime} min
</div>
+54 -50
View File
@@ -58,13 +58,10 @@ import { FilterOption } from "@silverbulletmd/common/types";
import { syntaxTree } from "@codemirror/language";
class PageState {
scrollTop: number;
selection: EditorSelection;
constructor(scrollTop: number, selection: EditorSelection) {
this.scrollTop = scrollTop;
this.selection = selection;
}
constructor(
readonly scrollTop: number,
readonly selection: EditorSelection
) {}
}
const saveInterval = 1000;
@@ -123,7 +120,7 @@ export class Editor {
this.system.registerSyscalls([], editorSyscalls(this));
this.system.registerSyscalls([], spaceSyscalls(this));
this.system.registerSyscalls([], indexerSyscalls(this.space));
this.system.registerSyscalls([], systemSyscalls(this.space));
this.system.registerSyscalls([], systemSyscalls(this));
this.system.registerSyscalls(
[],
markdownSyscalls(buildMarkdown(this.mdExtensions))
@@ -153,10 +150,6 @@ export class Editor {
}
});
let throttledRebuildEditorState = throttle(() => {
this.rebuildEditorState();
}, 100);
this.space.on({
pageChanged: (meta) => {
if (this.currentPage === meta.name) {
@@ -171,22 +164,10 @@ export class Editor {
pages: pages,
});
},
plugLoaded: (plugName, plug) => {
safeRun(async () => {
console.log("Plug load", plugName);
await this.system.load(plugName, plug, createIFrameSandbox);
throttledRebuildEditorState();
});
},
plugUnloaded: (plugName) => {
safeRun(async () => {
console.log("Plug unload", plugName);
await this.system.unload(plugName);
throttledRebuildEditorState();
});
},
});
await this.reloadPlugs();
if (this.pageNavigator.getCurrentPage() === "") {
await this.pageNavigator.navigate("start");
}
@@ -359,7 +340,7 @@ export class Editor {
mac: "Cmd-k",
run: (): boolean => {
this.viewDispatch({ type: "start-navigate" });
this.space.updatePageListAsync();
this.space.updatePageList();
return true;
},
},
@@ -427,6 +408,17 @@ export class Editor {
});
}
async reloadPlugs() {
await this.space.updatePageList();
await this.system.unloadAll();
console.log("(Re)loading plugs");
for (let pageInfo of this.space.listPlugs()) {
let { text } = await this.space.readPage(pageInfo.name);
await this.system.load(JSON.parse(text), createIFrameSandbox);
}
this.rebuildEditorState();
}
rebuildEditorState() {
const editorView = this.editorView;
if (editorView && this.currentPage) {
@@ -438,13 +430,16 @@ export class Editor {
markdownSyscalls(buildMarkdown(this.mdExtensions))
);
this.saveState();
editorView.setState(
this.createEditorState(this.currentPage, editorView.state.sliceDoc())
);
if (editorView.contentDOM) {
editorView.contentDOM.spellcheck = true;
}
editorView.focus();
this.restoreState(this.currentPage);
}
}
@@ -489,12 +484,7 @@ export class Editor {
// Persist current page state and nicely close page
if (this.currentPage) {
let pageState = this.openPages.get(this.currentPage);
if (pageState) {
pageState.selection = this.editorView!.state.selection;
pageState.scrollTop = this.editorView!.scrollDOM.scrollTop;
// console.log("Saved pageState", this.currentPage, pageState);
}
this.saveState();
this.space.unwatchPage(this.currentPage);
await this.save(true);
}
@@ -513,26 +503,11 @@ export class Editor {
}
let editorState = this.createEditorState(pageName, doc.text);
let pageState = this.openPages.get(pageName);
editorView.setState(editorState);
if (editorView.contentDOM) {
editorView.contentDOM.spellcheck = true;
}
if (!pageState) {
pageState = new PageState(0, editorState.selection);
this.openPages.set(pageName, pageState!);
editorView.dispatch({
selection: { anchor: 0 },
});
} else {
// Restore state
// console.log("Restoring selection state", pageState);
editorView.dispatch({
selection: pageState.selection,
});
editorView.scrollDOM.scrollTop = pageState!.scrollTop;
}
this.restoreState(pageName);
this.space.watchPage(pageName);
this.viewDispatch({
@@ -543,6 +518,30 @@ export class Editor {
await this.eventHook.dispatchEvent("editor:pageSwitched");
}
private restoreState(pageName: string) {
let pageState = this.openPages.get(pageName);
const editorView = this.editorView!;
if (pageState) {
// Restore state
// console.log("Restoring selection state", pageState);
editorView.dispatch({
selection: pageState.selection,
});
editorView.scrollDOM.scrollTop = pageState!.scrollTop;
}
editorView.focus();
}
private saveState() {
this.openPages.set(
this.currentPage!,
new PageState(
this.editorView!.scrollDOM.scrollTop,
this.editorView!.state.selection
)
);
}
ViewComponent(): React.ReactElement {
const [viewState, dispatch] = useReducer(reducer, initialViewState);
this.viewState = viewState;
@@ -625,6 +624,11 @@ export class Editor {
<Panel html={viewState.rhsHTML} flex={viewState.showRHS} />
)}
</div>
{!!viewState.showBHS && (
<div id="bhs">
<Panel html={viewState.bhsHTML} flex={1} />
</div>
)}
<StatusBar editorView={editor.editorView} />
</>
);
+12
View File
@@ -102,6 +102,18 @@ export default function reducer(
showLHS: 0,
lhsHTML: "",
};
case "show-bhs":
return {
...state,
showBHS: action.flex,
bhsHTML: action.html,
};
case "hide-bhs":
return {
...state,
showBHS: 0,
bhsHTML: "",
};
case "show-filterbox":
return {
...state,
+16 -3
View File
@@ -110,13 +110,26 @@ body {
height: 100%;
}
#bottom {
#bhs {
height: 200px;
width: 100%;
.panel {
iframe {
border: 0;
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
}
}
#status-bar {
height: 40px;
line-height: 40px;
padding: 0 10px;
text-align: right;
background-color: rgb(213, 213, 213);
border-top: rgb(193, 193, 193) 1px solid;
.inner {
}
}
+12
View File
@@ -92,6 +92,18 @@ export function editorSyscalls(editor: Editor): SysCallMapping {
type: "hide-lhs",
});
},
"editor.showBhs": (ctx, html: string, flex: number) => {
editor.viewDispatch({
type: "show-bhs",
flex,
html,
});
},
"editor.hideBhs": (ctx) => {
editor.viewDispatch({
type: "hide-bhs",
});
},
"editor.insertAtPos": (ctx, text: string, pos: number) => {
editor.editorView!.dispatch({
changes: {
+2 -2
View File
@@ -4,8 +4,8 @@ import { PageMeta } from "@silverbulletmd/common/types";
export function spaceSyscalls(editor: Editor): SysCallMapping {
return {
"space.listPages": async (): Promise<PageMeta[]> => {
return [...(await editor.space.listPages())];
"space.listPages": async (ctx, unfiltered = false): Promise<PageMeta[]> => {
return [...(await editor.space.listPages(unfiltered))];
},
"space.readPage": async (
ctx,
+6 -3
View File
@@ -1,7 +1,7 @@
import { SysCallMapping } from "@plugos/plugos/system";
import { Space } from "@silverbulletmd/common/spaces/space";
import type { Editor } from "../editor";
export function systemSyscalls(space: Space): SysCallMapping {
export function systemSyscalls(editor: Editor): SysCallMapping {
return {
"system.invokeFunction": async (
ctx,
@@ -17,7 +17,10 @@ export function systemSyscalls(space: Space): SysCallMapping {
return ctx.plug.invoke(name, args);
}
return space.invokeFunction(ctx.plug, env, name, args);
return editor.space.invokeFunction(ctx.plug, env, name, args);
},
"system.reloadPlugs": async () => {
return editor.reloadPlugs();
},
};
}
+6
View File
@@ -16,8 +16,10 @@ export type AppViewState = {
unsavedChanges: boolean;
showLHS: number; // 0 = hide, > 0 = flex
showRHS: number; // 0 = hide, > 0 = flex
showBHS: number;
rhsHTML: string;
lhsHTML: string;
bhsHTML: string;
allPages: Set<PageMeta>;
commands: Map<string, AppCommand>;
notifications: Notification[];
@@ -36,8 +38,10 @@ export const initialViewState: AppViewState = {
unsavedChanges: false,
showLHS: 0,
showRHS: 0,
showBHS: 0,
rhsHTML: "",
lhsHTML: "",
bhsHTML: "",
allPages: new Set(),
commands: new Map(),
notifications: [],
@@ -65,6 +69,8 @@ export type Action =
| { type: "hide-rhs" }
| { type: "show-lhs"; html: string; flex: number }
| { type: "hide-lhs" }
| { type: "show-bhs"; html: string; flex: number }
| { type: "hide-bhs" }
| {
type: "show-filterbox";
options: FilterOption[];