From f73acae41a40e9c82ff387586b25107d823ba338 Mon Sep 17 00:00:00 2001 From: Zef Hemel Date: Thu, 3 Mar 2022 10:35:32 +0100 Subject: [PATCH] Stuff --- plugins/.gitignore | 1 - plugins/Makefile | 2 +- plugins/core/core.plugin.json | 6 - plugins/core/page.ts | 8 +- webapp/package.json | 2 +- .../{navigation_bar.tsx => top_bar.tsx} | 11 +- webapp/src/customtags.ts | 2 + webapp/src/editor.tsx | 35 +- webapp/src/generated/core.plugin.json | 109 +++++ webapp/src/lineWrapper.ts | 19 +- webapp/src/markdown/commands.js | 234 ---------- webapp/src/markdown/commands.ts | 432 ++++++++++++------ webapp/src/markdown/index.js | 37 -- webapp/src/markdown/markdown.js | 75 --- webapp/src/parser.ts | 40 +- webapp/src/style.ts | 3 + webapp/src/styles/editor.scss | 80 ++-- webapp/src/styles/filter_box.scss | 39 +- webapp/src/styles/main.scss | 2 +- webapp/src/syscalls/editor.browser.ts | 4 +- 20 files changed, 571 insertions(+), 570 deletions(-) rename webapp/src/components/{navigation_bar.tsx => top_bar.tsx} (67%) create mode 100644 webapp/src/generated/core.plugin.json delete mode 100644 webapp/src/markdown/commands.js delete mode 100644 webapp/src/markdown/index.js delete mode 100644 webapp/src/markdown/markdown.js diff --git a/plugins/.gitignore b/plugins/.gitignore index 53c37a1..e69de29 100644 --- a/plugins/.gitignore +++ b/plugins/.gitignore @@ -1 +0,0 @@ -dist \ No newline at end of file diff --git a/plugins/Makefile b/plugins/Makefile index afbc043..c1524c8 100644 --- a/plugins/Makefile +++ b/plugins/Makefile @@ -1,7 +1,7 @@ DENO_BUNDLE=deno run --allow-read --allow-write --unstable bundle.ts --debug build: * mkdir -p dist - $(DENO_BUNDLE) core/core.plugin.json dist/core.plugin.json + $(DENO_BUNDLE) core/core.plugin.json ../webapp/src/generated/core.plugin.json entr: ls core/* | entr make \ No newline at end of file diff --git a/plugins/core/core.plugin.json b/plugins/core/core.plugin.json index b12ebbf..9d1fdff 100644 --- a/plugins/core/core.plugin.json +++ b/plugins/core/core.plugin.json @@ -1,8 +1,5 @@ { "commands": { - "Count Words": { - "invoke": "word_count_command" - }, "Navigate To page": { "invoke": "linkNavigate", "key": "Ctrl-Enter", @@ -68,9 +65,6 @@ "taskToggle": { "path": "./task.ts:taskToggle" }, - "word_count_command": { - "path": "./word_count_command.ts:wordCount" - }, "insertToday": { "path": "./dates.ts:insertToday" }, diff --git a/plugins/core/page.ts b/plugins/core/page.ts index c4c312a..a9d5363 100644 --- a/plugins/core/page.ts +++ b/plugins/core/page.ts @@ -29,9 +29,15 @@ export async function deletePage() { } export async function renamePage() { + // console.log("HELLO WORLD"); const pageMeta = await syscall("editor.getCurrentPage"); const oldName = pageMeta.name; - const newName = await syscall("editor.prompt", `Rename ${oldName} to:`); + console.log("Old name is", oldName); + const newName = await syscall( + "editor.prompt", + `Rename ${oldName} to:`, + oldName + ); if (!newName) { return; } diff --git a/webapp/package.json b/webapp/package.json index 0017d50..f14eeff 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -7,7 +7,7 @@ "license": "MIT", "browserslist": "> 0.5%, last 2 versions, not dead", "scripts": { - "start": "cp src/function_worker.js dist/ && parcel", + "start": "mkdir -p dist && cp src/function_worker.js dist/ && parcel", "build": "parcel build && cp src/function_worker.js dist/", "clean": "rm -rf dist", "check-watch": "tsc --noEmit --watch" diff --git a/webapp/src/components/navigation_bar.tsx b/webapp/src/components/top_bar.tsx similarity index 67% rename from webapp/src/components/navigation_bar.tsx rename to webapp/src/components/top_bar.tsx index b77f001..07fb17f 100644 --- a/webapp/src/components/navigation_bar.tsx +++ b/webapp/src/components/top_bar.tsx @@ -2,7 +2,14 @@ import { PageMeta } from "../types"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faFileLines } from "@fortawesome/free-solid-svg-icons"; -export function NavigationBar({ +function prettyName(s: string | undefined): string { + if (!s) { + return ""; + } + return s.replaceAll("/", " / "); +} + +export function TopBar({ currentPage, onClick, }: { @@ -15,7 +22,7 @@ export function NavigationBar({ - {currentPage?.name} + {prettyName(currentPage?.name)} ); diff --git a/webapp/src/customtags.ts b/webapp/src/customtags.ts index 337f2fd..18c823a 100644 --- a/webapp/src/customtags.ts +++ b/webapp/src/customtags.ts @@ -6,3 +6,5 @@ export const TagTag = Tag.define(); export const MentionTag = Tag.define(); export const TaskTag = Tag.define(); export const TaskMarkerTag = Tag.define(); +export const CommentTag = Tag.define(); +export const CommentMarkerTag = Tag.define(); diff --git a/webapp/src/editor.tsx b/webapp/src/editor.tsx index fe01394..530f769 100644 --- a/webapp/src/editor.tsx +++ b/webapp/src/editor.tsx @@ -8,7 +8,6 @@ import { import { closeBrackets, closeBracketsKeymap } from "@codemirror/closebrackets"; import { indentWithTab, standardKeymap } from "@codemirror/commands"; import { history, historyKeymap } from "@codemirror/history"; -import { indentOnInput, syntaxTree } from "@codemirror/language"; import { bracketMatching } from "@codemirror/matchbrackets"; import { searchKeymap } from "@codemirror/search"; import { EditorState, StateField, Transaction } from "@codemirror/state"; @@ -20,24 +19,31 @@ import { KeyBinding, keymap, } from "@codemirror/view"; + import React, { useEffect, useReducer } from "react"; import ReactDOM from "react-dom"; -import coreManifest from "../../plugins/dist/core.plugin.json"; +import coreManifest from "./generated/core.plugin.json"; +// @ts-ignore +window.coreManifest = coreManifest; +import { AppEvent, AppEventDispatcher, ClickEvent } from "./app_event"; import * as commands from "./commands"; import { CommandPalette } from "./components/command_palette"; -import { NavigationBar } from "./components/navigation_bar"; import { PageNavigator } from "./components/page_navigator"; import { StatusBar } from "./components/status_bar"; -import { Space } from "./space"; +import { TopBar } from "./components/top_bar"; +import { Indexer } from "./indexer"; import { lineWrapper } from "./lineWrapper"; import { markdown } from "./markdown"; +import { IPageNavigator, PathPageNavigator } from "./navigator"; import customMarkDown from "./parser"; import { BrowserSystem } from "./plugins/browser_system"; -import { Manifest, slashCommandRegexp } from "./plugins/types"; +import { Plugin } from "./plugins/runtime"; +import { slashCommandRegexp } from "./plugins/types"; import reducer from "./reducer"; +import { smartQuoteKeymap } from "./smart_quotes"; +import { Space } from "./space"; import customMarkdownStyle from "./style"; import dbSyscalls from "./syscalls/db.localstorage"; -import { Plugin } from "./plugins/runtime"; import editorSyscalls from "./syscalls/editor.browser"; import indexerSyscalls from "./syscalls/indexer.native"; import spaceSyscalls from "./syscalls/space.native"; @@ -48,16 +54,7 @@ import { initialViewState, PageMeta, } from "./types"; -import { - AppEvent, - AppEventDispatcher, - ClickEvent, - IndexEvent, -} from "./app_event"; import { safeRun } from "./util"; -import { Indexer } from "./indexer"; -import { IPageNavigator, PathPageNavigator } from "./navigator"; -import { smartQuoteKeymap } from "./smart_quotes"; class PageState { editorState: EditorState; @@ -203,7 +200,7 @@ export class Editor implements AppEventDispatcher { history(), drawSelection(), dropCursor(), - indentOnInput(), + // indentOnInput(), customMarkdownStyle, bracketMatching(), closeBrackets(), @@ -217,10 +214,12 @@ export class Editor implements AppEventDispatcher { lineWrapper([ { selector: "ATXHeading1", class: "line-h1" }, { selector: "ATXHeading2", class: "line-h2" }, - { selector: "ListItem", class: "line-li" }, + { selector: "ATXHeading3", class: "line-h3" }, + { selector: "ListItem", class: "line-li", nesting: true }, { selector: "Blockquote", class: "line-blockquote" }, { selector: "CodeBlock", class: "line-code" }, { selector: "FencedCode", class: "line-fenced-code" }, + { selector: "Comment", class: "line-comment" }, ]), keymap.of([ ...smartQuoteKeymap, @@ -535,7 +534,7 @@ export class Editor implements AppEventDispatcher { commands={viewState.commands} /> )} - { dispatch({ type: "start-navigate" }); diff --git a/webapp/src/generated/core.plugin.json b/webapp/src/generated/core.plugin.json new file mode 100644 index 0000000..4e685c2 --- /dev/null +++ b/webapp/src/generated/core.plugin.json @@ -0,0 +1,109 @@ +{ + "commands": { + "Navigate To page": { + "invoke": "linkNavigate", + "key": "Ctrl-Enter", + "mac": "Cmd-Enter" + }, + "Insert Current Date": { + "invoke": "insertToday", + "slashCommand": "/today" + }, + "Toggle : Heading 1": { + "invoke": "toggle_h1", + "mac": "Cmd-1", + "key": "Ctrl-1" + }, + "Toggle : Heading 2": { + "invoke": "toggle_h2", + "mac": "Cmd-2", + "key": "Ctrl-2" + }, + "Page: Delete": { + "invoke": "deletePage" + }, + "Page: Rename": { + "invoke": "renamePage" + }, + "Pages: Reindex": { + "invoke": "reindexPages" + }, + "Pages: Back Links": { + "invoke": "showBackLinks" + } + }, + "events": { + "page:click": [ + "taskToggle", + "clickNavigate" + ], + "editor:complete": [ + "pageComplete" + ], + "page:index": [ + "indexLinks" + ] + }, + "functions": { + "indexLinks": { + "path": "core/page.ts", + "code": "(function() {\n const pageLinkRegex = /\\[\\[([\\w\\s\\/\\:,\\.\\-]+)\\]\\]/;\n function syscall(name, ...args) {\n let reqId = Math.floor(Math.random() * 1000000);\n return new Promise((resolve, reject)=>{\n self.dispatchEvent(new CustomEvent(\"syscall\", {\n detail: {\n id: reqId,\n name: name,\n args: args,\n callback: resolve\n }\n }));\n });\n }\n const wikilinkRegex = new RegExp(pageLinkRegex, \"g\");\n async function indexLinks({ name , text }) {\n let backLinks = [];\n for (let match of text.matchAll(wikilinkRegex)){\n let toPage = match[1];\n let pos = match.index;\n backLinks.push({\n key: `pl:${toPage}:${pos}`,\n value: name\n });\n }\n console.log(\"Found\", backLinks.length, \"wiki link(s)\");\n await syscall(\"indexer.batchSet\", name, backLinks);\n }\n async function deletePage() {\n let pageMeta = await syscall(\"editor.getCurrentPage\");\n console.log(\"Navigating to start page\");\n await syscall(\"editor.navigate\", \"start\");\n console.log(\"Deleting page from space\");\n await syscall(\"space.deletePage\", pageMeta.name);\n console.log(\"Reloading page list\");\n await syscall(\"space.reloadPageList\");\n }\n async function renamePage() {\n const pageMeta = await syscall(\"editor.getCurrentPage\");\n const oldName = pageMeta.name;\n console.log(\"Old name is\", oldName);\n const newName = await syscall(\"editor.prompt\", `Rename ${oldName} to:`, oldName);\n if (!newName) {\n return;\n }\n console.log(\"New name\", newName);\n let pagesToUpdate = await getBackLinks(oldName);\n console.log(\"All pages containing backlinks\", pagesToUpdate);\n let text = await syscall(\"editor.getText\");\n console.log(\"Writing new page to space\");\n await syscall(\"space.writePage\", newName, text);\n console.log(\"Deleting page from space\");\n await syscall(\"space.deletePage\", oldName);\n console.log(\"Reloading page list\");\n await syscall(\"space.reloadPageList\");\n console.log(\"Navigating to new page\");\n await syscall(\"editor.navigate\", newName);\n let pageToUpdateSet = new Set();\n for (let pageToUpdate of pagesToUpdate){\n pageToUpdateSet.add(pageToUpdate.page);\n }\n for (let pageToUpdate1 of pageToUpdateSet){\n console.log(\"Now going to update links in\", pageToUpdate1);\n let { text } = await syscall(\"space.readPage\", pageToUpdate1);\n if (!text) {\n continue;\n }\n let newText = text.replaceAll(`[[${oldName}]]`, `[[${newName}]]`);\n if (text !== newText) {\n console.log(\"Changes made, saving...\");\n await syscall(\"space.writePage\", pageToUpdate1, newText);\n }\n }\n }\n async function getBackLinks(pageName) {\n let allBackLinks = await syscall(\"indexer.scanPrefixGlobal\", `pl:${pageName}:`);\n let pagesToUpdate = [];\n for (let { key , value } of allBackLinks){\n let keyParts = key.split(\":\");\n pagesToUpdate.push({\n page: value,\n pos: +keyParts[keyParts.length - 1]\n });\n }\n return pagesToUpdate;\n }\n async function showBackLinks() {\n const pageMeta = await syscall(\"editor.getCurrentPage\");\n let backLinks = await getBackLinks(pageMeta.name);\n console.log(\"Backlinks\", backLinks);\n }\n async function reindex() {\n await syscall(\"space.reindex\");\n }\n return {\n indexLinks: indexLinks,\n deletePage: deletePage,\n renamePage: renamePage,\n showBackLinks: showBackLinks,\n reindex: reindex\n };\n})();\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vVXNlcnMvemVmL2dpdC9udWdnZXQvd2ViYXBwL3NyYy9jb25zdGFudC50cyIsImZpbGU6Ly8vVXNlcnMvemVmL2dpdC9udWdnZXQvcGx1Z2lucy9jb3JlL2xpYi9zeXNjYWxsLnRzIiwiZmlsZTovLy9Vc2Vycy96ZWYvZ2l0L251Z2dldC9wbHVnaW5zL2NvcmUvcGFnZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0lBQU8sS0FBSyxDQUFDLGFBQWE7YUNBVixPQUFPLENBQUMsSUFBWSxLQUFLLElBQUksRUFBYyxDQUFDO1FBQzFELEdBQUcsQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxLQUFLLE9BQU87UUFFOUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sR0FBSyxDQUFDO1lBQ3ZDLElBQUksQ0FBQyxhQUFhLENBQ2hCLEdBQUcsQ0FBQyxXQUFXLENBQUMsQ0FBUyxVQUFFLENBQUM7Z0JBQzFCLE1BQU0sRUFBRSxDQUFDO29CQUNQLEVBQUUsRUFBRSxLQUFLO29CQUNULElBQUksRUFBRSxJQUFJO29CQUNWLElBQUksRUFBRSxJQUFJO29CQUNWLFFBQVEsRUFBRSxPQUFPO2dCQUNuQixDQUFDO1lBQ0gsQ0FBQztRQUVMLENBQUM7SUFDSCxDQUFDO0lDWEQsS0FBSyxDQUFDLGFBQWEsR0FBRyxHQUFHLENBQUMsTUFBTSxnQkFBZ0IsQ0FBRzttQkFFN0IsVUFBVSxDQUFDLENBQUMsQ0FBQyxJQUFJLEdBQUUsSUFBSSxFQUFhLENBQUMsRUFBRSxDQUFDO1FBQzVELEdBQUcsQ0FBQyxTQUFTLEdBQXFDLENBQUMsQ0FBQztRQUNwRCxHQUFHLEVBQUUsR0FBRyxDQUFDLEtBQUssSUFBSSxJQUFJLENBQUMsUUFBUSxDQUFDLGFBQWEsRUFBRyxDQUFDO1lBQy9DLEdBQUcsQ0FBQyxNQUFNLEdBQUcsS0FBSyxDQUFDLENBQUM7WUFDcEIsR0FBRyxDQUFDLEdBQUcs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\n", + "functionName": "indexLinks" + }, + "deletePage": { + "path": "core/page.ts", + "code": "(function() {\n const pageLinkRegex = /\\[\\[([\\w\\s\\/\\:,\\.\\-]+)\\]\\]/;\n function syscall(name, ...args) {\n let reqId = Math.floor(Math.random() * 1000000);\n return new Promise((resolve, reject)=>{\n self.dispatchEvent(new CustomEvent(\"syscall\", {\n detail: {\n id: reqId,\n name: name,\n args: args,\n callback: resolve\n }\n }));\n });\n }\n const wikilinkRegex = new RegExp(pageLinkRegex, \"g\");\n async function indexLinks({ name , text }) {\n let backLinks = [];\n for (let match of text.matchAll(wikilinkRegex)){\n let toPage = match[1];\n let pos = match.index;\n backLinks.push({\n key: `pl:${toPage}:${pos}`,\n value: name\n });\n }\n console.log(\"Found\", backLinks.length, \"wiki link(s)\");\n await syscall(\"indexer.batchSet\", name, backLinks);\n }\n async function deletePage() {\n let pageMeta = await syscall(\"editor.getCurrentPage\");\n console.log(\"Navigating to start page\");\n await syscall(\"editor.navigate\", \"start\");\n console.log(\"Deleting page from space\");\n await syscall(\"space.deletePage\", pageMeta.name);\n console.log(\"Reloading page list\");\n await syscall(\"space.reloadPageList\");\n }\n async function renamePage() {\n const pageMeta = await syscall(\"editor.getCurrentPage\");\n const oldName = pageMeta.name;\n console.log(\"Old name is\", oldName);\n const newName = await syscall(\"editor.prompt\", `Rename ${oldName} to:`, oldName);\n if (!newName) {\n return;\n }\n console.log(\"New name\", newName);\n let pagesToUpdate = await getBackLinks(oldName);\n console.log(\"All pages containing backlinks\", pagesToUpdate);\n let text = await syscall(\"editor.getText\");\n console.log(\"Writing new page to space\");\n await syscall(\"space.writePage\", newName, text);\n console.log(\"Deleting page from space\");\n await syscall(\"space.deletePage\", oldName);\n console.log(\"Reloading page list\");\n await syscall(\"space.reloadPageList\");\n console.log(\"Navigating to new page\");\n await syscall(\"editor.navigate\", newName);\n let pageToUpdateSet = new Set();\n for (let pageToUpdate of pagesToUpdate){\n pageToUpdateSet.add(pageToUpdate.page);\n }\n for (let pageToUpdate1 of pageToUpdateSet){\n console.log(\"Now going to update links in\", pageToUpdate1);\n let { text } = await syscall(\"space.readPage\", pageToUpdate1);\n if (!text) {\n continue;\n }\n let newText = text.replaceAll(`[[${oldName}]]`, `[[${newName}]]`);\n if (text !== newText) {\n console.log(\"Changes made, saving...\");\n await syscall(\"space.writePage\", pageToUpdate1, newText);\n }\n }\n }\n async function getBackLinks(pageName) {\n let allBackLinks = await syscall(\"indexer.scanPrefixGlobal\", `pl:${pageName}:`);\n let pagesToUpdate = [];\n for (let { key , value } of allBackLinks){\n let keyParts = key.split(\":\");\n pagesToUpdate.push({\n page: value,\n pos: +keyParts[keyParts.length - 1]\n });\n }\n return pagesToUpdate;\n }\n async function showBackLinks() {\n const pageMeta = await syscall(\"editor.getCurrentPage\");\n let backLinks = await getBackLinks(pageMeta.name);\n console.log(\"Backlinks\", backLinks);\n }\n async function reindex() {\n await syscall(\"space.reindex\");\n }\n return {\n indexLinks: indexLinks,\n deletePage: deletePage,\n renamePage: renamePage,\n showBackLinks: showBackLinks,\n reindex: reindex\n };\n})();\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vVXNlcnMvemVmL2dpdC9udWdnZXQvd2ViYXBwL3NyYy9jb25zdGFudC50cyIsImZpbGU6Ly8vVXNlcnMvemVmL2dpdC9udWdnZXQvcGx1Z2lucy9jb3JlL2xpYi9zeXNjYWxsLnRzIiwiZmlsZTovLy9Vc2Vycy96ZWYvZ2l0L251Z2dldC9wbHVnaW5zL2NvcmUvcGFnZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0lBQU8sS0FBSyxDQUFDLGFBQWE7YUNBVixPQUFPLENBQUMsSUFBWSxLQUFLLElBQUksRUFBYyxDQUFDO1FBQzFELEdBQUcsQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxLQUFLLE9BQU87UUFFOUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sR0FBSyxDQUFDO1lBQ3ZDLElBQUksQ0FBQyxhQUFhLENBQ2hCLEdBQUcsQ0FBQyxXQUFXLENBQUMsQ0FBUyxVQUFFLENBQUM7Z0JBQzFCLE1BQU0sRUFBRSxDQUFDO29CQUNQLEVBQUUsRUFBRSxLQUFLO29CQUNULElBQUksRUFBRSxJQUFJO29CQUNWLElBQUksRUFBRSxJQUFJO29CQUNWLFFBQVEsRUFBRSxPQUFPO2dCQUNuQixDQUFDO1lBQ0gsQ0FBQztRQUVMLENBQUM7SUFDSCxDQUFDO0lDWEQsS0FBSyxDQUFDLGFBQWEsR0FBRyxHQUFHLENBQUMsTUFBTSxnQkFBZ0IsQ0FBRzttQkFFN0IsVUFBVSxDQUFDLENBQUMsQ0FBQyxJQUFJLEdBQUUsSUFBSSxFQUFhLENBQUMsRUFBRSxDQUFDO1FBQzVELEdBQUcsQ0FBQyxTQUFTLEdBQXFDLENBQUMsQ0FBQztRQUNwRCxHQUFHLEVBQUUsR0FBRyxDQUFDLEtBQUssSUFBSSxJQUFJLENBQUMsUUFBUSxDQUFDLGFBQWEsRUFBRyxDQUFDO1lBQy9DLEdBQUcsQ0FBQyxNQUFNLEdBQUcsS0FBSyxDQUFDLENBQUM7WUFDcEIsR0FBRyxDQUFDLEdBQUcs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\n", + "functionName": "deletePage" + }, + "showBackLinks": { + "path": "core/page.ts", + "code": "(function() {\n const pageLinkRegex = /\\[\\[([\\w\\s\\/\\:,\\.\\-]+)\\]\\]/;\n function syscall(name, ...args) {\n let reqId = Math.floor(Math.random() * 1000000);\n return new Promise((resolve, reject)=>{\n self.dispatchEvent(new CustomEvent(\"syscall\", {\n detail: {\n id: reqId,\n name: name,\n args: args,\n callback: resolve\n }\n }));\n });\n }\n const wikilinkRegex = new RegExp(pageLinkRegex, \"g\");\n async function indexLinks({ name , text }) {\n let backLinks = [];\n for (let match of text.matchAll(wikilinkRegex)){\n let toPage = match[1];\n let pos = match.index;\n backLinks.push({\n key: `pl:${toPage}:${pos}`,\n value: name\n });\n }\n console.log(\"Found\", backLinks.length, \"wiki link(s)\");\n await syscall(\"indexer.batchSet\", name, backLinks);\n }\n async function deletePage() {\n let pageMeta = await syscall(\"editor.getCurrentPage\");\n console.log(\"Navigating to start page\");\n await syscall(\"editor.navigate\", \"start\");\n console.log(\"Deleting page from space\");\n await syscall(\"space.deletePage\", pageMeta.name);\n console.log(\"Reloading page list\");\n await syscall(\"space.reloadPageList\");\n }\n async function renamePage() {\n const pageMeta = await syscall(\"editor.getCurrentPage\");\n const oldName = pageMeta.name;\n console.log(\"Old name is\", oldName);\n const newName = await syscall(\"editor.prompt\", `Rename ${oldName} to:`, oldName);\n if (!newName) {\n return;\n }\n console.log(\"New name\", newName);\n let pagesToUpdate = await getBackLinks(oldName);\n console.log(\"All pages containing backlinks\", pagesToUpdate);\n let text = await syscall(\"editor.getText\");\n console.log(\"Writing new page to space\");\n await syscall(\"space.writePage\", newName, text);\n console.log(\"Deleting page from space\");\n await syscall(\"space.deletePage\", oldName);\n console.log(\"Reloading page list\");\n await syscall(\"space.reloadPageList\");\n console.log(\"Navigating to new page\");\n await syscall(\"editor.navigate\", newName);\n let pageToUpdateSet = new Set();\n for (let pageToUpdate of pagesToUpdate){\n pageToUpdateSet.add(pageToUpdate.page);\n }\n for (let pageToUpdate1 of pageToUpdateSet){\n console.log(\"Now going to update links in\", pageToUpdate1);\n let { text } = await syscall(\"space.readPage\", pageToUpdate1);\n if (!text) {\n continue;\n }\n let newText = text.replaceAll(`[[${oldName}]]`, `[[${newName}]]`);\n if (text !== newText) {\n console.log(\"Changes made, saving...\");\n await syscall(\"space.writePage\", pageToUpdate1, newText);\n }\n }\n }\n async function getBackLinks(pageName) {\n let allBackLinks = await syscall(\"indexer.scanPrefixGlobal\", `pl:${pageName}:`);\n let pagesToUpdate = [];\n for (let { key , value } of allBackLinks){\n let keyParts = key.split(\":\");\n pagesToUpdate.push({\n page: value,\n pos: +keyParts[keyParts.length - 1]\n });\n }\n return pagesToUpdate;\n }\n async function showBackLinks() {\n const pageMeta = await syscall(\"editor.getCurrentPage\");\n let backLinks = await getBackLinks(pageMeta.name);\n console.log(\"Backlinks\", backLinks);\n }\n async function reindex() {\n await syscall(\"space.reindex\");\n }\n return {\n indexLinks: indexLinks,\n deletePage: deletePage,\n renamePage: renamePage,\n showBackLinks: showBackLinks,\n reindex: reindex\n };\n})();\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vVXNlcnMvemVmL2dpdC9udWdnZXQvd2ViYXBwL3NyYy9jb25zdGFudC50cyIsImZpbGU6Ly8vVXNlcnMvemVmL2dpdC9udWdnZXQvcGx1Z2lucy9jb3JlL2xpYi9zeXNjYWxsLnRzIiwiZmlsZTovLy9Vc2Vycy96ZWYvZ2l0L251Z2dldC9wbHVnaW5zL2NvcmUvcGFnZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0lBQU8sS0FBSyxDQUFDLGFBQWE7YUNBVixPQUFPLENBQUMsSUFBWSxLQUFLLElBQUksRUFBYyxDQUFDO1FBQzFELEdBQUcsQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxLQUFLLE9BQU87UUFFOUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sR0FBSyxDQUFDO1lBQ3ZDLElBQUksQ0FBQyxhQUFhLENBQ2hCLEdBQUcsQ0FBQyxXQUFXLENBQUMsQ0FBUyxVQUFFLENBQUM7Z0JBQzFCLE1BQU0sRUFBRSxDQUFDO29CQUNQLEVBQUUsRUFBRSxLQUFLO29CQUNULElBQUksRUFBRSxJQUFJO29CQUNWLElBQUksRUFBRSxJQUFJO29CQUNWLFFBQVEsRUFBRSxPQUFPO2dCQUNuQixDQUFDO1lBQ0gsQ0FBQztRQUVMLENBQUM7SUFDSCxDQUFDO0lDWEQsS0FBSyxDQUFDLGFBQWEsR0FBRyxHQUFHLENBQUMsTUFBTSxnQkFBZ0IsQ0FBRzttQkFFN0IsVUFBVSxDQUFDLENBQUMsQ0FBQyxJQUFJLEdBQUUsSUFBSSxFQUFhLENBQUMsRUFBRSxDQUFDO1FBQzVELEdBQUcsQ0FBQyxTQUFTLEdBQXFDLENBQUMsQ0FBQztRQUNwRCxHQUFHLEVBQUUsR0FBRyxDQUFDLEtBQUssSUFBSSxJQUFJLENBQUMsUUFBUSxDQUFDLGFBQWEsRUFBRyxDQUFDO1lBQy9DLEdBQUcsQ0FBQyxNQUFNLEdBQUcsS0FBSyxDQUFDLENBQUM7WUFDcEIsR0FBRyxDQUFDLEdBQUcs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\n", + "functionName": "showBackLinks" + }, + "renamePage": { + "path": "core/page.ts", + "code": "(function() {\n const pageLinkRegex = /\\[\\[([\\w\\s\\/\\:,\\.\\-]+)\\]\\]/;\n function syscall(name, ...args) {\n let reqId = Math.floor(Math.random() * 1000000);\n return new Promise((resolve, reject)=>{\n self.dispatchEvent(new CustomEvent(\"syscall\", {\n detail: {\n id: reqId,\n name: name,\n args: args,\n callback: resolve\n }\n }));\n });\n }\n const wikilinkRegex = new RegExp(pageLinkRegex, \"g\");\n async function indexLinks({ name , text }) {\n let backLinks = [];\n for (let match of text.matchAll(wikilinkRegex)){\n let toPage = match[1];\n let pos = match.index;\n backLinks.push({\n key: `pl:${toPage}:${pos}`,\n value: name\n });\n }\n console.log(\"Found\", backLinks.length, \"wiki link(s)\");\n await syscall(\"indexer.batchSet\", name, backLinks);\n }\n async function deletePage() {\n let pageMeta = await syscall(\"editor.getCurrentPage\");\n console.log(\"Navigating to start page\");\n await syscall(\"editor.navigate\", \"start\");\n console.log(\"Deleting page from space\");\n await syscall(\"space.deletePage\", pageMeta.name);\n console.log(\"Reloading page list\");\n await syscall(\"space.reloadPageList\");\n }\n async function renamePage() {\n const pageMeta = await syscall(\"editor.getCurrentPage\");\n const oldName = pageMeta.name;\n console.log(\"Old name is\", oldName);\n const newName = await syscall(\"editor.prompt\", `Rename ${oldName} to:`, oldName);\n if (!newName) {\n return;\n }\n console.log(\"New name\", newName);\n let pagesToUpdate = await getBackLinks(oldName);\n console.log(\"All pages containing backlinks\", pagesToUpdate);\n let text = await syscall(\"editor.getText\");\n console.log(\"Writing new page to space\");\n await syscall(\"space.writePage\", newName, text);\n console.log(\"Deleting page from space\");\n await syscall(\"space.deletePage\", oldName);\n console.log(\"Reloading page list\");\n await syscall(\"space.reloadPageList\");\n console.log(\"Navigating to new page\");\n await syscall(\"editor.navigate\", newName);\n let pageToUpdateSet = new Set();\n for (let pageToUpdate of pagesToUpdate){\n pageToUpdateSet.add(pageToUpdate.page);\n }\n for (let pageToUpdate1 of pageToUpdateSet){\n console.log(\"Now going to update links in\", pageToUpdate1);\n let { text } = await syscall(\"space.readPage\", pageToUpdate1);\n if (!text) {\n continue;\n }\n let newText = text.replaceAll(`[[${oldName}]]`, `[[${newName}]]`);\n if (text !== newText) {\n console.log(\"Changes made, saving...\");\n await syscall(\"space.writePage\", pageToUpdate1, newText);\n }\n }\n }\n async function getBackLinks(pageName) {\n let allBackLinks = await syscall(\"indexer.scanPrefixGlobal\", `pl:${pageName}:`);\n let pagesToUpdate = [];\n for (let { key , value } of allBackLinks){\n let keyParts = key.split(\":\");\n pagesToUpdate.push({\n page: value,\n pos: +keyParts[keyParts.length - 1]\n });\n }\n return pagesToUpdate;\n }\n async function showBackLinks() {\n const pageMeta = await syscall(\"editor.getCurrentPage\");\n let backLinks = await getBackLinks(pageMeta.name);\n console.log(\"Backlinks\", backLinks);\n }\n async function reindex() {\n await syscall(\"space.reindex\");\n }\n return {\n indexLinks: indexLinks,\n deletePage: deletePage,\n renamePage: renamePage,\n showBackLinks: showBackLinks,\n reindex: reindex\n };\n})();\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vVXNlcnMvemVmL2dpdC9udWdnZXQvd2ViYXBwL3NyYy9jb25zdGFudC50cyIsImZpbGU6Ly8vVXNlcnMvemVmL2dpdC9udWdnZXQvcGx1Z2lucy9jb3JlL2xpYi9zeXNjYWxsLnRzIiwiZmlsZTovLy9Vc2Vycy96ZWYvZ2l0L251Z2dldC9wbHVnaW5zL2NvcmUvcGFnZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0lBQU8sS0FBSyxDQUFDLGFBQWE7YUNBVixPQUFPLENBQUMsSUFBWSxLQUFLLElBQUksRUFBYyxDQUFDO1FBQzFELEdBQUcsQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxLQUFLLE9BQU87UUFFOUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sR0FBSyxDQUFDO1lBQ3ZDLElBQUksQ0FBQyxhQUFhLENBQ2hCLEdBQUcsQ0FBQyxXQUFXLENBQUMsQ0FBUyxVQUFFLENBQUM7Z0JBQzFCLE1BQU0sRUFBRSxDQUFDO29CQUNQLEVBQUUsRUFBRSxLQUFLO29CQUNULElBQUksRUFBRSxJQUFJO29CQUNWLElBQUksRUFBRSxJQUFJO29CQUNWLFFBQVEsRUFBRSxPQUFPO2dCQUNuQixDQUFDO1lBQ0gsQ0FBQztRQUVMLENBQUM7SUFDSCxDQUFDO0lDWEQsS0FBSyxDQUFDLGFBQWEsR0FBRyxHQUFHLENBQUMsTUFBTSxnQkFBZ0IsQ0FBRzttQkFFN0IsVUFBVSxDQUFDLENBQUMsQ0FBQyxJQUFJLEdBQUUsSUFBSSxFQUFhLENBQUMsRUFBRSxDQUFDO1FBQzVELEdBQUcsQ0FBQyxTQUFTLEdBQXFDLENBQUMsQ0FBQztRQUNwRCxHQUFHLEVBQUUsR0FBRyxDQUFDLEtBQUssSUFBSSxJQUFJLENBQUMsUUFBUSxDQUFDLGFBQWEsRUFBRyxDQUFDO1lBQy9DLEdBQUcsQ0FBQyxNQUFNLEdBQUcsS0FBSyxDQUFDLENBQUM7WUFDcEIsR0FBRyxDQUFDLEdBQUcs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\n", + "functionName": "renamePage" + }, + "reindexPages": { + "path": "core/page.ts", + "code": "(function() {\n const pageLinkRegex = /\\[\\[([\\w\\s\\/\\:,\\.\\-]+)\\]\\]/;\n function syscall(name, ...args) {\n let reqId = Math.floor(Math.random() * 1000000);\n return new Promise((resolve, reject)=>{\n self.dispatchEvent(new CustomEvent(\"syscall\", {\n detail: {\n id: reqId,\n name: name,\n args: args,\n callback: resolve\n }\n }));\n });\n }\n const wikilinkRegex = new RegExp(pageLinkRegex, \"g\");\n async function indexLinks({ name , text }) {\n let backLinks = [];\n for (let match of text.matchAll(wikilinkRegex)){\n let toPage = match[1];\n let pos = match.index;\n backLinks.push({\n key: `pl:${toPage}:${pos}`,\n value: name\n });\n }\n console.log(\"Found\", backLinks.length, \"wiki link(s)\");\n await syscall(\"indexer.batchSet\", name, backLinks);\n }\n async function deletePage() {\n let pageMeta = await syscall(\"editor.getCurrentPage\");\n console.log(\"Navigating to start page\");\n await syscall(\"editor.navigate\", \"start\");\n console.log(\"Deleting page from space\");\n await syscall(\"space.deletePage\", pageMeta.name);\n console.log(\"Reloading page list\");\n await syscall(\"space.reloadPageList\");\n }\n async function renamePage() {\n const pageMeta = await syscall(\"editor.getCurrentPage\");\n const oldName = pageMeta.name;\n console.log(\"Old name is\", oldName);\n const newName = await syscall(\"editor.prompt\", `Rename ${oldName} to:`, oldName);\n if (!newName) {\n return;\n }\n console.log(\"New name\", newName);\n let pagesToUpdate = await getBackLinks(oldName);\n console.log(\"All pages containing backlinks\", pagesToUpdate);\n let text = await syscall(\"editor.getText\");\n console.log(\"Writing new page to space\");\n await syscall(\"space.writePage\", newName, text);\n console.log(\"Deleting page from space\");\n await syscall(\"space.deletePage\", oldName);\n console.log(\"Reloading page list\");\n await syscall(\"space.reloadPageList\");\n console.log(\"Navigating to new page\");\n await syscall(\"editor.navigate\", newName);\n let pageToUpdateSet = new Set();\n for (let pageToUpdate of pagesToUpdate){\n pageToUpdateSet.add(pageToUpdate.page);\n }\n for (let pageToUpdate1 of pageToUpdateSet){\n console.log(\"Now going to update links in\", pageToUpdate1);\n let { text } = await syscall(\"space.readPage\", pageToUpdate1);\n if (!text) {\n continue;\n }\n let newText = text.replaceAll(`[[${oldName}]]`, `[[${newName}]]`);\n if (text !== newText) {\n console.log(\"Changes made, saving...\");\n await syscall(\"space.writePage\", pageToUpdate1, newText);\n }\n }\n }\n async function getBackLinks(pageName) {\n let allBackLinks = await syscall(\"indexer.scanPrefixGlobal\", `pl:${pageName}:`);\n let pagesToUpdate = [];\n for (let { key , value } of allBackLinks){\n let keyParts = key.split(\":\");\n pagesToUpdate.push({\n page: value,\n pos: +keyParts[keyParts.length - 1]\n });\n }\n return pagesToUpdate;\n }\n async function showBackLinks() {\n const pageMeta = await syscall(\"editor.getCurrentPage\");\n let backLinks = await getBackLinks(pageMeta.name);\n console.log(\"Backlinks\", backLinks);\n }\n async function reindex() {\n await syscall(\"space.reindex\");\n }\n return {\n indexLinks: indexLinks,\n deletePage: deletePage,\n renamePage: renamePage,\n showBackLinks: showBackLinks,\n reindex: reindex\n };\n})();\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vVXNlcnMvemVmL2dpdC9udWdnZXQvd2ViYXBwL3NyYy9jb25zdGFudC50cyIsImZpbGU6Ly8vVXNlcnMvemVmL2dpdC9udWdnZXQvcGx1Z2lucy9jb3JlL2xpYi9zeXNjYWxsLnRzIiwiZmlsZTovLy9Vc2Vycy96ZWYvZ2l0L251Z2dldC9wbHVnaW5zL2NvcmUvcGFnZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0lBQU8sS0FBSyxDQUFDLGFBQWE7YUNBVixPQUFPLENBQUMsSUFBWSxLQUFLLElBQUksRUFBYyxDQUFDO1FBQzFELEdBQUcsQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxLQUFLLE9BQU87UUFFOUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sR0FBSyxDQUFDO1lBQ3ZDLElBQUksQ0FBQyxhQUFhLENBQ2hCLEdBQUcsQ0FBQyxXQUFXLENBQUMsQ0FBUyxVQUFFLENBQUM7Z0JBQzFCLE1BQU0sRUFBRSxDQUFDO29CQUNQLEVBQUUsRUFBRSxLQUFLO29CQUNULElBQUksRUFBRSxJQUFJO29CQUNWLElBQUksRUFBRSxJQUFJO29CQUNWLFFBQVEsRUFBRSxPQUFPO2dCQUNuQixDQUFDO1lBQ0gsQ0FBQztRQUVMLENBQUM7SUFDSCxDQUFDO0lDWEQsS0FBSyxDQUFDLGFBQWEsR0FBRyxHQUFHLENBQUMsTUFBTSxnQkFBZ0IsQ0FBRzttQkFFN0IsVUFBVSxDQUFDLENBQUMsQ0FBQyxJQUFJLEdBQUUsSUFBSSxFQUFhLENBQUMsRUFBRSxDQUFDO1FBQzVELEdBQUcsQ0FBQyxTQUFTLEdBQXFDLENBQUMsQ0FBQztRQUNwRCxHQUFHLEVBQUUsR0FBRyxDQUFDLEtBQUssSUFBSSxJQUFJLENBQUMsUUFBUSxDQUFDLGFBQWEsRUFBRyxDQUFDO1lBQy9DLEdBQUcsQ0FBQyxNQUFNLEdBQUcsS0FBSyxDQUFDLENBQUM7WUFDcEIsR0FBRyxDQUFDLEdBQUcs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\n", + "functionName": "reindex" + }, + "pageComplete": { + "path": "core/navigate.ts", + "code": "(function() {\n function syscall(name, ...args) {\n let reqId = Math.floor(Math.random() * 1000000);\n return new Promise((resolve, reject)=>{\n self.dispatchEvent(new CustomEvent(\"syscall\", {\n detail: {\n id: reqId,\n name: name,\n args: args,\n callback: resolve\n }\n }));\n });\n }\n async function navigate(syntaxNode) {\n if (!syntaxNode) {\n return;\n }\n console.log(\"Attempting to navigate based on syntax node\", syntaxNode);\n switch(syntaxNode.name){\n case \"WikiLinkPage\":\n await syscall(\"editor.navigate\", syntaxNode.text);\n break;\n case \"URL\":\n await syscall(\"editor.openUrl\", syntaxNode.text);\n break;\n case \"Link\":\n let match = /\\[[^\\\\]+\\]\\(([^\\)]+)\\)/.exec(syntaxNode.text);\n if (match) {\n await syscall(\"editor.openUrl\", match[1]);\n }\n }\n }\n async function linkNavigate() {\n navigate(await syscall(\"editor.getSyntaxNodeUnderCursor\"));\n }\n async function clickNavigate(event) {\n if (event.ctrlKey || event.metaKey) {\n let syntaxNode = await syscall(\"editor.getSyntaxNodeAtPos\", event.pos);\n navigate(syntaxNode);\n }\n }\n async function pageComplete() {\n let prefix = await syscall(\"editor.matchBefore\", \"\\\\[\\\\[[\\\\w\\\\s]*\");\n if (!prefix) {\n return null;\n }\n let allPages = await syscall(\"space.listPages\");\n return {\n from: prefix.from + 2,\n options: allPages.map((pageMeta)=>({\n label: pageMeta.name,\n type: \"page\"\n })\n )\n };\n }\n return {\n linkNavigate: linkNavigate,\n clickNavigate: clickNavigate,\n pageComplete: pageComplete\n };\n})();\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vVXNlcnMvemVmL2dpdC9udWdnZXQvcGx1Z2lucy9jb3JlL2xpYi9zeXNjYWxsLnRzIiwiZmlsZTovLy9Vc2Vycy96ZWYvZ2l0L251Z2dldC9wbHVnaW5zL2NvcmUvbmF2aWdhdGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjthQUFnQixPQUFPLENBQUMsSUFBWSxLQUFLLElBQUksRUFBYyxDQUFDO1FBQzFELEdBQUcsQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxLQUFLLE9BQU87UUFFOUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sR0FBSyxDQUFDO1lBQ3ZDLElBQUksQ0FBQyxhQUFhLENBQ2hCLEdBQUcsQ0FBQyxXQUFXLENBQUMsQ0FBUyxVQUFFLENBQUM7Z0JBQzFCLE1BQU0sRUFBRSxDQUFDO29CQUNQLEVBQUUsRUFBRSxLQUFLO29CQUNULElBQUksRUFBRSxJQUFJO29CQUNWLElBQUksRUFBRSxJQUFJO29CQUNWLFFBQVEsRUFBRSxPQUFPO2dCQUNuQixDQUFDO1lBQ0gsQ0FBQztRQUVMLENBQUM7SUFDSCxDQUFDO21CQ1pjLFFBQVEsQ0FBQyxVQUFlLEVBQUUsQ0FBQztRQUN4QyxFQUFFLEdBQUcsVUFBVSxFQUFFLENBQUM7WUFDaEIsTUFBTTtRQUNSLENBQUM7UUFDRCxPQUFPLENBQUMsR0FBRyxDQUFDLENBQTZDLDhDQUFFLFVBQVU7UUFDckUsTUFBTSxDQUFFLFVBQVUsQ0FBQyxJQUFJO1lBQ3JCLElBQUksQ0FBQyxDQUFjO2dCQUNqQixLQUFLLFNBQVMsQ0FBaUIsa0JBQUUsVUFBVSxDQUFDLElBQUk7Z0JBQ2hELEtBQUs7WUFDUCxJQUFJLENBQUMsQ0FBSztnQkFDUixLQUFLLFNBQVMsQ0FBZ0IsaUJBQUUsVUFBVSxDQUFDLElBQUk7Z0JBQy9DLEtBQUs7WUFDUCxJQUFJLENBQUMsQ0FBTTtnQkFFVCxHQUFHLENBQUMsS0FBSyw0QkFBNEIsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJO2dCQUN6RCxFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUM7b0JBQ1YsS0FBSyxTQUFTLENBQWdCLGlCQUFFLEtBQUssQ0FBQyxDQUFDO2dCQUN6QyxDQUFDOztJQUVQLENBQUM7bUJBRXFCLFlBQVksR0FBRyxDQUFDO1FBQ3BDLFFBQVEsQ0FBQyxLQUFLLFNBQVMsQ0FBaUM7SUFDMUQsQ0FBQzttQkFFcUIsYUFBYSxDQUFDLEtBQWlCLEVBQUUsQ0FBQztRQUN0RCxFQUFFLEVBQUUsS0FBSyxDQUFDLE9BQU8sSUFBSSxLQUFLLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDbkMsR0FBRyxDQUFDLFVBQVUsR0FBRyxLQUFLLFNBQVMsQ0FBMkIsNEJBQUUsS0FBSyxDQUFDLEdBQUc7WUFDckUsUUFBUSxDQUFDLFVBQVU7UUFDckIsQ0FBQztJQUNILENBQUM7bUJBRXFCLFlBQVksR0FBRyxDQUFDO1FBQ3BDLEdBQUcsQ0FBQyxNQUFNLEdBQUcsS0FBSyxTQUFTLENBQW9CLHFCQUFFLENBQWlCO1FBQ2xFLEVBQUUsR0FBRyxNQUFNLEVBQUUsQ0FBQztZQUNaLE1BQU0sQ0FBQyxJQUFJO1FBQ2IsQ0FBQztRQUNELEdBQUcsQ0FBQyxRQUFRLEdBQUcsS0FBSyxTQUFTLENBQWlCO1FBQzlDLE1BQU0sQ0FBQyxDQUFDO1lBQ04sSUFBSSxFQUFFLE1BQU0sQ0FBQyxJQUFJLEdBQUcsQ0FBQztZQUNyQixPQUFPLEVBQUUsUUFBUSxDQUFDLEdBQUcsRUFBRSxRQUFhLElBQU0sQ0FBQztvQkFDekMsS0FBSyxFQUFFLFFBQVEsQ0FBQyxJQUFJO29CQUNwQixJQUFJLEVBQUUsQ0FBTTtnQkFDZCxDQUFDOztRQUNILENBQUM7SUFDSCxDQUFDOztRQXhCcUIsWUFBWSxFQUFaLFlBQVk7UUFJWixhQUFhLEVBQWIsYUFBYTtRQU9iLFlBQVksRUFBWixZQUFZIn0=\n", + "functionName": "pageComplete" + }, + "linkNavigate": { + "path": "core/navigate.ts", + "code": "(function() {\n function syscall(name, ...args) {\n let reqId = Math.floor(Math.random() * 1000000);\n return new Promise((resolve, reject)=>{\n self.dispatchEvent(new CustomEvent(\"syscall\", {\n detail: {\n id: reqId,\n name: name,\n args: args,\n callback: resolve\n }\n }));\n });\n }\n async function navigate(syntaxNode) {\n if (!syntaxNode) {\n return;\n }\n console.log(\"Attempting to navigate based on syntax node\", syntaxNode);\n switch(syntaxNode.name){\n case \"WikiLinkPage\":\n await syscall(\"editor.navigate\", syntaxNode.text);\n break;\n case \"URL\":\n await syscall(\"editor.openUrl\", syntaxNode.text);\n break;\n case \"Link\":\n let match = /\\[[^\\\\]+\\]\\(([^\\)]+)\\)/.exec(syntaxNode.text);\n if (match) {\n await syscall(\"editor.openUrl\", match[1]);\n }\n }\n }\n async function linkNavigate() {\n navigate(await syscall(\"editor.getSyntaxNodeUnderCursor\"));\n }\n async function clickNavigate(event) {\n if (event.ctrlKey || event.metaKey) {\n let syntaxNode = await syscall(\"editor.getSyntaxNodeAtPos\", event.pos);\n navigate(syntaxNode);\n }\n }\n async function pageComplete() {\n let prefix = await syscall(\"editor.matchBefore\", \"\\\\[\\\\[[\\\\w\\\\s]*\");\n if (!prefix) {\n return null;\n }\n let allPages = await syscall(\"space.listPages\");\n return {\n from: prefix.from + 2,\n options: allPages.map((pageMeta)=>({\n label: pageMeta.name,\n type: \"page\"\n })\n )\n };\n }\n return {\n linkNavigate: linkNavigate,\n clickNavigate: clickNavigate,\n pageComplete: pageComplete\n };\n})();\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vVXNlcnMvemVmL2dpdC9udWdnZXQvcGx1Z2lucy9jb3JlL2xpYi9zeXNjYWxsLnRzIiwiZmlsZTovLy9Vc2Vycy96ZWYvZ2l0L251Z2dldC9wbHVnaW5zL2NvcmUvbmF2aWdhdGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjthQUFnQixPQUFPLENBQUMsSUFBWSxLQUFLLElBQUksRUFBYyxDQUFDO1FBQzFELEdBQUcsQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxLQUFLLE9BQU87UUFFOUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sR0FBSyxDQUFDO1lBQ3ZDLElBQUksQ0FBQyxhQUFhLENBQ2hCLEdBQUcsQ0FBQyxXQUFXLENBQUMsQ0FBUyxVQUFFLENBQUM7Z0JBQzFCLE1BQU0sRUFBRSxDQUFDO29CQUNQLEVBQUUsRUFBRSxLQUFLO29CQUNULElBQUksRUFBRSxJQUFJO29CQUNWLElBQUksRUFBRSxJQUFJO29CQUNWLFFBQVEsRUFBRSxPQUFPO2dCQUNuQixDQUFDO1lBQ0gsQ0FBQztRQUVMLENBQUM7SUFDSCxDQUFDO21CQ1pjLFFBQVEsQ0FBQyxVQUFlLEVBQUUsQ0FBQztRQUN4QyxFQUFFLEdBQUcsVUFBVSxFQUFFLENBQUM7WUFDaEIsTUFBTTtRQUNSLENBQUM7UUFDRCxPQUFPLENBQUMsR0FBRyxDQUFDLENBQTZDLDhDQUFFLFVBQVU7UUFDckUsTUFBTSxDQUFFLFVBQVUsQ0FBQyxJQUFJO1lBQ3JCLElBQUksQ0FBQyxDQUFjO2dCQUNqQixLQUFLLFNBQVMsQ0FBaUIsa0JBQUUsVUFBVSxDQUFDLElBQUk7Z0JBQ2hELEtBQUs7WUFDUCxJQUFJLENBQUMsQ0FBSztnQkFDUixLQUFLLFNBQVMsQ0FBZ0IsaUJBQUUsVUFBVSxDQUFDLElBQUk7Z0JBQy9DLEtBQUs7WUFDUCxJQUFJLENBQUMsQ0FBTTtnQkFFVCxHQUFHLENBQUMsS0FBSyw0QkFBNEIsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJO2dCQUN6RCxFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUM7b0JBQ1YsS0FBSyxTQUFTLENBQWdCLGlCQUFFLEtBQUssQ0FBQyxDQUFDO2dCQUN6QyxDQUFDOztJQUVQLENBQUM7bUJBRXFCLFlBQVksR0FBRyxDQUFDO1FBQ3BDLFFBQVEsQ0FBQyxLQUFLLFNBQVMsQ0FBaUM7SUFDMUQsQ0FBQzttQkFFcUIsYUFBYSxDQUFDLEtBQWlCLEVBQUUsQ0FBQztRQUN0RCxFQUFFLEVBQUUsS0FBSyxDQUFDLE9BQU8sSUFBSSxLQUFLLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDbkMsR0FBRyxDQUFDLFVBQVUsR0FBRyxLQUFLLFNBQVMsQ0FBMkIsNEJBQUUsS0FBSyxDQUFDLEdBQUc7WUFDckUsUUFBUSxDQUFDLFVBQVU7UUFDckIsQ0FBQztJQUNILENBQUM7bUJBRXFCLFlBQVksR0FBRyxDQUFDO1FBQ3BDLEdBQUcsQ0FBQyxNQUFNLEdBQUcsS0FBSyxTQUFTLENBQW9CLHFCQUFFLENBQWlCO1FBQ2xFLEVBQUUsR0FBRyxNQUFNLEVBQUUsQ0FBQztZQUNaLE1BQU0sQ0FBQyxJQUFJO1FBQ2IsQ0FBQztRQUNELEdBQUcsQ0FBQyxRQUFRLEdBQUcsS0FBSyxTQUFTLENBQWlCO1FBQzlDLE1BQU0sQ0FBQyxDQUFDO1lBQ04sSUFBSSxFQUFFLE1BQU0sQ0FBQyxJQUFJLEdBQUcsQ0FBQztZQUNyQixPQUFPLEVBQUUsUUFBUSxDQUFDLEdBQUcsRUFBRSxRQUFhLElBQU0sQ0FBQztvQkFDekMsS0FBSyxFQUFFLFFBQVEsQ0FBQyxJQUFJO29CQUNwQixJQUFJLEVBQUUsQ0FBTTtnQkFDZCxDQUFDOztRQUNILENBQUM7SUFDSCxDQUFDOztRQXhCcUIsWUFBWSxFQUFaLFlBQVk7UUFJWixhQUFhLEVBQWIsYUFBYTtRQU9iLFlBQVksRUFBWixZQUFZIn0=\n", + "functionName": "linkNavigate" + }, + "clickNavigate": { + "path": "core/navigate.ts", + "code": "(function() {\n function syscall(name, ...args) {\n let reqId = Math.floor(Math.random() * 1000000);\n return new Promise((resolve, reject)=>{\n self.dispatchEvent(new CustomEvent(\"syscall\", {\n detail: {\n id: reqId,\n name: name,\n args: args,\n callback: resolve\n }\n }));\n });\n }\n async function navigate(syntaxNode) {\n if (!syntaxNode) {\n return;\n }\n console.log(\"Attempting to navigate based on syntax node\", syntaxNode);\n switch(syntaxNode.name){\n case \"WikiLinkPage\":\n await syscall(\"editor.navigate\", syntaxNode.text);\n break;\n case \"URL\":\n await syscall(\"editor.openUrl\", syntaxNode.text);\n break;\n case \"Link\":\n let match = /\\[[^\\\\]+\\]\\(([^\\)]+)\\)/.exec(syntaxNode.text);\n if (match) {\n await syscall(\"editor.openUrl\", match[1]);\n }\n }\n }\n async function linkNavigate() {\n navigate(await syscall(\"editor.getSyntaxNodeUnderCursor\"));\n }\n async function clickNavigate(event) {\n if (event.ctrlKey || event.metaKey) {\n let syntaxNode = await syscall(\"editor.getSyntaxNodeAtPos\", event.pos);\n navigate(syntaxNode);\n }\n }\n async function pageComplete() {\n let prefix = await syscall(\"editor.matchBefore\", \"\\\\[\\\\[[\\\\w\\\\s]*\");\n if (!prefix) {\n return null;\n }\n let allPages = await syscall(\"space.listPages\");\n return {\n from: prefix.from + 2,\n options: allPages.map((pageMeta)=>({\n label: pageMeta.name,\n type: \"page\"\n })\n )\n };\n }\n return {\n linkNavigate: linkNavigate,\n clickNavigate: clickNavigate,\n pageComplete: pageComplete\n };\n})();\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vVXNlcnMvemVmL2dpdC9udWdnZXQvcGx1Z2lucy9jb3JlL2xpYi9zeXNjYWxsLnRzIiwiZmlsZTovLy9Vc2Vycy96ZWYvZ2l0L251Z2dldC9wbHVnaW5zL2NvcmUvbmF2aWdhdGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjthQUFnQixPQUFPLENBQUMsSUFBWSxLQUFLLElBQUksRUFBYyxDQUFDO1FBQzFELEdBQUcsQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxLQUFLLE9BQU87UUFFOUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sR0FBSyxDQUFDO1lBQ3ZDLElBQUksQ0FBQyxhQUFhLENBQ2hCLEdBQUcsQ0FBQyxXQUFXLENBQUMsQ0FBUyxVQUFFLENBQUM7Z0JBQzFCLE1BQU0sRUFBRSxDQUFDO29CQUNQLEVBQUUsRUFBRSxLQUFLO29CQUNULElBQUksRUFBRSxJQUFJO29CQUNWLElBQUksRUFBRSxJQUFJO29CQUNWLFFBQVEsRUFBRSxPQUFPO2dCQUNuQixDQUFDO1lBQ0gsQ0FBQztRQUVMLENBQUM7SUFDSCxDQUFDO21CQ1pjLFFBQVEsQ0FBQyxVQUFlLEVBQUUsQ0FBQztRQUN4QyxFQUFFLEdBQUcsVUFBVSxFQUFFLENBQUM7WUFDaEIsTUFBTTtRQUNSLENBQUM7UUFDRCxPQUFPLENBQUMsR0FBRyxDQUFDLENBQTZDLDhDQUFFLFVBQVU7UUFDckUsTUFBTSxDQUFFLFVBQVUsQ0FBQyxJQUFJO1lBQ3JCLElBQUksQ0FBQyxDQUFjO2dCQUNqQixLQUFLLFNBQVMsQ0FBaUIsa0JBQUUsVUFBVSxDQUFDLElBQUk7Z0JBQ2hELEtBQUs7WUFDUCxJQUFJLENBQUMsQ0FBSztnQkFDUixLQUFLLFNBQVMsQ0FBZ0IsaUJBQUUsVUFBVSxDQUFDLElBQUk7Z0JBQy9DLEtBQUs7WUFDUCxJQUFJLENBQUMsQ0FBTTtnQkFFVCxHQUFHLENBQUMsS0FBSyw0QkFBNEIsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJO2dCQUN6RCxFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUM7b0JBQ1YsS0FBSyxTQUFTLENBQWdCLGlCQUFFLEtBQUssQ0FBQyxDQUFDO2dCQUN6QyxDQUFDOztJQUVQLENBQUM7bUJBRXFCLFlBQVksR0FBRyxDQUFDO1FBQ3BDLFFBQVEsQ0FBQyxLQUFLLFNBQVMsQ0FBaUM7SUFDMUQsQ0FBQzttQkFFcUIsYUFBYSxDQUFDLEtBQWlCLEVBQUUsQ0FBQztRQUN0RCxFQUFFLEVBQUUsS0FBSyxDQUFDLE9BQU8sSUFBSSxLQUFLLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDbkMsR0FBRyxDQUFDLFVBQVUsR0FBRyxLQUFLLFNBQVMsQ0FBMkIsNEJBQUUsS0FBSyxDQUFDLEdBQUc7WUFDckUsUUFBUSxDQUFDLFVBQVU7UUFDckIsQ0FBQztJQUNILENBQUM7bUJBRXFCLFlBQVksR0FBRyxDQUFDO1FBQ3BDLEdBQUcsQ0FBQyxNQUFNLEdBQUcsS0FBSyxTQUFTLENBQW9CLHFCQUFFLENBQWlCO1FBQ2xFLEVBQUUsR0FBRyxNQUFNLEVBQUUsQ0FBQztZQUNaLE1BQU0sQ0FBQyxJQUFJO1FBQ2IsQ0FBQztRQUNELEdBQUcsQ0FBQyxRQUFRLEdBQUcsS0FBSyxTQUFTLENBQWlCO1FBQzlDLE1BQU0sQ0FBQyxDQUFDO1lBQ04sSUFBSSxFQUFFLE1BQU0sQ0FBQyxJQUFJLEdBQUcsQ0FBQztZQUNyQixPQUFPLEVBQUUsUUFBUSxDQUFDLEdBQUcsRUFBRSxRQUFhLElBQU0sQ0FBQztvQkFDekMsS0FBSyxFQUFFLFFBQVEsQ0FBQyxJQUFJO29CQUNwQixJQUFJLEVBQUUsQ0FBTTtnQkFDZCxDQUFDOztRQUNILENBQUM7SUFDSCxDQUFDOztRQXhCcUIsWUFBWSxFQUFaLFlBQVk7UUFJWixhQUFhLEVBQWIsYUFBYTtRQU9iLFlBQVksRUFBWixZQUFZIn0=\n", + "functionName": "clickNavigate" + }, + "taskToggle": { + "path": "core/task.ts", + "code": "(function() {\n function syscall(name, ...args) {\n let reqId = Math.floor(Math.random() * 1000000);\n return new Promise((resolve, reject)=>{\n self.dispatchEvent(new CustomEvent(\"syscall\", {\n detail: {\n id: reqId,\n name: name,\n args: args,\n callback: resolve\n }\n }));\n });\n }\n async function taskToggle(event) {\n let syntaxNode = await syscall(\"editor.getSyntaxNodeAtPos\", event.pos);\n if (syntaxNode && syntaxNode.name === \"TaskMarker\") {\n if (syntaxNode.text === \"[x]\" || syntaxNode.text === \"[X]\") {\n await syscall(\"editor.dispatch\", {\n changes: {\n from: syntaxNode.from,\n to: syntaxNode.to,\n insert: \"[ ]\"\n },\n selection: {\n anchor: event.pos\n }\n });\n } else {\n await syscall(\"editor.dispatch\", {\n changes: {\n from: syntaxNode.from,\n to: syntaxNode.to,\n insert: \"[x]\"\n },\n selection: {\n anchor: event.pos\n }\n });\n }\n }\n }\n return {\n taskToggle: taskToggle\n };\n})();\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vVXNlcnMvemVmL2dpdC9udWdnZXQvcGx1Z2lucy9jb3JlL2xpYi9zeXNjYWxsLnRzIiwiZmlsZTovLy9Vc2Vycy96ZWYvZ2l0L251Z2dldC9wbHVnaW5zL2NvcmUvdGFzay50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO2FBQWdCLE9BQU8sQ0FBQyxJQUFZLEtBQUssSUFBSSxFQUFjLENBQUM7UUFDMUQsR0FBRyxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLEtBQUssT0FBTztRQUU5QyxNQUFNLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxHQUFLLENBQUM7WUFDdkMsSUFBSSxDQUFDLGFBQWEsQ0FDaEIsR0FBRyxDQUFDLFdBQVcsQ0FBQyxDQUFTLFVBQUUsQ0FBQztnQkFDMUIsTUFBTSxFQUFFLENBQUM7b0JBQ1AsRUFBRSxFQUFFLEtBQUs7b0JBQ1QsSUFBSSxFQUFFLElBQUk7b0JBQ1YsSUFBSSxFQUFFLElBQUk7b0JBQ1YsUUFBUSxFQUFFLE9BQU87Z0JBQ25CLENBQUM7WUFDSCxDQUFDO1FBRUwsQ0FBQztJQUNILENBQUM7bUJDWnFCLFVBQVUsQ0FBQyxLQUFpQixFQUFFLENBQUM7UUFDbkQsR0FBRyxDQUFDLFVBQVUsR0FBRyxLQUFLLFNBQVMsQ0FBMkIsNEJBQUUsS0FBSyxDQUFDLEdBQUc7UUFDckUsRUFBRSxFQUFFLFVBQVUsSUFBSSxVQUFVLENBQUMsSUFBSSxLQUFLLENBQVksYUFBRSxDQUFDO1lBQ25ELEVBQUUsRUFBRSxVQUFVLENBQUMsSUFBSSxLQUFLLENBQUssUUFBSSxVQUFVLENBQUMsSUFBSSxLQUFLLENBQUssTUFBRSxDQUFDO2dCQUMzRCxLQUFLLFNBQVMsQ0FBaUIsa0JBQUUsQ0FBQztvQkFDaEMsT0FBTyxFQUFFLENBQUM7d0JBQ1IsSUFBSSxFQUFFLFVBQVUsQ0FBQyxJQUFJO3dCQUNyQixFQUFFLEVBQUUsVUFBVSxDQUFDLEVBQUU7d0JBQ2pCLE1BQU0sRUFBRSxDQUFLO29CQUNmLENBQUM7b0JBQ0QsU0FBUyxFQUFFLENBQUM7d0JBQ1YsTUFBTSxFQUFFLEtBQUssQ0FBQyxHQUFHO29CQUNuQixDQUFDO2dCQUNILENBQUM7WUFDSCxDQUFDLE1BQU0sQ0FBQztnQkFDTixLQUFLLFNBQVMsQ0FBaUIsa0JBQUUsQ0FBQztvQkFDaEMsT0FBTyxFQUFFLENBQUM7d0JBQ1IsSUFBSSxFQUFFLFVBQVUsQ0FBQyxJQUFJO3dCQUNyQixFQUFFLEVBQUUsVUFBVSxDQUFDLEVBQUU7d0JBQ2pCLE1BQU0sRUFBRSxDQUFLO29CQUNmLENBQUM7b0JBQ0QsU0FBUyxFQUFFLENBQUM7d0JBQ1YsTUFBTSxFQUFFLEtBQUssQ0FBQyxHQUFHO29CQUNuQixDQUFDO2dCQUNILENBQUM7WUFDSCxDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7O1FBM0JxQixVQUFVLEVBQVYsVUFBVSJ9\n", + "functionName": "taskToggle" + }, + "insertToday": { + "path": "core/dates.ts", + "code": "(function() {\n function syscall(name, ...args) {\n let reqId = Math.floor(Math.random() * 1000000);\n return new Promise((resolve, reject)=>{\n self.dispatchEvent(new CustomEvent(\"syscall\", {\n detail: {\n id: reqId,\n name: name,\n args: args,\n callback: resolve\n }\n }));\n });\n }\n async function insertToday() {\n let niceDate = new Date().toISOString().split(\"T\")[0];\n await syscall(\"editor.insertAtCursor\", niceDate);\n }\n return {\n insertToday: insertToday\n };\n})();\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vVXNlcnMvemVmL2dpdC9udWdnZXQvcGx1Z2lucy9jb3JlL2xpYi9zeXNjYWxsLnRzIiwiZmlsZTovLy9Vc2Vycy96ZWYvZ2l0L251Z2dldC9wbHVnaW5zL2NvcmUvZGF0ZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjthQUFnQixPQUFPLENBQUMsSUFBWSxLQUFLLElBQUksRUFBYyxDQUFDO1FBQzFELEdBQUcsQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxLQUFLLE9BQU87UUFFOUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sR0FBSyxDQUFDO1lBQ3ZDLElBQUksQ0FBQyxhQUFhLENBQ2hCLEdBQUcsQ0FBQyxXQUFXLENBQUMsQ0FBUyxVQUFFLENBQUM7Z0JBQzFCLE1BQU0sRUFBRSxDQUFDO29CQUNQLEVBQUUsRUFBRSxLQUFLO29CQUNULElBQUksRUFBRSxJQUFJO29CQUNWLElBQUksRUFBRSxJQUFJO29CQUNWLFFBQVEsRUFBRSxPQUFPO2dCQUNuQixDQUFDO1lBQ0gsQ0FBQztRQUVMLENBQUM7SUFDSCxDQUFDO21CQ2JxQixXQUFXLEdBQUcsQ0FBQztRQUNuQyxHQUFHLENBQUMsUUFBUSxHQUFHLEdBQUcsQ0FBQyxJQUFJLEdBQUcsV0FBVyxHQUFHLEtBQUssQ0FBQyxDQUFHLElBQUUsQ0FBQztRQUNwRCxLQUFLLFNBQVMsQ0FBdUIsd0JBQUUsUUFBUTtJQUNqRCxDQUFDOztRQUhxQixXQUFXLEVBQVgsV0FBVyJ9\n", + "functionName": "insertToday" + }, + "toggle_h1": { + "path": "core/markup.ts", + "code": "(function() {\n function syscall(name, ...args) {\n let reqId = Math.floor(Math.random() * 1000000);\n return new Promise((resolve, reject)=>{\n self.dispatchEvent(new CustomEvent(\"syscall\", {\n detail: {\n id: reqId,\n name: name,\n args: args,\n callback: resolve\n }\n }));\n });\n }\n async function toggleH1() {\n await togglePrefix(\"# \");\n }\n async function toggleH2() {\n await togglePrefix(\"## \");\n }\n function lookBack(s, pos, backString) {\n return s.substring(pos - backString.length, pos) === backString;\n }\n async function togglePrefix(prefix) {\n let text = await syscall(\"editor.getText\");\n let pos = await syscall(\"editor.getCursor\");\n if (text[pos] === \"\\n\") {\n pos--;\n }\n while(pos > 0 && text[pos] !== \"\\n\"){\n if (lookBack(text, pos, prefix)) {\n await syscall(\"editor.replaceRange\", pos - prefix.length, pos, \"\");\n return;\n }\n pos--;\n }\n if (pos) {\n pos++;\n }\n await syscall(\"editor.insertAtPos\", prefix, pos);\n }\n return {\n toggleH1: toggleH1,\n toggleH2: toggleH2\n };\n})();\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vVXNlcnMvemVmL2dpdC9udWdnZXQvcGx1Z2lucy9jb3JlL2xpYi9zeXNjYWxsLnRzIiwiZmlsZTovLy9Vc2Vycy96ZWYvZ2l0L251Z2dldC9wbHVnaW5zL2NvcmUvbWFya3VwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7YUFBZ0IsT0FBTyxDQUFDLElBQVksS0FBSyxJQUFJLEVBQWMsQ0FBQztRQUMxRCxHQUFHLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sS0FBSyxPQUFPO1FBRTlDLE1BQU0sQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLEdBQUssQ0FBQztZQUN2QyxJQUFJLENBQUMsYUFBYSxDQUNoQixHQUFHLENBQUMsV0FBVyxDQUFDLENBQVMsVUFBRSxDQUFDO2dCQUMxQixNQUFNLEVBQUUsQ0FBQztvQkFDUCxFQUFFLEVBQUUsS0FBSztvQkFDVCxJQUFJLEVBQUUsSUFBSTtvQkFDVixJQUFJLEVBQUUsSUFBSTtvQkFDVixRQUFRLEVBQUUsT0FBTztnQkFDbkIsQ0FBQztZQUNILENBQUM7UUFFTCxDQUFDO0lBQ0gsQ0FBQzttQkNicUIsUUFBUSxHQUFHLENBQUM7UUFDaEMsS0FBSyxDQUFDLFlBQVksQ0FBQyxDQUFJO0lBQ3pCLENBQUM7bUJBRXFCLFFBQVEsR0FBRyxDQUFDO1FBQ2hDLEtBQUssQ0FBQyxZQUFZLENBQUMsQ0FBSztJQUMxQixDQUFDO2FBRVEsUUFBUSxDQUFDLENBQVMsRUFBRSxHQUFXLEVBQUUsVUFBa0IsRUFBVyxDQUFDO1FBQ3RFLE1BQU0sQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLEdBQUcsR0FBRyxVQUFVLENBQUMsTUFBTSxFQUFFLEdBQUcsTUFBTSxVQUFVO0lBQ2pFLENBQUM7bUJBRWMsWUFBWSxDQUFDLE1BQWMsRUFBRSxDQUFDO1FBQzNDLEdBQUcsQ0FBQyxJQUFJLEdBQUksS0FBSyxTQUFTLENBQWdCO1FBQzFDLEdBQUcsQ0FBQyxHQUFHLEdBQUksS0FBSyxTQUFTLENBQWtCO1FBQzNDLEVBQUUsRUFBRSxJQUFJLENBQUMsR0FBRyxNQUFNLENBQUksS0FBRSxDQUFDO1lBQ3ZCLEdBQUc7UUFDTCxDQUFDO2NBQ00sR0FBRyxHQUFHLENBQUMsSUFBSSxJQUFJLENBQUMsR0FBRyxNQUFNLENBQUksSUFBRSxDQUFDO1lBQ3JDLEVBQUUsRUFBRSxRQUFRLENBQUMsSUFBSSxFQUFFLEdBQUcsRUFBRSxNQUFNLEdBQUcsQ0FBQztnQkFFaEMsS0FBSyxTQUFTLENBQXFCLHNCQUFFLEdBQUcsR0FBRyxNQUFNLENBQUMsTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUFFO2dCQUNqRSxNQUFNO1lBQ1IsQ0FBQztZQUNELEdBQUc7UUFDTCxDQUFDO1FBQ0QsRUFBRSxFQUFFLEdBQUcsRUFBRSxDQUFDO1lBQ1IsR0FBRztRQUNMLENBQUM7UUFDRCxLQUFLLFNBQVMsQ0FBb0IscUJBQUUsTUFBTSxFQUFFLEdBQUc7SUFDakQsQ0FBQzs7UUE5QnFCLFFBQVEsRUFBUixRQUFRO1FBSVIsUUFBUSxFQUFSLFFBQVEifQ==\n", + "functionName": "toggleH1" + }, + "toggle_h2": { + "path": "core/markup.ts", + "code": "(function() {\n function syscall(name, ...args) {\n let reqId = Math.floor(Math.random() * 1000000);\n return new Promise((resolve, reject)=>{\n self.dispatchEvent(new CustomEvent(\"syscall\", {\n detail: {\n id: reqId,\n name: name,\n args: args,\n callback: resolve\n }\n }));\n });\n }\n async function toggleH1() {\n await togglePrefix(\"# \");\n }\n async function toggleH2() {\n await togglePrefix(\"## \");\n }\n function lookBack(s, pos, backString) {\n return s.substring(pos - backString.length, pos) === backString;\n }\n async function togglePrefix(prefix) {\n let text = await syscall(\"editor.getText\");\n let pos = await syscall(\"editor.getCursor\");\n if (text[pos] === \"\\n\") {\n pos--;\n }\n while(pos > 0 && text[pos] !== \"\\n\"){\n if (lookBack(text, pos, prefix)) {\n await syscall(\"editor.replaceRange\", pos - prefix.length, pos, \"\");\n return;\n }\n pos--;\n }\n if (pos) {\n pos++;\n }\n await syscall(\"editor.insertAtPos\", prefix, pos);\n }\n return {\n toggleH1: toggleH1,\n toggleH2: toggleH2\n };\n})();\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vVXNlcnMvemVmL2dpdC9udWdnZXQvcGx1Z2lucy9jb3JlL2xpYi9zeXNjYWxsLnRzIiwiZmlsZTovLy9Vc2Vycy96ZWYvZ2l0L251Z2dldC9wbHVnaW5zL2NvcmUvbWFya3VwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7YUFBZ0IsT0FBTyxDQUFDLElBQVksS0FBSyxJQUFJLEVBQWMsQ0FBQztRQUMxRCxHQUFHLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sS0FBSyxPQUFPO1FBRTlDLE1BQU0sQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLEdBQUssQ0FBQztZQUN2QyxJQUFJLENBQUMsYUFBYSxDQUNoQixHQUFHLENBQUMsV0FBVyxDQUFDLENBQVMsVUFBRSxDQUFDO2dCQUMxQixNQUFNLEVBQUUsQ0FBQztvQkFDUCxFQUFFLEVBQUUsS0FBSztvQkFDVCxJQUFJLEVBQUUsSUFBSTtvQkFDVixJQUFJLEVBQUUsSUFBSTtvQkFDVixRQUFRLEVBQUUsT0FBTztnQkFDbkIsQ0FBQztZQUNILENBQUM7UUFFTCxDQUFDO0lBQ0gsQ0FBQzttQkNicUIsUUFBUSxHQUFHLENBQUM7UUFDaEMsS0FBSyxDQUFDLFlBQVksQ0FBQyxDQUFJO0lBQ3pCLENBQUM7bUJBRXFCLFFBQVEsR0FBRyxDQUFDO1FBQ2hDLEtBQUssQ0FBQyxZQUFZLENBQUMsQ0FBSztJQUMxQixDQUFDO2FBRVEsUUFBUSxDQUFDLENBQVMsRUFBRSxHQUFXLEVBQUUsVUFBa0IsRUFBVyxDQUFDO1FBQ3RFLE1BQU0sQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLEdBQUcsR0FBRyxVQUFVLENBQUMsTUFBTSxFQUFFLEdBQUcsTUFBTSxVQUFVO0lBQ2pFLENBQUM7bUJBRWMsWUFBWSxDQUFDLE1BQWMsRUFBRSxDQUFDO1FBQzNDLEdBQUcsQ0FBQyxJQUFJLEdBQUksS0FBSyxTQUFTLENBQWdCO1FBQzFDLEdBQUcsQ0FBQyxHQUFHLEdBQUksS0FBSyxTQUFTLENBQWtCO1FBQzNDLEVBQUUsRUFBRSxJQUFJLENBQUMsR0FBRyxNQUFNLENBQUksS0FBRSxDQUFDO1lBQ3ZCLEdBQUc7UUFDTCxDQUFDO2NBQ00sR0FBRyxHQUFHLENBQUMsSUFBSSxJQUFJLENBQUMsR0FBRyxNQUFNLENBQUksSUFBRSxDQUFDO1lBQ3JDLEVBQUUsRUFBRSxRQUFRLENBQUMsSUFBSSxFQUFFLEdBQUcsRUFBRSxNQUFNLEdBQUcsQ0FBQztnQkFFaEMsS0FBSyxTQUFTLENBQXFCLHNCQUFFLEdBQUcsR0FBRyxNQUFNLENBQUMsTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUFFO2dCQUNqRSxNQUFNO1lBQ1IsQ0FBQztZQUNELEdBQUc7UUFDTCxDQUFDO1FBQ0QsRUFBRSxFQUFFLEdBQUcsRUFBRSxDQUFDO1lBQ1IsR0FBRztRQUNMLENBQUM7UUFDRCxLQUFLLFNBQVMsQ0FBb0IscUJBQUUsTUFBTSxFQUFFLEdBQUc7SUFDakQsQ0FBQzs7UUE5QnFCLFFBQVEsRUFBUixRQUFRO1FBSVIsUUFBUSxFQUFSLFFBQVEifQ==\n", + "functionName": "toggleH2" + } + } +} \ No newline at end of file diff --git a/webapp/src/lineWrapper.ts b/webapp/src/lineWrapper.ts index 3930fd8..2d155bd 100644 --- a/webapp/src/lineWrapper.ts +++ b/webapp/src/lineWrapper.ts @@ -12,10 +12,12 @@ import { Range } from "@codemirror/rangeset"; interface WrapElement { selector: string; class: string; + nesting?: boolean; } function wrapLines(view: EditorView, wrapElements: WrapElement[]) { let widgets: Range[] = []; + let elementStack: string[] = []; for (let { from, to } of view.visibleRanges) { const doc = view.state.doc; syntaxTree(view.state).iterate({ @@ -25,12 +27,19 @@ function wrapLines(view: EditorView, wrapElements: WrapElement[]) { const bodyText = doc.sliceString(from, to); for (let wrapElement of wrapElements) { if (type.name == wrapElement.selector) { + if (wrapElement.nesting) { + elementStack.push(type.name); + } const bodyText = doc.sliceString(from, to); let idx = from; for (let line of bodyText.split("\n")) { + let cls = wrapElement.class; + if (wrapElement.nesting) { + cls = `${cls} ${cls}-${elementStack.length}`; + } widgets.push( Decoration.line({ - class: wrapElement.class, + class: cls, }).range(doc.lineAt(idx).from) ); idx += line.length + 1; @@ -38,7 +47,13 @@ function wrapLines(view: EditorView, wrapElements: WrapElement[]) { } } }, - leave(type, from: number, to: number) {}, + leave(type, from: number, to: number) { + for (let wrapElement of wrapElements) { + if (type.name == wrapElement.selector && wrapElement.nesting) { + elementStack.pop(); + } + } + }, }); } // Widgets have to be sorted by `from` in ascending order diff --git a/webapp/src/markdown/commands.js b/webapp/src/markdown/commands.js deleted file mode 100644 index 844b182..0000000 --- a/webapp/src/markdown/commands.js +++ /dev/null @@ -1,234 +0,0 @@ -import { EditorSelection } from "@codemirror/state"; -import { syntaxTree } from "@codemirror/language"; -import { markdownLanguage } from "./markdown"; -function nodeStart(node, doc) { - return doc.sliceString(node.from, node.from + 50); -} -class Context { - constructor(node, from, to, spaceBefore, spaceAfter, type, item) { - this.node = node; - this.from = from; - this.to = to; - this.spaceBefore = spaceBefore; - this.spaceAfter = spaceAfter; - this.type = type; - this.item = item; - } - blank(trailing = true) { - let result = this.spaceBefore; - if (this.node.name == "Blockquote") - result += ">"; - else - for (let i = this.to - this.from - result.length - this.spaceAfter.length; i > 0; i--) - result += " "; - return result + (trailing ? this.spaceAfter : ""); - } - marker(doc, add) { - let number = this.node.name == "OrderedList" ? String((+itemNumber(this.item, doc)[2] + add)) : ""; - return this.spaceBefore + number + this.type + this.spaceAfter; - } -} -function getContext(node, line, doc) { - let nodes = []; - for (let cur = node; cur && cur.name != "Document"; cur = cur.parent) { - if (cur.name == "ListItem" || cur.name == "Blockquote") - nodes.push(cur); - } - let context = [], pos = 0; - for (let i = nodes.length - 1; i >= 0; i--) { - let node = nodes[i], match, start = pos; - if (node.name == "Blockquote" && (match = /^[ \t]*>( ?)/.exec(line.slice(pos)))) { - pos += match[0].length; - context.push(new Context(node, start, pos, "", match[1], ">", null)); - } - else if (node.name == "ListItem" && node.parent.name == "OrderedList" && - (match = /^([ \t]*)\d+([.)])([ \t]*)/.exec(nodeStart(node, doc)))) { - let after = match[3], len = match[0].length; - if (after.length >= 4) { - after = after.slice(0, after.length - 4); - len -= 4; - } - pos += len; - context.push(new Context(node.parent, start, pos, match[1], after, match[2], node)); - } - else if (node.name == "ListItem" && node.parent.name == "BulletList" && - (match = /^([ \t]*)([-+*])([ \t]+)/.exec(nodeStart(node, doc)))) { - let after = match[3], len = match[0].length; - if (after.length > 4) { - after = after.slice(0, after.length - 4); - len -= 4; - } - pos += len; - context.push(new Context(node.parent, start, pos, match[1], after, match[2], node)); - } - } - return context; -} -function itemNumber(item, doc) { - return /^(\s*)(\d+)(?=[.)])/.exec(doc.sliceString(item.from, item.from + 10)); -} -function renumberList(after, doc, changes, offset = 0) { - for (let prev = -1, node = after;;) { - if (node.name == "ListItem") { - let m = itemNumber(node, doc); - let number = +m[2]; - if (prev >= 0) { - if (number != prev + 1) - return; - changes.push({ from: node.from + m[1].length, to: node.from + m[0].length, insert: String(prev + 2 + offset) }); - } - prev = number; - } - let next = node.nextSibling; - if (!next) - break; - node = next; - } -} -/// This command, when invoked in Markdown context with cursor -/// selection(s), will create a new line with the markup for -/// blockquotes and lists that were active on the old line. If the -/// cursor was directly after the end of the markup for the old line, -/// trailing whitespace and list markers are removed from that line. -/// -/// The command does nothing in non-Markdown context, so it should -/// not be used as the only binding for Enter (even in a Markdown -/// document, HTML and code regions might use a different language). -export const insertNewlineContinueMarkup = ({ state, dispatch }) => { - let tree = syntaxTree(state), { doc } = state; - let dont = null, changes = state.changeByRange(range => { - if (!range.empty || !markdownLanguage.isActiveAt(state, range.from)) - return dont = { range }; - let pos = range.from, line = doc.lineAt(pos); - let context = getContext(tree.resolveInner(pos, -1), line.text, doc); - while (context.length && context[context.length - 1].from > pos - line.from) - context.pop(); - if (!context.length) - return dont = { range }; - let inner = context[context.length - 1]; - if (inner.to - inner.spaceAfter.length > pos - line.from) - return dont = { range }; - let emptyLine = pos >= (inner.to - inner.spaceAfter.length) && !/\S/.test(line.text.slice(inner.to)); - // Empty line in list - if (inner.item && emptyLine) { - // First list item or blank line before: delete a level of markup - if (inner.node.firstChild.to >= pos || - line.from > 0 && !/[^\s>]/.test(doc.lineAt(line.from - 1).text)) { - let next = context.length > 1 ? context[context.length - 2] : null; - let delTo, insert = ""; - if (next && next.item) { // Re-add marker for the list at the next level - delTo = line.from + next.from; - insert = next.marker(doc, 1); - } - else { - delTo = line.from + (next ? next.to : 0); - } - let changes = [{ from: delTo, to: pos, insert }]; - if (inner.node.name == "OrderedList") - renumberList(inner.item, doc, changes, -2); - if (next && next.node.name == "OrderedList") - renumberList(next.item, doc, changes); - return { range: EditorSelection.cursor(delTo + insert.length), changes }; - } - else { // Move this line down - let insert = ""; - for (let i = 0, e = context.length - 2; i <= e; i++) - insert += context[i].blank(i < e); - insert += state.lineBreak; - return { range: EditorSelection.cursor(pos + insert.length), changes: { from: line.from, insert } }; - } - } - if (inner.node.name == "Blockquote" && emptyLine && line.from) { - let prevLine = doc.lineAt(line.from - 1), quoted = />\s*$/.exec(prevLine.text); - // Two aligned empty quoted lines in a row - if (quoted && quoted.index == inner.from) { - let changes = state.changes([{ from: prevLine.from + quoted.index, to: prevLine.to }, - { from: line.from + inner.from, to: line.to }]); - return { range: range.map(changes), changes }; - } - } - let changes = []; - if (inner.node.name == "OrderedList") - renumberList(inner.item, doc, changes); - let insert = state.lineBreak; - let continued = inner.item && inner.item.from < line.from; - // If not dedented - if (!continued || /^[\s\d.)\-+*>]*/.exec(line.text)[0].length >= inner.to) { - for (let i = 0, e = context.length - 1; i <= e; i++) - insert += i == e && !continued ? context[i].marker(doc, 1) : context[i].blank(); - } - let from = pos; - while (from > line.from && /\s/.test(line.text.charAt(from - line.from - 1))) - from--; - changes.push({ from, to: pos, insert }); - return { range: EditorSelection.cursor(from + insert.length), changes }; - }); - if (dont) - return false; - dispatch(state.update(changes, { scrollIntoView: true, userEvent: "input" })); - return true; -}; -function isMark(node) { - return node.name == "QuoteMark" || node.name == "ListMark"; -} -function contextNodeForDelete(tree, pos) { - let node = tree.resolveInner(pos, -1), scan = pos; - if (isMark(node)) { - scan = node.from; - node = node.parent; - } - for (let prev; prev = node.childBefore(scan);) { - if (isMark(prev)) { - scan = prev.from; - } - else if (prev.name == "OrderedList" || prev.name == "BulletList") { - node = prev.lastChild; - scan = node.to; - } - else { - break; - } - } - return node; -} -/// This command will, when invoked in a Markdown context with the -/// cursor directly after list or blockquote markup, delete one level -/// of markup. When the markup is for a list, it will be replaced by -/// spaces on the first invocation (a further invocation will delete -/// the spaces), to make it easy to continue a list. -/// -/// When not after Markdown block markup, this command will return -/// false, so it is intended to be bound alongside other deletion -/// commands, with a higher precedence than the more generic commands. -export const deleteMarkupBackward = ({ state, dispatch }) => { - let tree = syntaxTree(state); - let dont = null, changes = state.changeByRange(range => { - let pos = range.from, { doc } = state; - if (range.empty && markdownLanguage.isActiveAt(state, range.from)) { - let line = doc.lineAt(pos); - let context = getContext(contextNodeForDelete(tree, pos), line.text, doc); - if (context.length) { - let inner = context[context.length - 1]; - let spaceEnd = inner.to - inner.spaceAfter.length + (inner.spaceAfter ? 1 : 0); - // Delete extra trailing space after markup - if (pos - line.from > spaceEnd && !/\S/.test(line.text.slice(spaceEnd, pos - line.from))) - return { range: EditorSelection.cursor(line.from + spaceEnd), - changes: { from: line.from + spaceEnd, to: pos } }; - if (pos - line.from == spaceEnd) { - let start = line.from + inner.from; - // Replace a list item marker with blank space - if (inner.item && inner.node.from < inner.item.from && /\S/.test(line.text.slice(inner.from, inner.to))) - return { range, changes: { from: start, to: line.from + inner.to, insert: inner.blank() } }; - // Delete one level of indentation - if (start < pos) - return { range: EditorSelection.cursor(start), changes: { from: start, to: pos } }; - } - } - } - return dont = { range }; - }); - if (dont) - return false; - dispatch(state.update(changes, { scrollIntoView: true, userEvent: "delete" })); - return true; -}; diff --git a/webapp/src/markdown/commands.ts b/webapp/src/markdown/commands.ts index 65fa197..22e95a3 100644 --- a/webapp/src/markdown/commands.ts +++ b/webapp/src/markdown/commands.ts @@ -1,10 +1,15 @@ -import {StateCommand, Text, EditorSelection, ChangeSpec} from "@codemirror/state" -import {syntaxTree} from "@codemirror/language" -import {SyntaxNode, Tree} from "@lezer/common" -import {markdownLanguage} from "./markdown" +import { + StateCommand, + Text, + EditorSelection, + ChangeSpec, +} from "@codemirror/state"; +import { syntaxTree } from "@codemirror/language"; +import { SyntaxNode, Tree } from "@lezer/common"; +import { markdownLanguage } from "./markdown"; function nodeStart(node: SyntaxNode, doc: Text) { - return doc.sliceString(node.from, node.from + 50) + return doc.sliceString(node.from, node.from + 50); } class Context { @@ -19,65 +24,126 @@ class Context { ) {} blank(trailing: boolean = true) { - let result = this.spaceBefore - if (this.node.name == "Blockquote") result += ">" - else for (let i = this.to - this.from - result.length - this.spaceAfter.length; i > 0; i--) result += " " - return result + (trailing ? this.spaceAfter : "") + let result = this.spaceBefore; + if (this.node.name == "Blockquote") { + result += ">"; + } else if (this.node.name == "Comment") { + result += "%%"; + } else + for ( + let i = this.to - this.from - result.length - this.spaceAfter.length; + i > 0; + i-- + ) + result += " "; + return result + (trailing ? this.spaceAfter : ""); } marker(doc: Text, add: number) { - let number = this.node.name == "OrderedList" ? String((+itemNumber(this.item!, doc)[2] + add)) : "" - return this.spaceBefore + number + this.type + this.spaceAfter + let number = + this.node.name == "OrderedList" + ? String(+itemNumber(this.item!, doc)[2] + add) + : ""; + return this.spaceBefore + number + this.type + this.spaceAfter; } } function getContext(node: SyntaxNode, line: string, doc: Text) { - let nodes = [] - for (let cur: SyntaxNode | null = node; cur && cur.name != "Document"; cur = cur.parent) { - if (cur.name == "ListItem" || cur.name == "Blockquote") - nodes.push(cur) + let nodes = []; + for ( + let cur: SyntaxNode | null = node; + cur && cur.name != "Document"; + cur = cur.parent + ) { + if ( + cur.name == "ListItem" || + cur.name == "Blockquote" || + cur.name == "Comment" + ) + nodes.push(cur); } - let context = [], pos = 0 + let context = [], + pos = 0; for (let i = nodes.length - 1; i >= 0; i--) { - let node = nodes[i], match, start = pos - if (node.name == "Blockquote" && (match = /^[ \t]*>( ?)/.exec(line.slice(pos)))) { - pos += match[0].length - context.push(new Context(node, start, pos, "", match[1], ">", null)) - } else if (node.name == "ListItem" && node.parent!.name == "OrderedList" && - (match = /^([ \t]*)\d+([.)])([ \t]*)/.exec(nodeStart(node, doc)))) { - let after = match[3], len = match[0].length - if (after.length >= 4) { after = after.slice(0, after.length - 4); len -= 4 } - pos += len - context.push(new Context(node.parent!, start, pos, match[1], after, match[2], node)) - } else if (node.name == "ListItem" && node.parent!.name == "BulletList" && - (match = /^([ \t]*)([-+*])([ \t]+)/.exec(nodeStart(node, doc)))) { - let after = match[3], len = match[0].length - if (after.length > 4) { after = after.slice(0, after.length - 4); len -= 4 } - pos += len - context.push(new Context(node.parent!, start, pos, match[1], after, match[2], node)) + let node = nodes[i], + match, + start = pos; + if ( + node.name == "Blockquote" && + (match = /^[ \t]*>( ?)/.exec(line.slice(pos))) + ) { + pos += match[0].length; + context.push(new Context(node, start, pos, "", match[1], ">", null)); + } else if ( + node.name == "Comment" && + (match = /^[ \t]*%%( ?)/.exec(line.slice(pos))) + ) { + pos += match[0].length; + context.push(new Context(node, start, pos, "", match[1], "%%", null)); + } else if ( + node.name == "ListItem" && + node.parent!.name == "OrderedList" && + (match = /^([ \t]*)\d+([.)])([ \t]*)/.exec(nodeStart(node, doc))) + ) { + let after = match[3], + len = match[0].length; + if (after.length >= 4) { + after = after.slice(0, after.length - 4); + len -= 4; + } + pos += len; + context.push( + new Context(node.parent!, start, pos, match[1], after, match[2], node) + ); + } else if ( + node.name == "ListItem" && + node.parent!.name == "BulletList" && + (match = /^([ \t]*)([-+*])([ \t]+)/.exec(nodeStart(node, doc))) + ) { + let after = match[3], + len = match[0].length; + if (after.length > 4) { + after = after.slice(0, after.length - 4); + len -= 4; + } + pos += len; + context.push( + new Context(node.parent!, start, pos, match[1], after, match[2], node) + ); } } - return context + return context; } function itemNumber(item: SyntaxNode, doc: Text) { - return /^(\s*)(\d+)(?=[.)])/.exec(doc.sliceString(item.from, item.from + 10))! + return /^(\s*)(\d+)(?=[.)])/.exec( + doc.sliceString(item.from, item.from + 10) + )!; } -function renumberList(after: SyntaxNode, doc: Text, changes: ChangeSpec[], offset = 0) { - for (let prev = -1, node = after;;) { +function renumberList( + after: SyntaxNode, + doc: Text, + changes: ChangeSpec[], + offset = 0 +) { + for (let prev = -1, node = after; ; ) { if (node.name == "ListItem") { - let m = itemNumber(node, doc) - let number = +m[2] + let m = itemNumber(node, doc); + let number = +m[2]; if (prev >= 0) { - if (number != prev + 1) return - changes.push({from: node.from + m[1].length, to: node.from + m[0].length, insert: String(prev + 2 + offset)}) + if (number != prev + 1) return; + changes.push({ + from: node.from + m[1].length, + to: node.from + m[0].length, + insert: String(prev + 2 + offset), + }); } - prev = number + prev = number; } - let next = node.nextSibling - if (!next) break - node = next + let next = node.nextSibling; + if (!next) break; + node = next; } } @@ -90,93 +156,149 @@ function renumberList(after: SyntaxNode, doc: Text, changes: ChangeSpec[], offse /// The command does nothing in non-Markdown context, so it should /// not be used as the only binding for Enter (even in a Markdown /// document, HTML and code regions might use a different language). -export const insertNewlineContinueMarkup: StateCommand = ({state, dispatch}) => { - let tree = syntaxTree(state), {doc} = state - let dont = null, changes = state.changeByRange(range => { - if (!range.empty || !markdownLanguage.isActiveAt(state, range.from)) return dont = {range} - let pos = range.from, line = doc.lineAt(pos) - let context = getContext(tree.resolveInner(pos, -1), line.text, doc) - while (context.length && context[context.length - 1].from > pos - line.from) context.pop() - if (!context.length) return dont = {range} - let inner = context[context.length - 1] - if (inner.to - inner.spaceAfter.length > pos - line.from) return dont = {range} +export const insertNewlineContinueMarkup: StateCommand = ({ + state, + dispatch, +}) => { + let tree = syntaxTree(state), + { doc } = state; + let dont = null, + changes = state.changeByRange((range) => { + if (!range.empty || !markdownLanguage.isActiveAt(state, range.from)) + return (dont = { range }); + let pos = range.from, + line = doc.lineAt(pos); + let context = getContext(tree.resolveInner(pos, -1), line.text, doc); + while ( + context.length && + context[context.length - 1].from > pos - line.from + ) + context.pop(); + if (!context.length) return (dont = { range }); + let inner = context[context.length - 1]; + if (inner.to - inner.spaceAfter.length > pos - line.from) + return (dont = { range }); - let emptyLine = pos >= (inner.to - inner.spaceAfter.length) && !/\S/.test(line.text.slice(inner.to)) - // Empty line in list - if (inner.item && emptyLine) { - // First list item or blank line before: delete a level of markup - if (inner.node.firstChild!.to >= pos || - line.from > 0 && !/[^\s>]/.test(doc.lineAt(line.from - 1).text)) { - let next = context.length > 1 ? context[context.length - 2] : null - let delTo, insert = "" - if (next && next.item) { // Re-add marker for the list at the next level - delTo = line.from + next.from - insert = next.marker(doc, 1) + let emptyLine = + pos >= inner.to - inner.spaceAfter.length && + !/\S/.test(line.text.slice(inner.to)); + // Empty line in list + if (inner.item && emptyLine) { + // First list item or blank line before: delete a level of markup + if ( + inner.node.firstChild!.to >= pos || + (line.from > 0 && !/[^\s>]/.test(doc.lineAt(line.from - 1).text)) + ) { + let next = context.length > 1 ? context[context.length - 2] : null; + let delTo, + insert = ""; + if (next && next.item) { + // Re-add marker for the list at the next level + delTo = line.from + next.from; + insert = next.marker(doc, 1); + } else { + delTo = line.from + (next ? next.to : 0); + } + let changes: ChangeSpec[] = [{ from: delTo, to: pos, insert }]; + if (inner.node.name == "OrderedList") + renumberList(inner.item!, doc, changes, -2); + if (next && next.node.name == "OrderedList") + renumberList(next.item!, doc, changes); + return { + range: EditorSelection.cursor(delTo + insert.length), + changes, + }; } else { - delTo = line.from + (next ? next.to : 0) + // Move this line down + let insert = ""; + for (let i = 0, e = context.length - 2; i <= e; i++) + insert += context[i].blank(i < e); + insert += state.lineBreak; + return { + range: EditorSelection.cursor(pos + insert.length), + changes: { from: line.from, insert }, + }; } - let changes: ChangeSpec[] = [{from: delTo, to: pos, insert}] - if (inner.node.name == "OrderedList") renumberList(inner.item!, doc, changes, -2) - if (next && next.node.name == "OrderedList") renumberList(next.item!, doc, changes) - return {range: EditorSelection.cursor(delTo + insert.length), changes} - } else { // Move this line down - let insert = "" - for (let i = 0, e = context.length - 2; i <= e; i++) insert += context[i].blank(i < e) - insert += state.lineBreak - return {range: EditorSelection.cursor(pos + insert.length), changes: {from: line.from, insert}} } - } - if (inner.node.name == "Blockquote" && emptyLine && line.from) { - let prevLine = doc.lineAt(line.from - 1), quoted = />\s*$/.exec(prevLine.text) - // Two aligned empty quoted lines in a row - if (quoted && quoted.index == inner.from) { - let changes = state.changes([{from: prevLine.from + quoted.index, to: prevLine.to}, - {from: line.from + inner.from, to: line.to}]) - return {range: range.map(changes), changes} + if (inner.node.name == "Blockquote" && emptyLine && line.from) { + let prevLine = doc.lineAt(line.from - 1), + quoted = />\s*$/.exec(prevLine.text); + // Two aligned empty quoted lines in a row + if (quoted && quoted.index == inner.from) { + let changes = state.changes([ + { from: prevLine.from + quoted.index, to: prevLine.to }, + { from: line.from + inner.from, to: line.to }, + ]); + return { range: range.map(changes), changes }; + } } - } - let changes: ChangeSpec[] = [] - if (inner.node.name == "OrderedList") renumberList(inner.item!, doc, changes) - let insert = state.lineBreak - let continued = inner.item && inner.item.from < line.from - // If not dedented - if (!continued || /^[\s\d.)\-+*>]*/.exec(line.text)![0].length >= inner.to) { - for (let i = 0, e = context.length - 1; i <= e; i++) - insert += i == e && !continued ? context[i].marker(doc, 1) : context[i].blank() - } - let from = pos - while (from > line.from && /\s/.test(line.text.charAt(from - line.from - 1))) from-- - changes.push({from, to: pos, insert}) - return {range: EditorSelection.cursor(from + insert.length), changes} - }) - if (dont) return false - dispatch(state.update(changes, {scrollIntoView: true, userEvent: "input"})) - return true -} + if (inner.node.name == "Comment" && emptyLine && line.from) { + let prevLine = doc.lineAt(line.from - 1), + commented = /%%\s*$/.exec(prevLine.text); + // Two aligned empty quoted lines in a row + if (commented && commented.index == inner.from) { + let changes = state.changes([ + { from: prevLine.from + commented.index, to: prevLine.to }, + { from: line.from + inner.from, to: line.to }, + ]); + return { range: range.map(changes), changes }; + } + } + + let changes: ChangeSpec[] = []; + if (inner.node.name == "OrderedList") + renumberList(inner.item!, doc, changes); + let insert = state.lineBreak; + let continued = inner.item && inner.item.from < line.from; + // If not dedented + if ( + !continued || + /^[\s\d.)\-+*>]*/.exec(line.text)![0].length >= inner.to + ) { + for (let i = 0, e = context.length - 1; i <= e; i++) + insert += + i == e && !continued + ? context[i].marker(doc, 1) + : context[i].blank(); + } + let from = pos; + while ( + from > line.from && + /\s/.test(line.text.charAt(from - line.from - 1)) + ) + from--; + changes.push({ from, to: pos, insert }); + return { range: EditorSelection.cursor(from + insert.length), changes }; + }); + if (dont) return false; + dispatch(state.update(changes, { scrollIntoView: true, userEvent: "input" })); + return true; +}; function isMark(node: SyntaxNode) { - return node.name == "QuoteMark" || node.name == "ListMark" + return node.name == "QuoteMark" || node.name == "ListMark"; } function contextNodeForDelete(tree: Tree, pos: number) { - let node = tree.resolveInner(pos, -1), scan = pos + let node = tree.resolveInner(pos, -1), + scan = pos; if (isMark(node)) { - scan = node.from - node = node.parent! + scan = node.from; + node = node.parent!; } - for (let prev; prev = node.childBefore(scan);) { + for (let prev; (prev = node.childBefore(scan)); ) { if (isMark(prev)) { - scan = prev.from + scan = prev.from; } else if (prev.name == "OrderedList" || prev.name == "BulletList") { - node = prev.lastChild! - scan = node.to + node = prev.lastChild!; + scan = node.to; } else { - break + break; } } - return node + return node; } /// This command will, when invoked in a Markdown context with the @@ -188,34 +310,62 @@ function contextNodeForDelete(tree: Tree, pos: number) { /// When not after Markdown block markup, this command will return /// false, so it is intended to be bound alongside other deletion /// commands, with a higher precedence than the more generic commands. -export const deleteMarkupBackward: StateCommand = ({state, dispatch}) => { - let tree = syntaxTree(state) - let dont = null, changes = state.changeByRange(range => { - let pos = range.from, {doc} = state - if (range.empty && markdownLanguage.isActiveAt(state, range.from)) { - let line = doc.lineAt(pos) - let context = getContext(contextNodeForDelete(tree, pos), line.text, doc) - if (context.length) { - let inner = context[context.length - 1] - let spaceEnd = inner.to - inner.spaceAfter.length + (inner.spaceAfter ? 1 : 0) - // Delete extra trailing space after markup - if (pos - line.from > spaceEnd && !/\S/.test(line.text.slice(spaceEnd, pos - line.from))) - return {range: EditorSelection.cursor(line.from + spaceEnd), - changes: {from: line.from + spaceEnd, to: pos}} - if (pos - line.from == spaceEnd) { - let start = line.from + inner.from - // Replace a list item marker with blank space - if (inner.item && inner.node.from < inner.item.from && /\S/.test(line.text.slice(inner.from, inner.to))) - return {range, changes: {from: start, to: line.from + inner.to, insert: inner.blank()}} - // Delete one level of indentation - if (start < pos) - return {range: EditorSelection.cursor(start), changes: {from: start, to: pos}} +export const deleteMarkupBackward: StateCommand = ({ state, dispatch }) => { + let tree = syntaxTree(state); + let dont = null, + changes = state.changeByRange((range) => { + let pos = range.from, + { doc } = state; + if (range.empty && markdownLanguage.isActiveAt(state, range.from)) { + let line = doc.lineAt(pos); + let context = getContext( + contextNodeForDelete(tree, pos), + line.text, + doc + ); + if (context.length) { + let inner = context[context.length - 1]; + let spaceEnd = + inner.to - inner.spaceAfter.length + (inner.spaceAfter ? 1 : 0); + // Delete extra trailing space after markup + if ( + pos - line.from > spaceEnd && + !/\S/.test(line.text.slice(spaceEnd, pos - line.from)) + ) + return { + range: EditorSelection.cursor(line.from + spaceEnd), + changes: { from: line.from + spaceEnd, to: pos }, + }; + if (pos - line.from == spaceEnd) { + let start = line.from + inner.from; + // Replace a list item marker with blank space + if ( + inner.item && + inner.node.from < inner.item.from && + /\S/.test(line.text.slice(inner.from, inner.to)) + ) + return { + range, + changes: { + from: start, + to: line.from + inner.to, + insert: inner.blank(), + }, + }; + // Delete one level of indentation + if (start < pos) + return { + range: EditorSelection.cursor(start), + changes: { from: start, to: pos }, + }; + } } } - } - return dont = {range} - }) - if (dont) return false - dispatch(state.update(changes, {scrollIntoView: true, userEvent: "delete"})) - return true -} + return (dont = { range }); + }); + if (dont) return false; + dispatch( + state.update(changes, { scrollIntoView: true, userEvent: "delete" }) + ); + return true; +}; diff --git a/webapp/src/markdown/index.js b/webapp/src/markdown/index.js deleted file mode 100644 index 6b63484..0000000 --- a/webapp/src/markdown/index.js +++ /dev/null @@ -1,37 +0,0 @@ -import { Prec } from "@codemirror/state"; -import { keymap } from "@codemirror/view"; -import { LanguageSupport } from "@codemirror/language"; -import { MarkdownParser, parseCode } from "@lezer/markdown"; -import { html } from "@codemirror/lang-html"; -import { commonmarkLanguage, markdownLanguage, mkLang, getCodeParser } from "./markdown"; -import { insertNewlineContinueMarkup, deleteMarkupBackward } from "./commands"; -export { commonmarkLanguage, markdownLanguage, insertNewlineContinueMarkup, deleteMarkupBackward }; -/// A small keymap with Markdown-specific bindings. Binds Enter to -/// [`insertNewlineContinueMarkup`](#lang-markdown.insertNewlineContinueMarkup) -/// and Backspace to -/// [`deleteMarkupBackward`](#lang-markdown.deleteMarkupBackward). -export const markdownKeymap = [ - { key: "Enter", run: insertNewlineContinueMarkup }, - { key: "Backspace", run: deleteMarkupBackward } -]; -const htmlNoMatch = html({ matchClosingTags: false }); -/// Markdown language support. -export function markdown(config = {}) { - let { codeLanguages, defaultCodeLanguage, addKeymap = true, base: { parser } = commonmarkLanguage } = config; - if (!(parser instanceof MarkdownParser)) - throw new RangeError("Base parser provided to `markdown` should be a Markdown parser"); - let extensions = config.extensions ? [config.extensions] : []; - let support = [htmlNoMatch.support], defaultCode; - if (defaultCodeLanguage instanceof LanguageSupport) { - support.push(defaultCodeLanguage.support); - defaultCode = defaultCodeLanguage.language; - } - else if (defaultCodeLanguage) { - defaultCode = defaultCodeLanguage; - } - let codeParser = codeLanguages || defaultCode ? getCodeParser(codeLanguages || [], defaultCode) : undefined; - extensions.push(parseCode({ codeParser, htmlParser: htmlNoMatch.language.parser })); - if (addKeymap) - support.push(Prec.high(keymap.of(markdownKeymap))); - return new LanguageSupport(mkLang(parser.configure(extensions)), support); -} diff --git a/webapp/src/markdown/markdown.js b/webapp/src/markdown/markdown.js deleted file mode 100644 index 6c7b4bd..0000000 --- a/webapp/src/markdown/markdown.js +++ /dev/null @@ -1,75 +0,0 @@ -import { Language, defineLanguageFacet, languageDataProp, foldNodeProp, indentNodeProp, LanguageDescription, ParseContext } from "@codemirror/language"; -import { styleTags, tags as t } from "@codemirror/highlight"; -import { parser as baseParser, GFM, Subscript, Superscript, Emoji } from "@lezer/markdown"; -const data = defineLanguageFacet({ block: { open: "" } }); -export const commonmark = baseParser.configure({ - props: [ - styleTags({ - "Blockquote/...": t.quote, - HorizontalRule: t.contentSeparator, - "ATXHeading1/... SetextHeading1/...": t.heading1, - "ATXHeading2/... SetextHeading2/...": t.heading2, - "ATXHeading3/...": t.heading3, - "ATXHeading4/...": t.heading4, - "ATXHeading5/...": t.heading5, - "ATXHeading6/...": t.heading6, - "Comment CommentBlock": t.comment, - Escape: t.escape, - Entity: t.character, - "Emphasis/...": t.emphasis, - "StrongEmphasis/...": t.strong, - "Link/... Image/...": t.link, - "OrderedList/... BulletList/...": t.list, - // "CodeBlock/... FencedCode/...": t.blockComment, - "InlineCode CodeText": t.monospace, - URL: t.url, - "HeaderMark HardBreak QuoteMark ListMark LinkMark EmphasisMark CodeMark": t.processingInstruction, - "CodeInfo LinkLabel": t.labelName, - LinkTitle: t.string, - Paragraph: t.content - }), - foldNodeProp.add(type => { - if (!type.is("Block") || type.is("Document")) - return undefined; - return (tree, state) => ({ from: state.doc.lineAt(tree.from).to, to: tree.to }); - }), - indentNodeProp.add({ - Document: () => null - }), - languageDataProp.add({ - Document: data - }) - ] -}); -export function mkLang(parser) { - return new Language(data, parser, parser.nodeSet.types.find(t => t.name == "Document")); -} -/// Language support for strict CommonMark. -export const commonmarkLanguage = mkLang(commonmark); -const extended = commonmark.configure([GFM, Subscript, Superscript, Emoji, { - props: [ - styleTags({ - "TableDelimiter SubscriptMark SuperscriptMark StrikethroughMark": t.processingInstruction, - "TableHeader/...": t.heading, - "Strikethrough/...": t.strikethrough, - TaskMarker: t.atom, - Task: t.list, - Emoji: t.character, - "Subscript Superscript": t.special(t.content), - TableCell: t.content - }) - ] - }]); -/// Language support for [GFM](https://github.github.com/gfm/) plus -/// subscript, superscript, and emoji syntax. -export const markdownLanguage = mkLang(extended); -export function getCodeParser(languages, defaultLanguage) { - return (info) => { - let found = info && LanguageDescription.matchLanguageName(languages, info, true); - if (!found) - return defaultLanguage ? defaultLanguage.parser : null; - if (found.support) - return found.support.language.parser; - return ParseContext.getSkippingParser(found.load()); - }; -} diff --git a/webapp/src/parser.ts b/webapp/src/parser.ts index 971745e..4842b65 100644 --- a/webapp/src/parser.ts +++ b/webapp/src/parser.ts @@ -1,5 +1,11 @@ import { styleTags, tags as t } from "@codemirror/highlight"; -import { MarkdownConfig, TaskList } from "@lezer/markdown"; +import { + MarkdownConfig, + TaskList, + BlockContext, + LeafBlock, + LeafBlockParser, +} from "@lezer/markdown"; import { commonmark, mkLang } from "./markdown/markdown"; import * as ct from "./customtags"; import { pageLinkRegex } from "./constant"; @@ -77,6 +83,35 @@ const UnmarkedUrl: MarkdownConfig = { ], }; +class CommentParser implements LeafBlockParser { + nextLine() { + return false; + } + + finish(cx: BlockContext, leaf: LeafBlock) { + cx.addLeafElement( + leaf, + cx.elt("Comment", leaf.start, leaf.start + leaf.content.length, [ + // cx.elt("CommentMarker", leaf.start, leaf.start + 3), + ...cx.parser.parseInline(leaf.content.slice(3), leaf.start + 3), + ]) + ); + return true; + } +} +export const Comment: MarkdownConfig = { + defineNodes: [{ name: "Comment", block: true }], + parseBlock: [ + { + name: "Comment", + leaf(cx, leaf) { + return /^%%\s/.test(leaf.content) ? new CommentParser() : null; + }, + after: "SetextHeading", + }, + ], +}; + const TagLink: MarkdownConfig = { defineNodes: ["TagLink"], parseInline: [ @@ -102,6 +137,7 @@ const WikiMarkdown = commonmark.configure([ TagLink, TaskList, UnmarkedUrl, + Comment, { props: [ styleTags({ @@ -112,6 +148,8 @@ const WikiMarkdown = commonmark.configure([ Task: ct.TaskTag, TaskMarker: ct.TaskMarkerTag, Url: t.url, + Comment: ct.CommentTag, + // CommentMarker: ct.CommentMarkerTag, }), ], }, diff --git a/webapp/src/style.ts b/webapp/src/style.ts index 9acb6f3..f1a86ce 100644 --- a/webapp/src/style.ts +++ b/webapp/src/style.ts @@ -4,6 +4,7 @@ import * as ct from "./customtags"; export default HighlightStyle.define([ { tag: t.heading1, class: "h1" }, { tag: t.heading2, class: "h2" }, + { tag: t.heading3, class: "h3" }, { tag: t.link, class: "link" }, { tag: t.meta, class: "meta" }, { tag: t.quote, class: "quote" }, @@ -15,6 +16,8 @@ export default HighlightStyle.define([ { tag: ct.MentionTag, class: "mention" }, { tag: ct.TaskTag, class: "task" }, { tag: ct.TaskMarkerTag, class: "task-marker" }, + { tag: ct.CommentTag, class: "comment" }, + { tag: ct.CommentMarkerTag, class: "comment-marker" }, { tag: t.emphasis, class: "emphasis" }, { tag: t.strong, class: "strong" }, { tag: t.atom, class: "atom" }, diff --git a/webapp/src/styles/editor.scss b/webapp/src/styles/editor.scss index ac4fdab..c1e4e09 100644 --- a/webapp/src/styles/editor.scss +++ b/webapp/src/styles/editor.scss @@ -13,34 +13,29 @@ background-color: #d7e1f6 !important; } - .h1 { + .line-h1, + .line-h2, + .line-h3 { + background-color: rgba(0, 15, 52, 0.6); + color: #fff; + font-weight: bold; + padding: 2px 2px; + + .meta { + color: orange; + } + } + + .line-h1 { font-size: 1.5em; - color: #fff; - font-weight: bold; } - .cm-line.line-h1 { - display: block; - background-color: rgba(0, 15, 52, 0.6); - } - - .h1.meta { - color: orange; - } - - .h2 { + .line-h2 { font-size: 1.2em; - color: #fff; - font-weight: bold; } - .cm-line.line-h2 { - display: block; - background-color: rgba(0, 15, 52, 0.6); - } - - .h2.meta { - color: orange; + .line-h3 { + font-size: 1.1em; } /* Color list item this way */ @@ -66,10 +61,10 @@ } .line-blockquote { - background-color: #eee; + background-color: rgba(220, 220, 220, 0.5); color: #676767; - text-indent: calc(-1 * (var(--ident) + 3px)); - padding-left: var(--ident); + text-indent: -2ch; + padding-left: 2ch; } .emphasis { @@ -88,6 +83,7 @@ .link.url { color: #7e7d7d; } + .url:not(.link) { color: #0330cb; text-decoration: underline; @@ -109,12 +105,40 @@ color: #8d8d8d; } - .line-li { - text-indent: calc(-1 * var(--ident) - 3px); - margin-left: var(--ident); + .code { + background-color: #efefef; + } + + .line-li-1 { + text-indent: -2ch; + padding-left: 2ch; + } + + .line-li-1.line-li-2 { + text-indent: -4ch; + padding-left: 4ch; + } + + .line-li-1.line-li-2.line-li-3 { + text-indent: -6ch; + padding-left: 6ch; + } + + .line-li-1.line-li-2.line-li-3.line-li-4 { + text-indent: -8ch; + padding-left: 8ch; + } + + .line-li-1.line-li-2.line-li-3.line-li-4.line-li-5 { + text-indent: -10ch; + padding-left: 10ch; } .task-marker { background-color: #ddd; } + + .line-comment { + background-color: rgba(255, 255, 0, 0.5); + } } diff --git a/webapp/src/styles/filter_box.scss b/webapp/src/styles/filter_box.scss index 3e3a3d9..90d6edf 100644 --- a/webapp/src/styles/filter_box.scss +++ b/webapp/src/styles/filter_box.scss @@ -16,13 +16,29 @@ border-radius: 8px; box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px; - label { - color: var(--highlight-color); - } - .header { border-bottom: 1px rgb(108, 108, 108) solid; padding: 13px 10px 10px 10px; + display: flex; + label { + color: var(--highlight-color); + margin: 3px; + } + + input { + font-family: "Arial"; + background: transparent; + color: #000; + border: 0; + padding: 3px; + outline: 0; + font-size: 1em; + flex-grow: 100; + } + input::placeholder { + color: rgb(199, 199, 199); + font-weight: normal; + } } .help-text { @@ -45,21 +61,6 @@ } } - input { - font-family: "Arial"; - background: transparent; - color: #000; - border: 0; - padding: 3px; - outline: 0; - font-size: 1em; - } - - input::placeholder { - color: rgb(199, 199, 199); - font-weight: normal; - } - .option, .selected-option { padding: 8px; diff --git a/webapp/src/styles/main.scss b/webapp/src/styles/main.scss index 5161154..89d8b54 100644 --- a/webapp/src/styles/main.scss +++ b/webapp/src/styles/main.scss @@ -63,7 +63,7 @@ body { #editor { position: absolute; - top: 60px; + top: 55px; bottom: 30px; left: 0; right: 0; diff --git a/webapp/src/syscalls/editor.browser.ts b/webapp/src/syscalls/editor.browser.ts index 09c8572..d599f11 100644 --- a/webapp/src/syscalls/editor.browser.ts +++ b/webapp/src/syscalls/editor.browser.ts @@ -127,7 +127,7 @@ export default (editor: Editor) => ({ "editor.dispatch": (change: Transaction) => { editor.editorView!.dispatch(change); }, - "editor.prompt": (message: string): string | null => { - return prompt(message); + "editor.prompt": (message: string, defaultValue = ""): string | null => { + return prompt(message, defaultValue); }, });