Compare commits

...

19 Commits

Author SHA1 Message Date
Riccardo Ferretti
23cf5a021e v0.18.3 2022-04-17 14:59:15 +01:00
Riccardo Ferretti
8231ed14c5 Prepare for 0.18.3 2022-04-17 14:58:16 +01:00
Riccardo Ferretti
3bea283c04 Better reporting when link parsing fails, and making it not fail the whole graph computation 2022-04-17 14:56:45 +01:00
Riccardo Ferretti
a3cffe8418 v0.18.2 2022-04-14 21:58:57 +01:00
Riccardo Ferretti
675e7fa216 Prepare 0.18.2 2022-04-14 21:58:24 +01:00
Riccardo Ferretti
87d12bf3af Use VS Code URI in backlink and tag explorer panels 2022-04-14 21:55:52 +01:00
allcontributors[bot]
e118ab74b5 docs: add josephdecock as a contributor for code (#984)
* docs: update docs/index.md [skip ci]

* docs: update readme.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2022-04-14 22:45:21 +02:00
Joe DeCock
04a61eed0e Remove square brackets in preview on wikilinks with link definition (#979)
Remove references that are wiki links, they are not needed (because Foam will take care of the routing in the preview) and they cause the rendering of wiki links to be surrounded by square brackets.
2022-04-14 22:44:32 +02:00
allcontributors[bot]
350b3005f1 docs: add chrisUsick as a contributor for code (#983)
* docs: update docs/index.md [skip ci]

* docs: update readme.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2022-04-14 22:33:25 +02:00
Riccardo
f7293b1eb4 Fix #974: restore proper handling of section-only wikilinks (#981) 2022-04-14 21:53:42 +02:00
Chris Usick
672eb6ed20 Support direct links without labels (#980)
Fixes #975
2022-04-14 17:21:36 +02:00
Riccardo Ferretti
37a9bc49bc v0.18.1 2022-04-13 19:03:40 +02:00
Riccardo Ferretti
38741ca52e Prepare for 0.18.1 2022-04-13 19:03:09 +02:00
Riccardo
ed762618ed Fixed parsing issue of links with square brackets (#977)
Also added some tests for both links and wikilinks
Fixes #975
2022-04-13 19:00:03 +02:00
Riccardo
21a32382a2 Fixed issue with markdown direct link resolution (#972)
Fixes #726
2022-04-13 18:48:04 +02:00
Riccardo Ferretti
7e6c041b87 Fix linter error 2022-04-11 22:59:03 +02:00
Riccardo Ferretti
c9a0a1d53c createDocAndFocus now saves the resulting file 2022-04-11 22:45:59 +02:00
Riccardo Ferretti
0516088656 Fixed bug in template default text application 2022-04-11 22:45:35 +02:00
Riccardo
f98ff336bf Template to better support custom paths checks (#970)
Fixes #967
2022-04-11 16:50:04 +02:00
25 changed files with 326 additions and 162 deletions

View File

@@ -851,6 +851,24 @@
"contributions": [
"tool"
]
},
{
"login": "chrisUsick",
"name": "Chris Usick",
"avatar_url": "https://avatars.githubusercontent.com/u/6589365?v=4",
"profile": "http://cu-dev.ca",
"contributions": [
"code"
]
},
{
"login": "josephdecock",
"name": "Joe DeCock",
"avatar_url": "https://avatars.githubusercontent.com/u/1145533?v=4",
"profile": "https://github.com/josephdecock",
"contributions": [
"code"
]
}
],
"contributorsPerLine": 7,

View File

@@ -227,6 +227,8 @@ If that sounds like something you're interested in, I'd love to have you along o
</tr>
<tr>
<td align="center"><a href="http://Cliffordfajardo.com"><img src="https://avatars.githubusercontent.com/u/6743796?v=4?s=60" width="60px;" alt=""/><br /><sub><b>Clifford Fajardo </b></sub></a><br /><a href="#tool-cliffordfajardo" title="Tools">🔧</a></td>
<td align="center"><a href="http://cu-dev.ca"><img src="https://avatars.githubusercontent.com/u/6589365?v=4?s=60" width="60px;" alt=""/><br /><sub><b>Chris Usick</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=chrisUsick" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/josephdecock"><img src="https://avatars.githubusercontent.com/u/1145533?v=4?s=60" width="60px;" alt=""/><br /><sub><b>Joe DeCock</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=josephdecock" title="Code">💻</a></td>
</tr>
</table>

View File

@@ -4,5 +4,5 @@
],
"npmClient": "yarn",
"useWorkspaces": true,
"version": "0.18.0"
"version": "0.18.3"
}

View File

@@ -4,6 +4,26 @@ All notable changes to the "foam-vscode" extension will be documented in this fi
Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
## [0.18.3] - 2022-04-17
Fixes and Improvements:
- Better reporting when links fail to resolve
- Failing link resolution during graph computation no longer fatal
## [0.18.2] - 2022-04-14
Fixes and Improvements:
- Fixed parsing error on empty direct links (#980 - thanks @chrisUsick)
- Improved rendering in preview of wikilinks that have link definitions (#979 - thanks @josephdecock)
- Restored handling of section-only wikilinks (#981)
## [0.18.1] - 2022-04-13
Fixes and Improvements:
- Fixed parsing error for direct links with square brackets in them (#977)
- Improved markdown direct link resolution (#972)
- Improved templates support for custom paths (#970)
## [0.18.0] - 2022-04-11
Features:

View File

@@ -8,7 +8,7 @@
"type": "git"
},
"homepage": "https://github.com/foambubble/foam",
"version": "0.18.0",
"version": "0.18.3",
"license": "MIT",
"publisher": "foam",
"engines": {

View File

@@ -107,8 +107,18 @@ export class FoamGraph implements IDisposable {
for (const resource of this.workspace.resources()) {
for (const link of resource.links) {
const targetUri = this.workspace.resolveLink(resource, link);
this.connect(resource.uri, targetUri, link);
try {
const targetUri = this.workspace.resolveLink(resource, link);
this.connect(resource.uri, targetUri, link);
} catch (e) {
Logger.error(
`Error while resolving link ${
link.rawText
} in ${resource.uri.toFsPath()}, skipping.`,
link,
e
);
}
}
}

View File

@@ -12,8 +12,8 @@ describe('MarkdownLink', () => {
.links[0];
const parsed = MarkdownLink.analyzeLink(link);
expect(parsed.target).toEqual('wikilink');
expect(parsed.section).toBeUndefined();
expect(parsed.alias).toBeUndefined();
expect(parsed.section).toEqual('');
expect(parsed.alias).toEqual('');
});
it('should parse target and section', () => {
const link = parser.parse(
@@ -23,16 +23,36 @@ describe('MarkdownLink', () => {
const parsed = MarkdownLink.analyzeLink(link);
expect(parsed.target).toEqual('wikilink');
expect(parsed.section).toEqual('section');
expect(parsed.alias).toBeUndefined();
expect(parsed.alias).toEqual('');
});
it('should parse target and alias', () => {
const link = parser.parse(getRandomURI(), `this is a [[wikilink|alias]]`)
.links[0];
const parsed = MarkdownLink.analyzeLink(link);
expect(parsed.target).toEqual('wikilink');
expect(parsed.section).toBeUndefined();
expect(parsed.section).toEqual('');
expect(parsed.alias).toEqual('alias');
});
it('should parse links with square brackets #975', () => {
const link = parser.parse(
getRandomURI(),
`this is a [[wikilink [with] brackets]]`
).links[0];
const parsed = MarkdownLink.analyzeLink(link);
expect(parsed.target).toEqual('wikilink [with] brackets');
expect(parsed.section).toEqual('');
expect(parsed.alias).toEqual('');
});
it('should parse links with square brackets in alias #975', () => {
const link = parser.parse(
getRandomURI(),
`this is a [[wikilink|alias [with] brackets]]`
).links[0];
const parsed = MarkdownLink.analyzeLink(link);
expect(parsed.target).toEqual('wikilink');
expect(parsed.section).toEqual('');
expect(parsed.alias).toEqual('alias [with] brackets');
});
it('should parse target and alias with escaped separator', () => {
const link = parser.parse(
getRandomURI(),
@@ -40,7 +60,7 @@ describe('MarkdownLink', () => {
).links[0];
const parsed = MarkdownLink.analyzeLink(link);
expect(parsed.target).toEqual('wikilink');
expect(parsed.section).toBeUndefined();
expect(parsed.section).toEqual('');
expect(parsed.alias).toEqual('alias');
});
it('should parse target section and alias', () => {
@@ -57,9 +77,9 @@ describe('MarkdownLink', () => {
const link = parser.parse(getRandomURI(), `this is a [[#section]]`)
.links[0];
const parsed = MarkdownLink.analyzeLink(link);
expect(parsed.target).toBeUndefined();
expect(parsed.target).toEqual('');
expect(parsed.section).toEqual('section');
expect(parsed.alias).toBeUndefined();
expect(parsed.alias).toEqual('');
});
});
@@ -69,7 +89,7 @@ describe('MarkdownLink', () => {
.links[0];
const parsed = MarkdownLink.analyzeLink(link);
expect(parsed.target).toEqual('to/path.md');
expect(parsed.section).toBeUndefined();
expect(parsed.section).toEqual('');
expect(parsed.alias).toEqual('link');
});
it('should parse target and section', () => {
@@ -89,10 +109,28 @@ describe('MarkdownLink', () => {
range: Range.create(0, 0),
};
const parsed = MarkdownLink.analyzeLink(link);
expect(parsed.target).toBeUndefined();
expect(parsed.target).toEqual('');
expect(parsed.section).toEqual('section');
expect(parsed.alias).toEqual('link');
});
it('should parse links with square brackets in label #975', () => {
const link = parser.parse(
getRandomURI(),
`this is a [inbox [xyz]](to/path.md)`
).links[0];
const parsed = MarkdownLink.analyzeLink(link);
expect(parsed.target).toEqual('to/path.md');
expect(parsed.section).toEqual('');
expect(parsed.alias).toEqual('inbox [xyz]');
});
it('should parse links with empty label #975', () => {
const link = parser.parse(getRandomURI(), `this is a [](to/path.md)`)
.links[0];
const parsed = MarkdownLink.analyzeLink(link);
expect(parsed.target).toEqual('to/path.md');
expect(parsed.section).toEqual('');
expect(parsed.alias).toEqual('');
});
});
describe('rename wikilink', () => {

View File

@@ -5,27 +5,35 @@ export abstract class MarkdownLink {
/\[\[([^#|]+)?#?([^|]+)?\|?(.*)?\]\]/
);
private static directLinkRegex = new RegExp(
/\[([^\]]+)\]\(([^#]*)?#?([^\]]+)?\)/
/\[(.*)\]\(([^#]*)?#?([^\]]+)?\)/
);
public static analyzeLink(link: ResourceLink) {
if (link.type === 'wikilink') {
const [, target, section, alias] = this.wikilinkRegex.exec(link.rawText);
return {
target: target?.replace(/\\/g, ''),
section,
alias,
};
try {
if (link.type === 'wikilink') {
const [, target, section, alias] = this.wikilinkRegex.exec(
link.rawText
);
return {
target: target?.replace(/\\/g, '') ?? '',
section: section ?? '',
alias: alias ?? '',
};
}
if (link.type === 'link') {
const [, alias, target, section] = this.directLinkRegex.exec(
link.rawText
);
return {
target: target ?? '',
section: section ?? '',
alias: alias ?? '',
};
}
throw new Error(`Link of type ${link.type} is not supported`);
} catch (e) {
throw new Error(`Couldn't parse link ${link.rawText} - ${e}`);
}
if (link.type === 'link') {
const [, alias, target, section] = this.directLinkRegex.exec(
link.rawText
);
return { target, section, alias };
}
throw new Error(
`Unexpected state: link of type ${link.type} is not supported`
);
}
public static createUpdateLinkEdit(

View File

@@ -147,6 +147,39 @@ describe('Link resolution', () => {
expect(ws.resolveLink(noteA, noteA.links[1])).toEqual(noteC.uri);
expect(ws.resolveLink(noteA, noteA.links[2])).toEqual(noteD.uri);
});
it('should resolve wikilink with section identifier', () => {
const noteA = createTestNote({
uri: '/path/to/page-a.md',
links: [
// uppercased filename, lowercased slug
{ slug: 'page-b#section' },
],
});
const noteB = createTestNote({ uri: '/somewhere/PAGE-B.md' });
const ws = createTestWorkspace()
.set(noteA)
.set(noteB);
expect(ws.resolveLink(noteA, noteA.links[0])).toEqual(
noteB.uri.withFragment('section')
);
});
it('should resolve section-only wikilinks', () => {
const noteA = createTestNote({
uri: '/path/to/page-a.md',
links: [
// uppercased filename, lowercased slug
{ slug: '#section' },
],
});
const ws = createTestWorkspace().set(noteA);
expect(ws.resolveLink(noteA, noteA.links[0])).toEqual(
noteA.uri.withFragment('section')
);
});
});
describe('Markdown direct links', () => {

View File

@@ -133,9 +133,16 @@ export class MarkdownResourceProvider implements ResourceProvider {
break;
}
case 'link': {
// force ambiguous links to be treated as relative
const path =
target.startsWith('/') ||
target.startsWith('./') ||
target.startsWith('../')
? target
: './' + target;
targetUri =
workspace.find(target, resource.uri)?.uri ??
URI.placeholder(resource.uri.resolve(target).path);
workspace.find(path, resource.uri)?.uri ??
URI.placeholder(resource.uri.resolve(path).path);
if (section && !targetUri.isPlaceholder()) {
targetUri = targetUri.withFragment(section);
}

View File

@@ -81,7 +81,7 @@ describe('Daily note template', () => {
const config = workspace.getConfiguration('foam');
const uri = getDailyNotePath(config, targetDate);
await createDailyNoteIfNotExists(config, uri, targetDate);
await createDailyNoteIfNotExists(targetDate);
const doc = await showInEditor(uri);
const content = doc.editor.document.getText();

View File

@@ -1,9 +1,8 @@
import { workspace, WorkspaceConfiguration } from 'vscode';
import dateFormat from 'dateformat';
import { existsInFs } from './core/utils/path';
import { focusNote } from './utils';
import { URI } from './core/model/uri';
import { fromVsCodeUri } from './utils/vsc-utils';
import { fromVsCodeUri, toVsCodeUri } from './utils/vsc-utils';
import { NoteFactory } from './services/templates';
/**
@@ -15,21 +14,14 @@ import { NoteFactory } from './services/templates';
* @param date A given date to be formatted as filename.
*/
export async function openDailyNoteFor(date?: Date) {
const foamConfiguration = workspace.getConfiguration('foam');
const currentDate = date instanceof Date ? date : new Date();
const targetDate = date instanceof Date ? date : new Date();
const dailyNotePath = getDailyNotePath(foamConfiguration, currentDate);
const isNew = await createDailyNoteIfNotExists(
foamConfiguration,
dailyNotePath,
currentDate
);
const { didCreateFile, uri } = await createDailyNoteIfNotExists(targetDate);
// if a new file is created, the editor is automatically created
// but forcing the focus will block the template placeholders from working
// so we only explicitly focus on the note if the file already exists
if (!isNew) {
await focusNote(dailyNotePath, isNew);
if (!didCreateFile) {
await focusNote(uri, didCreateFile);
}
}
@@ -96,37 +88,31 @@ export function getDailyNoteFileName(
* In the case that the folders referenced in the file path also do not exist,
* this function will create all folders in the path.
*
* @param configuration The current workspace configuration.
* @param dailyNotePath The path to daily note file.
* @param currentDate The current date, to be used as a title.
* @returns Wether the file was created.
*/
export async function createDailyNoteIfNotExists(
configuration: WorkspaceConfiguration,
dailyNotePath: URI,
targetDate: Date
) {
if (await existsInFs(dailyNotePath.toFsPath())) {
return false;
}
export async function createDailyNoteIfNotExists(targetDate: Date) {
const configuration = workspace.getConfiguration('foam');
const pathFromLegacyConfiguration = getDailyNotePath(
configuration,
targetDate
);
const titleFormat: string =
configuration.get('openDailyNote.titleFormat') ??
configuration.get('openDailyNote.filenameFormat');
const templateFallbackText = `---
foam_template:
name: New Daily Note
description: Foam's default daily note template
filepath: "${workspace.asRelativePath(
toVsCodeUri(pathFromLegacyConfiguration)
)}"
---
# ${dateFormat(targetDate, titleFormat, false)}
`;
await NoteFactory.createFromDailyNoteTemplate(
dailyNotePath,
return await NoteFactory.createFromDailyNoteTemplate(
pathFromLegacyConfiguration,
templateFallbackText,
targetDate
);
return true;
}

View File

@@ -10,7 +10,7 @@ import { FoamWorkspace } from '../core/model/workspace';
import { FoamGraph } from '../core/model/graph';
import { Resource, ResourceLink } from '../core/model/note';
import { Range } from '../core/model/range';
import { fromVsCodeUri } from '../utils/vsc-utils';
import { fromVsCodeUri, toVsCodeUri } from '../utils/vsc-utils';
const feature: FoamFeature = {
activate: async (
@@ -133,7 +133,7 @@ export class BacklinkTreeItem extends vscode.TreeItem {
this.label = `${link.range.start.line}: ${this.label}`;
this.command = {
command: 'vscode.open',
arguments: [resource.uri, { selection: link.range }],
arguments: [toVsCodeUri(resource.uri), { selection: link.range }],
title: 'Go to link',
};
}

View File

@@ -117,7 +117,7 @@ const feature: FoamFeature = {
() => {
const resolver = new Resolver(new Map(), new Date());
NoteFactory.createFromTemplate(
return NoteFactory.createFromTemplate(
DEFAULT_TEMPLATE_URI,
resolver,
undefined,

View File

@@ -1,15 +1,15 @@
import { ExtensionContext, commands, workspace } from 'vscode';
import { ExtensionContext, commands } from 'vscode';
import { FoamFeature } from '../types';
import { openDailyNoteFor } from '../dated-notes';
import { getFoamVsCodeConfig } from '../services/config';
const feature: FoamFeature = {
activate: (context: ExtensionContext) => {
context.subscriptions.push(
commands.registerCommand('foam-vscode.open-daily-note', openDailyNoteFor)
);
if (
workspace.getConfiguration('foam').get('openDailyNote.onStartup', false)
) {
if (getFoamVsCodeConfig('openDailyNote.onStartup', false)) {
commands.executeCommand('foam-vscode.open-daily-note');
}
},

View File

@@ -13,7 +13,6 @@ import {
createDailyNoteIfNotExists,
getDailyNoteFileName,
openDailyNoteFor,
getDailyNotePath,
} from '../dated-notes';
import { FoamFeature } from '../types';
@@ -215,11 +214,7 @@ const datedNoteCommand = (date: Date) => {
return openDailyNoteFor(date);
}
if (foamNavigateOnSelect === 'createNote') {
return createDailyNoteIfNotExists(
foamConfig,
getDailyNotePath(foamConfig, date),
date
);
return createDailyNoteIfNotExists(date);
}
};

View File

@@ -11,6 +11,7 @@ import {
markdownItWithFoamLinks,
markdownItWithFoamTags,
markdownItWithNoteInclusion,
markdownItWithRemoveLinkReferences,
} from './preview-navigation';
describe('Link generation in preview', () => {
@@ -22,7 +23,11 @@ describe('Link generation in preview', () => {
links: [{ slug: 'placeholder' }],
});
const ws = new FoamWorkspace().set(noteA);
const md = markdownItWithFoamLinks(MarkdownIt(), ws);
const md = [
markdownItWithFoamLinks,
markdownItWithRemoveLinkReferences,
].reduce((acc, extension) => extension(acc, ws), MarkdownIt());
it('generates a link to a note', () => {
expect(md.render(`[[note-a]]`)).toEqual(
@@ -41,6 +46,14 @@ describe('Link generation in preview', () => {
`<p><a class='foam-placeholder-link' title="Link to non-existing resource" href="javascript:void(0);">random-text</a></p>\n`
);
});
it('generates a wikilink even when there is a link reference', () => {
const note = `[[note-a]]
[note-a]: <note-a.md> "Note A"`;
expect(md.render(note)).toEqual(
`<p><a class='foam-note-link' title='${noteA.title}' href='/path/to/note-a.md' data-href='/path/to/note-a.md'>note-a</a>\n[note-a]: &lt;note-a.md&gt; &quot;Note A&quot;</p>\n`
);
});
});
describe('Stylable tag generation in preview', () => {

View File

@@ -155,18 +155,17 @@ export const markdownItWithRemoveLinkReferences = (
) => {
md.inline.ruler.before('link', 'clear-references', state => {
if (state.env.references) {
Object.keys(state.env.references).forEach(refKey => {
// Forget about reference links that contain an alias divider
// Aliased reference links will lead the MarkdownParser to include wrong link references
if (refKey.includes(ALIAS_DIVIDER_CHAR)) {
delete state.env.references[refKey];
}
const src = state.src.toLowerCase();
const foamLinkRegEx = /\[\[([^[\]]+?)\]\]/g;
const foamLinks = [...src.matchAll(foamLinkRegEx)].map(m =>
m[1].toLowerCase()
);
// When the reference is present due to an inclusion of that note, we
// need to remove that reference. This ensures the MarkdownIt parser
// will not replace the wikilink syntax with an <a href> link and as a result
// break our inclusion logic.
if (state.src.toLowerCase().includes(`![[${refKey.toLowerCase()}]]`)) {
Object.keys(state.env.references).forEach(refKey => {
// Remove all references that have corresponding wikilinks.
// If the markdown parser sees a reference, it will format it before
// we get a chance to create the wikilink.
if (foamLinks.includes(refKey.toLowerCase())) {
delete state.env.references[refKey];
}
});

View File

@@ -164,16 +164,14 @@ export class TagReference extends vscode.TreeItem {
public readonly title: string;
constructor(public readonly tag: Tag, public readonly note: Resource) {
super(note.title, vscode.TreeItemCollapsibleState.None);
const uri = toVsCodeUri(note.uri);
this.title = note.title;
this.description = note.uri.path.replace(
vscode.workspace.getWorkspaceFolder(toVsCodeUri(note.uri))?.uri.path,
''
);
this.description = vscode.workspace.asRelativePath(uri);
this.tooltip = undefined;
this.command = {
command: 'vscode.open',
arguments: [
note.uri,
uri,
{
preview: true,
selection: toVsCodeRange(tag.range),

View File

@@ -37,6 +37,13 @@ const feature: FoamFeature = {
});
}
case 'placeholder': {
const title = uri.getName();
if (uri.isAbsolute()) {
return NoteFactory.createForPlaceholderWikilink(
title,
URI.file(uri.path)
);
}
const basedir =
vscode.workspace.workspaceFolders.length > 0
? vscode.workspace.workspaceFolders[0].uri
@@ -46,7 +53,6 @@ const feature: FoamFeature = {
if (basedir === undefined) {
return;
}
const title = uri.getName();
const target = fromVsCodeUri(basedir)
.resolve(uri, true)
.changeExtension('', '.md');

View File

@@ -4,8 +4,8 @@ export interface ConfigurationMonitor<T> extends Disposable {
(): T;
}
export const getFoamVsCodeConfig = <T>(key: string): T =>
workspace.getConfiguration('foam').get(key);
export const getFoamVsCodeConfig = <T>(key: string, defaultValue?: T): T =>
workspace.getConfiguration('foam').get(key, defaultValue);
export const updateFoamVsCodeConfig = <T>(key: string, value: T) =>
workspace.getConfiguration().update('foam.' + key, value);

View File

@@ -48,8 +48,9 @@ export async function createDocAndFocus(
toVsCodeUri(filepath),
new TextEncoder().encode('')
);
await focusNote(filepath, true, viewColumn);
await window.activeTextEditor.insertSnippet(text);
const note = await focusNote(filepath, true, viewColumn);
await note.editor.insertSnippet(text);
await note.document.save();
}
export async function replaceSelection(

View File

@@ -13,6 +13,7 @@ import {
replaceSelection,
} from './editor';
import { Resolver } from './variable-resolver';
import dateFormat from 'dateformat';
/**
* The templates directory
@@ -69,6 +70,32 @@ export async function getTemplates(): Promise<URI[]> {
return templates;
}
export async function getTemplateInfo(
templateUri: URI,
templateFallbackText = '',
resolver: Resolver
) {
const templateText = existsSync(templateUri.toFsPath())
? await workspace.fs
.readFile(toVsCodeUri(templateUri))
.then(bytes => bytes.toString())
: templateFallbackText;
const templateWithResolvedVariables = await resolver.resolveText(
templateText
);
const [
templateMetadata,
templateWithFoamFrontmatterRemoved,
] = extractFoamTemplateFrontmatterMetadata(templateWithResolvedVariables);
return {
metadata: templateMetadata,
text: templateWithFoamFrontmatterRemoved,
};
}
export const NoteFactory = {
/**
* Creates a new note using a template.
@@ -81,72 +108,67 @@ export const NoteFactory = {
templateUri: URI,
resolver: Resolver,
filepathFallbackURI?: URI,
templateFallbackText = ''
): Promise<void> => {
const templateText = existsSync(templateUri.toFsPath())
? await workspace.fs
.readFile(toVsCodeUri(templateUri))
.then(bytes => bytes.toString())
: templateFallbackText;
const selectedContent = findSelectionContent();
if (selectedContent?.content) {
resolver.define('FOAM_SELECTED_TEXT', selectedContent?.content);
}
let templateWithResolvedVariables: string;
templateFallbackText = '',
onFileExists?: (filePath: URI) => Promise<string | undefined>
): Promise<{ didCreateFile: boolean; uri: URI | undefined }> => {
try {
templateWithResolvedVariables = await resolver.resolveText(templateText);
onFileExists = onFileExists
? onFileExists
: (existingFile: URI) => {
const filename = existingFile.getBasename();
return askUserForFilepathConfirmation(existingFile, filename);
};
const template = await getTemplateInfo(
templateUri,
templateFallbackText,
resolver
);
const selectedContent = findSelectionContent();
if (selectedContent?.content) {
resolver.define('FOAM_SELECTED_TEXT', selectedContent?.content);
}
const templateSnippet = new SnippetString(template.text);
let newFilePath = await determineNewNoteFilepath(
template.metadata.get('filepath'),
filepathFallbackURI,
resolver
);
while (existsSync(newFilePath.toFsPath())) {
const proposedNewFilepath = await onFileExists(newFilePath);
if (proposedNewFilepath === undefined) {
return { didCreateFile: false, uri: newFilePath };
}
newFilePath = URI.file(proposedNewFilepath);
}
await createDocAndFocus(
templateSnippet,
newFilePath,
selectedContent ? ViewColumn.Beside : ViewColumn.Active
);
if (selectedContent !== undefined) {
const newNoteTitle = newFilePath.getName();
await replaceSelection(
selectedContent.document,
selectedContent.selection,
`[[${newNoteTitle}]]`
);
}
return { didCreateFile: true, uri: newFilePath };
} catch (err) {
if (err instanceof UserCancelledOperation) {
return;
}
throw err;
}
const [
templateMetadata,
templateWithFoamFrontmatterRemoved,
] = extractFoamTemplateFrontmatterMetadata(templateWithResolvedVariables);
const templateSnippet = new SnippetString(
templateWithFoamFrontmatterRemoved
);
let filepath = await determineNewNoteFilepath(
templateMetadata.get('filepath'),
filepathFallbackURI,
resolver
);
if (existsSync(filepath.toFsPath())) {
const filename = filepath.getBasename();
const newFilepath = await askUserForFilepathConfirmation(
filepath,
filename
);
if (newFilepath === undefined) {
return;
}
filepath = URI.file(newFilepath);
}
await createDocAndFocus(
templateSnippet,
filepath,
selectedContent ? ViewColumn.Beside : ViewColumn.Active
);
if (selectedContent !== undefined) {
const newNoteTitle = filepath.getName();
await replaceSelection(
selectedContent.document,
selectedContent.selection,
`[[${newNoteTitle}]]`
);
}
},
/**
@@ -158,13 +180,17 @@ export const NoteFactory = {
filepathFallbackURI: URI,
templateFallbackText: string,
targetDate: Date
): Promise<void> => {
const resolver = new Resolver(new Map(), targetDate);
): Promise<{ didCreateFile: boolean; uri: URI | undefined }> => {
const resolver = new Resolver(
new Map().set('FOAM_TITLE', dateFormat(targetDate, 'yyyy-mm-dd', false)),
targetDate
);
return NoteFactory.createFromTemplate(
DAILY_NOTE_TEMPLATE_URI,
resolver,
filepathFallbackURI,
templateFallbackText
templateFallbackText,
_ => Promise.resolve(undefined)
);
},
@@ -176,7 +202,7 @@ export const NoteFactory = {
createForPlaceholderWikilink: (
wikilinkPlaceholder: string,
filepathFallbackURI: URI
): Promise<void> => {
): Promise<{ didCreateFile: boolean; uri: URI | undefined }> => {
const resolver = new Resolver(
new Map().set('FOAM_TITLE', wikilinkPlaceholder),
new Date()

View File

@@ -161,6 +161,8 @@ export async function focusNote(
const { range } = editor.document.lineAt(lineCount - 1);
editor.selection = new Selection(range.end, range.end);
}
return { document, editor };
}
export function getContainsTooltip(titles: string[]): string {

View File

@@ -5,7 +5,7 @@
👀*This is an early stage project under rapid development. For updates join the [Foam community Discord](https://foambubble.github.io/join-discord/g)! 💬*
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-92-orange.svg?style=flat-square)](#contributors-)
[![All Contributors](https://img.shields.io/badge/all_contributors-94-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
[![Discord Chat](https://img.shields.io/discord/729975036148056075?color=748AD9&label=discord%20chat&style=flat-square)](https://foambubble.github.io/join-discord/g)
@@ -315,6 +315,8 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
</tr>
<tr>
<td align="center"><a href="http://Cliffordfajardo.com"><img src="https://avatars.githubusercontent.com/u/6743796?v=4?s=60" width="60px;" alt=""/><br /><sub><b>Clifford Fajardo </b></sub></a><br /><a href="#tool-cliffordfajardo" title="Tools">🔧</a></td>
<td align="center"><a href="http://cu-dev.ca"><img src="https://avatars.githubusercontent.com/u/6589365?v=4?s=60" width="60px;" alt=""/><br /><sub><b>Chris Usick</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=chrisUsick" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/josephdecock"><img src="https://avatars.githubusercontent.com/u/1145533?v=4?s=60" width="60px;" alt=""/><br /><sub><b>Joe DeCock</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=josephdecock" title="Code">💻</a></td>
</tr>
</table>