From 6914d4bc319781b4dc2b0d657bee77db405af2bf Mon Sep 17 00:00:00 2001 From: aphymi Date: Wed, 10 Sep 2025 02:28:21 -0400 Subject: [PATCH] Add command to toggle markdown syntax rendering (#1502) * feat: add command to toggle clean mode * refactor: simplify wiki_link no-clean-mode logic * refactor: use more sensible clean-mode toggling logic * fix: fix clean-mode-off not lasting across reloads * refactor: move var declaration to where it's used * feat: add root data attribute for clean mode state This allows writing styles based on whether clean mode is currently enabled or disabled. * feat: reset clean-mode-off syntax color * feat: un-hide lua directives in clean-mode-off * style: format changes from 60379b1 * feat: rename 'Toggle Clean Mode' command 'Toggle Clean Mode' is now 'Toggle Markdown Syntax Rendering', and along with the change in semantics, now defaults to false. The associated variables have also been renamed. * docs: add MD syntax rendering command to docs --- plugs/editor/editor.plug.yaml | 4 ++++ plugs/editor/editor.ts | 20 ++++++++++++++++++++ web/PAGE_TEMPLATES.ts | 2 +- web/cm_plugins/clean.ts | 12 ++++++++++-- web/cm_plugins/inline_content.ts | 5 ++++- web/cm_plugins/lua_directive.ts | 5 ++++- web/cm_plugins/wiki_link.ts | 4 +++- web/editor_ui.tsx | 5 +++++ web/styles/theme.scss | 9 +++++++++ web/ui_types.ts | 2 ++ website/Live Preview.md | 2 +- 11 files changed, 63 insertions(+), 7 deletions(-) diff --git a/plugs/editor/editor.plug.yaml b/plugs/editor/editor.plug.yaml index 7571b82d..1db9bb78 100644 --- a/plugs/editor/editor.plug.yaml +++ b/plugs/editor/editor.plug.yaml @@ -10,6 +10,10 @@ functions: path: "./editor.ts:toggleDarkMode" command: name: "Editor: Toggle Dark Mode" + toggleMarkdownSyntaxRendering: + path: "./editor.ts:toggleMarkdownSyntaxRendering" + command: + name: "Editor: Toggle Markdown Syntax Rendering" newWindow: path: editor.ts:newWindowCommand command: diff --git a/plugs/editor/editor.ts b/plugs/editor/editor.ts index b7a47a26..e79ad6e9 100644 --- a/plugs/editor/editor.ts +++ b/plugs/editor/editor.ts @@ -12,6 +12,16 @@ export async function setEditorMode() { if (await clientStore.get("darkMode")) { await editor.setUiOption("darkMode", true); } + const markdownSyntaxRendering = await clientStore.get( + "markdownSyntaxRendering", + ); + if (markdownSyntaxRendering != null) { + await editor.setUiOption( + "markdownSyntaxRendering", + markdownSyntaxRendering, + ); + await editor.rebuildEditorState(); + } } export function openCommandPalette() { @@ -41,6 +51,16 @@ export async function toggleDarkMode() { await editor.reloadUI(); } +export async function toggleMarkdownSyntaxRendering() { + let renderingSyntax = await editor.getUiOption( + "markdownSyntaxRendering", + ); + renderingSyntax = !renderingSyntax; + await clientStore.set("markdownSyntaxRendering", renderingSyntax); + await editor.setUiOption("markdownSyntaxRendering", renderingSyntax); + await editor.rebuildEditorState(); +} + export async function centerCursorCommand() { const pos = await editor.getCursor(); await editor.moveCursor(pos, true); diff --git a/web/PAGE_TEMPLATES.ts b/web/PAGE_TEMPLATES.ts index b9de561a..7a69f975 100644 --- a/web/PAGE_TEMPLATES.ts +++ b/web/PAGE_TEMPLATES.ts @@ -18,7 +18,7 @@ _Ah, so that explains the name!_ * Start typing \`:party\` to trigger the emoji picker 🎉 * Type \`/\` somewhere in the text to invoke a **slash command**. * If this matches your personality type, there is also an \`Editor: Toggle Vim Mode\` command to switch to Vim mode. If you cannot figure out how to exit it (classic vim issue), just run that same command again. _Phew!_ -* As you may have noticed, while SilverBullet uses [markdown](https://www.markdownguide.org/) underneath, it also “live previews” it to give a bit more of a WYSIWYG feel. You can always move your cursor “into” the underlying code by \`Alt-clicking\` it (even links and widgets, which we’ll get to later). +* As you may have noticed, while SilverBullet uses [markdown](https://www.markdownguide.org/) underneath, it also “live previews” it to give a bit more of a WYSIWYG feel. You can always move your cursor “into” the underlying code by \`Alt-clicking\` it (even links and widgets, which we’ll get to later), or reveal it permanently with the \`Toggle Markdown Syntax Rendering\` command. While SilverBullet implements (most) of [CommonMark](https://commonmark.org/), it also adds a few extensions that are SilverBullet-specific. Most notably, it adds the \`\${Lua expression}\` syntax to render Lua expressions inline. diff --git a/web/cm_plugins/clean.ts b/web/cm_plugins/clean.ts index eebd7c5c..ca0ac42a 100644 --- a/web/cm_plugins/clean.ts +++ b/web/cm_plugins/clean.ts @@ -17,7 +17,17 @@ import { hashtagPlugin } from "./hashtag.ts"; import type { ClickEvent } from "@silverbulletmd/silverbullet/type/client"; export function cleanModePlugins(client: Client) { + const pluginsNeededEvenWhenRenderingSyntax = [ + luaDirectivePlugin(client), + cleanWikiLinkPlugin(client), + ]; + + if (client.ui.viewState.uiOptions.markdownSyntaxRendering) { + return pluginsNeededEvenWhenRenderingSyntax; + } + return [ + ...pluginsNeededEvenWhenRenderingSyntax, linkPlugin(client), blockquotePlugin(), admonitionPlugin(), @@ -42,9 +52,7 @@ export function cleanModePlugins(client: Client) { }), listBulletPlugin(), tablePlugin(client), - cleanWikiLinkPlugin(client), cleanEscapePlugin(), - luaDirectivePlugin(client), hashtagPlugin(), ] as Extension[]; } diff --git a/web/cm_plugins/inline_content.ts b/web/cm_plugins/inline_content.ts index 9c22772c..21ec26ae 100644 --- a/web/cm_plugins/inline_content.ts +++ b/web/cm_plugins/inline_content.ts @@ -32,7 +32,10 @@ export function inlineContentPlugin(client: Client) { return; } - if (!isCursorInRange(state, [from, to])) { + const renderingSyntax = client.ui.viewState.uiOptions + .markdownSyntaxRendering; + const cursorIsInRange = isCursorInRange(state, [from, to]); + if (!renderingSyntax && !cursorIsInRange) { widgets.push(invisibleDecoration.range(from, to)); } diff --git a/web/cm_plugins/lua_directive.ts b/web/cm_plugins/lua_directive.ts index 9dd91797..364d955b 100644 --- a/web/cm_plugins/lua_directive.ts +++ b/web/cm_plugins/lua_directive.ts @@ -143,7 +143,10 @@ export function luaDirectivePlugin(client: Client) { ), }).range(node.to), ); - widgets.push(invisibleDecoration.range(node.from, node.to)); + + if (!client.ui.viewState.uiOptions.markdownSyntaxRendering) { + widgets.push(invisibleDecoration.range(node.from, node.to)); + } }, }); diff --git a/web/cm_plugins/wiki_link.ts b/web/cm_plugins/wiki_link.ts index 2e36de1d..0f754cda 100644 --- a/web/cm_plugins/wiki_link.ts +++ b/web/cm_plugins/wiki_link.ts @@ -62,7 +62,9 @@ export function cleanWikiLinkPlugin(client: Client) { "default": "", }[linkStatus]; - if (isCursorInRange(state, [from, to])) { + const renderingSyntax = + client.ui.viewState.uiOptions.markdownSyntaxRendering; + if (isCursorInRange(state, [from, to]) || renderingSyntax) { // Only attach a CSS class, then get out if (linkStatus !== "default") { widgets.push( diff --git a/web/editor_ui.tsx b/web/editor_ui.tsx index 1fdcef27..e98c6198 100644 --- a/web/editor_ui.tsx +++ b/web/editor_ui.tsx @@ -127,6 +127,11 @@ export class MainUI { }); }, [viewState.uiOptions.darkMode]); + useEffect(() => { + document.documentElement.dataset.markdownSyntaxRendering = + viewState.uiOptions.markdownSyntaxRendering ? "on" : "off"; + }, [viewState.uiOptions.markdownSyntaxRendering]); + useEffect(() => { // Need to dispatch a resize event so that the top_bar can pick it up globalThis.dispatchEvent(new Event("resize")); diff --git a/web/styles/theme.scss b/web/styles/theme.scss index 1f4fcfec..3f3b3831 100644 --- a/web/styles/theme.scss +++ b/web/styles/theme.scss @@ -279,6 +279,15 @@ html[data-theme="dark"] { --editor-directive-background-color: #4c4c4c7d; } +html[data-markdown-syntax-rendering="on"] { + --editor-meta-color: unset; + --editor-directive-mark-color: unset; + + #sb-main .cm-editor .sb-lua-directive-block { + margin-top: 0.5em; + } +} + .sb-admonition[admonition="note" i] { .sb-admonition-type { &::before { diff --git a/web/ui_types.ts b/web/ui_types.ts index db3ce722..0466ca35 100644 --- a/web/ui_types.ts +++ b/web/ui_types.ts @@ -39,6 +39,7 @@ export type AppViewState = { uiOptions: { vimMode: boolean; darkMode?: boolean; + markdownSyntaxRendering: boolean; forcedROMode: boolean; customStyles?: string; }; @@ -76,6 +77,7 @@ export const initialViewState: AppViewState = { uiOptions: { vimMode: false, darkMode: undefined, + markdownSyntaxRendering: false, forcedROMode: false, }, isMobile: false, diff --git a/website/Live Preview.md b/website/Live Preview.md index 7ef13825..e11b3e66 100644 --- a/website/Live Preview.md +++ b/website/Live Preview.md @@ -2,4 +2,4 @@ SilverBullet uses a “live preview” markdown editor. This mechanism is heavil It reduces visual noise by not constantly showing [[Markdown]] codes such as `[SilverBullet website](https://silverbullet.md)`, only showing the underlying Markdown formatting code when the cursor is placed inside. -In SilverBullet, you can always see the underlying format by moving your cursor “inside.” **Alt-clicking** on any piece of formatted text will move your cursor there and reveal the underlying (markdown) code. +In SilverBullet, you can always see the underlying format by moving your cursor “inside.” **Alt-clicking** on any piece of formatted text will move your cursor there and reveal the underlying (markdown) code, or you can reveal it permanently with the `Toggle Markdown Syntax Rendering` command.