Skip to content

Commit eee364d

Browse files
authored
Feat #879: Content embedding style (#1279)
* Add content extractor and enable it as an option for note embed type * Fix content extractor edgecase where note title has lines above it
1 parent 3ed2bcd commit eee364d

File tree

3 files changed

+225
-15
lines changed

3 files changed

+225
-15
lines changed

packages/foam-vscode/package.json

+6-2
Original file line numberDiff line numberDiff line change
@@ -578,11 +578,15 @@
578578
"default": "full-card",
579579
"enum": [
580580
"full-inline",
581-
"full-card"
581+
"full-card",
582+
"content-inline",
583+
"content-card"
582584
],
583585
"enumDescriptions": [
584586
"Include the section with title and style inline",
585-
"Include the section with title and style it within a container"
587+
"Include the section with title and style it within a container",
588+
"Include the section without title and style inline",
589+
"Include the section without title and style it within a container"
586590
]
587591
},
588592
"foam.graph.titleMaxLength": {

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

+186-11
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {
1515
const parser = createMarkdownParser();
1616

1717
describe('Displaying included notes in preview', () => {
18-
it('should render an included note in flat mode', async () => {
18+
it('should render an included note in full inline mode', async () => {
1919
const note = await createFile('This is the text of note A', [
2020
'preview',
2121
'note-a.md',
@@ -47,7 +47,7 @@ describe('Displaying included notes in preview', () => {
4747
await deleteFile(note);
4848
});
4949

50-
it('should render an included note in container mode', async () => {
50+
it('should render an included note in full card mode', async () => {
5151
const note = await createFile('This is the text of note A', [
5252
'preview',
5353
'note-a.md',
@@ -75,7 +75,7 @@ describe('Displaying included notes in preview', () => {
7575
await deleteFile(note);
7676
});
7777

78-
it('should render an included section', async () => {
78+
it('should render an included section in full inline mode', async () => {
7979
// here we use createFile as the test note doesn't fill in
8080
// all the metadata we need
8181
const note = await createFile(
@@ -121,7 +121,7 @@ This is the third section of note E
121121
await deleteFile(note);
122122
});
123123

124-
it('should render an included section in container mode', async () => {
124+
it('should render an included section in full card mode', async () => {
125125
const note = await createFile(
126126
`
127127
# Section 1
@@ -163,6 +163,168 @@ This is the third section of note E
163163
await deleteFile(note);
164164
});
165165

166+
it('should not render the title of a note in content inline mode', async () => {
167+
const note = await createFile(
168+
`
169+
# Title
170+
## Section 1
171+
172+
This is the first section of note E`,
173+
['note-e.md']
174+
);
175+
const parser = createMarkdownParser([]);
176+
const ws = new FoamWorkspace().set(parser.parse(note.uri, note.content));
177+
178+
await withModifiedFoamConfiguration(
179+
CONFIG_EMBED_NOTE_IN_CONTAINER,
180+
null,
181+
async () => {
182+
await withModifiedFoamConfiguration(
183+
CONFIG_EMBED_NOTE_TYPE,
184+
'content-inline',
185+
() => {
186+
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);
187+
188+
expect(
189+
md.render(`This is the root node.
190+
191+
![[note-e]]`)
192+
).toMatch(
193+
`<p>This is the root node.</p>
194+
<p><h2>Section 1</h2>
195+
<p>This is the first section of note E</p>
196+
</p>`
197+
);
198+
}
199+
);
200+
}
201+
);
202+
203+
await deleteFile(note);
204+
});
205+
206+
it('should not render the title of a note in content card mode', async () => {
207+
const note = await createFile(
208+
`# Title
209+
## Section 1
210+
211+
This is the first section of note E
212+
`,
213+
['note-e.md']
214+
);
215+
const parser = createMarkdownParser([]);
216+
const ws = new FoamWorkspace().set(parser.parse(note.uri, note.content));
217+
218+
await withModifiedFoamConfiguration(
219+
CONFIG_EMBED_NOTE_IN_CONTAINER,
220+
null,
221+
async () => {
222+
await withModifiedFoamConfiguration(
223+
CONFIG_EMBED_NOTE_TYPE,
224+
'content-card',
225+
() => {
226+
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);
227+
228+
const res = md.render(`This is the root node. ![[note-e.md]]`);
229+
230+
expect(res).toContain('This is the root node');
231+
expect(res).toContain('embed-container-note');
232+
expect(res).toContain('Section 1');
233+
expect(res).toContain('This is the first section of note E');
234+
expect(res).not.toContain('Title');
235+
}
236+
);
237+
}
238+
);
239+
240+
await deleteFile(note);
241+
});
242+
243+
it('should not render the section title, but still render subsection titles in content inline mode', async () => {
244+
const note = await createFile(
245+
`# Title
246+
247+
248+
## Section 1
249+
This is the first section of note E
250+
251+
### Subsection a
252+
This is the first subsection of note E
253+
`,
254+
['note-e.md']
255+
);
256+
const parser = createMarkdownParser([]);
257+
const ws = new FoamWorkspace().set(parser.parse(note.uri, note.content));
258+
259+
await withModifiedFoamConfiguration(
260+
CONFIG_EMBED_NOTE_IN_CONTAINER,
261+
null,
262+
async () => {
263+
await withModifiedFoamConfiguration(
264+
CONFIG_EMBED_NOTE_TYPE,
265+
'content-inline',
266+
() => {
267+
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);
268+
269+
expect(
270+
md.render(`This is the root node.
271+
272+
![[note-e#Section 1]]`)
273+
).toMatch(
274+
`<p>This is the root node.</p>
275+
<p><p>This is the first section of note E</p>
276+
<h3>Subsection a</h3>
277+
<p>This is the first subsection of note E</p>
278+
</p>`
279+
);
280+
}
281+
);
282+
}
283+
);
284+
285+
await deleteFile(note);
286+
});
287+
288+
it('should not render the subsection title in content mode if you link to it and regardless of its level', async () => {
289+
const note = await createFile(
290+
`# Title
291+
## Section 1
292+
This is the first section of note E
293+
294+
### Subsection a
295+
This is the first subsection of note E`,
296+
['note-e.md']
297+
);
298+
const parser = createMarkdownParser([]);
299+
const ws = new FoamWorkspace().set(parser.parse(note.uri, note.content));
300+
301+
await withModifiedFoamConfiguration(
302+
CONFIG_EMBED_NOTE_IN_CONTAINER,
303+
null,
304+
async () => {
305+
await withModifiedFoamConfiguration(
306+
CONFIG_EMBED_NOTE_TYPE,
307+
'content-inline',
308+
() => {
309+
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);
310+
311+
expect(
312+
md.render(`This is the root node.
313+
314+
![[note-e#Subsection a]]`)
315+
).toMatch(
316+
`<p>This is the root node.</p>
317+
<p><p>This is the first subsection of note E</p>
318+
</p>`
319+
);
320+
}
321+
);
322+
}
323+
);
324+
325+
await deleteFile(note);
326+
});
327+
166328
it('should fallback to the bare text when the note is not found', () => {
167329
const md = markdownItWikilinkEmbed(
168330
MarkdownIt(),
@@ -187,14 +349,27 @@ This is the third section of note E
187349
const ws = new FoamWorkspace()
188350
.set(parser.parse(noteA.uri, noteA.content))
189351
.set(parser.parse(noteB.uri, noteB.content));
190-
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);
191-
const res = md.render(noteBText);
192352

193-
expect(res).toContain('This is the text of note B which includes');
194-
expect(res).toContain('This is the text of note A which includes');
195-
expect(res).toContain('Cyclic link detected for wikilink');
353+
await withModifiedFoamConfiguration(
354+
CONFIG_EMBED_NOTE_IN_CONTAINER,
355+
null,
356+
async () => {
357+
await withModifiedFoamConfiguration(
358+
CONFIG_EMBED_NOTE_TYPE,
359+
'full-card',
360+
() => {
361+
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);
362+
const res = md.render(noteBText);
363+
364+
expect(res).toContain('This is the text of note B which includes');
365+
expect(res).toContain('This is the text of note A which includes');
366+
expect(res).toContain('Cyclic link detected for wikilink');
367+
}
368+
);
369+
}
370+
);
196371

197-
deleteFile(noteA);
198-
deleteFile(noteB);
372+
await deleteFile(noteA);
373+
await deleteFile(noteB);
199374
});
200375
});

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

+33-2
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,14 @@ export const markdownItWikilinkEmbed = (
5050

5151
switch (includedNote.type) {
5252
case 'note': {
53-
const { noteScope: _, noteStyle } = retrieveNoteConfig();
53+
const { noteScope, noteStyle } = retrieveNoteConfig();
5454

55-
const extractor: EmbedNoteExtractor = fullExtractor;
55+
const extractor: EmbedNoteExtractor =
56+
noteScope === 'full'
57+
? fullExtractor
58+
: noteScope === 'content'
59+
? contentExtractor
60+
: fullExtractor;
5661

5762
const formatter: EmbedNoteFormatter =
5863
noteStyle === 'card'
@@ -162,6 +167,32 @@ function fullExtractor(
162167
return noteText;
163168
}
164169

170+
function contentExtractor(
171+
note: Resource,
172+
parser: ResourceParser,
173+
workspace: FoamWorkspace
174+
): string {
175+
let noteText = readFileSync(note.uri.toFsPath()).toString();
176+
let section = Resource.findSection(note, note.uri.fragment);
177+
if (!note.uri.fragment) {
178+
// if there's no fragment(section), the wikilink is linking to the entire note,
179+
// in which case we need to remove the title. We could just use rows.shift()
180+
// but should the note start with blank lines, it will only remove the first blank line
181+
// leaving the title
182+
// A better way is to find where the actual title starts by assuming it's at section[0]
183+
// then we treat it as the same case as link to a section
184+
section = note.sections.length ? note.sections[0] : null;
185+
}
186+
let rows = noteText.split('\n');
187+
if (isSome(section)) {
188+
rows = rows.slice(section.range.start.line, section.range.end.line);
189+
}
190+
rows.shift();
191+
noteText = rows.join('\n');
192+
noteText = withLinksRelativeToWorkspaceRoot(noteText, parser, workspace);
193+
return noteText;
194+
}
195+
165196
/**
166197
* A type of function that renders note content with the desired style in html
167198
*/

0 commit comments

Comments
 (0)