From 3583a2b96237a1c06b253af85a026648d059c3f1 Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Tue, 17 May 2022 16:19:40 +0200 Subject: [PATCH] #337 - Add support for other fm types --- CHANGELOG.md | 1 + src/commands/Settings.ts | 2 +- src/extension.ts | 1 + src/helpers/ArticleHelper.ts | 7 ++-- src/parsers/FrontMatterParser.ts | 41 ++++++++++++++++++++++-- src/providers/MarkdownFoldingProvider.ts | 18 +++++++---- 6 files changed, 58 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 956817a8..3db2cfb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - [#333](https://github.com/estruyf/vscode-front-matter/issues/333): Automatically mark Jekyll posts in `_drafts` folder as draft - [#335](https://github.com/estruyf/vscode-front-matter/issues/335): Merge media snippets with content snippets to allow you to define multiple media snippets and use these in your content - [#336](https://github.com/estruyf/vscode-front-matter/issues/336): Support added for inverting the draft field so that SSGs/authors can use a published field instead +- [#337](https://github.com/estruyf/vscode-front-matter/issues/337): Allow multiple front matter types to be used. ### ⚡️ Optimizations diff --git a/src/commands/Settings.ts b/src/commands/Settings.ts index 165986fe..5a129441 100644 --- a/src/commands/Settings.ts +++ b/src/commands/Settings.ts @@ -238,7 +238,7 @@ export class Settings { data[matterProp] = [...new Set(taxonomies)].sort(); const spaces = vscode.window.activeTextEditor?.options?.tabSize; // Update the file - fs.writeFileSync(file.path, FrontMatterParser.toFile(article.content, article.data, { + fs.writeFileSync(file.path, FrontMatterParser.toFile(article.content, article.data, mdFile, { indent: spaces || 2 } as DumpOptions as any), { encoding: "utf8" }); } diff --git a/src/extension.ts b/src/extension.ts index 92356929..40095bd8 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -211,6 +211,7 @@ export async function activate(context: vscode.ExtensionContext) { subscriptions.push(vscode.workspace.onDidChangeTextDocument((TextDocumentChangeEvent) => { const filePath = TextDocumentChangeEvent.document.uri.fsPath; if (filePath && !filePath.toLowerCase().startsWith(`extension-output`)) { + MarkdownFoldingProvider.triggerHighlighting(); statusDebouncer(() => triggerShowDraftStatus(`onDidChangeTextEditorSelection`), 200); } })); diff --git a/src/helpers/ArticleHelper.ts b/src/helpers/ArticleHelper.ts index e6ad3113..fc7be101 100644 --- a/src/helpers/ArticleHelper.ts +++ b/src/helpers/ArticleHelper.ts @@ -115,7 +115,7 @@ export class ArticleHelper { const lastLine = lines.pop(); const endsWithNewLine = lastLine !== undefined && lastLine.trim() === ""; - let newMarkdown = this.stringifyFrontMatter(article.content, Object.assign({}, article.data)); + let newMarkdown = this.stringifyFrontMatter(article.content, Object.assign({}, article.data), document?.getText()); // Logic to not include a new line at the end of the file if (!endsWithNewLine) { @@ -150,8 +150,9 @@ export class ArticleHelper { * * @param content * @param data + * @param originalContent */ - public static stringifyFrontMatter(content: string, data: any) { + public static stringifyFrontMatter(content: string, data: any, originalContent?: string) { const indentArray = Settings.get(SETTING_INDENT_ARRAY) as boolean; const commaSeparated = Settings.get(SETTING_COMMA_SEPARATED_FIELDS); @@ -165,7 +166,7 @@ export class ArticleHelper { } } - return FrontMatterParser.toFile(content, data, ({ + return FrontMatterParser.toFile(content, data, originalContent, ({ noArrayIndent: !indentArray, skipInvalid: true, noCompatMode: true, diff --git a/src/parsers/FrontMatterParser.ts b/src/parsers/FrontMatterParser.ts index b26a1b4d..dc1ac1a9 100644 --- a/src/parsers/FrontMatterParser.ts +++ b/src/parsers/FrontMatterParser.ts @@ -16,8 +16,13 @@ export interface ParsedFrontMatter { export class FrontMatterParser { public static currentContent: string | null = null; + /** + * Convert the current content to a Front Matter object + * @param content + * @returns + */ public static fromFile(content: string): ParsedFrontMatter { - const format = getFormatOpts(this.getLanguage()); + const format = getFormatOpts(this.getLanguageFromContent(content)); FrontMatterParser.currentContent = content; const result = matter(content, { ...Engines, ...format }); // in the absent of a body when serializing an entry we use an empty one @@ -29,13 +34,21 @@ export class FrontMatterParser { }; } + /** + * Convert the Front Matter object to text + * @param content + * @param metadata + * @param options + * @returns + */ public static toFile( content: string, metadata: Object, + originalContent?: string, options?: any ) { // Stringify to YAML if the format was not set - const format = getFormatOpts(this.getLanguage()); + const format = getFormatOpts(this.getLanguageFromContent(originalContent)); const trimLastLineBreak = content.slice(-1) !== '\n'; const file = matter.stringify(content, metadata, { @@ -46,6 +59,30 @@ export class FrontMatterParser { return trimLastLineBreak && file.slice(-1) === '\n' ? file.substring(0, file.length - 1) : file; } + /** + * Validate the type of front matter language that is used + * @param contents + */ + public static getLanguageFromContent(contents: string | undefined) { + if (!contents) { + return this.getLanguage(); + } + + if (contents.startsWith(`+++`)) { + return "toml"; + } else if (contents.startsWith(`---`)) { + return "yaml"; + } else if (contents.startsWith(`{`)) { + return "json"; + } else { + return "yaml"; + } + } + + /** + * Get the front matter language type + * @returns + */ private static getLanguage() { const language = Settings.get(SETTING_FRONTMATTER_TYPE) as string || "YAML"; return language.toLowerCase(); diff --git a/src/providers/MarkdownFoldingProvider.ts b/src/providers/MarkdownFoldingProvider.ts index 34bc482c..755c6f55 100644 --- a/src/providers/MarkdownFoldingProvider.ts +++ b/src/providers/MarkdownFoldingProvider.ts @@ -4,6 +4,7 @@ import { CancellationToken, FoldingContext, FoldingRange, FoldingRangeKind, Fold import { SETTING_CONTENT_FRONTMATTER_HIGHLIGHT, SETTING_CONTENT_SUPPORTED_FILETYPES, SETTING_FRONTMATTER_TYPE } from '../constants'; import { Settings } from '../helpers'; import { FrontMatterDecorationProvider } from './FrontMatterDecorationProvider'; +import { FrontMatterParser } from '../parsers'; export class MarkdownFoldingProvider implements FoldingRangeProvider { private static start: number | null = null; @@ -43,7 +44,7 @@ export class MarkdownFoldingProvider implements FoldingRangeProvider { if (isSupported) { const fmHighlight = Settings.get(SETTING_CONTENT_FRONTMATTER_HIGHLIGHT); - const range = this.getFrontMatterRange(); + const range = MarkdownFoldingProvider.getFrontMatterRange(); if (range) { if (MarkdownFoldingProvider.decType !== null) { @@ -64,17 +65,22 @@ export class MarkdownFoldingProvider implements FoldingRangeProvider { * @returns */ public static getFrontMatterRange(document?: TextDocument) { - const language = Settings.get(SETTING_FRONTMATTER_TYPE) as string || "YAML"; + const content = document?.getText(); + const language = FrontMatterParser.getLanguageFromContent(content); let lineStart = "---"; - let lineEnd = "---"; - if (language === "TOML") { + let lineEnd = lineStart; + + if (language.toLowerCase() === "toml") { lineStart = "+++"; lineEnd = lineStart; + } else if (language.toLowerCase() === "json") { + lineStart = "{"; + lineEnd = "}"; } - if (document) { - const lines = document.getText().split('\n'); + if (content) { + const lines = content.split('\n'); let start = null; let end = null;