diff --git a/packages/foam-vscode/src/features/create-from-template.ts b/packages/foam-vscode/src/features/create-from-template.ts index d2b21541b..0032cc464 100644 --- a/packages/foam-vscode/src/features/create-from-template.ts +++ b/packages/foam-vscode/src/features/create-from-template.ts @@ -1,10 +1,11 @@ import { - window, commands, ExtensionContext, - workspace, + QuickPickItem, SnippetString, Uri, + window, + workspace, } from 'vscode'; import * as path from 'path'; import { FoamFeature } from '../types'; @@ -31,7 +32,13 @@ export class UserCancelledOperation extends Error { const knownFoamVariables = new Set(['FOAM_TITLE']); -const defaultTemplateDefaultText: string = '# ${FOAM_TITLE}'; // eslint-disable-line no-template-curly-in-string +const defaultTemplateDefaultText: string = `--- +foam_template: + name: New Note + description: Foam's default new note template +--- +# \${FOAM_TITLE} +`; const defaultTemplateUri = Uri.joinPath(templatesDir, 'new-note.md'); const templateContent = `# \${1:$TM_FILENAME_BASE} @@ -53,9 +60,21 @@ For a full list of features see [the VS Code snippets page](https://code.visuals 2. create a note from this template by running the \`Foam: Create New Note From Template\` command `; -async function getTemplates(): Promise { +async function templateMetadata(templateUri: Uri): Promise { + const contents = await workspace.fs + .readFile(templateUri) + .then(bytes => bytes.toString()); + let templateMetadata: object, _templateWithFoamFrontmatterRemoved: string; + [ + templateMetadata, + _templateWithFoamFrontmatterRemoved, + ] = extractFoamTemplateFrontmatterMetadata(contents); + return templateMetadata; +} + +async function getTemplates(): Promise { const templates = await workspace.findFiles('.foam/templates/**.md'); - return templates.map(template => path.basename(template.path)); + return templates; } async function offerToCreateTemplate(): Promise { @@ -155,12 +174,73 @@ export function substituteFoamVariables( return templateText; } +function sortTemplatesMetadata(templatesMetadata: object[]) { + // Sort by name's existence, name, then path + return templatesMetadata.sort((t1, t2) => { + if (t1['name'] === undefined && t2['name'] !== undefined) { + return 1; + } + + if (t1['name'] !== undefined && t2['name'] === undefined) { + return -1; + } + + if (t1['name'] > t2['name']) { + return 1; + } + + if (t1['name'] < t2['name']) { + return -1; + } + + if (t1['templatePath'] > t2['templatePath']) { + return 1; + } + + if (t1['templatePath'] < t2['templatePath']) { + return -1; + } + + return 0; + }); +} + async function askUserForTemplate() { const templates = await getTemplates(); if (templates.length === 0) { return offerToCreateTemplate(); } - return await window.showQuickPick(templates, { + + const templatesMetadata = sortTemplatesMetadata( + await Promise.all( + templates.map(async templateUri => { + const metadata = await templateMetadata(templateUri); + metadata['templatePath'] = path.basename(templateUri.path); + return metadata; + }) + ) + ); + + const items: QuickPickItem[] = await Promise.all( + templatesMetadata.map(metadata => { + const label = metadata['name'] || metadata['templatePath']; + const description = metadata['name'] ? metadata['templatePath'] : null; + const detail = metadata['description']; + const item = { + label: label, + description: description, + detail: detail, + }; + Object.keys(item).forEach(key => { + if (!item[key]) { + delete item[key]; + } + }); + return item; + }) + ); + + return await window.showQuickPick(items, { placeHolder: 'Select a template to use.', }); } @@ -300,7 +380,9 @@ async function createNoteFromTemplate( if (selectedTemplate === undefined) { return; } - templateFilename = selectedTemplate as string; + templateFilename = + (selectedTemplate as QuickPickItem).description || + (selectedTemplate as QuickPickItem).label; const templateUri = Uri.joinPath(templatesDir, templateFilename); const templateText = await workspace.fs .readFile(templateUri) diff --git a/packages/foam-vscode/src/utils/template-frontmatter-parser.test.ts b/packages/foam-vscode/src/utils/template-frontmatter-parser.test.ts index f9da4519c..623e19267 100644 --- a/packages/foam-vscode/src/utils/template-frontmatter-parser.test.ts +++ b/packages/foam-vscode/src/utils/template-frontmatter-parser.test.ts @@ -61,6 +61,8 @@ foo: bar test('Returns the `foam_template` metadata when it is used in its own frontmatter block', () => { const input = `--- foam_template: + name: My Note Template + description: This is my note template filepath: journal/$CURRENT_YEAR-$CURRENT_MONTH-$CURRENT_DATE_$FOAM_TITLE.md --- @@ -73,6 +75,8 @@ foam_template: const expected = [ { + name: 'My Note Template', + description: 'This is my note template', filepath: 'journal/$CURRENT_YEAR-$CURRENT_MONTH-$CURRENT_DATE_$FOAM_TITLE.md', }, @@ -86,6 +90,8 @@ foam_template: const input = `--- foam_template: filepath: journal/$CURRENT_YEAR-$CURRENT_MONTH-$CURRENT_DATE_$FOAM_TITLE.md + description: This is my note template + name: My Note Template --- --- @@ -116,6 +122,8 @@ more_metadata: *info { filepath: 'journal/$CURRENT_YEAR-$CURRENT_MONTH-$CURRENT_DATE_$FOAM_TITLE.md', + description: 'This is my note template', + name: 'My Note Template', }, output, ]; @@ -127,7 +135,9 @@ more_metadata: *info const input = `--- foo: bar foam_template: + name: My Note Template filepath: journal/$CURRENT_YEAR-$CURRENT_MONTH-$CURRENT_DATE_$FOAM_TITLE.md + description: This is my note template # A YAML comment metadata: &info title: The Gentlemen @@ -150,8 +160,10 @@ more_metadata: *info const expected = [ { + name: 'My Note Template', filepath: 'journal/$CURRENT_YEAR-$CURRENT_MONTH-$CURRENT_DATE_$FOAM_TITLE.md', + description: 'This is my note template', }, output, ]; @@ -165,7 +177,9 @@ describe('removeFoamMetadata', () => { const input = `--- foo: bar foam_template: &foam_template # A YAML comment + description: This is my note template filepath: journal/$CURRENT_YEAR-$CURRENT_MONTH-$CURRENT_DATE_$FOAM_TITLE.md # A YAML comment + name: My Note Template # A YAML comment metadata: &info title: The Gentlemen diff --git a/packages/foam-vscode/src/utils/template-frontmatter-parser.ts b/packages/foam-vscode/src/utils/template-frontmatter-parser.ts index ac87e53db..db3395f81 100644 --- a/packages/foam-vscode/src/utils/template-frontmatter-parser.ts +++ b/packages/foam-vscode/src/utils/template-frontmatter-parser.ts @@ -47,5 +47,8 @@ export function extractFoamTemplateFrontmatterMetadata( } export function removeFoamMetadata(contents: string) { - return contents.replace(/^\s*foam_template:.*?\n\s*filepath:.*\n/gm, ''); + return contents.replace( + /^\s*foam_template:.*?\n(?:\s*(?:filepath|name|description):.*\n)+/gm, + '' + ); }