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(content): support prismjs diff highlight #624

Merged
merged 3 commits into from
Aug 31, 2023
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
31 changes: 31 additions & 0 deletions apps/docs-app/docs/features/routing/content.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,37 @@ Analog is a meta-framework for Angular.
[Back Home](./)
```

### Using the diff Highlight Plugin

Analog supports highlighting diff changes with PrismJS. Add the `diff`
language and `diff-highlight` plugin imports to `app.config.ts`:

```ts
import 'prismjs/components/prism-diff';
import 'prismjs/plugins/diff-highlight/prism-diff-highlight';
```

Use the `diff` language tag to highlight them or
`diff-<language>` to highlight the diff changes in a specific language.

````md
```diff
- This is a sentence.
+ This is a longer sentence.
```

```diff-typescript
- const foo = 'bar';
+ const foo = 'baz';
```
````

To highlight changed line backgrounds instead of just the text, add this import to your global stylesheet:

```css
@import 'prismjs/plugins/diff-highlight/prism-diff-highlight.css';
```

## Defining Content Files

For more flexibility, markdown content files can be provided in the `src/content` folder. Here you can list markdown files such as blog posts.
Expand Down
36 changes: 36 additions & 0 deletions packages/content/src/lib/markdown-content-renderer.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,40 @@ describe('MarkdownContentRendererService', () => {
'<pre class="language-typescript"><code class="language-typescript">'
);
});

it('render should correctly highlight diff code blocks', async () => {
const { service } = setup();
window.Prism.languages['diff'] = {};
let testCode = "```diff-javascript\nconsole.log('Hello, world!');\n```";
let result = await service.render(testCode);

expect(result).toContain(
'<pre class="language-diff-javascript diff-highlight"><code class="language-diff-javascript diff-highlight">'
);

testCode = "```diff-typescript\nconsole.log('Hello, world!');\n```";
result = await service.render(testCode);

expect(result).toContain(
'<pre class="language-diff-typescript diff-highlight"><code class="language-diff-typescript diff-highlight">'
);
});

it('render should fall back to language-only highlighting if `diff` plugin is not imported', async () => {
const { service } = setup();
window.Prism.languages['diff'] = undefined;
let testCode = "```diff-javascript\nconsole.log('Hello, world!');\n```";
let result = await service.render(testCode);

expect(result).toContain(
'<pre class="language-javascript"><code class="language-javascript">'
);

testCode = "```diff-typescript\nconsole.log('Hello, world!');\n```";
result = await service.render(testCode);

expect(result).toContain(
'<pre class="language-typescript"><code class="language-typescript">'
);
});
});
50 changes: 32 additions & 18 deletions packages/content/src/lib/marked-setup.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export class MarkedSetupService {

constructor() {
const renderer = new marked.Renderer();
renderer.code = (code, lang) => {
renderer.code = (code: string, lang: string) => {
// Let's do a language based detection like on GitHub
// So we can still have non-interpreted mermaid code
if (lang === 'mermaid') {
Expand All @@ -35,37 +35,51 @@ export class MarkedSetupService {
if (!lang) {
return '<pre><code>' + code + '</code></pre>';
}
const langClass = 'language-' + lang;
const html =
'<pre class="' +
langClass +
'"><code class="' +
langClass +
'">' +
code +
'</code></pre>';
return html;

const classes =
lang.startsWith('diff') && Prism.languages['diff']
? `language-${lang} diff-highlight`
: `language-${lang.replace('diff-', '')}`;
return `<pre class="${classes}"><code class="${classes}">${code}</code></pre>`;
};

marked.use(
gfmHeadingId(),
markedHighlight({
async: true,
highlight: (code, lang) => {
lang = lang || 'typescript';
highlight: (code: string, lang: string) => {
let diff = lang?.startsWith('diff-');
lang = diff ? lang.replace('diff-', '') : lang || 'typescript';

if (diff && !Prism.languages['diff']) {
diff = false;
console.warn(`Notice:
---------------------------------------------------------------------------------------
The \`diff\` language and plugin are not available in the provided setup.
To enable it, add the following imports your \`main.ts\`:
import 'prismjs/components/prism-diff';
import 'prismjs/plugins/diff-highlight/prism-diff-highlight';
---------------------------------------------------------------------------------------
`);
}

if (!Prism.languages[lang]) {
if (lang !== 'mermaid') {
console.warn(`Notice:
---------------------------------------------------------------------------------------
The requested language '${lang}' is not available with the provided setup.
To enable, import your main.ts as:
import 'prismjs/components/prism-${lang}';
The requested language '${lang}' is not available in the provided setup.
To enable it, add the following import your \`main.ts\`:
import 'prismjs/components/prism-${lang}';
---------------------------------------------------------------------------------------
`);
`);
}
return code;
}
return Prism.highlight(code, Prism.languages[lang], lang);
return Prism.highlight(
code,
diff ? Prism.languages['diff'] : Prism.languages[lang],
lang
);
},
}),
{
Expand Down