From a1ee808ed593f2c548e8d1c9ae3059633cefbd07 Mon Sep 17 00:00:00 2001 From: Elio Date: Tue, 3 Aug 2021 14:16:35 +0200 Subject: [PATCH] #44 - New article creation command --- package-lock.json | 20 ++++++ package.json | 27 +++++++- src/commands/Folders.ts | 134 ++++++++++++++++++++++++++++++++++++ src/constants/settings.ts | 4 +- src/extension.ts | 30 +++++--- src/models/ContentFolder.ts | 5 ++ src/models/index.ts | 2 + 7 files changed, 210 insertions(+), 12 deletions(-) create mode 100644 src/commands/Folders.ts create mode 100644 src/models/ContentFolder.ts diff --git a/package-lock.json b/package-lock.json index 99536e12..5d56b45e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -94,6 +94,21 @@ "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==", "dev": true }, + "@types/lodash": { + "version": "4.14.172", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.172.tgz", + "integrity": "sha512-/BHF5HAx3em7/KkzVKm3LrsD6HZAXuXO1AJZQ3cRRBZj4oHZDviWPYu0aEplAqDFNHZPW6d3G7KN+ONcCCC7pw==", + "dev": true + }, + "@types/lodash.uniqby": { + "version": "4.7.6", + "resolved": "https://registry.npmjs.org/@types/lodash.uniqby/-/lodash.uniqby-4.7.6.tgz", + "integrity": "sha512-9wBhrm1y6asW50Joj6tsySCNUgzK2tCqL7vtKIej0E9RyeBFdcte7fxUosmFuMoOU0eHqOMK76kCCrK99jxHgg==", + "dev": true, + "requires": { + "@types/lodash": "*" + } + }, "@types/mdast": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.7.tgz", @@ -2759,6 +2774,11 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "lodash.uniqby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz", + "integrity": "sha1-2ZwHpmnp5tJOE2Lf4mbGdhavEwI=" + }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", diff --git a/package.json b/package.json index a38130b1..dff23459 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,9 @@ "onCommand:frontMatter.setLastModifiedDate", "onCommand:frontMatter.generateSlug", "onCommand:frontMatter.createFromTemplate", + "onCommand:frontMatter.registerFolder", + "onCommand:frontMatter.unregisterFolder", + "onCommand:frontMatter.createContent", "onView:frontMatter.explorer" ], "main": "./dist/extension", @@ -171,6 +174,11 @@ "type": "array", "default": [], "markdownDescription": "Specify the path to a Node.js script to execute. The current file path will be provided as an argument." + }, + "frontMatter.content.folders": { + "type": "array", + "default": [], + "markdownDescription": "This array of folders defines where the extension can easily create new content by running the create article command." } } }, @@ -222,6 +230,10 @@ { "command": "frontMatter.unregisterFolder", "title": "Front Matter: Unregister folder" + }, + { + "command": "frontMatter.createContent", + "title": "Front Matter: Create content" } ], "menus": { @@ -230,6 +242,16 @@ "command": "frontMatter.createFromTemplate", "when": "explorerResourceIsFolder", "group": "Front Matter@1" + }, + { + "command": "frontMatter.registerFolder", + "when": "explorerResourceIsFolder", + "group": "Front Matter@2" + }, + { + "command": "frontMatter.unregisterFolder", + "when": "explorerResourceIsFolder && resourcePath in frontMatter.registeredFolders", + "group": "Front Matter@3" } ] }, @@ -255,6 +277,7 @@ "@iarna/toml": "2.2.3", "@types/glob": "7.1.3", "@types/js-yaml": "3.12.1", + "@types/lodash.uniqby": "4.7.6", "@types/mocha": "^5.2.6", "@types/node": "10.17.48", "@types/react": "17.0.0", @@ -277,5 +300,7 @@ "webpack": "4.44.2", "webpack-cli": "3.3.12" }, - "dependencies": {} + "dependencies": { + "lodash.uniqby": "4.7.0" + } } diff --git a/src/commands/Folders.ts b/src/commands/Folders.ts new file mode 100644 index 00000000..17351c3d --- /dev/null +++ b/src/commands/Folders.ts @@ -0,0 +1,134 @@ +import { commands, Uri, workspace, window } from "vscode"; +import { CONFIG_KEY, EXTENSION_NAME, SETTINGS_CONTENT_FOLDERS } from "../constants"; +import { basename } from "path"; +import { ContentFolder } from "../models"; +import uniqBy = require("lodash.uniqby"); +import { VscodeCollapsible } from "@bendera/vscode-webview-elements/dist/vscode-collapsible"; +import { Template } from "./Template"; + +export class Folders { + + public static async create() { + const folders = Folders.get(); + + if (!folders || folders.length === 0) { + window.showWarningMessage(`${EXTENSION_NAME}: There are no known content locations defined in this project.`); + return; + } + + const selectedFolder = await window.showQuickPick(folders.map(f => f.title), { + placeHolder: `Select where you want to create your content` + }); + + if (!selectedFolder) { + window.showWarningMessage(`${EXTENSION_NAME}: You didn't select a place where you wanted to create your content.`); + return; + } + + const location = folders.find(f => f.title === selectedFolder); + if (location) { + const folderPath = Folders.getFolderPath(Uri.file(location.fsPath)); + if (folderPath) { + Template.create(folderPath); + } + } + } + + /** + * Register the new folder path + * @param folder + */ + public static async register(folder: Uri) { + if (folder && folder.path) { + const wslPath = folder.path.replace(/\//g, '\\'); + + let folders = Folders.get(); + + const exists = folders.find(f => f.paths.includes(folder.path) || f.paths.includes(wslPath)); + + if (exists) { + return window.showInformationMessage(`Folder is already registered`); + } + + const folderName = await window.showInputBox({ + prompt: `Which name would you like to specify for this folder?`, + placeHolder: `Folder name`, + value: basename(folder.fsPath) + }); + + folders.push({ + title: folderName, + fsPath: folder.fsPath, + paths: [ + folder.path, + wslPath + ] + } as ContentFolder); + + folders = uniqBy(folders, f => f.fsPath); + await Folders.update(folders); + } + + Folders.updateVsCodeCtx(); + } + + /** + * Unregister a folder path + * @param folder + */ + public static async unregister(folder: Uri) { + if (folder && folder.path) { + let folders = Folders.get(); + folders = folders.filter(f => f.fsPath !== folder.fsPath); + await Folders.update(folders); + } + + Folders.updateVsCodeCtx(); + } + + /** + * Update the registered folders context + */ + public static updateVsCodeCtx() { + const folders = Folders.get(); + let allFolders: string[] = []; + for (const folder of folders) { + allFolders = [...allFolders, ...folder.paths] + } + commands.executeCommand('setContext', 'frontMatter.registeredFolders', allFolders); + } + + /** + * Retrieve the folder path + * @param folder + * @returns + */ + public static getFolderPath(folder: Uri) { + let folderPath = ""; + if (folder && folder.fsPath) { + folderPath = folder.fsPath; + } else if (workspace.workspaceFolders && workspace.workspaceFolders.length > 0) { + folderPath = workspace.workspaceFolders[0].uri.fsPath; + } + return folderPath; + } + + /** + * Get the folder settings + * @returns + */ + private static get() { + const config = workspace.getConfiguration(CONFIG_KEY); + const folders: ContentFolder[] = config.get(SETTINGS_CONTENT_FOLDERS) as ContentFolder[]; + return folders; + } + + /** + * Update the folder settings + * @param folders + */ + private static async update(folders: ContentFolder[]) { + const config = workspace.getConfiguration(CONFIG_KEY); + await config.update(SETTINGS_CONTENT_FOLDERS, folders); + } +} \ No newline at end of file diff --git a/src/constants/settings.ts b/src/constants/settings.ts index befd3921..03ca7684 100644 --- a/src/constants/settings.ts +++ b/src/constants/settings.ts @@ -26,4 +26,6 @@ export const SETTING_TEMPLATES_PREFIX = "templates.prefix"; export const SETTING_PANEL_FREEFORM = "panel.freeform"; -export const SETTING_CUSTOM_SCRIPTS = "custom.scripts"; \ No newline at end of file +export const SETTING_CUSTOM_SCRIPTS = "custom.scripts"; + +export const SETTINGS_CONTENT_FOLDERS = "content.folders"; \ No newline at end of file diff --git a/src/extension.ts b/src/extension.ts index 93ef664e..fe8c2b60 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,5 +1,6 @@ import * as vscode from 'vscode'; import { Article, Settings, StatusListener } from './commands'; +import { Folders } from './commands/Folders'; import { Template } from './commands/Template'; import { TaxonomyType } from './models'; import { TagType } from './viewpanel/TagType'; @@ -9,7 +10,7 @@ let frontMatterStatusBar: vscode.StatusBarItem; let debouncer: { (fnc: any, time: number): void; }; let collection: vscode.DiagnosticCollection; -export function activate({ subscriptions, extensionUri }: vscode.ExtensionContext) { +export async function activate({ subscriptions, extensionUri }: vscode.ExtensionContext) { collection = vscode.languages.createDiagnosticCollection('frontMatter'); const explorerSidebar = ExplorerView.getInstance(extensionUri); @@ -59,14 +60,11 @@ export function activate({ subscriptions, extensionUri }: vscode.ExtensionContex Article.generateSlug(); }); - let createFromTemplate = vscode.commands.registerCommand('frontMatter.createFromTemplate', (e: vscode.Uri) => { - let folderPath = ""; - if (e && e.fsPath) { - folderPath = e.fsPath; - } else if (vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0) { - folderPath = vscode.workspace.workspaceFolders[0].uri.fsPath; - } - Template.create(folderPath); + let createFromTemplate = vscode.commands.registerCommand('frontMatter.createFromTemplate', (folder: vscode.Uri) => { + const folderPath = Folders.getFolderPath(folder); + if (folderPath) { + Template.create(folderPath); + } }); const toggleDraftCommand = 'frontMatter.toggleDraft'; @@ -75,6 +73,15 @@ export function activate({ subscriptions, extensionUri }: vscode.ExtensionContex triggerShowDraftStatus(); }); + // Register project folders + const registerFolder = vscode.commands.registerCommand(`frontMatter.registerFolder`, Folders.register); + + const unregisterFolder = vscode.commands.registerCommand(`frontMatter.unregisterFolder`, Folders.unregister); + + const createContent = vscode.commands.registerCommand(`frontMatter.createContent`, Folders.create); + + Folders.updateVsCodeCtx(); + // Create the status bar frontMatterStatusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 100); frontMatterStatusBar.command = toggleDraftCommand; @@ -99,6 +106,9 @@ export function activate({ subscriptions, extensionUri }: vscode.ExtensionContex subscriptions.push(generateSlug); subscriptions.push(createFromTemplate); subscriptions.push(toggleDraft); + subscriptions.push(registerFolder); + subscriptions.push(unregisterFolder); + subscriptions.push(createContent); } export function deactivate() {} @@ -115,4 +125,4 @@ const debounceShowDraftTrigger = () => { clearTimeout(timeout); timeout = setTimeout(functionCall, time) as any; }; -}; +}; \ No newline at end of file diff --git a/src/models/ContentFolder.ts b/src/models/ContentFolder.ts new file mode 100644 index 00000000..806a8e59 --- /dev/null +++ b/src/models/ContentFolder.ts @@ -0,0 +1,5 @@ +export interface ContentFolder { + title: string; + fsPath: string; + paths: string[]; +} \ No newline at end of file diff --git a/src/models/index.ts b/src/models/index.ts index bbe2fda6..73ab3027 100644 --- a/src/models/index.ts +++ b/src/models/index.ts @@ -1 +1,3 @@ +export * from './ContentFolder'; +export * from './PanelSettings'; export * from './TaxonomyType';