From 28ad4d0c73fdab08c4d4f62b2ebb9dbc6cbbbd09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20D=C3=B6rfelt?= Date: Tue, 31 Oct 2023 16:06:04 +0100 Subject: [PATCH 1/5] add permanent trailing space overlay for testing --- src/whitespacer.css | 11 +++++++++++ src/whitespacer.ts | 19 ++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/whitespacer.css b/src/whitespacer.css index aebc9c4..a285ed6 100644 --- a/src/whitespacer.css +++ b/src/whitespacer.css @@ -1,3 +1,4 @@ +/* all whitespaces */ .CodeMirror .cm-tab::before { content: "→"; opacity: 0.3; @@ -12,3 +13,13 @@ position: absolute; opacity: 0.3; } + +/* trailing spaces only */ +.CodeMirror .cm-trailingspace > .cm-tab::before { + color: "black" !important; + opacity: 1 !important; +} +.CodeMirror .cm-trailingspace::before { + color: "black" !important; + opacity: 1 !important; +} diff --git a/src/whitespacer.ts b/src/whitespacer.ts index 33a70ee..852a18c 100644 --- a/src/whitespacer.ts +++ b/src/whitespacer.ts @@ -13,13 +13,30 @@ module.exports = { if (!prev && val) { cm.addOverlay({ name: "whitespaces", - token: function nextToken(stream) { + token: function (stream) { if (stream.next() === " ") { togglingLabel = !togglingLabel; return `whitespace-${togglingLabel ? "a" : "b"}`; } }, }); + + cm.addOverlay({ + name: "trailingspaces", + token: function (stream) { + const stringLengthWithoutTrailingWhitespaces = + stream.string.trimEnd().length; + + if (stringLengthWithoutTrailingWhitespaces > stream.pos) { + // advance to last char that isn't whitespace + stream.pos = stringLengthWithoutTrailingWhitespaces; + return null; + } + // rest of the stream are trailing spaces + stream.pos++; + return "trailingspace"; + }, + }); } }); }, From eede89357474325408677a153e11a92e87f97139 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20D=C3=B6rfelt?= Date: Tue, 31 Oct 2023 17:08:42 +0100 Subject: [PATCH 2/5] move the overlays to separate array --- src/whitespacer.ts | 73 +++++++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 33 deletions(-) diff --git a/src/whitespacer.ts b/src/whitespacer.ts index 852a18c..0e4322a 100644 --- a/src/whitespacer.ts +++ b/src/whitespacer.ts @@ -1,47 +1,54 @@ +const overlays = [ + { + name: "whitespaces", + token: function (stream) { + if (stream.next() === " ") { + console.log(this.togglingLabel); + this.togglingLabel = !this.togglingLabel; + return `whitespace-${this.togglingLabel ? "a" : "b"}`; + } + }, + // We need two separate classes for consecutive space characters. + // Else all spaces after the first one are ignored (not sure why). + togglingLabel: false, + }, + { + name: "trailingspaces", + token: function (stream) { + const stringLengthWithoutTrailingWhitespaces = + stream.string.trimEnd().length; + + if (stringLengthWithoutTrailingWhitespaces > stream.pos) { + // advance to last char that isn't whitespace + stream.pos = stringLengthWithoutTrailingWhitespaces; + return null; + } + // rest of the stream are trailing spaces + stream.pos++; + return "trailingspace"; + }, + }, +]; + module.exports = { default: function (_context) { return { plugin: function (CodeMirror) { - CodeMirror.defineOption("showWhitespaces", false, (cm, val, prev) => { + CodeMirror.defineOption("enableWhitespacer", false, (cm, val, prev) => { if (prev === CodeMirror.Init) prev = false; - if (prev && !val) cm.removeOverlay("whitespaces"); - - // We need two separate classes for consecutive space characters. - // Else all spaces after the first one are ignored (not sure why). - let togglingLabel = false; + if (prev && !val) + for (let overlay of overlays) cm.removeOverlay(overlay); if (!prev && val) { - cm.addOverlay({ - name: "whitespaces", - token: function (stream) { - if (stream.next() === " ") { - togglingLabel = !togglingLabel; - return `whitespace-${togglingLabel ? "a" : "b"}`; - } - }, - }); - - cm.addOverlay({ - name: "trailingspaces", - token: function (stream) { - const stringLengthWithoutTrailingWhitespaces = - stream.string.trimEnd().length; - - if (stringLengthWithoutTrailingWhitespaces > stream.pos) { - // advance to last char that isn't whitespace - stream.pos = stringLengthWithoutTrailingWhitespaces; - return null; - } - // rest of the stream are trailing spaces - stream.pos++; - return "trailingspace"; - }, - }); + const enabledOverlays = ["whitespaces", "trailingspaces"]; + for (let overlay of overlays) + if (enabledOverlays.includes(overlay.name)) + cm.addOverlay(overlay); } }); }, codeMirrorResources: [], - codeMirrorOptions: { showWhitespaces: true }, + codeMirrorOptions: { enableWhitespacer: true }, assets: function () { return [{ name: "whitespacer.css" }]; }, From 52db9185b1899e21daeb38670dd753d66891d4cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20D=C3=B6rfelt?= Date: Tue, 31 Oct 2023 18:11:21 +0100 Subject: [PATCH 3/5] use dedicated classes to enable switching the overlays on/off Remove the line ending, since it it either buggy or I don't understand the tokenization. --- src/whitespacer.css | 23 +++++------------------ src/whitespacer.ts | 11 +++++++---- 2 files changed, 12 insertions(+), 22 deletions(-) diff --git a/src/whitespacer.css b/src/whitespacer.css index a285ed6..0f55da0 100644 --- a/src/whitespacer.css +++ b/src/whitespacer.css @@ -1,25 +1,12 @@ -/* all whitespaces */ -.CodeMirror .cm-tab::before { +.CodeMirror .cm-ws-whitespace-tab > .cm-tab::before, +.CodeMirror .cm-ws-trailingspace > .cm-tab::before { content: "→"; opacity: 0.3; } -.CodeMirror-line > span::after { - content: "¬"; - opacity: 0.3; -} -.CodeMirror .cm-whitespace-a::before, -.CodeMirror .cm-whitespace-b::before { +.CodeMirror .cm-ws-whitespace-a::before, +.CodeMirror .cm-ws-whitespace-b::before, +.CodeMirror .cm-ws-trailingspace::before { content: "·"; position: absolute; opacity: 0.3; } - -/* trailing spaces only */ -.CodeMirror .cm-trailingspace > .cm-tab::before { - color: "black" !important; - opacity: 1 !important; -} -.CodeMirror .cm-trailingspace::before { - color: "black" !important; - opacity: 1 !important; -} diff --git a/src/whitespacer.ts b/src/whitespacer.ts index 0e4322a..769fec0 100644 --- a/src/whitespacer.ts +++ b/src/whitespacer.ts @@ -2,10 +2,13 @@ const overlays = [ { name: "whitespaces", token: function (stream) { - if (stream.next() === " ") { - console.log(this.togglingLabel); + const nextCharacter = stream.next(); + if (nextCharacter === " ") { this.togglingLabel = !this.togglingLabel; - return `whitespace-${this.togglingLabel ? "a" : "b"}`; + return `ws-whitespace-${this.togglingLabel ? "a" : "b"}`; + } else if (nextCharacter === " ") { + // TODO: why doesn't "\t" work? + return "ws-whitespace-tab"; } }, // We need two separate classes for consecutive space characters. @@ -25,7 +28,7 @@ const overlays = [ } // rest of the stream are trailing spaces stream.pos++; - return "trailingspace"; + return "ws-trailingspace"; }, }, ]; From 46fcd10e13ae080634c27135d2b3bd2a70a6c539 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20D=C3=B6rfelt?= Date: Tue, 31 Oct 2023 19:01:21 +0100 Subject: [PATCH 4/5] add a setting and the logic behind it --- src/index.ts | 28 +++++++++++++++++++++++++++- src/whitespacer.ts | 26 +++++++++++++++++++------- 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/src/index.ts b/src/index.ts index dcb3356..45f7f10 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,14 +1,40 @@ import joplin from "api"; -import { ContentScriptType } from "api/types"; +import { ContentScriptType, SettingItemType } from "api/types"; const contentScriptId = "whitespacer"; joplin.plugins.register({ onStart: async function () { + await joplin.settings.registerSettings({ + whiteSpaceMode: { + value: "allWhitespaces", + isEnum: true, + type: SettingItemType.String, + section: "whitespacerSection", + label: "Show Whitespaces", + public: true, + options: { + allWhitespaces: "All Whitespaces", + trailingWhitespaces: "Trailing Whitespaces Only", + }, + }, + }); + await joplin.contentScripts.register( ContentScriptType.CodeMirrorPlugin, contentScriptId, "./whitespacer.js" ); + + await joplin.contentScripts.onMessage( + contentScriptId, + async (message: { function: string; name: string }) => { + if (message.function === "getSetting") { + return await joplin.settings.value(message.name); + } else { + console.info("Invalid function", message.function); + } + } + ); }, }); diff --git a/src/whitespacer.ts b/src/whitespacer.ts index 769fec0..3d44af8 100644 --- a/src/whitespacer.ts +++ b/src/whitespacer.ts @@ -1,6 +1,6 @@ const overlays = [ { - name: "whitespaces", + name: "allWhitespaces", token: function (stream) { const nextCharacter = stream.next(); if (nextCharacter === " ") { @@ -16,7 +16,7 @@ const overlays = [ togglingLabel: false, }, { - name: "trailingspaces", + name: "trailingWhitespaces", token: function (stream) { const stringLengthWithoutTrailingWhitespaces = stream.string.trimEnd().length; @@ -34,7 +34,7 @@ const overlays = [ ]; module.exports = { - default: function (_context) { + default: function (context) { return { plugin: function (CodeMirror) { CodeMirror.defineOption("enableWhitespacer", false, (cm, val, prev) => { @@ -43,10 +43,22 @@ module.exports = { for (let overlay of overlays) cm.removeOverlay(overlay); if (!prev && val) { - const enabledOverlays = ["whitespaces", "trailingspaces"]; - for (let overlay of overlays) - if (enabledOverlays.includes(overlay.name)) - cm.addOverlay(overlay); + async function getSetting(timeout: number, name: string) { + const enabledOverlay = await context.postMessage({ + function: "getSetting", + name: "whiteSpaceMode", + }); + + if (enabledOverlay) { + for (let overlay of overlays) + if (overlay.name === enabledOverlay) cm.addOverlay(overlay); + } else { + setTimeout(getSetting, timeout * 2, name); + } + } + + // Wait until the settings are available. + setTimeout(getSetting, 100, "whiteSpaceMode"); } }); }, From a9a013e80e68e058cb0aacfe77022f0356584588 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20D=C3=B6rfelt?= Date: Tue, 31 Oct 2023 19:16:11 +0100 Subject: [PATCH 5/5] fix trailing whitespaces in code blocks --- src/whitespacer.css | 5 +++-- src/whitespacer.ts | 10 ++++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/whitespacer.css b/src/whitespacer.css index 0f55da0..2dc5010 100644 --- a/src/whitespacer.css +++ b/src/whitespacer.css @@ -1,11 +1,12 @@ .CodeMirror .cm-ws-whitespace-tab > .cm-tab::before, -.CodeMirror .cm-ws-trailingspace > .cm-tab::before { +.CodeMirror .cm-ws-trailingspace-tab > .cm-tab::before { content: "→"; opacity: 0.3; } .CodeMirror .cm-ws-whitespace-a::before, .CodeMirror .cm-ws-whitespace-b::before, -.CodeMirror .cm-ws-trailingspace::before { +.CodeMirror .cm-ws-trailingspace-a::before, +.CodeMirror .cm-ws-trailingspace-b::before { content: "·"; position: absolute; opacity: 0.3; diff --git a/src/whitespacer.ts b/src/whitespacer.ts index 3d44af8..c5216ff 100644 --- a/src/whitespacer.ts +++ b/src/whitespacer.ts @@ -27,9 +27,15 @@ const overlays = [ return null; } // rest of the stream are trailing spaces - stream.pos++; - return "ws-trailingspace"; + const nextCharacter = stream.next(); + if (nextCharacter === " ") { + this.togglingLabel = !this.togglingLabel; + return `ws-trailingspace-${this.togglingLabel ? "a" : "b"}`; + } else if (nextCharacter === " ") { + return "ws-trailingspace-tab"; + } }, + togglingLabel: false, }, ];