From 8c33be6b2346a740e346bc62eb2009fc91898222 Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Wed, 28 Aug 2019 20:23:55 +0200 Subject: [PATCH] #3 - Included the new remapping command --- CHANGELOG.md | 5 + README.md | 19 ++- package.json | 5 + src/commands/Article.ts | 117 +++++++++++++ src/commands/FrontMatter.ts | 311 ---------------------------------- src/commands/Settings.ts | 245 ++++++++++++++++++++++++++ src/commands/StatusBar.ts | 37 ++++ src/commands/index.ts | 4 +- src/extension.ts | 23 ++- src/helpers/ArticleHelper.ts | 30 ++++ src/helpers/FilesHelper.ts | 19 +++ src/helpers/SettingsHelper.ts | 37 ++++ src/helpers/index.ts | 3 + 13 files changed, 529 insertions(+), 326 deletions(-) create mode 100644 src/commands/Article.ts delete mode 100644 src/commands/FrontMatter.ts create mode 100644 src/commands/Settings.ts create mode 100644 src/commands/StatusBar.ts create mode 100644 src/helpers/ArticleHelper.ts create mode 100644 src/helpers/FilesHelper.ts create mode 100644 src/helpers/SettingsHelper.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index a6674e77..8f7718be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,13 @@ # Change Log +## [0.0.7] - 2019-08-28 + +- Added command to remap tags or categories in all posts: `Front Matter: Remap tag/category in all articles` + ## [0.0.6] - 2019-08-28 - Updated `package.json` file to include preview label +- Added the status bar item to quickly view and update the draft status of an article ## [0.0.5] - 2019-08-27 diff --git a/README.md b/README.md index 6c45e0aa..c448bf1d 100644 --- a/README.md +++ b/README.md @@ -7,21 +7,30 @@ This VSCode extension simplifies working with front matter of your markdown arti ## Available commands: **Front Matter: Create ** - - Creates a new and allows you to automatically include it into your post + +Creates a new and allows you to automatically include it into your post ![Create tag or category](./assets/create-tag-category.gif) **Front Matter: Insert ** - - Inserts a selected into the front matter of your article/post/... + +Inserts a selected into the front matter of your article/post/... ![Insert tags or categories](./assets/insert-tag-category.gif) **Front Matter: Export all tags & categories to your settings** - - Export all the already used tags & categories in your articles/posts/... to your user settings + +Export all the already used tags & categories in your articles/posts/... to your user settings + +**Front Matter: Remap tag/category in all articles** + +This is commands helps you quickly update/remap a tag or category in all your markdown files. You'll be asked to select the taxonomy type (*tag* or *category*), the old taxonomy value and the new one. + +> **Info**: Once the remapping is completed, the taxonomy tags/categories will be updated in your user settings. **Front Matter: Set current date** - - Update the `date` property of the current article/post/... to the current date & time. +Update the `date` property of the current article/post/... to the current date & time. > **Optional**: if you want, you can specify the format of the date property by adding your own preference in your settings. Settings key: `frontMatter.taxonomy.dateFormat`. Check [date-fns formating](https://date-fns.org/v2.0.1/docs/format) for more information which patterns you can use. @@ -39,7 +48,7 @@ The tags and categories are stored in the project VSCode user settings. You can ## Usage - Start by opening the command prompt: - - Windows ⇧+ctrl+P + - Windows: ⇧+ctrl+P - Mac: ⇧+⌘+P - Use one of the commands from above diff --git a/package.json b/package.json index 0c7d6b41..69b3b91e 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "onCommand:frontMatter.createTag", "onCommand:frontMatter.createCategory", "onCommand:frontMatter.exportTaxonomy", + "onCommand:frontMatter.remap", "onCommand:frontMatter.setDate" ], "main": "./dist/extension", @@ -85,6 +86,10 @@ "command": "frontMatter.exportTaxonomy", "title": "Front Matter: Export all tags & categories to your settings" }, + { + "command": "frontMatter.remap", + "title": "Front Matter: Remap tag/category in all articles" + }, { "command": "frontMatter.setDate", "title": "Front Matter: Set current date" diff --git a/src/commands/Article.ts b/src/commands/Article.ts new file mode 100644 index 00000000..da5be4ce --- /dev/null +++ b/src/commands/Article.ts @@ -0,0 +1,117 @@ +import * as vscode from 'vscode'; +import { TaxonomyType } from "../models"; +import { CONFIG_KEY, ACTION_TAXONOMY_TAGS, ACTION_TAXONOMY_CATEGORIES, ACTION_DATE_FORMAT } from "../constants/settings"; +import { format } from "date-fns"; +import { ArticleHelper, SettingsHelper } from '../helpers'; + + +export class Article { + + /** + * Insert taxonomy + * + * @param type + */ + public static async insert(type: TaxonomyType) { + const config = vscode.workspace.getConfiguration(CONFIG_KEY); + const editor = vscode.window.activeTextEditor; + if (!editor) { + return; + } + + const article = ArticleHelper.getFrontMatter(editor); + if (!article) { + return; + } + + let options: vscode.QuickPickItem[] = []; + const matterProp: string = type === TaxonomyType.Tag ? "tags" : "categories"; + + // Add the selected options to the options array + if (article.data[matterProp]) { + const propData = article.data[matterProp]; + if (propData && propData.length > 0) { + options = [...propData].map(p => ({ + label: p, + picked: true + } as vscode.QuickPickItem)); + } + } + + // Add all the known options to the selection list + const crntOptions = SettingsHelper.getTaxonomy(type); + if (crntOptions && crntOptions.length > 0) { + for (const crntOpt of crntOptions) { + if (!options.find(o => o.label === crntOpt)) { + options.push({ + label: crntOpt + }); + } + } + } + + if (options.length === 0) { + vscode.window.showInformationMessage(`No ${type === TaxonomyType.Tag ? "tags" : "categories"} configured.`); + return; + } + + const selectedOptions = await vscode.window.showQuickPick(options, { + placeHolder: `Select your ${type === TaxonomyType.Tag ? "tags" : "categories"} to insert`, + canPickMany: true + }); + + if (selectedOptions) { + article.data[matterProp] = selectedOptions.map(o => o.label); + } + + ArticleHelper.update(editor, article); + } + + /** + * Sets the article date + */ + public static async setDate() { + const config = vscode.workspace.getConfiguration(CONFIG_KEY); + const editor = vscode.window.activeTextEditor; + if (!editor) { + return; + } + + const article = ArticleHelper.getFrontMatter(editor); + if (!article) { + return; + } + + const dateFormat = config.get(ACTION_DATE_FORMAT) as string; + try { + if (dateFormat && typeof dateFormat === "string") { + article.data["date"] = format(new Date(), dateFormat); + } else { + article.data["date"] = new Date(); + } + + ArticleHelper.update(editor, article); + } catch (e) { + vscode.window.showErrorMessage(`Front Matter: Something failed while parsing the date format. Check your "${CONFIG_KEY}${ACTION_DATE_FORMAT}" setting.`); + console.log(e.message); + } + } + + /** + * Toggle the page its draft mode + */ + public static async toggleDraft() { + const editor = vscode.window.activeTextEditor; + if (!editor) { + return; + } + const article = ArticleHelper.getFrontMatter(editor); + if (!article) { + return; + } + + const newDraftStatus = !article.data["draft"]; + article.data["draft"] = newDraftStatus; + ArticleHelper.update(editor, article); + } +} \ No newline at end of file diff --git a/src/commands/FrontMatter.ts b/src/commands/FrontMatter.ts deleted file mode 100644 index 298717eb..00000000 --- a/src/commands/FrontMatter.ts +++ /dev/null @@ -1,311 +0,0 @@ -import * as vscode from 'vscode'; -import { TaxonomyType } from "../models"; -import { CONFIG_KEY, ACTION_TAXONOMY_TAGS, ACTION_TAXONOMY_CATEGORIES, ACTION_DATE_FORMAT } from "../constants/settings"; -import * as matter from "gray-matter"; -import { format } from "date-fns"; - - -export class FrontMatter { - - /** - * Insert taxonomy - * - * @param type - */ - public static async insert(type: TaxonomyType) { - const config = vscode.workspace.getConfiguration(CONFIG_KEY); - const editor = vscode.window.activeTextEditor; - if (!editor) { - return; - } - - const article = this.getArticleData(editor); - if (!article) { - return; - } - - let options: vscode.QuickPickItem[] = []; - const matterProp: string = type === TaxonomyType.Tag ? "tags" : "categories"; - - // Add the selected options to the options array - if (article.data[matterProp]) { - const propData = article.data[matterProp]; - if (propData && propData.length > 0) { - options = [...propData].map(p => ({ - label: p, - picked: true - } as vscode.QuickPickItem)); - } - } - - // Add all the known options to the selection list - const configSetting = type === TaxonomyType.Tag ? ACTION_TAXONOMY_TAGS : ACTION_TAXONOMY_CATEGORIES; - const crntOptions = config.get(configSetting) as string[]; - if (crntOptions && crntOptions.length > 0) { - for (const crntOpt of crntOptions) { - if (!options.find(o => o.label === crntOpt)) { - options.push({ - label: crntOpt - }); - } - } - } - - if (options.length === 0) { - vscode.window.showInformationMessage(`No ${type === TaxonomyType.Tag ? "tags" : "categories"} configured.`); - return; - } - - const selectedOptions = await vscode.window.showQuickPick(options, { - placeHolder: `Select your ${type === TaxonomyType.Tag ? "tags" : "categories"} to insert`, - canPickMany: true - }); - - if (selectedOptions) { - article.data[matterProp] = selectedOptions.map(o => o.label); - } - - this.updatePage(editor, article); - } - - /** - * Create a new taxonomy - * - * @param type - */ - public static async create(type: TaxonomyType) { - const newOption = await vscode.window.showInputBox({ - prompt: `Insert the value of the ${type === TaxonomyType.Tag ? "tag" : "category"} that you want to add to your configuration.`, - placeHolder: `Name of the ${type === TaxonomyType.Tag ? "tag" : "category"}` - }); - - if (newOption) { - const config = vscode.workspace.getConfiguration(CONFIG_KEY); - const configSetting = type === TaxonomyType.Tag ? ACTION_TAXONOMY_TAGS : ACTION_TAXONOMY_CATEGORIES; - let options = config.get(configSetting) as string[]; - if (!options) { - options = []; - } - - if (options.find(o => o === newOption)) { - vscode.window.showInformationMessage(`The provided ${type === TaxonomyType.Tag ? "tag" : "category"} already exists.`); - return; - } - - options.push(newOption); - config.update(configSetting, options); - - // Ask if the new term needs to be added to the page - const addToPage = await vscode.window.showQuickPick(["yes", "no"], { canPickMany: false, placeHolder: `Do you want to add the new ${type === TaxonomyType.Tag ? "tag" : "category"} to the page?` }); - - if (addToPage && addToPage === "yes") { - const editor = vscode.window.activeTextEditor; - if (!editor) { - return; - } - - const article = this.getArticleData(editor); - if (!article) { - return; - } - - const matterProp: string = type === TaxonomyType.Tag ? "tags" : "categories"; - // Add the selected options to the options array - if (article.data[matterProp]) { - const propData: string[] = article.data[matterProp]; - if (propData && !propData.find(o => o === newOption)) { - propData.push(newOption); - } - } else { - article.data[matterProp] = [newOption]; - } - - this.updatePage(editor, article); - } - } - } - - /** - * Export the tags/categories front matter to the user settings - */ - public static async export() { - const config = vscode.workspace.getConfiguration(CONFIG_KEY); - - // Retrieve all the Markdown files - const mdFiles = await vscode.workspace.findFiles('**/*.md', "**/node_modules/**"); - const markdownFiles = await vscode.workspace.findFiles('**/*.markdown', "**/node_modules/**"); - if (!mdFiles && !markdownFiles) { - vscode.window.showInformationMessage(`No MD files found.`); - return; - } - - const allMdFiles = mdFiles.concat(markdownFiles); - - vscode.window.withProgress({ - location: vscode.ProgressLocation.Notification, - title: `Front Matter: exporting tags and categories`, - cancellable: false - }, async (progress) => { - // Fetching all tags and categories from MD files - let tags: string[] = []; - let categories: string[] = []; - - // Set the initial progress - const progressNr = allMdFiles.length/100; - progress.report({ increment: 0}); - - let i = 0; - for (const file of allMdFiles) { - progress.report({ increment: (++i/progressNr) }); - const mdFile = await vscode.workspace.openTextDocument(file); - if (mdFile) { - const txtData = mdFile.getText(); - if (txtData) { - try { - const article = matter(txtData); - if (article && article.data) { - const { data } = article; - const mdTags = data["tags"]; - const mdCategories = data["categories"]; - if (mdTags) { - tags = [...tags, ...mdTags]; - } - if (mdCategories) { - categories = [...categories, ...mdCategories]; - } - } - } catch (e) { - // Continue with the next file - } - } - } - } - - // Retrieve the currently known tags, and add the new ones - let crntTags: string[] = config.get(ACTION_TAXONOMY_TAGS) as string[]; - if (!crntTags) { crntTags = []; } - crntTags = [...crntTags, ...tags]; - // Update the tags and filter out the duplicates - crntTags = [...new Set(crntTags)]; - crntTags = crntTags.sort(); - config.update(ACTION_TAXONOMY_TAGS, crntTags); - - // Retrieve the currently known tags, and add the new ones - let crntCategories: string[] = config.get(ACTION_TAXONOMY_CATEGORIES) as string[]; - if (!crntCategories) { crntCategories = []; } - crntCategories = [...crntCategories, ...categories]; - // Update the categories and filter out the duplicates - crntCategories = [...new Set(crntCategories)]; - crntCategories = crntCategories.sort(); - config.update(ACTION_TAXONOMY_CATEGORIES, crntCategories); - - // Done - vscode.window.showInformationMessage(`Front Matter: export completed. Tags: ${crntTags.length} - Categories: ${crntCategories.length}.`); - }); - } - - /** - * Sets the article date - */ - public static async setDate() { - const config = vscode.workspace.getConfiguration(CONFIG_KEY); - const editor = vscode.window.activeTextEditor; - if (!editor) { - return; - } - - const article = this.getArticleData(editor); - if (!article) { - return; - } - - const dateFormat = config.get(ACTION_DATE_FORMAT) as string; - try { - if (dateFormat && typeof dateFormat === "string") { - article.data["date"] = format(new Date(), dateFormat); - } else { - article.data["date"] = new Date(); - } - - this.updatePage(editor, article); - } catch (e) { - vscode.window.showErrorMessage(`Front Matter: Something failed while parsing the date format. Check your "${CONFIG_KEY}${ACTION_DATE_FORMAT}" setting.`); - console.log(e.message); - } - } - - /** - * Update the text of the status bar - * - * @param frontMatterStatusBar - */ - public static async showDraftStatus(frontMatterSB: vscode.StatusBarItem) { - const draftMsg = "in draft"; - const publishMsg = "to publish"; - - let editor = vscode.window.activeTextEditor; - if (editor && editor.document && editor.document.languageId.toLowerCase() === "markdown") { - try { - const article = this.getArticleData(editor); - if (article && typeof article.data["draft"] !== "undefined") { - console.log(`Draft status: ${article.data["draft"]}`); - if (article.data["draft"] === true) { - frontMatterSB.text = `$(book) ${draftMsg}`; - frontMatterSB.show(); - } else if (article.data["draft"] === false) { - frontMatterSB.text = `$(book) ${publishMsg}`; - frontMatterSB.show(); - } - return; - } - } catch (e) { - // Nothing to do - } - } - - frontMatterSB.hide(); - } - - /** - * Toggle the page its draft mode - */ - public static async toggleDraft() { - const editor = vscode.window.activeTextEditor; - if (!editor) { - return; - } - const article = this.getArticleData(editor); - if (!article) { - return; - } - - const newDraftStatus = !article.data["draft"]; - article.data["draft"] = newDraftStatus; - this.updatePage(editor, article); - } - - /** - * Get the contents of the current article - * - * @param editor - */ - private static getArticleData(editor: vscode.TextEditor) { - const article = matter(editor.document.getText()); - if (article && article.data) { - return article; - } - return null; - } - - /** - * Store the new information in the file - * - * @param editor - * @param article - */ - private static async updatePage(editor: vscode.TextEditor, article: matter.GrayMatterFile) { - const newMarkdown = matter.stringify(article.content, article.data); - const nrOfLines = editor.document.lineCount as number; - await editor.edit(builder => builder.replace(new vscode.Range(new vscode.Position(0, 0), new vscode.Position(nrOfLines, 0)), newMarkdown)); - } -} \ No newline at end of file diff --git a/src/commands/Settings.ts b/src/commands/Settings.ts new file mode 100644 index 00000000..59a16a8a --- /dev/null +++ b/src/commands/Settings.ts @@ -0,0 +1,245 @@ +import * as vscode from 'vscode'; +import * as matter from 'gray-matter'; +import * as fs from 'fs'; +import { TaxonomyType } from "../models"; +import { CONFIG_KEY, ACTION_TAXONOMY_TAGS, ACTION_TAXONOMY_CATEGORIES } from '../constants'; +import { ArticleHelper, SettingsHelper, FilesHelper } from '../helpers'; + +export class Settings { + + /** + * Create a new taxonomy + * + * @param type + */ + public static async create(type: TaxonomyType) { + const newOption = await vscode.window.showInputBox({ + prompt: `Insert the value of the ${type === TaxonomyType.Tag ? "tag" : "category"} that you want to add to your configuration.`, + placeHolder: `Name of the ${type === TaxonomyType.Tag ? "tag" : "category"}` + }); + + if (newOption) { + const config = vscode.workspace.getConfiguration(CONFIG_KEY); + const configSetting = type === TaxonomyType.Tag ? ACTION_TAXONOMY_TAGS : ACTION_TAXONOMY_CATEGORIES; + let options = config.get(configSetting) as string[]; + if (!options) { + options = []; + } + + if (options.find(o => o === newOption)) { + vscode.window.showInformationMessage(`The provided ${type === TaxonomyType.Tag ? "tag" : "category"} already exists.`); + return; + } + + options.push(newOption); + await SettingsHelper.update(type, options); + + // Ask if the new term needs to be added to the page + const addToPage = await vscode.window.showQuickPick(["yes", "no"], { canPickMany: false, placeHolder: `Do you want to add the new ${type === TaxonomyType.Tag ? "tag" : "category"} to the page?` }); + + if (addToPage && addToPage === "yes") { + const editor = vscode.window.activeTextEditor; + if (!editor) { + return; + } + + const article = ArticleHelper.getFrontMatter(editor); + if (!article) { + return; + } + + const matterProp: string = type === TaxonomyType.Tag ? "tags" : "categories"; + // Add the selected options to the options array + if (article.data[matterProp]) { + const propData: string[] = article.data[matterProp]; + if (propData && !propData.find(o => o === newOption)) { + propData.push(newOption); + } + } else { + article.data[matterProp] = [newOption]; + } + + ArticleHelper.update(editor, article); + } + } + } + + + /** + * Export the tags/categories front matter to the user settings + */ + public static async export() { + const config = vscode.workspace.getConfiguration(CONFIG_KEY); + + // Retrieve all the Markdown files + const allMdFiles = await FilesHelper.getMdFiles(); + if (!allMdFiles) { + return; + } + + vscode.window.withProgress({ + location: vscode.ProgressLocation.Notification, + title: `Front Matter: exporting tags and categories`, + cancellable: false + }, async (progress) => { + // Fetching all tags and categories from MD files + let tags: string[] = []; + let categories: string[] = []; + + // Set the initial progress + const progressNr = allMdFiles.length/100; + progress.report({ increment: 0}); + + let i = 0; + for (const file of allMdFiles) { + progress.report({ increment: (++i/progressNr) }); + const mdFile = await vscode.workspace.openTextDocument(file); + if (mdFile) { + const txtData = mdFile.getText(); + if (txtData) { + try { + const article = matter(txtData); + if (article && article.data) { + const { data } = article; + const mdTags = data["tags"]; + const mdCategories = data["categories"]; + if (mdTags) { + tags = [...tags, ...mdTags]; + } + if (mdCategories) { + categories = [...categories, ...mdCategories]; + } + } + } catch (e) { + // Continue with the next file + } + } + } + } + + // Retrieve the currently known tags, and add the new ones + let crntTags: string[] = config.get(ACTION_TAXONOMY_TAGS) as string[]; + if (!crntTags) { crntTags = []; } + crntTags = [...crntTags, ...tags]; + // Update the tags and filter out the duplicates + crntTags = [...new Set(crntTags)]; + crntTags = crntTags.sort(); + await config.update(ACTION_TAXONOMY_TAGS, crntTags); + + // Retrieve the currently known tags, and add the new ones + let crntCategories: string[] = config.get(ACTION_TAXONOMY_CATEGORIES) as string[]; + if (!crntCategories) { crntCategories = []; } + crntCategories = [...crntCategories, ...categories]; + // Update the categories and filter out the duplicates + crntCategories = [...new Set(crntCategories)]; + crntCategories = crntCategories.sort(); + await config.update(ACTION_TAXONOMY_CATEGORIES, crntCategories); + + // Done + vscode.window.showInformationMessage(`Front Matter: export completed. Tags: ${crntTags.length} - Categories: ${crntCategories.length}.`); + }); + } + + + /** + * Remap a tag or category to a new one + */ + public static async remap() { + const config = vscode.workspace.getConfiguration(CONFIG_KEY); + + const taxType = await vscode.window.showQuickPick([ + "Tag", + "Category" + ], { + placeHolder: `What do you want to remap?`, + canPickMany: false + }); + if (!taxType) { + return; + } + + const type = taxType === "Tag" ? TaxonomyType.Tag : TaxonomyType.Category; + const options = SettingsHelper.getTaxonomy(type); + + if (!options || options.length === 0) { + vscode.window.showInformationMessage(`No ${type === TaxonomyType.Tag ? "tags" : "categories"} configured.`); + return; + } + + const selectedOption = await vscode.window.showQuickPick(options, { + placeHolder: `Select your ${type === TaxonomyType.Tag ? "tags" : "categories"} to insert`, + canPickMany: false + }); + + if (!selectedOption) { + return; + } + + const newOptionValue = await vscode.window.showInputBox({ + prompt: `Insert the value of the ${type === TaxonomyType.Tag ? "tag" : "category"} with which you want to remap "${selectedOption}".`, + placeHolder: `Name of the ${type === TaxonomyType.Tag ? "tag" : "category"}` + }); + + if (!newOptionValue) { + vscode.window.showInformationMessage(`You didn't provide a new value.`); + return; + } + + // Retrieve all the markdown files + const allMdFiles = await FilesHelper.getMdFiles(); + if (!allMdFiles) { + return; + } + + vscode.window.withProgress({ + location: vscode.ProgressLocation.Notification, + title: `Front Matter: remapping "${selectedOption}" ${type === TaxonomyType.Tag ? "tag" : "category"} to "${newOptionValue}".`, + cancellable: false + }, async (progress) => { + // Set the initial progress + const progressNr = allMdFiles.length/100; + progress.report({ increment: 0}); + + const matterProp: string = type === TaxonomyType.Tag ? "tags" : "categories"; + + let i = 0; + for (const file of allMdFiles) { + progress.report({ increment: (++i/progressNr) }); + const mdFile = await vscode.workspace.openTextDocument(file); + if (mdFile) { + const txtData = mdFile.getText(); + if (txtData) { + try { + const article = matter(txtData); + if (article && article.data) { + const { data } = article; + const options: string[] = data[matterProp]; + if (options && options.length > 0) { + const idx = options.findIndex(o => o === selectedOption); + if (idx !== -1) { + options[idx] = newOptionValue; + data[matterProp] = [...new Set(options)].sort(); + + // Update the file + fs.writeFileSync(mdFile.fileName, matter.stringify(article.content, article.data), { encoding: "utf8" }); + } + } + } + } catch (e) { + // Continue with the next file + } + } + } + } + + // Update the settings + const idx = options.findIndex(o => o === selectedOption); + if (idx !== -1) { + options[idx] = newOptionValue; + } else { + options.push(newOptionValue); + } + await SettingsHelper.update(type, options); + }); + } +} \ No newline at end of file diff --git a/src/commands/StatusBar.ts b/src/commands/StatusBar.ts new file mode 100644 index 00000000..cc0e9d22 --- /dev/null +++ b/src/commands/StatusBar.ts @@ -0,0 +1,37 @@ +import * as vscode from 'vscode'; +import { ArticleHelper } from '../helpers'; + +export class StatusBar { + + /** + * Update the text of the status bar + * + * @param frontMatterStatusBar + */ + public static async showDraftStatus(frontMatterSB: vscode.StatusBarItem) { + const draftMsg = "in draft"; + const publishMsg = "to publish"; + + let editor = vscode.window.activeTextEditor; + if (editor && editor.document && editor.document.languageId.toLowerCase() === "markdown") { + try { + const article = ArticleHelper.getFrontMatter(editor); + if (article && typeof article.data["draft"] !== "undefined") { + console.log(`Draft status: ${article.data["draft"]}`); + if (article.data["draft"] === true) { + frontMatterSB.text = `$(book) ${draftMsg}`; + frontMatterSB.show(); + } else if (article.data["draft"] === false) { + frontMatterSB.text = `$(book) ${publishMsg}`; + frontMatterSB.show(); + } + return; + } + } catch (e) { + // Nothing to do + } + } + + frontMatterSB.hide(); + } +} \ No newline at end of file diff --git a/src/commands/index.ts b/src/commands/index.ts index 692adf72..7e11499b 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -1 +1,3 @@ -export * from './FrontMatter'; +export * from './Article'; +export * from './Settings'; +export * from './StatusBar'; diff --git a/src/extension.ts b/src/extension.ts index d7341a4c..7b003096 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,5 +1,5 @@ import * as vscode from 'vscode'; -import { FrontMatter } from './commands'; +import { Article, Settings, StatusBar } from './commands'; import { TaxonomyType } from './models'; let frontMatterStatusBar: vscode.StatusBarItem; @@ -8,32 +8,36 @@ let debouncer: { (fnc: any, time: number): void; }; export function activate({ subscriptions }: vscode.ExtensionContext) { let insertTags = vscode.commands.registerCommand('frontMatter.insertTags', () => { - FrontMatter.insert(TaxonomyType.Tag); + Article.insert(TaxonomyType.Tag); }); let insertCategories = vscode.commands.registerCommand('frontMatter.insertCategories', () => { - FrontMatter.insert(TaxonomyType.Category); + Article.insert(TaxonomyType.Category); }); let createTag = vscode.commands.registerCommand('frontMatter.createTag', () => { - FrontMatter.create(TaxonomyType.Tag); + Settings.create(TaxonomyType.Tag); }); let createCategory = vscode.commands.registerCommand('frontMatter.createCategory', () => { - FrontMatter.create(TaxonomyType.Category); + Settings.create(TaxonomyType.Category); }); let exportTaxonomy = vscode.commands.registerCommand('frontMatter.exportTaxonomy', () => { - FrontMatter.export(); + Settings.export(); + }); + + let remap = vscode.commands.registerCommand('frontMatter.remap', () => { + Settings.remap(); }); let setDate = vscode.commands.registerCommand('frontMatter.setDate', () => { - FrontMatter.setDate(); + Article.setDate(); }); const toggleDraftCommand = 'frontMatter.toggleDraft'; const toggleDraft = vscode.commands.registerCommand(toggleDraftCommand, async () => { - await FrontMatter.toggleDraft(); + await Article.toggleDraft(); triggerShowDraftStatus(); }); @@ -54,6 +58,7 @@ export function activate({ subscriptions }: vscode.ExtensionContext) { subscriptions.push(createTag); subscriptions.push(createCategory); subscriptions.push(exportTaxonomy); + subscriptions.push(remap); subscriptions.push(setDate); subscriptions.push(toggleDraft); } @@ -61,7 +66,7 @@ export function activate({ subscriptions }: vscode.ExtensionContext) { export function deactivate() {} const triggerShowDraftStatus = () => { - debouncer(() => { FrontMatter.showDraftStatus(frontMatterStatusBar); }, 1000); + debouncer(() => { StatusBar.showDraftStatus(frontMatterStatusBar); }, 1000); }; const debounceShowDraftTrigger = () => { diff --git a/src/helpers/ArticleHelper.ts b/src/helpers/ArticleHelper.ts new file mode 100644 index 00000000..6397994b --- /dev/null +++ b/src/helpers/ArticleHelper.ts @@ -0,0 +1,30 @@ +import * as vscode from 'vscode'; +import * as matter from "gray-matter"; + +export class ArticleHelper { + + /** + * Get the contents of the current article + * + * @param editor + */ + public static getFrontMatter(editor: vscode.TextEditor) { + const article = matter(editor.document.getText()); + if (article && article.data) { + return article; + } + return null; + } + + /** + * Store the new information in the file + * + * @param editor + * @param article + */ + public static async update(editor: vscode.TextEditor, article: matter.GrayMatterFile) { + const newMarkdown = matter.stringify(article.content, article.data); + const nrOfLines = editor.document.lineCount as number; + await editor.edit(builder => builder.replace(new vscode.Range(new vscode.Position(0, 0), new vscode.Position(nrOfLines, 0)), newMarkdown)); + } +} \ No newline at end of file diff --git a/src/helpers/FilesHelper.ts b/src/helpers/FilesHelper.ts new file mode 100644 index 00000000..7cb44a3a --- /dev/null +++ b/src/helpers/FilesHelper.ts @@ -0,0 +1,19 @@ +import * as vscode from 'vscode'; + +export class FilesHelper { + + /** + * Retrieve all markdown files from the current project + */ + public static async getMdFiles(): Promise { + const mdFiles = await vscode.workspace.findFiles('**/*.md', "**/node_modules/**"); + const markdownFiles = await vscode.workspace.findFiles('**/*.markdown', "**/node_modules/**"); + if (!mdFiles && !markdownFiles) { + vscode.window.showInformationMessage(`No MD files found.`); + return null; + } + + const allMdFiles = mdFiles.concat(markdownFiles); + return allMdFiles; + } +} \ No newline at end of file diff --git a/src/helpers/SettingsHelper.ts b/src/helpers/SettingsHelper.ts new file mode 100644 index 00000000..1e7843d2 --- /dev/null +++ b/src/helpers/SettingsHelper.ts @@ -0,0 +1,37 @@ +import * as vscode from 'vscode'; +import { TaxonomyType } from '../models'; +import { ACTION_TAXONOMY_TAGS, ACTION_TAXONOMY_CATEGORIES, CONFIG_KEY } from '../constants'; + +export class SettingsHelper { + + /** + * Return the taxonomy settings + * + * @param type + */ + public static getTaxonomy(type: TaxonomyType) { + const config = vscode.workspace.getConfiguration(CONFIG_KEY); + // Add all the known options to the selection list + const configSetting = type === TaxonomyType.Tag ? ACTION_TAXONOMY_TAGS : ACTION_TAXONOMY_CATEGORIES; + const crntOptions = config.get(configSetting) as string[]; + if (crntOptions && crntOptions.length > 0) { + return crntOptions; + } + return null; + } + + /** + * Update the taxonomy settings + * + * @param config + * @param type + * @param options + */ + static async update(type: TaxonomyType, options: string[]) { + const config = vscode.workspace.getConfiguration(CONFIG_KEY); + const configSetting = type === TaxonomyType.Tag ? ACTION_TAXONOMY_TAGS : ACTION_TAXONOMY_CATEGORIES; + options = [...new Set(options)]; + options = options.sort(); + await config.update(configSetting, options); + } +} \ No newline at end of file diff --git a/src/helpers/index.ts b/src/helpers/index.ts index a40b6607..8b8c1a2b 100644 --- a/src/helpers/index.ts +++ b/src/helpers/index.ts @@ -1 +1,4 @@ +export * from './ArticleHelper'; +export * from './FilesHelper'; +export * from './SettingsHelper'; export * from './StringHelpers';