Skip to content

Commit 6c1d686

Browse files
authored
Feat #879: Different embedding styles prep (#1273)
* Refactor note embedding to be extensible * Prepare new setting to replace preview.embedNoteInContainer * Fix wikilink-embed e2e tests * Improve readability * Set embedNoteInContainer to null in e2e tests to more closely mimic live state
1 parent e773e1f commit 6c1d686

File tree

4 files changed

+178
-54
lines changed

4 files changed

+178
-54
lines changed

packages/foam-vscode/package.json

+14-1
Original file line numberDiff line numberDiff line change
@@ -570,7 +570,20 @@
570570
"foam.preview.embedNoteInContainer": {
571571
"type": "boolean",
572572
"default": true,
573-
"description": "Wrap embedded notes in a container when displayed in preview panel"
573+
"description": "Wrap embedded notes in a container when displayed in preview panel",
574+
"deprecationMessage": "*DEPRECATED* use foam.preview.embedNoteType instead."
575+
},
576+
"foam.preview.embedNoteType": {
577+
"type": "string",
578+
"default": "full-card",
579+
"enum": [
580+
"full-inline",
581+
"full-card"
582+
],
583+
"enumDescriptions": [
584+
"Include the section with title and style inline",
585+
"Include the section with title and style it within a container"
586+
]
574587
},
575588
"foam.graph.titleMaxLength": {
576589
"type": "number",

packages/foam-vscode/src/features/preview/wikilink-embed.spec.ts

+58-33
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
} from '../../test/test-utils-vscode';
99
import {
1010
default as markdownItWikilinkEmbed,
11+
CONFIG_EMBED_NOTE_TYPE,
1112
CONFIG_EMBED_NOTE_IN_CONTAINER,
1213
} from './wikilink-embed';
1314

@@ -22,18 +23,24 @@ describe('Displaying included notes in preview', () => {
2223
const ws = new FoamWorkspace().set(parser.parse(note.uri, note.content));
2324
await withModifiedFoamConfiguration(
2425
CONFIG_EMBED_NOTE_IN_CONTAINER,
25-
false,
26-
() => {
27-
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);
28-
29-
expect(
30-
md.render(`This is the root node.
26+
null,
27+
async () => {
28+
await withModifiedFoamConfiguration(
29+
CONFIG_EMBED_NOTE_TYPE,
30+
'full-inline',
31+
() => {
32+
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);
33+
34+
expect(
35+
md.render(`This is the root node.
3136
3237
![[note-a]]`)
33-
).toMatch(
34-
`<p>This is the root node.</p>
38+
).toMatch(
39+
`<p>This is the root node.</p>
3540
<p><p>This is the text of note A</p>
3641
</p>`
42+
);
43+
}
3744
);
3845
}
3946
);
@@ -47,16 +54,22 @@ describe('Displaying included notes in preview', () => {
4754
]);
4855
const ws = new FoamWorkspace().set(parser.parse(note.uri, note.content));
4956

50-
await await withModifiedFoamConfiguration(
57+
await withModifiedFoamConfiguration(
5158
CONFIG_EMBED_NOTE_IN_CONTAINER,
52-
true,
53-
() => {
54-
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);
55-
56-
const res = md.render(`This is the root node. ![[note-a]]`);
57-
expect(res).toContain('This is the root node');
58-
expect(res).toContain('embed-container-note');
59-
expect(res).toContain('This is the text of note A');
59+
null,
60+
async () => {
61+
await withModifiedFoamConfiguration(
62+
CONFIG_EMBED_NOTE_TYPE,
63+
'full-card',
64+
() => {
65+
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);
66+
67+
const res = md.render(`This is the root node. ![[note-a]]`);
68+
expect(res).toContain('This is the root node');
69+
expect(res).toContain('embed-container-note');
70+
expect(res).toContain('This is the text of note A');
71+
}
72+
);
6073
}
6174
);
6275
await deleteFile(note);
@@ -84,17 +97,23 @@ This is the third section of note E
8497

8598
await withModifiedFoamConfiguration(
8699
CONFIG_EMBED_NOTE_IN_CONTAINER,
87-
false,
88-
() => {
89-
expect(
90-
md.render(`This is the root node.
100+
null,
101+
async () => {
102+
await withModifiedFoamConfiguration(
103+
CONFIG_EMBED_NOTE_TYPE,
104+
'full-inline',
105+
() => {
106+
expect(
107+
md.render(`This is the root node.
91108
92109
![[note-e#Section 2]]`)
93-
).toMatch(
94-
`<p>This is the root node.</p>
110+
).toMatch(
111+
`<p>This is the root node.</p>
95112
<p><h1>Section 2</h1>
96113
<p>This is the second section of note E</p>
97114
</p>`
115+
);
116+
}
98117
);
99118
}
100119
);
@@ -121,17 +140,23 @@ This is the third section of note E
121140

122141
await withModifiedFoamConfiguration(
123142
CONFIG_EMBED_NOTE_IN_CONTAINER,
124-
true,
125-
() => {
126-
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);
127-
128-
const res = md.render(
129-
`This is the root node. ![[note-e-container#Section 3]]`
143+
null,
144+
async () => {
145+
await withModifiedFoamConfiguration(
146+
CONFIG_EMBED_NOTE_TYPE,
147+
'full-card',
148+
() => {
149+
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);
150+
151+
const res = md.render(
152+
`This is the root node. ![[note-e-container#Section 3]]`
153+
);
154+
expect(res).toContain('This is the root node');
155+
expect(res).toContain('embed-container-note');
156+
expect(res).toContain('Section 3');
157+
expect(res).toContain('This is the third section of note E');
158+
}
130159
);
131-
expect(res).toContain('This is the root node');
132-
expect(res).toContain('embed-container-note');
133-
expect(res).toContain('Section 3');
134-
expect(res).toContain('This is the third section of note E');
135160
}
136161
);
137162

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { retrieveNoteConfig } from './wikilink-embed';
2+
import * as config from '../../services/config';
3+
4+
describe('Wikilink Note Embedding', () => {
5+
afterEach(() => {
6+
jest.clearAllMocks();
7+
});
8+
9+
describe('Config Parsing', () => {
10+
it('should use preview.embedNoteType if deprecated preview.embedNoteInContainer not used', () => {
11+
jest
12+
.spyOn(config, 'getFoamVsCodeConfig')
13+
.mockReturnValueOnce('full-card')
14+
.mockReturnValueOnce(false);
15+
16+
const { noteScope, noteStyle } = retrieveNoteConfig();
17+
expect(noteScope).toEqual('full');
18+
expect(noteStyle).toEqual('card');
19+
});
20+
21+
it('should use preview.embedNoteInContainer if set', () => {
22+
jest
23+
.spyOn(config, 'getFoamVsCodeConfig')
24+
.mockReturnValueOnce('full-inline')
25+
.mockReturnValueOnce(true);
26+
27+
const { noteScope, noteStyle } = retrieveNoteConfig();
28+
expect(noteScope).toEqual('full');
29+
expect(noteStyle).toEqual('card');
30+
});
31+
});
32+
});

packages/foam-vscode/src/features/preview/wikilink-embed.ts

+74-20
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { Position } from '../../core/model/position';
1515
import { TextEdit } from '../../core/services/text-edit';
1616

1717
export const CONFIG_EMBED_NOTE_IN_CONTAINER = 'preview.embedNoteInContainer';
18+
export const CONFIG_EMBED_NOTE_TYPE = 'preview.embedNoteType';
1819
const refsStack: string[] = [];
1920

2021
export const markdownItWikilinkEmbed = (
@@ -45,27 +46,23 @@ export const markdownItWikilinkEmbed = (
4546
return `<div class="foam-cyclic-link-warning">Cyclic link detected for wikilink: ${wikilink}</div>`;
4647
}
4748
let content = `Embed for [[${wikilink}]]`;
49+
let html: string;
50+
4851
switch (includedNote.type) {
4952
case 'note': {
50-
let noteText = readFileSync(includedNote.uri.toFsPath()).toString();
51-
const section = Resource.findSection(
52-
includedNote,
53-
includedNote.uri.fragment
54-
);
55-
if (isSome(section)) {
56-
const rows = noteText.split('\n');
57-
noteText = rows
58-
.slice(section.range.start.line, section.range.end.line)
59-
.join('\n');
60-
}
61-
noteText = withLinksRelativeToWorkspaceRoot(
62-
noteText,
63-
parser,
64-
workspace
65-
);
66-
content = getFoamVsCodeConfig(CONFIG_EMBED_NOTE_IN_CONTAINER)
67-
? `<div class="embed-container-note">${md.render(noteText)}</div>`
68-
: noteText;
53+
const { noteScope: _, noteStyle } = retrieveNoteConfig();
54+
55+
const extractor: EmbedNoteExtractor = fullExtractor;
56+
57+
const formatter: EmbedNoteFormatter =
58+
noteStyle === 'card'
59+
? cardFormatter
60+
: noteStyle === 'inline'
61+
? inlineFormatter
62+
: cardFormatter;
63+
64+
content = extractor(includedNote, parser, workspace);
65+
html = formatter(content, md);
6966
break;
7067
}
7168
case 'attachment':
@@ -74,14 +71,15 @@ export const markdownItWikilinkEmbed = (
7471
${md.renderInline('[[' + wikilink + ']]')}<br/>
7572
Embed for attachments is not supported
7673
</div>`;
74+
html = md.render(content);
7775
break;
7876
case 'image':
7977
content = `<div class="embed-container-image">${md.render(
8078
`![](${md.normalizeLink(includedNote.uri.path)})`
8179
)}</div>`;
80+
html = md.render(content);
8281
break;
8382
}
84-
const html = md.render(content);
8583
refsStack.pop();
8684
return html;
8785
} catch (e) {
@@ -123,4 +121,60 @@ function withLinksRelativeToWorkspaceRoot(
123121
return text;
124122
}
125123

124+
export function retrieveNoteConfig(): {
125+
noteScope: string;
126+
noteStyle: string;
127+
} {
128+
let config = getFoamVsCodeConfig<string>(CONFIG_EMBED_NOTE_TYPE); // ex. full-inline
129+
let [noteScope, noteStyle] = config.split('-');
130+
131+
// **DEPRECATED** setting to be removed
132+
// for now it overrides the above to preserve user settings if they have it set
133+
if (getFoamVsCodeConfig<boolean>(CONFIG_EMBED_NOTE_IN_CONTAINER, false)) {
134+
noteStyle = 'card';
135+
}
136+
return { noteScope, noteStyle };
137+
}
138+
139+
/**
140+
* A type of function that gets the desired content of the note
141+
*/
142+
export type EmbedNoteExtractor = (
143+
note: Resource,
144+
parser: ResourceParser,
145+
workspace: FoamWorkspace
146+
) => string;
147+
148+
function fullExtractor(
149+
note: Resource,
150+
parser: ResourceParser,
151+
workspace: FoamWorkspace
152+
): string {
153+
let noteText = readFileSync(note.uri.toFsPath()).toString();
154+
const section = Resource.findSection(note, note.uri.fragment);
155+
if (isSome(section)) {
156+
const rows = noteText.split('\n');
157+
noteText = rows
158+
.slice(section.range.start.line, section.range.end.line)
159+
.join('\n');
160+
}
161+
noteText = withLinksRelativeToWorkspaceRoot(noteText, parser, workspace);
162+
return noteText;
163+
}
164+
165+
/**
166+
* A type of function that renders note content with the desired style in html
167+
*/
168+
export type EmbedNoteFormatter = (content: string, md: markdownit) => string;
169+
170+
function cardFormatter(content: string, md: markdownit): string {
171+
return md.render(
172+
`<div class="embed-container-note">${md.render(content)}</div>`
173+
);
174+
}
175+
176+
function inlineFormatter(content: string, md: markdownit): string {
177+
return md.render(content);
178+
}
179+
126180
export default markdownItWikilinkEmbed;

0 commit comments

Comments
 (0)