Skip to content

Commit

Permalink
Merge pull request #16 from IgnaceMaes/document-custom-grammar
Browse files Browse the repository at this point in the history
docs: add advanced config section
  • Loading branch information
IgnaceMaes committed Sep 3, 2023
2 parents 69c9988 + 89832a2 commit 429caf1
Show file tree
Hide file tree
Showing 6 changed files with 191 additions and 5 deletions.
7 changes: 3 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:

steps:
- uses: actions/checkout@v3
- uses: NullVoxPopuli/action-setup-pnpm@v2
- uses: wyvox/action-setup-pnpm@v2
with:
node-version: 16
- name: Lint
Expand All @@ -34,10 +34,9 @@ jobs:

steps:
- uses: actions/checkout@v3
- uses: NullVoxPopuli/action-setup-pnpm@v2
- uses: wyvox/action-setup-pnpm@v2
with:
node-version: 16
no-lockfile: true
- name: Run Tests
run: pnpm test

Expand All @@ -61,7 +60,7 @@ jobs:

steps:
- uses: actions/checkout@v3
- uses: NullVoxPopuli/action-setup-pnpm@v2
- uses: wyvox/action-setup-pnpm@v2
with:
node-version: 16
- name: Run Tests
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
uses: actions/checkout@v3

- name: Setup pnpm and Node.js 16
uses: NullVoxPopuli/action-setup-pnpm@v2
uses: wyvox/action-setup-pnpm@v2
with:
node-version: 16

Expand Down
7 changes: 7 additions & 0 deletions docs-app/app/components/sidebar.gts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ const Sidebar: TOC<{}> = <template>
<SidebarItem @text='Glint types' />
<SidebarItem @text='Configure (optional)' />
<Separator />

<SidebarTitle @text='Options' />
<SidebarItem @text='Language' />
<SidebarItem @text='Theme' />
Expand All @@ -62,6 +63,12 @@ const Sidebar: TOC<{}> = <template>
<SidebarItem @text='Line highlighting' />
<SidebarItem @text='Loading state' />
<SidebarItem @text='Custom fonts' />
<Separator />

<SidebarTitle @text='Advanced' />
<SidebarItem @text='Custom grammar' />
<SidebarItem @text='Custom theme' />
<SidebarItem @text='Fastboot' />
</ul>

<p class="text-xs text-gray-500 mt-4">Built by
Expand Down
79 changes: 79 additions & 0 deletions docs-app/app/controllers/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,85 @@ function foo(x, y) {
</Tab>
</CodeGroup>`;

loadCustomGrammar = `import Route from '@ember/routing/route';
import { service } from '@ember/service';
export default class ApplicationRoute extends Route {
@service shiki;
async beforeModel() {
await this.loadCustomGrammar();
}
async loadCustomGrammar() {
// Shiki has to be initialized before the highlighter is available
await this.shiki.initialize.perform();
// Get custom grammar
const grammarTextmateDefinition = 'https://raw.githubusercontent.com/IgnaceMaes/glimmer-textmate-grammar/main/handlebars.tmLanguage.json';
const glimmerHandlebarsGrammar = await fetch(grammarTextmateDefinition);
const glimmerHandlebars = {
id: 'handlebars',
path: '',
scopeName: 'text.html.handlebars',
grammar: await glimmerHandlebarsGrammar.json(),
aliases: ['hbs'],
};
// Load embedded languages first
await this.shiki.loadLanguageAndEmbedded('js');
await this.shiki.loadLanguageAndEmbedded('css');
// Finally, register the custom language to the Shiki highlighter
await this.shiki.highlighter?.loadLanguage(glimmerHandlebars);
}
}`;

loadCustomTheme = `import Route from '@ember/routing/route';
import { service } from '@ember/service';
export default class ApplicationRoute extends Route {
@service shiki;
async beforeModel() {
await this.loadCustomTheme();
}
async loadCustomTheme() {
// Shiki has to be initialized before the highlighter is available
await this.shiki.initialize.perform();
// Fetch custom theme
const nightOwlTheme = await fetch(
'https://raw.githubusercontent.com/sdras/night-owl-vscode-theme/main/themes/Night%20Owl-color-theme.json',
);
const nightOwlThemeJson = await nightOwlTheme.json();
// Make sure the name is set, as this is the value to be passed to the CodeBlock theme argument
nightOwlThemeJson.name = 'Night Owl';
await this.shiki.highlighter?.loadTheme(nightOwlThemeJson);
}
}`;

fastbootConfig = `module.exports = function () {
return {
buildSandboxGlobals(defaultGlobals) {
return Object.assign({}, defaultGlobals, {
fetch: fetch,
AbortController,
ReadableStream:
typeof ReadableStream !== 'undefined'
? ReadableStream
: require('node:stream/web').ReadableStream,
WritableStream:
typeof WritableStream !== 'undefined'
? WritableStream
: require('node:stream/web').WritableStream,
TransformStream:
typeof TransformStream !== 'undefined'
? TransformStream
: require('node:stream/web').TransformStream,
Headers: typeof Headers !== 'undefined' ? Headers : undefined,
});
},
};
};`;

changeTheme = (event: Event) => {
this.theme = (event.target as HTMLSelectElement).value;
};
Expand Down
31 changes: 31 additions & 0 deletions docs-app/app/routes/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,37 @@ export default class ApplicationRoute extends Route {
@service declare shiki: ShikiService;

async beforeModel() {
await this.loadCustomTheme();
}

async loadCustomGrammar() {
// Shiki has to be initialized before the highlighter is available
await this.shiki.initialize.perform();
// Get custom grammar
const glimmerHandlebarsGrammar = await fetch(
'https://raw.githubusercontent.com/IgnaceMaes/glimmer-textmate-grammar/main/handlebars.tmLanguage.json',
);
const glimmerHandlebars = {
id: 'handlebars',
path: '',
scopeName: 'text.html.handlebars',
grammar: await glimmerHandlebarsGrammar.json(),
aliases: ['hbs'],
};
// Load embedded languages first
await this.shiki.loadLanguageAndEmbedded('js');
await this.shiki.loadLanguageAndEmbedded('css');
// Finally, register the custom language to the Shiki highlighter
await this.shiki.highlighter?.loadLanguage(glimmerHandlebars);
}

async loadCustomTheme() {
await this.shiki.initialize.perform();
const nightOwlTheme = await fetch(
'https://raw.githubusercontent.com/sdras/night-owl-vscode-theme/main/themes/Night%20Owl-color-theme.json',
);
const nightOwlThemeJson = await nightOwlTheme.json();
nightOwlThemeJson.name = 'Night Owl';
await this.shiki.highlighter?.loadTheme(nightOwlThemeJson);
}
}
70 changes: 70 additions & 0 deletions docs-app/app/templates/application.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,76 @@ function foo(x, y) {
</div>
<CodeBlock @code={{this.fontComicSans}} @language="hbs" />

<hr class="my-16 h-px border-0 bg-gray-700" />

<SectionTitle @text="Advanced" />
<SectionSubtitle @text="Custom grammar" />

<p>Shiki supports loading custom language grammar definitions in the
TextMate format. This can be useful if a new language hasn't landed in
the base package yet, or if you want to use a custom definition for an
existing language.</p>

<p>A great use case for this is Ember's template syntax. Ember uses
Glimmer to render component with templates defined in a
<InlineCode>.hbs</InlineCode>
file. Glimmer grammar, however, is more extensive than handlebars. If
you want to opt into Glimmer syntax parsing, you can load custom Glimmer
grammar for the
<InlineCode>handlebars</InlineCode>
language definition. Here's an example of how you could do it:</p>

<CodeBlock
@name="app/routes/application.js"
@code={{this.loadCustomGrammar}}
@language="js"
/>
<p>Note: this is just an example way of how it's made possible, but not the recommended approach per se. In the future a more ergonomic, officially recommended way might be added.</p>

<SectionSubtitle @text="Custom theme" />
<p>Shiki ships with 29 themes available by default, but any VS Code theme
can be loaded dynamically. Simply register the theme config JSON and
pass the theme name to the
<InlineCode>CodeBlock</InlineCode>
component.</p>

<p>The following example shows a custom theme <InlineCode>Night Owl</InlineCode>:</p>

<CodeBlock
@name="app/routes/application.js"
@code={{this.loadCustomTheme}}
@language="js"
@theme="Night Owl"
style="--ember-shiki-background-color: #011627"
/>
<p>Note: this is just an example way of how it's made possible, but not the recommended approach per se. In the future a more ergonomic, officially recommended way might be added.</p>

<SectionSubtitle @text="Fastboot" />
<p>The
<InlineCode>CodeBlock</InlineCode>
component automatically detects Fastboot if it's used in the app and
makes sure the rendering awaits until the highlighting is completed.</p>

<p>Shiki makes use of
<InlineCode>fetch</InlineCode>
which is not available in the runtime environment of Fastboot by
default. To make it available, set the globals in your fastboot config.
Note that fetch is only built into Node.js starting from v18. If you
want to support older versions you can install and import
<InlineCode>node-fetch</InlineCode>.</p>

<CodeBlock
@name="config/fastboot.js"
@code={{this.fastbootConfig}}
@language="js"
/>
<p>Prember for pre-rendering the app to static html is also supported.
Make sure to use at least version
<InlineCode>^2.0.0</InlineCode>
so the
<InlineCode>fastboot.js</InlineCode>
config is correctly applied.</p>

{{outlet}}
</div>
</article>
Expand Down

0 comments on commit 429caf1

Please sign in to comment.