Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat #879: Content embedding style #1279

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions packages/foam-vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -578,11 +578,15 @@
"default": "full-card",
"enum": [
"full-inline",
"full-card"
"full-card",
"content-inline",
"content-card"
],
"enumDescriptions": [
"Include the section with title and style inline",
"Include the section with title and style it within a container"
"Include the section with title and style it within a container",
"Include the section without title and style inline",
"Include the section without title and style it within a container"
]
},
"foam.graph.titleMaxLength": {
Expand Down
197 changes: 186 additions & 11 deletions packages/foam-vscode/src/features/preview/wikilink-embed.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
const parser = createMarkdownParser();

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

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

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

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

it('should not render the title of a note in content inline mode', async () => {
const note = await createFile(
`
# Title
## Section 1

This is the first section of note E`,
['note-e.md']
);
const parser = createMarkdownParser([]);
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);

expect(
md.render(`This is the root node.

![[note-e]]`)
).toMatch(
`<p>This is the root node.</p>
<p><h2>Section 1</h2>
<p>This is the first section of note E</p>
</p>`
);
}
);
}
);

await deleteFile(note);
});

it('should not render the title of a note in content card mode', async () => {
const note = await createFile(
`# Title
## Section 1

This is the first section of note E
`,
['note-e.md']
);
const parser = createMarkdownParser([]);
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);

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');
}
);
}
);

await deleteFile(note);
});

it('should not render the section title, but still render subsection titles in content inline mode', async () => {
const note = await createFile(
`# Title


## Section 1
This is the first section of note E

### Subsection a
This is the first subsection of note E
`,
['note-e.md']
);
const parser = createMarkdownParser([]);
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);

expect(
md.render(`This is the root node.

![[note-e#Section 1]]`)
).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>`
);
}
);
}
);

await deleteFile(note);
});

it('should not render the subsection title in content mode if you link to it and regardless of its level', async () => {
const note = await createFile(
`# Title
## Section 1
This is the first section of note E

### Subsection a
This is the first subsection of note E`,
['note-e.md']
);
const parser = createMarkdownParser([]);
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);

expect(
md.render(`This is the root node.

![[note-e#Subsection a]]`)
).toMatch(
`<p>This is the root node.</p>
<p><p>This is the first subsection of note E</p>
</p>`
);
}
);
}
);

await deleteFile(note);
});

it('should fallback to the bare text when the note is not found', () => {
const md = markdownItWikilinkEmbed(
MarkdownIt(),
Expand All @@ -187,14 +349,27 @@ This is the third section of note E
const ws = new FoamWorkspace()
.set(parser.parse(noteA.uri, noteA.content))
.set(parser.parse(noteB.uri, noteB.content));
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');
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);

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');
}
);
}
);

deleteFile(noteA);
deleteFile(noteB);
await deleteFile(noteA);
await deleteFile(noteB);
});
});
35 changes: 33 additions & 2 deletions packages/foam-vscode/src/features/preview/wikilink-embed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,14 @@ export const markdownItWikilinkEmbed = (

switch (includedNote.type) {
case 'note': {
const { noteScope: _, noteStyle } = retrieveNoteConfig();
const { noteScope, noteStyle } = retrieveNoteConfig();

const extractor: EmbedNoteExtractor = fullExtractor;
const extractor: EmbedNoteExtractor =
noteScope === 'full'
? fullExtractor
: noteScope === 'content'
? contentExtractor
: fullExtractor;

const formatter: EmbedNoteFormatter =
noteStyle === 'card'
Expand Down Expand Up @@ -162,6 +167,32 @@ function fullExtractor(
return noteText;
}

function contentExtractor(
note: Resource,
parser: ResourceParser,
workspace: FoamWorkspace
): string {
let noteText = readFileSync(note.uri.toFsPath()).toString();
let section = Resource.findSection(note, note.uri.fragment);
if (!note.uri.fragment) {
// if there's no fragment(section), the wikilink is linking to the entire note,
// in which case we need to remove the title. We could just use rows.shift()
// but should the note start with blank lines, it will only remove the first blank line
// leaving the title
// A better way is to find where the actual title starts by assuming it's at section[0]
// then we treat it as the same case as link to a section
section = note.sections.length ? note.sections[0] : null;
}
let rows = noteText.split('\n');
if (isSome(section)) {
rows = rows.slice(section.range.start.line, section.range.end.line);
}
rows.shift();
noteText = rows.join('\n');
noteText = withLinksRelativeToWorkspaceRoot(noteText, parser, workspace);
return noteText;
}

/**
* A type of function that renders note content with the desired style in html
*/
Expand Down
Loading