Compare commits

...

9 Commits

Author SHA1 Message Date
Riccardo Ferretti
3d6f98351f v0.19.5 2022-09-01 13:11:11 +02:00
Riccardo Ferretti
970c30f08c Preparation for next release 2022-09-01 13:10:41 +02:00
Riccardo Ferretti
8556982b17 #1056: by default don't show images and attachments in graph view 2022-09-01 13:06:20 +02:00
Matthias Thym
1ab9520c5c Fix link to tag explorer in readme (#1060) 2022-09-01 12:34:38 +02:00
Riccardo
2a72bde111 Use note title in link completion (#1059)
* added setting for completion label

* added alias support

* Disable extra commit characters when automatically adding an alias

* added tests
2022-08-20 00:29:08 +02:00
Riccardo Ferretti
2385bd75b5 Keep extension for attachments when generating references 2022-08-19 16:43:49 +02:00
Riccardo
53d2e7aaed refactor: moved panel modules in own directory (#1055) 2022-08-18 17:18:03 +02:00
allcontributors[bot]
48c13ef400 docs: add dmurph as a contributor for code (#1054)
* 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-08-17 23:47:32 +02:00
Riccardo
3ab30547eb Add FOAM_DATE_WEEK variable (#1053)
* Update variable-resolver.ts to include week number
* Added tests

Co-authored-by: Daniel Murphy <danielmurphy161@gmail.com>
2022-08-17 23:46:14 +02:00
23 changed files with 350 additions and 98 deletions

View File

@@ -932,6 +932,15 @@
"contributions": [
"doc"
]
},
{
"login": "dmurph",
"name": "Daniel Murphy",
"avatar_url": "https://avatars.githubusercontent.com/u/294026?v=4",
"profile": "http://www.dmurph.com",
"contributions": [
"code"
]
}
],
"contributorsPerLine": 7,

View File

@@ -236,6 +236,7 @@ If that sounds like something you're interested in, I'd love to have you along o
<td align="center"><a href="https://github.com/lingyv-li"><img src="https://avatars.githubusercontent.com/u/8937944?v=4?s=60" width="60px;" alt=""/><br /><sub><b>Larry Li</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=lingyv-li" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/infogulch"><img src="https://avatars.githubusercontent.com/u/133882?v=4?s=60" width="60px;" alt=""/><br /><sub><b>Joe Taber</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=infogulch" title="Documentation">📖</a></td>
<td align="center"><a href="https://www.readingsnail.pe.kr"><img src="https://avatars.githubusercontent.com/u/1904967?v=4?s=60" width="60px;" alt=""/><br /><sub><b>Woosuk Park</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=readingsnail" title="Documentation">📖</a></td>
<td align="center"><a href="http://www.dmurph.com"><img src="https://avatars.githubusercontent.com/u/294026?v=4?s=60" width="60px;" alt=""/><br /><sub><b>Daniel Murphy</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=dmurph" title="Code">💻</a></td>
</tr>
</table>

View File

@@ -4,5 +4,5 @@
],
"npmClient": "yarn",
"useWorkspaces": true,
"version": "0.19.4"
"version": "0.19.5"
}

View File

@@ -4,6 +4,14 @@ 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.19.5] - 2022-09-01
Fixes and Improvements:
- Added `FOAM_DATE_WEEK` variable (#1053 - Thanks @dmurph)
- Fixed extension inclusion when generating references for attachments
- Link completion label can be note title as well as path (#1059)
- Images and attachments are not shown by default in graph view (#1056)
## [0.19.4] - 2022-08-07
Fixes and Improvements:

View File

@@ -8,7 +8,7 @@
"type": "git"
},
"homepage": "https://github.com/foambubble/foam",
"version": "0.19.4",
"version": "0.19.5",
"license": "MIT",
"publisher": "foam",
"engines": {
@@ -243,6 +243,34 @@
"configuration": {
"title": "Foam",
"properties": {
"foam.completion.label": {
"type": "string",
"default": "path",
"description": "Describes what note property to use as a label for completion items",
"enum": [
"path",
"title",
"identifier"
],
"enumDescriptions": [
"Use the path of the note",
"Use the title of the note",
"Use the identifier of the note"
]
},
"foam.completion.useAlias": {
"type": "string",
"default": "never",
"description": "Specifies in which cases to use an alias when creating a wikilink",
"enum": [
"never",
"whenPathDiffersFromTitle"
],
"enumDescriptions": [
"Never use aliases in completion items",
"Use alias if resource path is different from title"
]
},
"foam.files.ignore": {
"type": [
"array"

View File

@@ -301,6 +301,21 @@ describe('Generation of markdown references', () => {
expect(references.map(r => r.url)).toEqual(['page-b.md', 'page-c.md']);
});
it('should always add extensions for attachments, even when includeExtension = false', () => {
const workspace = createTestWorkspace();
const noteA = createNoteFromMarkdown(
'Link to [[page-b]] and [[image.png]]',
'/dir1/page-a.md'
);
workspace
.set(noteA)
.set(createNoteFromMarkdown('Content of note B', '/dir1/page-b.md'))
.set(createNoteFromMarkdown('', '/dir1/image.png'));
const references = createMarkdownReferences(workspace, noteA.uri, false);
expect(references.map(r => r.url)).toEqual(['page-b', 'image.png']);
});
it('should use relative paths', () => {
const workspace = createTestWorkspace();
const noteA = createNoteFromMarkdown(

View File

@@ -181,7 +181,7 @@ to generate markdown reference list`
}
let relativeUri = target.uri.relativeTo(noteUri.getDirectory());
if (!includeExtension) {
if (!includeExtension && relativeUri.path.endsWith('.md')) {
relativeUri = relativeUri.changeExtension('*', '');
}

View File

@@ -1,34 +1,26 @@
import { FoamFeature } from '../types';
import * as commands from './commands';
import dataviz from './dataviz';
import * as panels from './panels';
import dateSnippets from './date-snippets';
import tagsExplorer from './tags-tree-view';
import orphans from './orphans';
import placeholders from './placeholders';
import backlinks from './backlinks';
import hoverProvider from './hover-provider';
import previewNavigation from './preview';
import preview from './preview';
import completionProvider, { completionCursorMove } from './link-completion';
import tagCompletionProvider from './tag-completion';
import linkDecorations from './document-decorator';
import navigationProviders from './navigation-provider';
import wikilinkDiagnostics from './wikilink-diagnostics';
import refactor from './refactor';
import { FoamFeature } from '../types';
export const features: FoamFeature[] = [
...Object.values(commands),
...Object.values(panels),
refactor,
navigationProviders,
wikilinkDiagnostics,
tagsExplorer,
dataviz,
dateSnippets,
orphans,
placeholders,
backlinks,
hoverProvider,
linkDecorations,
previewNavigation,
preview,
completionProvider,
tagCompletionProvider,
completionCursorMove,

View File

@@ -7,10 +7,11 @@ import {
closeEditors,
createFile,
showInEditor,
withModifiedFoamConfiguration,
} from '../test/test-utils-vscode';
import { fromVsCodeUri } from '../utils/vsc-utils';
import {
CompletionProvider,
WikilinkCompletionProvider,
SectionCompletionProvider,
} from './link-completion';
@@ -63,7 +64,7 @@ describe('Link Completion', () => {
it('should not return any link for empty documents', async () => {
const { uri } = await createFile('');
const { doc } = await showInEditor(uri);
const provider = new CompletionProvider(ws, graph);
const provider = new WikilinkCompletionProvider(ws, graph);
const links = await provider.provideCompletionItems(
doc,
@@ -76,7 +77,7 @@ describe('Link Completion', () => {
it('should not return link outside the wikilink brackets', async () => {
const { uri } = await createFile('[[file]] then');
const { doc } = await showInEditor(uri);
const provider = new CompletionProvider(ws, graph);
const provider = new WikilinkCompletionProvider(ws, graph);
const links = await provider.provideCompletionItems(
doc,
@@ -90,7 +91,7 @@ describe('Link Completion', () => {
for (const text of ['[[', '[[file]] [[', '[[file]] #tag [[']) {
const { uri } = await createFile(text);
const { doc } = await showInEditor(uri);
const provider = new CompletionProvider(ws, graph);
const provider = new WikilinkCompletionProvider(ws, graph);
const links = await provider.provideCompletionItems(
doc,
@@ -110,6 +111,103 @@ describe('Link Completion', () => {
}
});
it('should support label setting', async () => {
const { uri: noteUri, content } = await createFile(`# My Note Title`);
const workspace = createTestWorkspace();
workspace.set(parser.parse(noteUri, content));
const provider = new WikilinkCompletionProvider(
workspace,
FoamGraph.fromWorkspace(workspace)
);
const { uri } = await createFile('[[');
const { doc } = await showInEditor(uri);
await withModifiedFoamConfiguration(
'completion.label',
'title',
async () => {
const links = await provider.provideCompletionItems(
doc,
new vscode.Position(0, 3)
);
expect(links.items.map(i => i.label)).toEqual(['My Note Title']);
}
);
await withModifiedFoamConfiguration(
'completion.label',
'path',
async () => {
const links = await provider.provideCompletionItems(
doc,
new vscode.Position(0, 3)
);
expect(links.items.map(i => i.label)).toEqual([noteUri.getBasename()]);
}
);
await withModifiedFoamConfiguration(
'completion.label',
'identifier',
async () => {
const links = await provider.provideCompletionItems(
doc,
new vscode.Position(0, 3)
);
expect(links.items.map(i => i.label)).toEqual([
workspace.getIdentifier(noteUri),
]);
}
);
});
it('should support alias setting', async () => {
const { uri: noteUri, content } = await createFile(`# My Note Title`);
const workspace = createTestWorkspace();
workspace.set(parser.parse(noteUri, content));
const provider = new WikilinkCompletionProvider(
workspace,
FoamGraph.fromWorkspace(workspace)
);
const { uri } = await createFile('[[');
const { doc } = await showInEditor(uri);
await withModifiedFoamConfiguration(
'completion.useAlias',
'never',
async () => {
const links = await provider.provideCompletionItems(
doc,
new vscode.Position(0, 3)
);
expect(links.items.map(i => i.insertText)).toEqual([
workspace.getIdentifier(noteUri),
]);
}
);
await withModifiedFoamConfiguration(
'completion.useAlias',
'whenPathDiffersFromTitle',
async () => {
const links = await provider.provideCompletionItems(
doc,
new vscode.Position(0, 3)
);
expect(links.items.map(i => i.insertText)).toEqual([
`${workspace.getIdentifier(noteUri)}|My Note Title`,
]);
}
);
});
it('should return sections for other notes', async () => {
for (const text of [
'[[file-name#',
@@ -171,7 +269,7 @@ alias: alias-a
ws.set(parser.parse(uri, content));
const { doc } = await showInEditor(uri);
const provider = new CompletionProvider(ws, graph);
const provider = new WikilinkCompletionProvider(ws, graph);
const links = await provider.provideCompletionItems(
doc,

View File

@@ -1,8 +1,10 @@
import * as vscode from 'vscode';
import { Foam } from '../core/model/foam';
import { FoamGraph } from '../core/model/graph';
import { Resource } from '../core/model/note';
import { URI } from '../core/model/uri';
import { FoamWorkspace } from '../core/model/workspace';
import { getFoamVsCodeConfig } from '../services/config';
import { FoamFeature } from '../types';
import { getNoteTooltip, mdDocSelector } from '../utils';
import { fromVsCodeUri, toVsCodeUri } from '../utils/vsc-utils';
@@ -28,7 +30,7 @@ const feature: FoamFeature = {
context.subscriptions.push(
vscode.languages.registerCompletionItemProvider(
mdDocSelector,
new CompletionProvider(foam.workspace, foam.graph),
new WikilinkCompletionProvider(foam.workspace, foam.graph),
'['
),
vscode.languages.registerCompletionItemProvider(
@@ -159,7 +161,7 @@ export class SectionCompletionProvider
}
}
export class CompletionProvider
export class WikilinkCompletionProvider
implements vscode.CompletionItemProvider<vscode.CompletionItem> {
constructor(private ws: FoamWorkspace, private graph: FoamGraph) {}
@@ -186,20 +188,45 @@ export class CompletionProvider
position.line,
position.character
);
const labelStyle = getCompletionLabelSetting();
const aliasSetting = getCompletionAliasSetting();
const resources = this.ws.list().map(resource => {
const label = vscode.workspace.asRelativePath(toVsCodeUri(resource.uri));
const resourceIsDocument =
['attachment', 'image'].indexOf(resource.type) === -1;
const identifier = this.ws.getIdentifier(resource.uri);
const label = !resourceIsDocument
? identifier
: labelStyle === 'path'
? vscode.workspace.asRelativePath(toVsCodeUri(resource.uri))
: labelStyle === 'title'
? resource.title
: identifier;
const item = new ResourceCompletionItem(
label,
vscode.CompletionItemKind.File,
resource.uri
);
item.sortText =
resource.type === 'attachment' ? `1-${item.label}` : `0-${item.label}`;
item.filterText = resource.uri.getName();
item.insertText = this.ws.getIdentifier(resource.uri);
item.detail = vscode.workspace.asRelativePath(toVsCodeUri(resource.uri));
item.sortText = resourceIsDocument
? `0-${item.label}`
: `1-${item.label}`;
const useAlias =
resourceIsDocument &&
aliasSetting !== 'never' &&
wikilinkRequiresAlias(resource);
item.insertText = useAlias
? `${identifier}|${resource.title}`
: identifier;
item.commitCharacters = useAlias ? [] : linkCommitCharacters;
item.range = replacementRange;
item.command = COMPLETION_CURSOR_MOVE;
item.commitCharacters = linkCommitCharacters;
return item;
});
const aliases = this.ws.list().flatMap(resource =>
@@ -265,4 +292,23 @@ class ResourceCompletionItem extends vscode.CompletionItem {
}
}
function getCompletionLabelSetting() {
const labelStyle: 'path' | 'title' | 'identifier' = getFoamVsCodeConfig(
'completion.label'
);
return labelStyle;
}
function getCompletionAliasSetting() {
const aliasStyle: 'never' | 'whenPathDiffersFromTitle' = getFoamVsCodeConfig(
'completion.useAlias'
);
return aliasStyle;
}
const normalize = (text: string) => text.toLocaleLowerCase().trim();
function wikilinkRequiresAlias(resource: Resource) {
return normalize(resource.uri.getName()) !== normalize(resource.title);
}
export default feature;

View File

@@ -1,17 +1,17 @@
import { workspace, window } from 'vscode';
import { createTestNote, createTestWorkspace } from '../test/test-utils';
import { createTestNote, createTestWorkspace } from '../../test/test-utils';
import {
cleanWorkspace,
closeEditors,
createNote,
getUriInWorkspace,
} from '../test/test-utils-vscode';
} from '../../test/test-utils-vscode';
import { BacklinksTreeDataProvider, BacklinkTreeItem } from './backlinks';
import { ResourceTreeItem } from '../utils/grouped-resources-tree-data-provider';
import { OPEN_COMMAND } from './commands/open-resource';
import { toVsCodeUri } from '../utils/vsc-utils';
import { FoamGraph } from '../core/model/graph';
import { URI } from '../core/model/uri';
import { ResourceTreeItem } from '../../utils/grouped-resources-tree-data-provider';
import { OPEN_COMMAND } from '../commands/open-resource';
import { toVsCodeUri } from '../../utils/vsc-utils';
import { FoamGraph } from '../../core/model/graph';
import { URI } from '../../core/model/uri';
describe('Backlinks panel', () => {
beforeAll(async () => {

View File

@@ -1,16 +1,16 @@
import * as vscode from 'vscode';
import { groupBy } from 'lodash';
import { URI } from '../core/model/uri';
import { URI } from '../../core/model/uri';
import { getNoteTooltip, isNone } from '../utils';
import { FoamFeature } from '../types';
import { ResourceTreeItem } from '../utils/grouped-resources-tree-data-provider';
import { Foam } from '../core/model/foam';
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, toVsCodeUri } from '../utils/vsc-utils';
import { getNoteTooltip, isNone } from '../../utils';
import { FoamFeature } from '../../types';
import { ResourceTreeItem } from '../../utils/grouped-resources-tree-data-provider';
import { Foam } from '../../core/model/foam';
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, toVsCodeUri } from '../../utils/vsc-utils';
const feature: FoamFeature = {
activate: async (

View File

@@ -1,11 +1,11 @@
import * as vscode from 'vscode';
import { FoamFeature } from '../types';
import { FoamFeature } from '../../types';
import { TextDecoder } from 'util';
import { getGraphStyle, getTitleMaxLength } from '../settings';
import { isSome } from '../utils';
import { Foam } from '../core/model/foam';
import { Logger } from '../core/utils/log';
import { fromVsCodeUri } from '../utils/vsc-utils';
import { getGraphStyle, getTitleMaxLength } from '../../settings';
import { isSome } from '../../utils';
import { Foam } from '../../core/model/foam';
import { Logger } from '../../core/utils/log';
import { fromVsCodeUri } from '../../utils/vsc-utils';
const feature: FoamFeature = {
activate: (context: vscode.ExtensionContext, foamPromise: Promise<Foam>) => {

View File

@@ -0,0 +1,5 @@
export { default as backlinks } from './backlinks';
export { default as dataviz } from './dataviz';
export { default as orphans } from './orphans';
export { default as placeholders } from './placeholders';
export { default as tags } from './tags-explorer';

View File

@@ -1,5 +1,5 @@
import { FoamGraph } from '../core/model/graph';
import { createTestNote, createTestWorkspace } from '../test/test-utils';
import { FoamGraph } from '../../core/model/graph';
import { createTestNote, createTestWorkspace } from '../../test/test-utils';
import { isOrphan } from './orphans';
const orphanA = createTestNote({

View File

@@ -1,15 +1,15 @@
import * as vscode from 'vscode';
import { Foam } from '../core/model/foam';
import { FoamGraph } from '../core/model/graph';
import { URI } from '../core/model/uri';
import { getOrphansConfig } from '../settings';
import { FoamFeature } from '../types';
import { Foam } from '../../core/model/foam';
import { FoamGraph } from '../../core/model/graph';
import { URI } from '../../core/model/uri';
import { getOrphansConfig } from '../../settings';
import { FoamFeature } from '../../types';
import {
GroupedResourcesTreeDataProvider,
ResourceTreeItem,
UriTreeItem,
} from '../utils/grouped-resources-tree-data-provider';
import { fromVsCodeUri } from '../utils/vsc-utils';
} from '../../utils/grouped-resources-tree-data-provider';
import { fromVsCodeUri } from '../../utils/vsc-utils';
const feature: FoamFeature = {
activate: async (

View File

@@ -1,12 +1,12 @@
import * as vscode from 'vscode';
import { Foam } from '../core/model/foam';
import { getPlaceholdersConfig } from '../settings';
import { FoamFeature } from '../types';
import { Foam } from '../../core/model/foam';
import { getPlaceholdersConfig } from '../../settings';
import { FoamFeature } from '../../types';
import {
GroupedResourcesTreeDataProvider,
UriTreeItem,
} from '../utils/grouped-resources-tree-data-provider';
import { fromVsCodeUri } from '../utils/vsc-utils';
} from '../../utils/grouped-resources-tree-data-provider';
import { fromVsCodeUri } from '../../utils/vsc-utils';
const feature: FoamFeature = {
activate: async (

View File

@@ -1,10 +1,10 @@
import { createTestNote, readFileFromFs } from '../test/test-utils';
import { cleanWorkspace, closeEditors } from '../test/test-utils-vscode';
import { TagItem, TagReference, TagsProvider } from './tags-tree-view';
import { bootstrap, Foam } from '../core/model/foam';
import { MarkdownResourceProvider } from '../core/services/markdown-provider';
import { FileDataStore, Matcher } from '../core/services/datastore';
import { createMarkdownParser } from '../core/services/markdown-parser';
import { createTestNote, readFileFromFs } from '../../test/test-utils';
import { cleanWorkspace, closeEditors } from '../../test/test-utils-vscode';
import { TagItem, TagReference, TagsProvider } from './tags-explorer';
import { bootstrap, Foam } from '../../core/model/foam';
import { MarkdownResourceProvider } from '../../core/services/markdown-provider';
import { FileDataStore, Matcher } from '../../core/services/datastore';
import { createMarkdownParser } from '../../core/services/markdown-parser';
describe('Tags tree panel', () => {
let _foam: Foam;

View File

@@ -1,11 +1,11 @@
import { URI } from '../core/model/uri';
import { URI } from '../../core/model/uri';
import * as vscode from 'vscode';
import { FoamFeature } from '../types';
import { getNoteTooltip, isSome } from '../utils';
import { toVsCodeRange, toVsCodeUri } from '../utils/vsc-utils';
import { Foam } from '../core/model/foam';
import { FoamWorkspace } from '../core/model/workspace';
import { Resource, Tag } from '../core/model/note';
import { FoamFeature } from '../../types';
import { getNoteTooltip, isSome } from '../../utils';
import { toVsCodeRange, toVsCodeUri } from '../../utils/vsc-utils';
import { Foam } from '../../core/model/foam';
import { FoamWorkspace } from '../../core/model/workspace';
import { Resource, Tag } from '../../core/model/note';
const TAG_SEPARATOR = '/';
const feature: FoamFeature = {

View File

@@ -2,8 +2,8 @@ import { window } from 'vscode';
import { Resolver } from './variable-resolver';
import { Variable } from '../core/common/snippetParser';
describe('substituteFoamVariables', () => {
test('Does nothing if no Foam-specific variables are used', async () => {
describe('variable-resolver, text substitution', () => {
it('should do nothing if no Foam-specific variables are used', async () => {
const input = `
# \${AnotherVariable} <-- Unrelated to Foam
# \${AnotherVariable:default_value} <-- Unrelated to Foam
@@ -31,7 +31,7 @@ describe('substituteFoamVariables', () => {
expect(await resolver.resolveText(input)).toEqual(input);
});
test('Correctly substitutes variables that are substrings of one another', async () => {
it('should correctly substitute variables that are substrings of one another', async () => {
// FOAM_TITLE is a substring of FOAM_TITLE_NON_EXISTENT_VARIABLE
// If we're not careful with how we substitute the values
// we can end up putting the FOAM_TITLE in place FOAM_TITLE_NON_EXISTENT_VARIABLE should be.
@@ -56,8 +56,8 @@ describe('substituteFoamVariables', () => {
});
});
describe('resolveFoamVariables', () => {
test('Does nothing for unknown Foam-specific variables', async () => {
describe('variable-resolver, variable resolution', () => {
it('should do nothing for unknown Foam-specific variables', async () => {
const variables = [new Variable('FOAM_FOO')];
const expected = new Map<string, string>();
@@ -67,7 +67,7 @@ describe('resolveFoamVariables', () => {
expect(await resolver.resolveAll(variables)).toEqual(expected);
});
test('Resolves FOAM_TITLE', async () => {
it('should resolve FOAM_TITLE', async () => {
const foamTitle = 'My note title';
const variables = [new Variable('FOAM_TITLE'), new Variable('FOAM_SLUG')];
@@ -84,7 +84,7 @@ describe('resolveFoamVariables', () => {
expect(await resolver.resolveAll(variables)).toEqual(expected);
});
test('Resolves FOAM_TITLE without asking the user when it is provided', async () => {
it('should resolve FOAM_TITLE without asking the user when it is provided', async () => {
const foamTitle = 'My note title';
const variables = [new Variable('FOAM_TITLE')];
@@ -97,7 +97,7 @@ describe('resolveFoamVariables', () => {
expect(await resolver.resolveAll(variables)).toEqual(expected);
});
test('Resolves FOAM_DATE_* properties with current day by default', async () => {
it('should resolve FOAM_DATE_* properties with current day by default', async () => {
const variables = [
new Variable('FOAM_DATE_YEAR'),
new Variable('FOAM_DATE_YEAR_SHORT'),
@@ -134,7 +134,7 @@ describe('resolveFoamVariables', () => {
);
});
test('Resolves FOAM_DATE_* properties with given date', async () => {
it('should resolve FOAM_DATE_* properties with given date', async () => {
const targetDate = new Date(2021, 9, 12, 1, 2, 3);
const variables = [
new Variable('FOAM_DATE_YEAR'),
@@ -149,6 +149,7 @@ describe('resolveFoamVariables', () => {
new Variable('FOAM_DATE_MINUTE'),
new Variable('FOAM_DATE_SECOND'),
new Variable('FOAM_DATE_SECONDS_UNIX'),
new Variable('FOAM_DATE_WEEK'),
];
const expected = new Map<string, string>();
@@ -161,6 +162,7 @@ describe('resolveFoamVariables', () => {
expected.set('FOAM_DATE_DAY_NAME', 'Tuesday');
expected.set('FOAM_DATE_DAY_NAME_SHORT', 'Tue');
expected.set('FOAM_DATE_HOUR', '01');
expected.set('FOAM_DATE_WEEK', '41');
expected.set('FOAM_DATE_MINUTE', '02');
expected.set('FOAM_DATE_SECOND', '03');
expected.set(
@@ -173,10 +175,35 @@ describe('resolveFoamVariables', () => {
expect(await resolver.resolveAll(variables)).toEqual(expected);
});
describe('FOAM_DATE_WEEK', () => {
it('should start counting weeks from 1', async () => {
// week number starts from 1, not 0
// the first "partial week" of the year is really the last of the previous
const resolver = new Resolver(
new Map<string, string>(),
new Date(2021, 0, 1, 1, 2, 3)
);
expect(await resolver.resolve(new Variable('FOAM_DATE_WEEK'))).toEqual(
'53'
);
});
it('should pad week number to 2 digits', async () => {
// week number is 2-digit
const resolver = new Resolver(
new Map<string, string>(),
new Date(2021, 0, 7, 1, 2, 3)
);
expect(await resolver.resolve(new Variable('FOAM_DATE_WEEK'))).toEqual(
'01'
);
});
});
});
describe('resolveFoamTemplateVariables', () => {
test('Does nothing for template without Foam-specific variables', async () => {
describe('variable-resolver, resolveText', () => {
it('should do nothing for template without Foam-specific variables', async () => {
const input = `
# \${AnotherVariable} <-- Unrelated to Foam
# \${AnotherVariable:default_value} <-- Unrelated to Foam
@@ -191,7 +218,7 @@ describe('resolveFoamTemplateVariables', () => {
expect(await resolver.resolveText(input)).toEqual(expected);
});
test('Does nothing for unknown Foam-specific variables', async () => {
it('should do nothing for unknown Foam-specific variables', async () => {
const input = `
# $FOAM_FOO
# \${FOAM_FOO}
@@ -204,7 +231,7 @@ describe('resolveFoamTemplateVariables', () => {
expect(await resolver.resolveText(input)).toEqual(expected);
});
test('Appends FOAM_SELECTED_TEXT with a newline to the template if there is selected text but FOAM_SELECTED_TEXT is not referenced and the template ends in a newline', async () => {
it('should append FOAM_SELECTED_TEXT with a newline to the template if there is selected text but FOAM_SELECTED_TEXT is not referenced and the template ends in a newline', async () => {
const foamTitle = 'My note title';
jest
@@ -221,7 +248,7 @@ describe('resolveFoamTemplateVariables', () => {
expect(await resolver.resolveText(input)).toEqual(expected);
});
test('Appends FOAM_SELECTED_TEXT with a newline to the template if there is selected text but FOAM_SELECTED_TEXT is not referenced and the template ends in multiple newlines', async () => {
it('should append FOAM_SELECTED_TEXT with a newline to the template if there is selected text but FOAM_SELECTED_TEXT is not referenced and the template ends in multiple newlines', async () => {
const foamTitle = 'My note title';
jest
@@ -238,7 +265,7 @@ describe('resolveFoamTemplateVariables', () => {
expect(await resolver.resolveText(input)).toEqual(expected);
});
test('Appends FOAM_SELECTED_TEXT without a newline to the template if there is selected text but FOAM_SELECTED_TEXT is not referenced and the template does not end in a newline', async () => {
it('should append FOAM_SELECTED_TEXT without a newline to the template if there is selected text but FOAM_SELECTED_TEXT is not referenced and the template does not end in a newline', async () => {
const foamTitle = 'My note title';
jest
@@ -255,7 +282,7 @@ describe('resolveFoamTemplateVariables', () => {
expect(await resolver.resolveText(input)).toEqual(expected);
});
test('Does not append FOAM_SELECTED_TEXT to a template if there is no selected text and is not referenced', async () => {
it('should not append FOAM_SELECTED_TEXT to a template if there is no selected text and is not referenced', async () => {
const foamTitle = 'My note title';
jest

View File

@@ -18,6 +18,7 @@ const knownFoamVariables = new Set([
'FOAM_DATE_MONTH_NAME',
'FOAM_DATE_MONTH_NAME_SHORT',
'FOAM_DATE_DATE',
'FOAM_DATE_WEEK',
'FOAM_DATE_DAY_NAME',
'FOAM_DATE_DAY_NAME_SHORT',
'FOAM_DATE_HOUR',
@@ -165,6 +166,25 @@ export class Resolver implements VariableResolver {
String(this.foamDate.getDate().valueOf()).padStart(2, '0')
);
break;
case 'FOAM_DATE_WEEK': {
// https://en.wikipedia.org/wiki/ISO_8601#Week_dates
const date = new Date(this.foamDate);
// Find Thursday of this week starting on Monday
date.setDate(date.getDate() + 4 - (date.getDay() || 7));
const thursday = date.getTime();
// Find January 1st
date.setMonth(0); // January
date.setDate(1); // 1st
const janFirst = date.getTime();
// Round the amount of days to compensate for daylight saving time
const days = Math.round((thursday - janFirst) / 86400000); // 1 day = 86400000 ms
const weekDay = Math.floor(days / 7) + 1;
value = Promise.resolve(String(weekDay.valueOf()).padStart(2, '0'));
break;
}
case 'FOAM_DATE_DAY_NAME':
value = Promise.resolve(
this.foamDate.toLocaleString('default', { weekday: 'long' })

View File

@@ -85,6 +85,8 @@ let model = {
style: defaultStyle,
showNodesOfType: {
placeholder: true,
image: false,
attachment: false,
note: true,
tag: true,
},

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-101-orange.svg?style=flat-square)](#contributors-)
[![All Contributors](https://img.shields.io/badge/all_contributors-102-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)
@@ -91,7 +91,7 @@ See for each occurrence the context in which it lives, as well as a preview of t
### Tag Explorer Panel
Tag your notes and navigate them with the [Tag Explorer](https://foambubble.github.io/foam/user/user/features/tags).
Tag your notes and navigate them with the [Tag Explorer](https://foambubble.github.io/foam/user/features/tags).
Foam also supports hierarchical tags.
![Tag Explorer Panel](./assets/screenshots/feature-tags-panel.gif)
@@ -327,6 +327,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<td align="center"><a href="https://github.com/lingyv-li"><img src="https://avatars.githubusercontent.com/u/8937944?v=4?s=60" width="60px;" alt=""/><br /><sub><b>Larry Li</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=lingyv-li" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/infogulch"><img src="https://avatars.githubusercontent.com/u/133882?v=4?s=60" width="60px;" alt=""/><br /><sub><b>Joe Taber</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=infogulch" title="Documentation">📖</a></td>
<td align="center"><a href="https://www.readingsnail.pe.kr"><img src="https://avatars.githubusercontent.com/u/1904967?v=4?s=60" width="60px;" alt=""/><br /><sub><b>Woosuk Park</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=readingsnail" title="Documentation">📖</a></td>
<td align="center"><a href="http://www.dmurph.com"><img src="https://avatars.githubusercontent.com/u/294026?v=4?s=60" width="60px;" alt=""/><br /><sub><b>Daniel Murphy</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=dmurph" title="Code">💻</a></td>
</tr>
</table>