mirror of
https://github.com/foambubble/foam.git
synced 2026-01-11 06:58:11 -05:00
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8bd679c751 | ||
|
|
8986ee286c | ||
|
|
51b1af1981 | ||
|
|
4276e8043f | ||
|
|
8d1e9b15ce | ||
|
|
bfcfad32e8 | ||
|
|
abe18cc961 | ||
|
|
9490aa2dad | ||
|
|
6c3f4588b3 | ||
|
|
21b8c5b827 | ||
|
|
c66ed74aea | ||
|
|
3876811fb6 | ||
|
|
d9299ee9d4 | ||
|
|
23e21a62f3 | ||
|
|
e7c8d5a4eb | ||
|
|
3ef1b69b2e | ||
|
|
5859b2a9c6 | ||
|
|
54086fdd7e | ||
|
|
a308dfd109 | ||
|
|
e327115673 | ||
|
|
c019767476 |
@@ -1058,6 +1058,15 @@
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "dcarosone",
|
||||
"name": "Daniel Carosone",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/11495017?v=4",
|
||||
"profile": "https://github.com/dcarosone",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
|
||||
8
.github/workflows/update-docs.yml
vendored
8
.github/workflows/update-docs.yml
vendored
@@ -6,6 +6,8 @@ on:
|
||||
- master
|
||||
paths:
|
||||
- docs/user/**/*
|
||||
- docs/.vscode/**/*
|
||||
- docs/assets/**/*
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
@@ -20,11 +22,15 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
path: foam
|
||||
- name: Copy and fixup user docs files
|
||||
- name: Copy and fixup user docs files
|
||||
id: copy
|
||||
run: |
|
||||
rm -r foam-template/docs
|
||||
rm -r foam-template/assets
|
||||
rm -r foam-template/.vscode
|
||||
cp -r foam/docs/user foam-template/docs
|
||||
cp -r foam/docs/assets foam-template/assets
|
||||
cp -r foam/docs/.vscode foam-template/.vscode
|
||||
|
||||
# Strip autogenerated wikileaks references because
|
||||
# they are not an appropriate default user experience.
|
||||
|
||||
10
docs/.vscode/extensions.json
vendored
10
docs/.vscode/extensions.json
vendored
@@ -5,17 +5,11 @@
|
||||
// Foam's own extension
|
||||
"foam.foam-vscode",
|
||||
|
||||
// Prettier for auto formatting code
|
||||
"esbenp.prettier-vscode",
|
||||
|
||||
// GitLens for seeing version history inline
|
||||
"eamodio.gitlens",
|
||||
|
||||
// Tons of markdown goodies (lists, tables of content, so much more)
|
||||
"yzhang.markdown-all-in-one",
|
||||
|
||||
// Graph visualizer
|
||||
"tchayen.markdown-links",
|
||||
// Prettier for auto formatting code
|
||||
"esbenp.prettier-vscode",
|
||||
|
||||
// Understated grayscale theme (light and dark variants)
|
||||
"philipbe.theme-gray-matter"
|
||||
|
||||
4
docs/.vscode/foam.json
vendored
4
docs/.vscode/foam.json
vendored
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"purpose": "this file exists to tell the foam-vscode plugin that it's currently in a foam workspace",
|
||||
"future": "we may use this for custom configuration"
|
||||
}
|
||||
2
docs/.vscode/keybindings.json
vendored
2
docs/.vscode/keybindings.json
vendored
@@ -3,6 +3,6 @@
|
||||
[
|
||||
{
|
||||
"key": "cmd+shift+n",
|
||||
"command": "vscodeMarkdownNotes.newNote"
|
||||
"command": "foam-vscode.create-note"
|
||||
}
|
||||
]
|
||||
|
||||
13
docs/.vscode/settings.json
vendored
13
docs/.vscode/settings.json
vendored
@@ -5,7 +5,6 @@
|
||||
"editor.overviewRulerBorder": false,
|
||||
"editor.lineHeight": 24,
|
||||
"foam.edit.linkReferenceDefinitions": "withExtensions",
|
||||
"vscodeMarkdownNotes.noteCompletionConvention": "noExtension",
|
||||
"[markdown]": {
|
||||
"editor.quickSuggestions": {
|
||||
"other": true,
|
||||
@@ -13,21 +12,11 @@
|
||||
"strings": false
|
||||
}
|
||||
},
|
||||
"cSpell.language": "en-GB",
|
||||
"git.enableSmartCommit": true,
|
||||
"git.postCommitCommand": "sync",
|
||||
"spellright.language": [
|
||||
"en"
|
||||
],
|
||||
"spellright.documentTypes": [
|
||||
"markdown",
|
||||
"plaintext"
|
||||
],
|
||||
"files.exclude": {
|
||||
"_site/**": true
|
||||
},
|
||||
"files.insertFinalNewline": true,
|
||||
"markdown.styles": [
|
||||
".vscode/custom-tag-style.css"
|
||||
]
|
||||
"markdown.styles": [".vscode/custom-tag-style.css"]
|
||||
}
|
||||
|
||||
1
docs/.vscode/spellright.dict
vendored
1
docs/.vscode/spellright.dict
vendored
@@ -1 +0,0 @@
|
||||
Backlinking
|
||||
BIN
docs/assets/images/note-embed-type-demo.gif
Normal file
BIN
docs/assets/images/note-embed-type-demo.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 568 KiB |
@@ -255,6 +255,7 @@ If that sounds like something you're interested in, I'd love to have you along o
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://amnesiak.org/me"><img src="https://avatars.githubusercontent.com/u/952059?v=4?s=60" width="60px;" alt="Tony Cheneau"/><br /><sub><b>Tony Cheneau</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=tcheneau" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/nicholas-l"><img src="https://avatars.githubusercontent.com/u/12977174?v=4?s=60" width="60px;" alt="Nicholas Latham"/><br /><sub><b>Nicholas Latham</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=nicholas-l" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://thara.dev"><img src="https://avatars.githubusercontent.com/u/1532891?v=4?s=60" width="60px;" alt="Tomochika Hara"/><br /><sub><b>Tomochika Hara</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=thara" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/dcarosone"><img src="https://avatars.githubusercontent.com/u/11495017?v=4?s=60" width="60px;" alt="Daniel Carosone"/><br /><sub><b>Daniel Carosone</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=dcarosone" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
29
docs/user/features/built-in-note-embedding-types.md
Normal file
29
docs/user/features/built-in-note-embedding-types.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Built-In Note Embedding Types
|
||||
|
||||
When embedding a note, there are a few ways to modify the scope of the content as well as its display style. The following are Foam keywords that are used to describe note embedding.
|
||||
|
||||
Note, this only applies to note embedding, not embedding of attachments or images.
|
||||
|
||||

|
||||
|
||||
## Scope
|
||||
|
||||
- `full` - the entire note in the case of `![[note]]` or the entire section in the case of `![[note#section1]]`
|
||||
- `content` - everything excluding the title of the section. So the entire note minus the title for `![[note]]`, or the entire section minus the section header for `![[note#section1]]`
|
||||
|
||||
## Style
|
||||
|
||||
- `card` - outlines the embedded note with a border
|
||||
- `inline` - adds the note continuously as if the text were part of the calling note
|
||||
|
||||
## Default Setting
|
||||
|
||||
Foam expresses note display type as `<scope>-<style>`.
|
||||
|
||||
By default, Foam configures note embedding to be `full-card`. That is, whenever the standard embedding syntax is used, `![[note]]`, the note will have `full` scope and `card` style display. This setting is stored under `foam.preview.embedNoteStyle` and can be modified.
|
||||
|
||||
## Explicit Modifiers
|
||||
|
||||
Prepend the wikilink with one of the scope or style keywords, or a combination of the two to explicitly modify a note embedding if you would like to override the default setting.
|
||||
|
||||
For example, given your `foam.embedNoteStyle` is set to `content-card`, embedding a note with standard syntax `![[note-a]]` would show a bordered note without its title. Say, for a specific `note-b` you would like to display the title. You can simply use one of the above keywords to override your default setting like so: `full![[note-b]]`. In this case, `full` overrides the default `content` scope and because a style is not specified, it falls back to the default style setting, `card`. If you would like it to be inline, override that as well: `full-inline![[note-b]]`.
|
||||
@@ -8,13 +8,16 @@ Including a note can be done by adding an `!` before a wikilink definition. For
|
||||
|
||||
## Custom styling
|
||||
|
||||
Displaying the inclusion of notes allows for some custom styling, see [[custom-markdown-preview-styles]]
|
||||
To modify how an embedded note looks and the scope of its content, see [[built-in-note-embedding-types]]
|
||||
|
||||
For more fine-grained custom styling, see [[custom-markdown-preview-styles]]
|
||||
|
||||
## Future possibilities
|
||||
|
||||
Work on this feature is evolving and progressing. See the [[inclusion-of-notes]] proposal for the current discussion.
|
||||
|
||||
[//begin]: # "Autogenerated link references for markdown compatibility"
|
||||
[custom-markdown-preview-styles]: custom-markdown-preview-styles.md "Custom Markdown Preview Styles"
|
||||
[inclusion-of-notes]: ../../dev/proposals/inclusion-of-notes.md "Inclusion of notes Proposal "
|
||||
[//end]: # "Autogenerated link references"
|
||||
[//begin]: # 'Autogenerated link references for markdown compatibility'
|
||||
[built-in-note-embedding-types]: built-in-note-embedding-types.md 'Built-In Note Embedding Types'
|
||||
[custom-markdown-preview-styles]: custom-markdown-preview-styles.md 'Custom Markdown Preview Styles'
|
||||
[inclusion-of-notes]: ../../dev/proposals/inclusion-of-notes.md 'Inclusion of notes Proposal '
|
||||
[//end]: # 'Autogenerated link references'
|
||||
|
||||
@@ -20,7 +20,10 @@ Remember, with `CTRL/CMD+click` on a wikilink you can navigate to the note, or c
|
||||
|
||||
## Support for sections
|
||||
|
||||
Foam supports autocompletion, navigation, embedding and diagnostics for note sections. Just use the standard wiki syntax of `[[resource#Section Title]]`.
|
||||
Foam supports autocompletion, navigation, embedding and diagnostics for note sections. Just use the standard wiki syntax of `[[resource#Section Title]]`.
|
||||
- If it's an external file, `[your link will need the filename](other-file.md#that-section-I-want-to-link-to)`, but
|
||||
- if it's an anchor within the same document, `[you just need an octothorpe and the section name](#that-section-above)`.
|
||||
- Doesn't matter what heading-level the anchor is; whether you're linking to an `H1` like `# MEN WALK ON MOON` or an `H2` like `## Astronauts Land on Plain`, the link syntax uses a single octothorpe: `[Walk!](#men-walk-on-moon)` and `[Land!](#astronauts-land-on-plain-collect-rocks-plant-flag)`. Autocomplete is your friend here.
|
||||
|
||||
## Markdown compatibility
|
||||
|
||||
|
||||
@@ -6,11 +6,11 @@ This list is subject to change.
|
||||
|
||||
- [Foam for VSCode](https://marketplace.visualstudio.com/items?itemName=foam.foam-vscode) (alpha)
|
||||
- [Markdown All In One](https://marketplace.visualstudio.com/items?itemName=yzhang.markdown-all-in-one)
|
||||
- [Paste Image](https://marketplace.visualstudio.com/items?itemName=mushan.vscode-paste-image)
|
||||
- [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)
|
||||
|
||||
## Extensions For Additional Features
|
||||
|
||||
These extensions are not (yet?) defined in `.vscode/extensions.json`, but have been used by others and shown to play nice with Foam.
|
||||
These extensions are not defined in `.vscode/extensions.json`, but have been used by others and shown to play nice with Foam.
|
||||
|
||||
- [Emojisense](https://marketplace.visualstudio.com/items?itemName=bierner.emojisense)
|
||||
- [Markdown Emoji](https://marketplace.visualstudio.com/items?itemName=bierner.markdown-emoji) (adds `:smile:` syntax, works with emojisense to provide autocomplete for this syntax)
|
||||
|
||||
@@ -2,8 +2,12 @@
|
||||
|
||||
This #recipe allows you to paste images on to your notes.
|
||||
|
||||
You can directly link and paste images that are copied to the clipboard using either the [Paste
|
||||
Image](https://marketplace.visualstudio.com/items?itemName=mushan.vscode-paste-image)
|
||||
extension, or the [Markdown Image](https://marketplace.visualstudio.com/items?itemName=hancel.markdown-image) extension.
|
||||
VScode (since
|
||||
[1.79](https://code.visualstudio.com/updates/v1_79#_copy-external-media-files-into-workspace-on-drop-or-paste-for-markdown))
|
||||
now has the ability to paste images from the clipboard, or drag-and-drop image
|
||||
files, directly into markdown documents. The file will be created in the
|
||||
workspace, and a link generated in Markdown format.
|
||||
|
||||
The former does not have MDX support (yet), the latter does.
|
||||
VSCode settings under `Markdown > Copy Files` and `Markdown > Editor > Drop` can
|
||||
be used to configure where the files get placed in your workspace, how they're
|
||||
named, how conflicts with existing files are handled, and more.
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
],
|
||||
"npmClient": "yarn",
|
||||
"useWorkspaces": true,
|
||||
"version": "0.25.2"
|
||||
"version": "0.25.5"
|
||||
}
|
||||
|
||||
@@ -4,6 +4,27 @@ 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.25.5] - 2023-11-30
|
||||
|
||||
Fixes and Improvements:
|
||||
|
||||
- Using note title in preview (#1309)
|
||||
|
||||
## [0.25.4] - 2023-09-19
|
||||
|
||||
Fixes and Improvements:
|
||||
|
||||
- Added support for linking sections within same document (#1289)
|
||||
- Fixed note embedding bug (#1286 - thanks @badsketch)
|
||||
|
||||
## [0.25.3] - 2023-09-07
|
||||
|
||||
Fixes and Improvements:
|
||||
|
||||
- Fixed incorrect handling of embedding of non-existing notes (#1283 - thanks @badsketch)
|
||||
- Introduced Note Embedding Sytanx (#1281 - thanks @badsketch)
|
||||
- Attachments are not considered when computing orphan notes (#1242)
|
||||
|
||||
## [0.25.2] - 2023-09-02
|
||||
|
||||
Fixes and Improvements:
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"type": "git"
|
||||
},
|
||||
"homepage": "https://github.com/foambubble/foam",
|
||||
"version": "0.25.2",
|
||||
"version": "0.25.5",
|
||||
"license": "MIT",
|
||||
"publisher": "foam",
|
||||
"engines": {
|
||||
@@ -609,12 +609,6 @@
|
||||
],
|
||||
"description": "Whether or not to navigate to the target daily note when a daily note snippet is selected."
|
||||
},
|
||||
"foam.preview.embedNoteInContainer": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Wrap embedded notes in a container when displayed in preview panel",
|
||||
"deprecationMessage": "*DEPRECATED* use foam.preview.embedNoteType instead."
|
||||
},
|
||||
"foam.preview.embedNoteType": {
|
||||
"type": "string",
|
||||
"default": "full-card",
|
||||
|
||||
@@ -4,7 +4,14 @@ import { FoamWorkspace } from '../model/workspace';
|
||||
import { IDisposable } from '../common/lifecycle';
|
||||
import { ResourceProvider } from '../model/provider';
|
||||
|
||||
const imageExtensions = ['.png', '.jpg', '.jpeg', '.gif', '.svg', '.webp'];
|
||||
export const imageExtensions = [
|
||||
'.png',
|
||||
'.jpg',
|
||||
'.jpeg',
|
||||
'.gif',
|
||||
'.svg',
|
||||
'.webp',
|
||||
];
|
||||
|
||||
const asResource = (uri: URI): Resource => {
|
||||
const type = imageExtensions.includes(uri.getExtension())
|
||||
|
||||
@@ -316,4 +316,40 @@ describe('Generation of markdown references', () => {
|
||||
'../dir3/page-c.md',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should generate links for embedded notes that are formatted properly', () => {
|
||||
const workspace = createTestWorkspace();
|
||||
const noteA = createNoteFromMarkdown(
|
||||
'Link to ![[page-b]] and [[page-c]]',
|
||||
'/dir1/page-a.md'
|
||||
);
|
||||
workspace
|
||||
.set(noteA)
|
||||
.set(createNoteFromMarkdown('Content of note B', '/dir2/page-b.md'))
|
||||
.set(createNoteFromMarkdown('Content of note C', '/dir3/page-c.md'));
|
||||
|
||||
const references = createMarkdownReferences(workspace, noteA.uri, true);
|
||||
expect(references.map(r => [r.url, r.label])).toEqual([
|
||||
['../dir2/page-b.md', 'page-b'],
|
||||
['../dir3/page-c.md', 'page-c'],
|
||||
]);
|
||||
});
|
||||
|
||||
it('should not generate links for placeholders', () => {
|
||||
const workspace = createTestWorkspace();
|
||||
const noteA = createNoteFromMarkdown(
|
||||
'Link to ![[page-b]] and [[page-c]] and [[does-not-exist]] and ![[does-not-exist-either]]',
|
||||
'/dir1/page-a.md'
|
||||
);
|
||||
workspace
|
||||
.set(noteA)
|
||||
.set(createNoteFromMarkdown('Content of note B', '/dir2/page-b.md'))
|
||||
.set(createNoteFromMarkdown('Content of note C', '/dir3/page-c.md'));
|
||||
|
||||
const references = createMarkdownReferences(workspace, noteA.uri, true);
|
||||
expect(references.map(r => r.url)).toEqual([
|
||||
'../dir2/page-b.md',
|
||||
'../dir3/page-c.md',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -139,10 +139,12 @@ export function createMarkdownReferences(
|
||||
|
||||
// [wikilink-text]: path/to/file.md "Page title"
|
||||
return {
|
||||
label:
|
||||
link.rawText.indexOf('[[') > -1
|
||||
? link.rawText.substring(2, link.rawText.length - 2)
|
||||
: link.rawText,
|
||||
// embedded looks like ![[note-a]]
|
||||
// regular note looks like [[note-a]]
|
||||
label: link.rawText.substring(
|
||||
link.isEmbed ? 3 : 2,
|
||||
link.rawText.length - 2
|
||||
),
|
||||
url: relativeUri.path,
|
||||
title: target.title,
|
||||
};
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import * as vscode from 'vscode';
|
||||
import { Foam } from '../../core/model/foam';
|
||||
import { createMatcherAndDataStore } from '../../services/editor';
|
||||
import { getOrphansConfig } from '../../settings';
|
||||
import { getAttachmentsExtensions, getOrphansConfig } from '../../settings';
|
||||
import { GroupedResourcesTreeDataProvider } from './utils/grouped-resources-tree-data-provider';
|
||||
import { ResourceTreeItem, UriTreeItem } from './utils/tree-view-utils';
|
||||
import { IMatcher } from '../../core/services/datastore';
|
||||
import { FoamWorkspace } from '../../core/model/workspace';
|
||||
import { FoamGraph } from '../../core/model/graph';
|
||||
import { URI } from '../../core/model/uri';
|
||||
import { imageExtensions } from '../../core/services/attachment-provider';
|
||||
|
||||
const EXCLUDE_TYPES = ['image', 'attachment'];
|
||||
export default async function activate(
|
||||
@@ -66,6 +68,13 @@ export class OrphanTreeView extends GroupedResourcesTreeDataProvider {
|
||||
.filter(
|
||||
uri =>
|
||||
!EXCLUDE_TYPES.includes(this.workspace.find(uri)?.type) &&
|
||||
this.graph.getConnections(uri).length === 0
|
||||
this.graph.getBacklinks(uri).length === 0 &&
|
||||
this.graph.getLinks(uri).filter(c => !isAttachment(c.target))
|
||||
.length === 0
|
||||
);
|
||||
}
|
||||
|
||||
function isAttachment(uri: URI) {
|
||||
const ext = [...getAttachmentsExtensions(), ...imageExtensions];
|
||||
return ext.includes(uri.getExtension());
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
import {
|
||||
default as markdownItWikilinkEmbed,
|
||||
CONFIG_EMBED_NOTE_TYPE,
|
||||
CONFIG_EMBED_NOTE_IN_CONTAINER,
|
||||
} from './wikilink-embed';
|
||||
|
||||
const parser = createMarkdownParser();
|
||||
@@ -22,25 +21,19 @@ describe('Displaying included notes in preview', () => {
|
||||
]);
|
||||
const ws = new FoamWorkspace().set(parser.parse(note.uri, note.content));
|
||||
await withModifiedFoamConfiguration(
|
||||
CONFIG_EMBED_NOTE_IN_CONTAINER,
|
||||
null,
|
||||
async () => {
|
||||
await withModifiedFoamConfiguration(
|
||||
CONFIG_EMBED_NOTE_TYPE,
|
||||
'full-inline',
|
||||
() => {
|
||||
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);
|
||||
CONFIG_EMBED_NOTE_TYPE,
|
||||
'full-inline',
|
||||
() => {
|
||||
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);
|
||||
|
||||
expect(
|
||||
md.render(`This is the root node.
|
||||
expect(
|
||||
md.render(`This is the root node.
|
||||
|
||||
![[note-a]]`)
|
||||
).toMatch(
|
||||
`<p>This is the root node.</p>
|
||||
).toMatch(
|
||||
`<p>This is the root node.</p>
|
||||
<p><p>This is the text of note A</p>
|
||||
</p>`
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
@@ -55,21 +48,15 @@ describe('Displaying included notes in preview', () => {
|
||||
const ws = new FoamWorkspace().set(parser.parse(note.uri, note.content));
|
||||
|
||||
await withModifiedFoamConfiguration(
|
||||
CONFIG_EMBED_NOTE_IN_CONTAINER,
|
||||
null,
|
||||
async () => {
|
||||
await withModifiedFoamConfiguration(
|
||||
CONFIG_EMBED_NOTE_TYPE,
|
||||
'full-card',
|
||||
() => {
|
||||
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);
|
||||
CONFIG_EMBED_NOTE_TYPE,
|
||||
'full-card',
|
||||
() => {
|
||||
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);
|
||||
|
||||
const res = md.render(`This is the root node. ![[note-a]]`);
|
||||
expect(res).toContain('This is the root node');
|
||||
expect(res).toContain('embed-container-note');
|
||||
expect(res).toContain('This is the text of note A');
|
||||
}
|
||||
);
|
||||
const res = md.render(`This is the root node. ![[note-a]]`);
|
||||
expect(res).toContain('This is the root node');
|
||||
expect(res).toContain('embed-container-note');
|
||||
expect(res).toContain('This is the text of note A');
|
||||
}
|
||||
);
|
||||
await deleteFile(note);
|
||||
@@ -96,24 +83,18 @@ This is the third section of note E
|
||||
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);
|
||||
|
||||
await withModifiedFoamConfiguration(
|
||||
CONFIG_EMBED_NOTE_IN_CONTAINER,
|
||||
null,
|
||||
async () => {
|
||||
await withModifiedFoamConfiguration(
|
||||
CONFIG_EMBED_NOTE_TYPE,
|
||||
'full-inline',
|
||||
() => {
|
||||
expect(
|
||||
md.render(`This is the root node.
|
||||
CONFIG_EMBED_NOTE_TYPE,
|
||||
'full-inline',
|
||||
() => {
|
||||
expect(
|
||||
md.render(`This is the root node.
|
||||
|
||||
![[note-e#Section 2]]`)
|
||||
).toMatch(
|
||||
`<p>This is the root node.</p>
|
||||
).toMatch(
|
||||
`<p>This is the root node.</p>
|
||||
<p><h1>Section 2</h1>
|
||||
<p>This is the second section of note E</p>
|
||||
</p>`
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
@@ -139,24 +120,18 @@ This is the third section of note E
|
||||
const ws = new FoamWorkspace().set(parser.parse(note.uri, note.content));
|
||||
|
||||
await withModifiedFoamConfiguration(
|
||||
CONFIG_EMBED_NOTE_IN_CONTAINER,
|
||||
null,
|
||||
async () => {
|
||||
await withModifiedFoamConfiguration(
|
||||
CONFIG_EMBED_NOTE_TYPE,
|
||||
'full-card',
|
||||
() => {
|
||||
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);
|
||||
CONFIG_EMBED_NOTE_TYPE,
|
||||
'full-card',
|
||||
() => {
|
||||
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);
|
||||
|
||||
const res = md.render(
|
||||
`This is the root node. ![[note-e-container#Section 3]]`
|
||||
);
|
||||
expect(res).toContain('This is the root node');
|
||||
expect(res).toContain('embed-container-note');
|
||||
expect(res).toContain('Section 3');
|
||||
expect(res).toContain('This is the third section of note E');
|
||||
}
|
||||
const res = md.render(
|
||||
`This is the root node. ![[note-e-container#Section 3]]`
|
||||
);
|
||||
expect(res).toContain('This is the root node');
|
||||
expect(res).toContain('embed-container-note');
|
||||
expect(res).toContain('Section 3');
|
||||
expect(res).toContain('This is the third section of note E');
|
||||
}
|
||||
);
|
||||
|
||||
@@ -176,26 +151,20 @@ This is the first section of note E`,
|
||||
const ws = new FoamWorkspace().set(parser.parse(note.uri, note.content));
|
||||
|
||||
await withModifiedFoamConfiguration(
|
||||
CONFIG_EMBED_NOTE_IN_CONTAINER,
|
||||
null,
|
||||
async () => {
|
||||
await withModifiedFoamConfiguration(
|
||||
CONFIG_EMBED_NOTE_TYPE,
|
||||
'content-inline',
|
||||
() => {
|
||||
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);
|
||||
CONFIG_EMBED_NOTE_TYPE,
|
||||
'content-inline',
|
||||
() => {
|
||||
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);
|
||||
|
||||
expect(
|
||||
md.render(`This is the root node.
|
||||
expect(
|
||||
md.render(`This is the root node.
|
||||
|
||||
![[note-e]]`)
|
||||
).toMatch(
|
||||
`<p>This is the root node.</p>
|
||||
).toMatch(
|
||||
`<p>This is the root node.</p>
|
||||
<p><h2>Section 1</h2>
|
||||
<p>This is the first section of note E</p>
|
||||
</p>`
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
@@ -216,24 +185,18 @@ This is the first section of note E
|
||||
const ws = new FoamWorkspace().set(parser.parse(note.uri, note.content));
|
||||
|
||||
await withModifiedFoamConfiguration(
|
||||
CONFIG_EMBED_NOTE_IN_CONTAINER,
|
||||
null,
|
||||
async () => {
|
||||
await withModifiedFoamConfiguration(
|
||||
CONFIG_EMBED_NOTE_TYPE,
|
||||
'content-card',
|
||||
() => {
|
||||
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);
|
||||
CONFIG_EMBED_NOTE_TYPE,
|
||||
'content-card',
|
||||
() => {
|
||||
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);
|
||||
|
||||
const res = md.render(`This is the root node. ![[note-e.md]]`);
|
||||
const res = md.render(`This is the root node. ![[note-e.md]]`);
|
||||
|
||||
expect(res).toContain('This is the root node');
|
||||
expect(res).toContain('embed-container-note');
|
||||
expect(res).toContain('Section 1');
|
||||
expect(res).toContain('This is the first section of note E');
|
||||
expect(res).not.toContain('Title');
|
||||
}
|
||||
);
|
||||
expect(res).toContain('This is the root node');
|
||||
expect(res).toContain('embed-container-note');
|
||||
expect(res).toContain('Section 1');
|
||||
expect(res).toContain('This is the first section of note E');
|
||||
expect(res).not.toContain('Title');
|
||||
}
|
||||
);
|
||||
|
||||
@@ -257,27 +220,21 @@ This is the first subsection of note E
|
||||
const ws = new FoamWorkspace().set(parser.parse(note.uri, note.content));
|
||||
|
||||
await withModifiedFoamConfiguration(
|
||||
CONFIG_EMBED_NOTE_IN_CONTAINER,
|
||||
null,
|
||||
async () => {
|
||||
await withModifiedFoamConfiguration(
|
||||
CONFIG_EMBED_NOTE_TYPE,
|
||||
'content-inline',
|
||||
() => {
|
||||
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);
|
||||
CONFIG_EMBED_NOTE_TYPE,
|
||||
'content-inline',
|
||||
() => {
|
||||
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);
|
||||
|
||||
expect(
|
||||
md.render(`This is the root node.
|
||||
expect(
|
||||
md.render(`This is the root node.
|
||||
|
||||
![[note-e#Section 1]]`)
|
||||
).toMatch(
|
||||
`<p>This is the root node.</p>
|
||||
).toMatch(
|
||||
`<p>This is the root node.</p>
|
||||
<p><p>This is the first section of note E</p>
|
||||
<h3>Subsection a</h3>
|
||||
<p>This is the first subsection of note E</p>
|
||||
</p>`
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
@@ -299,25 +256,19 @@ This is the first subsection of note E`,
|
||||
const ws = new FoamWorkspace().set(parser.parse(note.uri, note.content));
|
||||
|
||||
await withModifiedFoamConfiguration(
|
||||
CONFIG_EMBED_NOTE_IN_CONTAINER,
|
||||
null,
|
||||
async () => {
|
||||
await withModifiedFoamConfiguration(
|
||||
CONFIG_EMBED_NOTE_TYPE,
|
||||
'content-inline',
|
||||
() => {
|
||||
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);
|
||||
CONFIG_EMBED_NOTE_TYPE,
|
||||
'content-inline',
|
||||
() => {
|
||||
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);
|
||||
|
||||
expect(
|
||||
md.render(`This is the root node.
|
||||
expect(
|
||||
md.render(`This is the root node.
|
||||
|
||||
![[note-e#Subsection a]]`)
|
||||
).toMatch(
|
||||
`<p>This is the root node.</p>
|
||||
).toMatch(
|
||||
`<p>This is the root node.</p>
|
||||
<p><p>This is the first subsection of note E</p>
|
||||
</p>`
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
@@ -325,6 +276,82 @@ This is the first subsection of note E`,
|
||||
await deleteFile(note);
|
||||
});
|
||||
|
||||
it('should allow a note embedding type to be overridden if a modifier is passed in', async () => {
|
||||
const note = await createFile(
|
||||
`
|
||||
# Section 1
|
||||
This is the first section of note E
|
||||
|
||||
# Section 2
|
||||
This is the second section of note E
|
||||
|
||||
# Section 3
|
||||
This is the third section of note E
|
||||
`,
|
||||
['note-e.md']
|
||||
);
|
||||
const parser = createMarkdownParser([]);
|
||||
const ws = new FoamWorkspace().set(parser.parse(note.uri, note.content));
|
||||
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);
|
||||
|
||||
await withModifiedFoamConfiguration(
|
||||
CONFIG_EMBED_NOTE_TYPE,
|
||||
'full-inline',
|
||||
() => {
|
||||
expect(
|
||||
md.render(`This is the root node.
|
||||
|
||||
content![[note-e#Section 2]]
|
||||
|
||||
full![[note-e#Section 3]]`)
|
||||
).toMatch(
|
||||
`<p>This is the root node.</p>
|
||||
<p><p>This is the second section of note E</p>
|
||||
</p>
|
||||
<p><h1>Section 3</h1>
|
||||
<p>This is the third section of note E</p>
|
||||
</p>
|
||||
`
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
await deleteFile(note);
|
||||
});
|
||||
|
||||
it('should allow a note embedding type to be overridden if two modifiers are passed in', async () => {
|
||||
const note = await createFile(
|
||||
`
|
||||
# Section 1
|
||||
This is the first section of note E
|
||||
|
||||
# Section 2
|
||||
This is the second section of note E
|
||||
`,
|
||||
['note-e.md']
|
||||
);
|
||||
const parser = createMarkdownParser([]);
|
||||
const ws = new FoamWorkspace().set(parser.parse(note.uri, note.content));
|
||||
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);
|
||||
|
||||
await withModifiedFoamConfiguration(
|
||||
CONFIG_EMBED_NOTE_TYPE,
|
||||
'full-inline',
|
||||
() => {
|
||||
const res = md.render(`This is the root node.
|
||||
|
||||
content-card![[note-e#Section 2]]`);
|
||||
|
||||
expect(res).toContain('This is the root node');
|
||||
expect(res).toContain('embed-container-note');
|
||||
expect(res).toContain('This is the second section of note E');
|
||||
expect(res).not.toContain('Section 2');
|
||||
}
|
||||
);
|
||||
|
||||
await deleteFile(note);
|
||||
});
|
||||
|
||||
it('should fallback to the bare text when the note is not found', () => {
|
||||
const md = markdownItWikilinkEmbed(
|
||||
MarkdownIt(),
|
||||
@@ -337,6 +364,27 @@ This is the first subsection of note E`,
|
||||
);
|
||||
});
|
||||
|
||||
it('should render the bare text for an embedded note that is embedding a note that is not found', async () => {
|
||||
const note = await createFile(
|
||||
'This is the text of note A which includes ![[does-not-exist]]',
|
||||
['note.md']
|
||||
);
|
||||
|
||||
const ws = new FoamWorkspace().set(parser.parse(note.uri, note.content));
|
||||
|
||||
await withModifiedFoamConfiguration(
|
||||
CONFIG_EMBED_NOTE_TYPE,
|
||||
'full-inline',
|
||||
() => {
|
||||
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);
|
||||
expect(md.render(`This is the root node. ![[note]]`)).toMatch(
|
||||
`<p>This is the root node. <p>This is the text of note A which includes ![[does-not-exist]]</p>
|
||||
</p>`
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should display a warning in case of cyclical inclusions', async () => {
|
||||
const noteA = await createFile(
|
||||
'This is the text of note A which includes ![[note-b]]',
|
||||
@@ -351,21 +399,15 @@ This is the first subsection of note E`,
|
||||
.set(parser.parse(noteB.uri, noteB.content));
|
||||
|
||||
await withModifiedFoamConfiguration(
|
||||
CONFIG_EMBED_NOTE_IN_CONTAINER,
|
||||
null,
|
||||
async () => {
|
||||
await withModifiedFoamConfiguration(
|
||||
CONFIG_EMBED_NOTE_TYPE,
|
||||
'full-card',
|
||||
() => {
|
||||
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);
|
||||
const res = md.render(noteBText);
|
||||
CONFIG_EMBED_NOTE_TYPE,
|
||||
'full-card',
|
||||
() => {
|
||||
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);
|
||||
const res = md.render(noteBText);
|
||||
|
||||
expect(res).toContain('This is the text of note B which includes');
|
||||
expect(res).toContain('This is the text of note A which includes');
|
||||
expect(res).toContain('Cyclic link detected for wikilink');
|
||||
}
|
||||
);
|
||||
expect(res).toContain('This is the text of note B which includes');
|
||||
expect(res).toContain('This is the text of note A which includes');
|
||||
expect(res).toContain('Cyclic link detected for wikilink');
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import { retrieveNoteConfig } from './wikilink-embed';
|
||||
import {
|
||||
WIKILINK_EMBED_REGEX,
|
||||
WIKILINK_EMBED_REGEX_GROUPS,
|
||||
retrieveNoteConfig,
|
||||
} from './wikilink-embed';
|
||||
import * as config from '../../services/config';
|
||||
|
||||
describe('Wikilink Note Embedding', () => {
|
||||
@@ -6,25 +10,81 @@ describe('Wikilink Note Embedding', () => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('Wikilink Parsing', () => {
|
||||
it('should match a wikilink item including a modifier and wikilink', () => {
|
||||
// no configuration
|
||||
expect('![[note-a]]').toMatch(WIKILINK_EMBED_REGEX);
|
||||
|
||||
// one of the configurations
|
||||
expect('full![[note-a]]').toMatch(WIKILINK_EMBED_REGEX);
|
||||
expect('content![[note-a]]').toMatch(WIKILINK_EMBED_REGEX);
|
||||
expect('inline![[note-a]]').toMatch(WIKILINK_EMBED_REGEX);
|
||||
expect('card![[note-a]]').toMatch(WIKILINK_EMBED_REGEX);
|
||||
|
||||
// any combination of configurations
|
||||
expect('full-inline![[note-a]]').toMatch(WIKILINK_EMBED_REGEX);
|
||||
expect('full-card![[note-a]]').toMatch(WIKILINK_EMBED_REGEX);
|
||||
expect('content-inline![[note-a]]').toMatch(WIKILINK_EMBED_REGEX);
|
||||
expect('content-card![[note-a]]').toMatch(WIKILINK_EMBED_REGEX);
|
||||
});
|
||||
|
||||
it('should only match the wikilink if there are unrecognized keywords', () => {
|
||||
const match1 = 'random-word![[note-a]]'.match(WIKILINK_EMBED_REGEX);
|
||||
expect(match1[0]).toEqual('![[note-a]]');
|
||||
expect(match1[1]).toEqual('![[note-a]]');
|
||||
|
||||
const match2 = 'foo![[note-a#section 1]]'.match(WIKILINK_EMBED_REGEX);
|
||||
expect(match2[0]).toEqual('![[note-a#section 1]]');
|
||||
expect(match2[1]).toEqual('![[note-a#section 1]]');
|
||||
});
|
||||
|
||||
it('should group the wikilink into modifier and wikilink', () => {
|
||||
const match1 = 'content![[note-a]]'.match(WIKILINK_EMBED_REGEX_GROUPS);
|
||||
expect(match1[0]).toEqual('content![[note-a]]');
|
||||
expect(match1[1]).toEqual('content');
|
||||
expect(match1[2]).toEqual('note-a');
|
||||
|
||||
const match2 = 'full-inline![[note-a#section 1]]'.match(
|
||||
WIKILINK_EMBED_REGEX_GROUPS
|
||||
);
|
||||
expect(match2[0]).toEqual('full-inline![[note-a#section 1]]');
|
||||
expect(match2[1]).toEqual('full-inline');
|
||||
expect(match2[2]).toEqual('note-a#section 1');
|
||||
|
||||
const match3 = '![[note-a#section 1]]'.match(WIKILINK_EMBED_REGEX_GROUPS);
|
||||
expect(match3[0]).toEqual('![[note-a#section 1]]');
|
||||
expect(match3[1]).toEqual(undefined);
|
||||
expect(match3[2]).toEqual('note-a#section 1');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Config Parsing', () => {
|
||||
it('should use preview.embedNoteType if deprecated preview.embedNoteInContainer not used', () => {
|
||||
it('should use preview.embedNoteType if an explicit modifier is not passed in', () => {
|
||||
jest
|
||||
.spyOn(config, 'getFoamVsCodeConfig')
|
||||
.mockReturnValueOnce('full-card')
|
||||
.mockReturnValueOnce(false);
|
||||
.mockReturnValueOnce('full-card');
|
||||
|
||||
const { noteScope, noteStyle } = retrieveNoteConfig();
|
||||
const { noteScope, noteStyle } = retrieveNoteConfig(undefined);
|
||||
expect(noteScope).toEqual('full');
|
||||
expect(noteStyle).toEqual('card');
|
||||
});
|
||||
|
||||
it('should use preview.embedNoteInContainer if set', () => {
|
||||
it('should use explicit modifier over user settings if passed in', () => {
|
||||
jest
|
||||
.spyOn(config, 'getFoamVsCodeConfig')
|
||||
.mockReturnValueOnce('full-inline')
|
||||
.mockReturnValueOnce(true);
|
||||
.mockReturnValueOnce('full-inline')
|
||||
.mockReturnValueOnce('full-inline');
|
||||
|
||||
const { noteScope, noteStyle } = retrieveNoteConfig();
|
||||
let { noteScope, noteStyle } = retrieveNoteConfig('content-card');
|
||||
expect(noteScope).toEqual('content');
|
||||
expect(noteStyle).toEqual('card');
|
||||
|
||||
({ noteScope, noteStyle } = retrieveNoteConfig('content'));
|
||||
expect(noteScope).toEqual('content');
|
||||
expect(noteStyle).toEqual('inline');
|
||||
|
||||
({ noteScope, noteStyle } = retrieveNoteConfig('card'));
|
||||
expect(noteScope).toEqual('full');
|
||||
expect(noteStyle).toEqual('card');
|
||||
});
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import { readFileSync } from 'fs';
|
||||
import { workspace as vsWorkspace } from 'vscode';
|
||||
import markdownItRegex from 'markdown-it-regex';
|
||||
import { isSome } from '../../utils';
|
||||
import { isSome, isNone } from '../../utils';
|
||||
import { FoamWorkspace } from '../../core/model/workspace';
|
||||
import { Logger } from '../../core/utils/log';
|
||||
import { Resource, ResourceParser } from '../../core/model/note';
|
||||
@@ -14,7 +14,13 @@ import { MarkdownLink } from '../../core/services/markdown-link';
|
||||
import { Position } from '../../core/model/position';
|
||||
import { TextEdit } from '../../core/services/text-edit';
|
||||
|
||||
export const CONFIG_EMBED_NOTE_IN_CONTAINER = 'preview.embedNoteInContainer';
|
||||
export const WIKILINK_EMBED_REGEX =
|
||||
/((?:(?:full|content)-(?:inline|card)|full|content|inline|card)?!\[\[[^[\]]+?\]\])/;
|
||||
// we need another regex because md.use(regex, replace) only permits capturing one group
|
||||
// so we capture the entire possible wikilink item (ex. content-card![[note]]) using WIKILINK_EMBED_REGEX and then
|
||||
// use WIKILINK_EMBED_REGEX_GROUPER to parse it into the modifier(content-card) and the wikilink(note)
|
||||
export const WIKILINK_EMBED_REGEX_GROUPS =
|
||||
/((?:\w+)|(?:(?:\w+)-(?:\w+)))?!\[\[([^[\]]+?)\]\]/;
|
||||
export const CONFIG_EMBED_NOTE_TYPE = 'preview.embedNoteType';
|
||||
const refsStack: string[] = [];
|
||||
|
||||
@@ -25,9 +31,13 @@ export const markdownItWikilinkEmbed = (
|
||||
) => {
|
||||
return md.use(markdownItRegex, {
|
||||
name: 'embed-wikilinks',
|
||||
regex: /!\[\[([^[\]]+?)\]\]/,
|
||||
replace: (wikilink: string) => {
|
||||
regex: WIKILINK_EMBED_REGEX,
|
||||
replace: (wikilinkItem: string) => {
|
||||
try {
|
||||
const [_, noteEmbedModifier, wikilink] = wikilinkItem.match(
|
||||
WIKILINK_EMBED_REGEX_GROUPS
|
||||
);
|
||||
|
||||
const includedNote = workspace.find(wikilink);
|
||||
|
||||
if (!includedNote) {
|
||||
@@ -50,7 +60,8 @@ export const markdownItWikilinkEmbed = (
|
||||
|
||||
switch (includedNote.type) {
|
||||
case 'note': {
|
||||
const { noteScope, noteStyle } = retrieveNoteConfig();
|
||||
const { noteScope, noteStyle } =
|
||||
retrieveNoteConfig(noteEmbedModifier);
|
||||
|
||||
const extractor: EmbedNoteExtractor =
|
||||
noteScope === 'full'
|
||||
@@ -89,7 +100,7 @@ Embed for attachments is not supported
|
||||
return html;
|
||||
} catch (e) {
|
||||
Logger.error(
|
||||
`Error while including [[${wikilink}]] into the current document of the Preview panel`,
|
||||
`Error while including ${wikilinkItem} into the current document of the Preview panel`,
|
||||
e
|
||||
);
|
||||
return '';
|
||||
@@ -111,6 +122,11 @@ function withLinksRelativeToWorkspaceRoot(
|
||||
.map(link => {
|
||||
const info = MarkdownLink.analyzeLink(link);
|
||||
const resource = workspace.find(info.target);
|
||||
// embedded notes that aren't created are still collected
|
||||
// return null so it can be filtered in the next step
|
||||
if (isNone(resource)) {
|
||||
return null;
|
||||
}
|
||||
const pathFromRoot = vsWorkspace.asRelativePath(
|
||||
toVsCodeUri(resource.uri)
|
||||
);
|
||||
@@ -118,6 +134,7 @@ function withLinksRelativeToWorkspaceRoot(
|
||||
target: pathFromRoot,
|
||||
});
|
||||
})
|
||||
.filter(linkEdits => !isNone(linkEdits))
|
||||
.sort((a, b) => Position.compareTo(b.range.start, a.range.start));
|
||||
const text = edits.reduce(
|
||||
(text, edit) => TextEdit.apply(text, edit),
|
||||
@@ -126,17 +143,22 @@ function withLinksRelativeToWorkspaceRoot(
|
||||
return text;
|
||||
}
|
||||
|
||||
export function retrieveNoteConfig(): {
|
||||
export function retrieveNoteConfig(explicitModifier: string | undefined): {
|
||||
noteScope: string;
|
||||
noteStyle: string;
|
||||
} {
|
||||
let config = getFoamVsCodeConfig<string>(CONFIG_EMBED_NOTE_TYPE); // ex. full-inline
|
||||
let [noteScope, noteStyle] = config.split('-');
|
||||
|
||||
// **DEPRECATED** setting to be removed
|
||||
// for now it overrides the above to preserve user settings if they have it set
|
||||
if (getFoamVsCodeConfig<boolean>(CONFIG_EMBED_NOTE_IN_CONTAINER, false)) {
|
||||
noteStyle = 'card';
|
||||
// an explicit modifier will always override corresponding user setting
|
||||
if (explicitModifier !== undefined) {
|
||||
if (['full', 'content'].includes(explicitModifier)) {
|
||||
noteScope = explicitModifier;
|
||||
} else if (['card', 'inline'].includes(explicitModifier)) {
|
||||
noteStyle = explicitModifier;
|
||||
} else {
|
||||
[noteScope, noteStyle] = explicitModifier.split('-');
|
||||
}
|
||||
}
|
||||
return { noteScope, noteStyle };
|
||||
}
|
||||
|
||||
@@ -26,9 +26,9 @@ describe('Link generation in preview', () => {
|
||||
markdownItRemoveLinkReferences,
|
||||
].reduce((acc, extension) => extension(acc, ws), MarkdownIt());
|
||||
|
||||
it('generates a link to a note', () => {
|
||||
it('generates a link to a note using the note title as link', () => {
|
||||
expect(md.render(`[[note-a]]`)).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></p>\n`
|
||||
`<p><a class='foam-note-link' title='${noteA.title}' href='/path/to/note-a.md' data-href='/path/to/note-a.md'>${noteA.title}</a></p>\n`
|
||||
);
|
||||
});
|
||||
|
||||
@@ -48,13 +48,22 @@ describe('Link generation in preview', () => {
|
||||
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]: <note-a.md> "Note A"</p>\n`
|
||||
`<p><a class='foam-note-link' title='${noteA.title}' href='/path/to/note-a.md' data-href='/path/to/note-a.md'>${noteA.title}</a>\n[note-a]: <note-a.md> "Note A"</p>\n`
|
||||
);
|
||||
});
|
||||
|
||||
it('generates a link to a section within the note', () => {
|
||||
expect(md.render(`[[#sec]]`)).toEqual(
|
||||
`<p><a class='foam-note-link' title='sec' href='#sec' data-href='#sec'>#sec</a></p>\n`
|
||||
);
|
||||
expect(md.render(`[[#Section Name]]`)).toEqual(
|
||||
`<p><a class='foam-note-link' title='Section Name' href='#section-name' data-href='#section-name'>#Section Name</a></p>\n`
|
||||
);
|
||||
});
|
||||
|
||||
it('generates a link to a note with a specific section', () => {
|
||||
expect(md.render(`[[note-b#sec2]]`)).toEqual(
|
||||
`<p><a class='foam-note-link' title='My second note#sec2' href='/path2/to/note-b.md#sec2' data-href='/path2/to/note-b.md#sec2'>note-b#sec2</a></p>\n`
|
||||
`<p><a class='foam-note-link' title='My second note#sec2' href='/path2/to/note-b.md#sec2' data-href='/path2/to/note-b.md#sec2'>${noteB.title}#sec2</a></p>\n`
|
||||
);
|
||||
});
|
||||
|
||||
@@ -66,7 +75,7 @@ describe('Link generation in preview', () => {
|
||||
|
||||
it('generates a link to a note if the note exists, but the section does not exist', () => {
|
||||
expect(md.render(`[[note-b#nonexistentsec]]`)).toEqual(
|
||||
`<p><a class='foam-note-link' title='My second note#nonexistentsec' href='/path2/to/note-b.md#nonexistentsec' data-href='/path2/to/note-b.md#nonexistentsec'>note-b#nonexistentsec</a></p>\n`
|
||||
`<p><a class='foam-note-link' title='My second note#nonexistentsec' href='/path2/to/note-b.md#nonexistentsec' data-href='/path2/to/note-b.md#nonexistentsec'>${noteB.title}#nonexistentsec</a></p>\n`
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import { toVsCodeUri } from '../../utils/vsc-utils';
|
||||
import { MarkdownLink } from '../../core/services/markdown-link';
|
||||
import { Range } from '../../core/model/range';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { toSlug } from '../../utils/slug';
|
||||
|
||||
export const markdownItWikilinkNavigation = (
|
||||
md: markdownit,
|
||||
@@ -26,18 +27,32 @@ export const markdownItWikilinkNavigation = (
|
||||
isEmbed: false,
|
||||
});
|
||||
const formattedSection = section ? `#${section}` : '';
|
||||
const linkSection = section ? `#${toSlug(section)}` : '';
|
||||
const label = isEmpty(alias) ? `${target}${formattedSection}` : alias;
|
||||
|
||||
// [[#section]] links
|
||||
if (target.length === 0) {
|
||||
// we don't have a good way to check if the section exists within the
|
||||
// open file, so we just create a regular link for it
|
||||
return getResourceLink(section, linkSection, label);
|
||||
}
|
||||
|
||||
const resource = workspace.find(target);
|
||||
if (isNone(resource)) {
|
||||
return getPlaceholderLink(label);
|
||||
}
|
||||
|
||||
const link = `${vscode.workspace.asRelativePath(
|
||||
const resourceLabel = isEmpty(alias)
|
||||
? `${resource.title}${formattedSection}`
|
||||
: alias;
|
||||
const resourceLink = `/${vscode.workspace.asRelativePath(
|
||||
toVsCodeUri(resource.uri)
|
||||
)}${formattedSection}`;
|
||||
const title = `${resource.title}${formattedSection}`;
|
||||
return `<a class='foam-note-link' title='${title}' href='/${link}' data-href='/${link}'>${label}</a>`;
|
||||
)}`;
|
||||
return getResourceLink(
|
||||
`${resource.title}${formattedSection}`,
|
||||
`${resourceLink}${linkSection}`,
|
||||
resourceLabel
|
||||
);
|
||||
} catch (e) {
|
||||
Logger.error(
|
||||
`Error while creating link for [[${wikilink}]] in Preview panel`,
|
||||
@@ -52,4 +67,7 @@ export const markdownItWikilinkNavigation = (
|
||||
const getPlaceholderLink = (content: string) =>
|
||||
`<a class='foam-placeholder-link' title="Link to non-existing resource" href="javascript:void(0);">${content}</a>`;
|
||||
|
||||
const getResourceLink = (title: string, link: string, label: string) =>
|
||||
`<a class='foam-note-link' title='${title}' href='${link}' data-href='${link}'>${label}</a>`;
|
||||
|
||||
export default markdownItWikilinkNavigation;
|
||||
|
||||
@@ -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 -->
|
||||
[](#contributors-)
|
||||
[](#contributors-)
|
||||
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
||||
|
||||
[](https://marketplace.visualstudio.com/items?itemName=foam.foam-vscode)
|
||||
@@ -347,6 +347,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://amnesiak.org/me"><img src="https://avatars.githubusercontent.com/u/952059?v=4?s=60" width="60px;" alt="Tony Cheneau"/><br /><sub><b>Tony Cheneau</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=tcheneau" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/nicholas-l"><img src="https://avatars.githubusercontent.com/u/12977174?v=4?s=60" width="60px;" alt="Nicholas Latham"/><br /><sub><b>Nicholas Latham</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=nicholas-l" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://thara.dev"><img src="https://avatars.githubusercontent.com/u/1532891?v=4?s=60" width="60px;" alt="Tomochika Hara"/><br /><sub><b>Tomochika Hara</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=thara" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/dcarosone"><img src="https://avatars.githubusercontent.com/u/11495017?v=4?s=60" width="60px;" alt="Daniel Carosone"/><br /><sub><b>Daniel Carosone</b></sub></a><br /><a href="https://github.com/foambubble/foam/commits?author=dcarosone" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
Reference in New Issue
Block a user