Skip to content

Commit

Permalink
Feat #879: Different embedding styles prep (#1273)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
badsketch authored Aug 23, 2023
1 parent e773e1f commit 6c1d686
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 54 deletions.
15 changes: 14 additions & 1 deletion packages/foam-vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,20 @@
"foam.preview.embedNoteInContainer": {
"type": "boolean",
"default": true,
"description": "Wrap embedded notes in a container when displayed in preview panel"
"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",
"enum": [
"full-inline",
"full-card"
],
"enumDescriptions": [
"Include the section with title and style inline",
"Include the section with title and style it within a container"
]
},
"foam.graph.titleMaxLength": {
"type": "number",
Expand Down
91 changes: 58 additions & 33 deletions packages/foam-vscode/src/features/preview/wikilink-embed.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from '../../test/test-utils-vscode';
import {
default as markdownItWikilinkEmbed,
CONFIG_EMBED_NOTE_TYPE,
CONFIG_EMBED_NOTE_IN_CONTAINER,
} from './wikilink-embed';

Expand All @@ -22,18 +23,24 @@ describe('Displaying included notes in preview', () => {
const ws = new FoamWorkspace().set(parser.parse(note.uri, note.content));
await withModifiedFoamConfiguration(
CONFIG_EMBED_NOTE_IN_CONTAINER,
false,
() => {
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);

expect(
md.render(`This is the root node.
null,
async () => {
await withModifiedFoamConfiguration(
CONFIG_EMBED_NOTE_TYPE,
'full-inline',
() => {
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);

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>`
);
}
);
}
);
Expand All @@ -47,16 +54,22 @@ describe('Displaying included notes in preview', () => {
]);
const ws = new FoamWorkspace().set(parser.parse(note.uri, note.content));

await await withModifiedFoamConfiguration(
await withModifiedFoamConfiguration(
CONFIG_EMBED_NOTE_IN_CONTAINER,
true,
() => {
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');
null,
async () => {
await withModifiedFoamConfiguration(
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');
}
);
}
);
await deleteFile(note);
Expand Down Expand Up @@ -84,17 +97,23 @@ This is the third section of note E

await withModifiedFoamConfiguration(
CONFIG_EMBED_NOTE_IN_CONTAINER,
false,
() => {
expect(
md.render(`This is the root node.
null,
async () => {
await withModifiedFoamConfiguration(
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>`
);
}
);
}
);
Expand All @@ -121,17 +140,23 @@ This is the third section of note E

await withModifiedFoamConfiguration(
CONFIG_EMBED_NOTE_IN_CONTAINER,
true,
() => {
const md = markdownItWikilinkEmbed(MarkdownIt(), ws, parser);

const res = md.render(
`This is the root node. ![[note-e-container#Section 3]]`
null,
async () => {
await withModifiedFoamConfiguration(
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');
}
);
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');
}
);

Expand Down
32 changes: 32 additions & 0 deletions packages/foam-vscode/src/features/preview/wikilink-embed.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { retrieveNoteConfig } from './wikilink-embed';
import * as config from '../../services/config';

describe('Wikilink Note Embedding', () => {
afterEach(() => {
jest.clearAllMocks();
});

describe('Config Parsing', () => {
it('should use preview.embedNoteType if deprecated preview.embedNoteInContainer not used', () => {
jest
.spyOn(config, 'getFoamVsCodeConfig')
.mockReturnValueOnce('full-card')
.mockReturnValueOnce(false);

const { noteScope, noteStyle } = retrieveNoteConfig();
expect(noteScope).toEqual('full');
expect(noteStyle).toEqual('card');
});

it('should use preview.embedNoteInContainer if set', () => {
jest
.spyOn(config, 'getFoamVsCodeConfig')
.mockReturnValueOnce('full-inline')
.mockReturnValueOnce(true);

const { noteScope, noteStyle } = retrieveNoteConfig();
expect(noteScope).toEqual('full');
expect(noteStyle).toEqual('card');
});
});
});
94 changes: 74 additions & 20 deletions packages/foam-vscode/src/features/preview/wikilink-embed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { Position } from '../../core/model/position';
import { TextEdit } from '../../core/services/text-edit';

export const CONFIG_EMBED_NOTE_IN_CONTAINER = 'preview.embedNoteInContainer';
export const CONFIG_EMBED_NOTE_TYPE = 'preview.embedNoteType';
const refsStack: string[] = [];

export const markdownItWikilinkEmbed = (
Expand Down Expand Up @@ -45,27 +46,23 @@ export const markdownItWikilinkEmbed = (
return `<div class="foam-cyclic-link-warning">Cyclic link detected for wikilink: ${wikilink}</div>`;
}
let content = `Embed for [[${wikilink}]]`;
let html: string;

switch (includedNote.type) {
case 'note': {
let noteText = readFileSync(includedNote.uri.toFsPath()).toString();
const section = Resource.findSection(
includedNote,
includedNote.uri.fragment
);
if (isSome(section)) {
const rows = noteText.split('\n');
noteText = rows
.slice(section.range.start.line, section.range.end.line)
.join('\n');
}
noteText = withLinksRelativeToWorkspaceRoot(
noteText,
parser,
workspace
);
content = getFoamVsCodeConfig(CONFIG_EMBED_NOTE_IN_CONTAINER)
? `<div class="embed-container-note">${md.render(noteText)}</div>`
: noteText;
const { noteScope: _, noteStyle } = retrieveNoteConfig();

const extractor: EmbedNoteExtractor = fullExtractor;

const formatter: EmbedNoteFormatter =
noteStyle === 'card'
? cardFormatter
: noteStyle === 'inline'
? inlineFormatter
: cardFormatter;

content = extractor(includedNote, parser, workspace);
html = formatter(content, md);
break;
}
case 'attachment':
Expand All @@ -74,14 +71,15 @@ export const markdownItWikilinkEmbed = (
${md.renderInline('[[' + wikilink + ']]')}<br/>
Embed for attachments is not supported
</div>`;
html = md.render(content);
break;
case 'image':
content = `<div class="embed-container-image">${md.render(
`![](${md.normalizeLink(includedNote.uri.path)})`
)}</div>`;
html = md.render(content);
break;
}
const html = md.render(content);
refsStack.pop();
return html;
} catch (e) {
Expand Down Expand Up @@ -123,4 +121,60 @@ function withLinksRelativeToWorkspaceRoot(
return text;
}

export function retrieveNoteConfig(): {
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';
}
return { noteScope, noteStyle };
}

/**
* A type of function that gets the desired content of the note
*/
export type EmbedNoteExtractor = (
note: Resource,
parser: ResourceParser,
workspace: FoamWorkspace
) => string;

function fullExtractor(
note: Resource,
parser: ResourceParser,
workspace: FoamWorkspace
): string {
let noteText = readFileSync(note.uri.toFsPath()).toString();
const section = Resource.findSection(note, note.uri.fragment);
if (isSome(section)) {
const rows = noteText.split('\n');
noteText = rows
.slice(section.range.start.line, section.range.end.line)
.join('\n');
}
noteText = withLinksRelativeToWorkspaceRoot(noteText, parser, workspace);
return noteText;
}

/**
* A type of function that renders note content with the desired style in html
*/
export type EmbedNoteFormatter = (content: string, md: markdownit) => string;

function cardFormatter(content: string, md: markdownit): string {
return md.render(
`<div class="embed-container-note">${md.render(content)}</div>`
);
}

function inlineFormatter(content: string, md: markdownit): string {
return md.render(content);
}

export default markdownItWikilinkEmbed;

0 comments on commit 6c1d686

Please sign in to comment.