From 9bd06909c89caddf46ba5e5ccd739a613040490d Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Tue, 30 Nov 2021 15:05:28 +0100 Subject: [PATCH] #194 - WYSIWYG controls implementation --- CHANGELOG.md | 11 +++ assets/icons/bold-dark.svg | 5 ++ assets/icons/bold-light.svg | 5 ++ assets/icons/code-dark.svg | 6 ++ assets/icons/code-light.svg | 6 ++ assets/icons/codeblock-dark.svg | 7 ++ assets/icons/codeblock-light.svg | 7 ++ assets/icons/italic-dark.svg | 6 ++ assets/icons/italic-light.svg | 6 ++ assets/icons/strikethrough-dark.svg | 5 ++ assets/icons/strikethrough-light.svg | 5 ++ package.json | 84 ++++++++++++++++++++ src/commands/Wysiwyg.ts | 114 +++++++++++++++++++++++++++ src/constants/Extension.ts | 7 ++ src/constants/context.ts | 1 + src/constants/settings.ts | 1 + src/extension.ts | 4 + 17 files changed, 280 insertions(+) create mode 100644 assets/icons/bold-dark.svg create mode 100644 assets/icons/bold-light.svg create mode 100644 assets/icons/code-dark.svg create mode 100644 assets/icons/code-light.svg create mode 100644 assets/icons/codeblock-dark.svg create mode 100644 assets/icons/codeblock-light.svg create mode 100644 assets/icons/italic-dark.svg create mode 100644 assets/icons/italic-light.svg create mode 100644 assets/icons/strikethrough-dark.svg create mode 100644 assets/icons/strikethrough-light.svg create mode 100644 src/commands/Wysiwyg.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index b7a38790..38ade742 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Change Log +## [5.7.0] - 2021-12-xx + +### 🎨 Enhancements + +- [#188](https://github.com/estruyf/vscode-front-matter/issues/188): Support for `.markdown` files added to the dashboard +- [#194](https://github.com/estruyf/vscode-front-matter/issues/194): WYSIWYG controls added for markdown files + configuration to enable/disable the functionality + +### 🐞 Fixes + +- [#191](https://github.com/estruyf/vscode-front-matter/issues/191): Fix beta settings page + ## [5.6.0] - 2021-11-23 ### 🎨 Enhancements diff --git a/assets/icons/bold-dark.svg b/assets/icons/bold-dark.svg new file mode 100644 index 00000000..6ba1d39f --- /dev/null +++ b/assets/icons/bold-dark.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/assets/icons/bold-light.svg b/assets/icons/bold-light.svg new file mode 100644 index 00000000..9c887220 --- /dev/null +++ b/assets/icons/bold-light.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/assets/icons/code-dark.svg b/assets/icons/code-dark.svg new file mode 100644 index 00000000..a99e9aeb --- /dev/null +++ b/assets/icons/code-dark.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/assets/icons/code-light.svg b/assets/icons/code-light.svg new file mode 100644 index 00000000..1c0e436e --- /dev/null +++ b/assets/icons/code-light.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/assets/icons/codeblock-dark.svg b/assets/icons/codeblock-dark.svg new file mode 100644 index 00000000..8145c45f --- /dev/null +++ b/assets/icons/codeblock-dark.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/assets/icons/codeblock-light.svg b/assets/icons/codeblock-light.svg new file mode 100644 index 00000000..29714eb5 --- /dev/null +++ b/assets/icons/codeblock-light.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/assets/icons/italic-dark.svg b/assets/icons/italic-dark.svg new file mode 100644 index 00000000..ac651c36 --- /dev/null +++ b/assets/icons/italic-dark.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/assets/icons/italic-light.svg b/assets/icons/italic-light.svg new file mode 100644 index 00000000..427ab51d --- /dev/null +++ b/assets/icons/italic-light.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/assets/icons/strikethrough-dark.svg b/assets/icons/strikethrough-dark.svg new file mode 100644 index 00000000..a8a8a038 --- /dev/null +++ b/assets/icons/strikethrough-dark.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/assets/icons/strikethrough-light.svg b/assets/icons/strikethrough-light.svg new file mode 100644 index 00000000..bd67607c --- /dev/null +++ b/assets/icons/strikethrough-light.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/package.json b/package.json index 8e3831e4..24ad340b 100644 --- a/package.json +++ b/package.json @@ -240,6 +240,12 @@ }, "scope": "Content" }, + "frontMatter.content.wysiwyg": { + "type": "boolean", + "default": true, + "markdownDescription": "Specifies if you want to enable/disable the What You See, Is What You Get (WYSIWYG) markdown controls. [Check in the docs](https://frontmatter.codes/docs/settings#frontMatter.content.wysiwyg)", + "scope": "Content" + }, "frontMatter.custom.scripts": { "type": "array", "default": [], @@ -819,6 +825,51 @@ "command": "frontMatter.setLastModifiedDate", "title": "Set lastmod date", "category": "Front matter" + }, + { + "command": "frontMatter.content.bold", + "title": "Bold", + "category": "Front matter", + "icon": { + "light": "assets/icons/bold-light.svg", + "dark": "assets/icons/bold-dark.svg" + } + }, + { + "command": "frontMatter.content.italic", + "title": "Italic", + "category": "Front matter", + "icon": { + "light": "assets/icons/italic-light.svg", + "dark": "assets/icons/italic-dark.svg" + } + }, + { + "command": "frontMatter.content.strikethrough", + "title": "Strikethrough", + "category": "Front matter", + "icon": { + "light": "assets/icons/strikethrough-light.svg", + "dark": "assets/icons/strikethrough-dark.svg" + } + }, + { + "command": "frontMatter.content.code", + "title": "Code", + "category": "Front matter", + "icon": { + "light": "assets/icons/code-light.svg", + "dark": "assets/icons/code-dark.svg" + } + }, + { + "command": "frontMatter.content.codeblock", + "title": "Codeblock", + "category": "Front matter", + "icon": { + "light": "assets/icons/codeblock-light.svg", + "dark": "assets/icons/codeblock-dark.svg" + } } ], "menus": { @@ -828,6 +879,31 @@ "group": "navigation@-99", "when": "resourceLangId == markdown" }, + { + "command": "frontMatter.content.bold", + "group": "navigation@-130", + "when": "resourceLangId == markdown && frontMatter:markdown:wysiwyg" + }, + { + "command": "frontMatter.content.italic", + "group": "navigation@-129", + "when": "resourceLangId == markdown && frontMatter:markdown:wysiwyg" + }, + { + "command": "frontMatter.content.strikethrough", + "group": "navigation@-128", + "when": "resourceLangId == markdown && frontMatter:markdown:wysiwyg" + }, + { + "command": "frontMatter.content.code", + "group": "navigation@-127", + "when": "resourceLangId == markdown && frontMatter:markdown:wysiwyg" + }, + { + "command": "frontMatter.content.codeblock", + "group": "navigation@-126", + "when": "resourceLangId == markdown && frontMatter:markdown:wysiwyg" + }, { "command": "frontMatter.dashboard", "group": "navigation@-98", @@ -888,6 +964,14 @@ { "command": "frontMatter.dashboard.close", "when": "false" + }, + { + "command": "frontMatter.content.bold", + "when": "false" + }, + { + "command": "frontMatter.content.italic", + "when": "false" } ], "view/title": [ diff --git a/src/commands/Wysiwyg.ts b/src/commands/Wysiwyg.ts new file mode 100644 index 00000000..1e8e8dd9 --- /dev/null +++ b/src/commands/Wysiwyg.ts @@ -0,0 +1,114 @@ +import { commands, window, Selection } from "vscode"; +import { COMMAND_NAME, CONTEXT, SETTINGS_CONTENT_WYSIWYG } from "../constants"; +import { Settings } from "../helpers"; + +enum MarkupType { + bold = 1, + italic, + strikethrough, + code, + codeblock +} + +export class Wysiwyg { + + /** + * Registers the markup commands for the WYSIWYG controls + * @param subscriptions + * @returns + */ + public static async registerCommands(subscriptions: any) { + + const wysiwygEnabled = Settings.get(SETTINGS_CONTENT_WYSIWYG); + + if (!wysiwygEnabled) { + return; + } + + await commands.executeCommand('setContext', CONTEXT.wysiwyg, true); + + subscriptions.push(commands.registerCommand(COMMAND_NAME.bold, () => this.addMarkup(MarkupType.bold))); + subscriptions.push(commands.registerCommand(COMMAND_NAME.italic, () => this.addMarkup(MarkupType.italic))); + subscriptions.push(commands.registerCommand(COMMAND_NAME.strikethrough, () => this.addMarkup(MarkupType.strikethrough))); + subscriptions.push(commands.registerCommand(COMMAND_NAME.code, () => this.addMarkup(MarkupType.code))); + subscriptions.push(commands.registerCommand(COMMAND_NAME.codeblock, () => this.addMarkup(MarkupType.codeblock))); + } + + /** + * Add the markup to the content + * @param type + * @returns + */ + private static async addMarkup(type: MarkupType) { + const editor = window.activeTextEditor; + if (!editor) { + return; + } + + const selection = editor.selection; + const hasTextSelection = !selection.isEmpty; + + const markers = this.getMarkers(type); + if (!markers) { + return; + } + + const crntSelection = selection.active; + + if (hasTextSelection) { + // Replace the selection and surround with the markup + const selectionText = editor.document.getText(selection); + + editor.edit(builder => { + builder.replace(selection, markers + selectionText + markers); + }); + } else { + // Insert the markers where cursor is located. + let newPosition = crntSelection.with(crntSelection.line, crntSelection.character + markers.length); + + await editor.edit(builder => { + builder.insert(newPosition, markers + this.lineBreak(type) + markers) + }); + + if (type === MarkupType.codeblock) { + newPosition = crntSelection.with(crntSelection.line + 1, 0); + } + + editor.selection = new Selection(newPosition, newPosition); + } + } + + /** + * Check if linebreak needs to be added + * @param type + * @returns + */ + private static lineBreak(type: MarkupType) { + if (type === MarkupType.codeblock) { + return `\n\n`; + } + return ""; + } + + /** + * Retrieve the type of markers + * @param type + * @returns + */ + private static getMarkers(type: MarkupType) { + switch(type) { + case MarkupType.bold: + return `**`; + case MarkupType.italic: + return `*`; + case MarkupType.strikethrough: + return `~~`; + case MarkupType.code: + return "`"; + case MarkupType.codeblock: + return "```"; + default: + return; + } + } +} \ No newline at end of file diff --git a/src/constants/Extension.ts b/src/constants/Extension.ts index 49ce954d..72528aeb 100644 --- a/src/constants/Extension.ts +++ b/src/constants/Extension.ts @@ -32,4 +32,11 @@ export const COMMAND_NAME = { promote: getCommandName("promoteSettings"), insertImage: getCommandName("insertImage"), createFolder: getCommandName("createFolder"), + + // WYSIWYG + bold: getCommandName("content.bold"), + italic: getCommandName("content.italic"), + strikethrough: getCommandName("content.strikethrough"), + code: getCommandName("content.code"), + codeblock: getCommandName("content.codeblock"), }; \ No newline at end of file diff --git a/src/constants/context.ts b/src/constants/context.ts index a8754720..376640ad 100644 --- a/src/constants/context.ts +++ b/src/constants/context.ts @@ -4,4 +4,5 @@ export const CONTEXT = { canOpenDashboard: "frontMatterCanOpenDashboard", isEnabled: "frontMatter:enabled", isDashboardOpen: "frontMatter:dashboard:open", + wysiwyg: "frontMatter:markdown:wysiwyg", }; \ No newline at end of file diff --git a/src/constants/settings.ts b/src/constants/settings.ts index 06eb3bb0..528f4d11 100644 --- a/src/constants/settings.ts +++ b/src/constants/settings.ts @@ -43,6 +43,7 @@ export const SETTINGS_CONTENT_STATIC_FOLDER = "content.publicFolder"; export const SETTINGS_CONTENT_FRONTMATTER_HIGHLIGHT = "content.fmHighlight"; export const SETTINGS_CONTENT_DRAFT_FIELD = "content.draftField"; export const SETTINGS_CONTENT_SORTING = "content.sorting"; +export const SETTINGS_CONTENT_WYSIWYG = "content.wysiwyg"; export const SETTINGS_CONTENT_SORTING_DEFAULT = "content.defaultSorting"; export const SETTINGS_MEDIA_SORTING_DEFAULT = "content.defaultSorting"; diff --git a/src/extension.ts b/src/extension.ts index 3995918a..301be612 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -16,6 +16,7 @@ import { DashboardData } from './models/DashboardData'; import { Settings as SettingsHelper } from './helpers'; import { Content } from './commands/Content'; import ContentProvider from './providers/ContentProvider'; +import { Wysiwyg } from './commands/Wysiwyg'; let frontMatterStatusBar: vscode.StatusBarItem; let statusDebouncer: { (fnc: any, time: number): void; }; @@ -183,6 +184,9 @@ export async function activate(context: vscode.ExtensionContext) { // Create the editor experience for bulk scripts subscriptions.push(vscode.workspace.registerTextDocumentContentProvider(ContentProvider.scheme, new ContentProvider())); + // What you see, is what you get + Wysiwyg.registerCommands(subscriptions); + // Subscribe all commands subscriptions.push( insertTags,