Skip to content

Commit

Permalink
Replace prism with shiki
Browse files Browse the repository at this point in the history
  • Loading branch information
msujew committed Sep 6, 2024
1 parent 8461fcb commit 7f4ff28
Show file tree
Hide file tree
Showing 21 changed files with 939 additions and 308 deletions.
2 changes: 1 addition & 1 deletion hugo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ enableRobotsTXT = true
# Needed for mermaid shortcode
unsafe = true
[markup.highlight]
codeFences = false # Disable Hugo's code highlighter as it conflicts with prism's highligher.
codeFences = false # Disable Hugo's code highlighter as it conflicts with our custom shiki highlighter.
[markup.tableOfContents]
startLevel = 1
endLevel = 9
Expand Down
2 changes: 1 addition & 1 deletion hugo/content/docs/learn/minilogo/customizing_cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ If you've been following along from the hello world example produced by the yeom

If you have errors with regards to any imports of `HelloWorld...`, this is likely related to your `grammar NAME` in your langium file being something different than the original `HelloWorld`. The name of these imports will change based on your grammar file's name after `npm run langium:generate`, so in each case you should be able to change each import to `MyLanguage...` to resolve the issue.

You may also have build errors related to the generator logic, especially if it was written for the hello-world semantic model. For now, we can comment out the generator function's contents in **src/cli/generator.ts**, return an empty string, and comment/remove the imports to make Typescript happy. In the next tutorial, we'll come back to it and implement an initial version of a generator for our language.
You may also have build errors related to the generator logic, especially if it was written for the hello-world semantic model. For now, we can comment out the generator function's contents in **src/cli/generator.ts**, return an empty string, and comment/remove the imports to make TypeScript happy. In the next tutorial, we'll come back to it and implement an initial version of a generator for our language.

If you have any other errors while building, double check that the exported & imported names match up. More often than note there's a small discrepancy here, especially when you use a different language name than the default.

Expand Down
2 changes: 1 addition & 1 deletion hugo/content/docs/learn/workflow/generate_ast.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ Mind the gaps (question marks) for the cross-references inside the greetings. Th

You can test the parser by comparing the generated AST with the expected AST. Here is an example:

```typescript
```ts
import { createHelloWorldServices } from "./your-project//hello-world-module.js";
import { EmptyFileSystem } from "langium";
import { parseHelper } from "langium/test";
Expand Down
4 changes: 2 additions & 2 deletions hugo/content/docs/learn/workflow/generate_everything.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Depending on your domain and on your requirements there are different ways to ge

The simplest way is to generate text into a string. Let's print out every greeting from the `hello-world` example.

```typescript
```ts
import type { Model } from '../language/generated/ast.js';

export function generateJavaScript(model: Model): string {
Expand All @@ -27,7 +27,7 @@ ${model.greetings

You can test the generator by comparing the generated text with the expected text. Here is an example.

```typescript
```ts
import { EmptyFileSystem } from "langium";
import { parseHelper } from "langium/test";
import { createHelloWorldServices } from "./your-project/hello-world-module.js";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ export interface ScopeComputation {
}
```

So, while the scope computation is defining what symbols are globally exported (like using the `export` keyword in Typescript), the scope provider is the place to implement the `import` of these symbols using the index manager and the semantics of your import logic.
So, while the scope computation is defining what symbols are globally exported (like using the `export` keyword in TypeScript), the scope provider is the place to implement the `import` of these symbols using the index manager and the semantics of your import logic.

## Cross-reference resolution from a high-level perspective

Expand Down
2 changes: 1 addition & 1 deletion hugo/content/docs/recipes/multiple-languages.md
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ After doing so, your name should display a warning, stating that you cannot gree

In this section we will list common mistakes.

* One prominent mistake is forgetting to build Langium and Typescript files, before running the extension.
* One prominent mistake is forgetting to build Langium and TypeScript files, before running the extension.

* Since we are basically just copy-pasting given configuration, be aware of what you are pasting. Make sure that the code still makes sense after copying. You probably forgot to adapt the pasted code.

Expand Down
14 changes: 7 additions & 7 deletions hugo/content/docs/recipes/performance/caches.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ We will have a computation for each person that determines from which publisher

Let's build a "publisher inferer service". First let's create a small database of known publishers and known persons:

```typescript
```ts
type KnownPublisher = 'DC' | 'Marvel' | 'Egmont';
const KnownPersonNames: Record<KnownPublisher, string[]> = {
DC: ['Superman', 'Batman', 'Aquaman', 'Wonderwoman', 'Flash'],
Expand All @@ -42,15 +42,15 @@ const KnownPersonNames: Record<KnownPublisher, string[]> = {

For our service we define an interface:

```typescript
```ts
export interface InferPublisherService {
inferPublisher(person: Person): KnownPublisher | undefined;
}
```

Now we implement the service:

```typescript
```ts
class UncachedInferPublisherService implements InferPublisherService {
inferPublisher(person: Person): KnownPublisher | undefined {
for (const [publisher, persons] of Object.entries(KnownPersonNames)) {
Expand All @@ -67,7 +67,7 @@ class UncachedInferPublisherService implements InferPublisherService {

Now we want to cache the results of the `inferPublisher` method. We can use the `DocumentCache` for this. We will reuse the uncached service as base class and override the `inferPublisher` method:

```typescript
```ts
export class CachedInferPublisherService extends UncachedInferPublisherService {
private readonly cache: DocumentCache<Person, KnownPublisher | undefined>;
constructor(services: HelloWorldServices) {
Expand All @@ -87,7 +87,7 @@ export class CachedInferPublisherService extends UncachedInferPublisherService {

To use this service, let's create a validator that checks if the publisher of a person is known. Go to the `hello-world-validator.ts` file and add the following code:

```typescript
```ts
import type { ValidationAcceptor, ValidationChecks } from 'langium';
import type { HelloWorldAstType, Person } from './generated/ast.js';
import type { HelloWorldServices } from './hello-world-module.js';
Expand Down Expand Up @@ -130,7 +130,7 @@ export class HelloWorldValidator {

Finally, we need to register the service in the module. Go to the `hello-world-module.ts` file and add the following code:

```typescript
```ts
export type HelloWorldAddedServices = {
utilities: {
inferPublisherService: InferPublisherService
Expand Down Expand Up @@ -172,7 +172,7 @@ All of these caches are disposable compared to a simple `Map<K, V>`. If you disp
<details>
<summary>Full implementation</summary>

```typescript
```ts
import { AstUtils, DocumentCache } from "langium";
import { Person } from "./generated/ast.js";
import { HelloWorldServices } from "./hello-world-module.js";
Expand Down
2 changes: 1 addition & 1 deletion hugo/content/docs/recipes/scoping/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ title: "Scoping"
weight: 100
---

You likely know scopes from programming, where some variables are only available from certain areas (such as blocks) in your program. For example, take the short Typescript snippet below. Based on the block (scope) where a variable is declared, it may or may not be available at another location in the same program.
You likely know scopes from programming, where some variables are only available from certain areas (such as blocks) in your program. For example, take the short TypeScript snippet below. Based on the block (scope) where a variable is declared, it may or may not be available at another location in the same program.

```ts
let x = 42;
Expand Down
12 changes: 6 additions & 6 deletions hugo/content/docs/recipes/scoping/file-based.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ npm run langium:generate

The index manager shall get all persons that are marked with the export keyword. In Langium this is done by overriding the `ScopeComputation.getExports(…)` function. Here is the implementation:

```typescript
```ts
export class HelloWorldScopeComputation extends DefaultScopeComputation {
override async computeExports(document: LangiumDocument<AstNode>): Promise<AstNodeDescription[]> {
const model = document.parseResult.value as Model;
Expand All @@ -73,7 +73,7 @@ export class HelloWorldScopeComputation extends DefaultScopeComputation {

After that, you need to register the `HelloWorldScopeComputation` in the `HelloWorldModule`:

```typescript
```ts
export const HelloWorldModule: Module<HelloWorldServices, PartialLangiumServices & HelloWorldAddedServices> = {
//...
references: {
Expand All @@ -88,7 +88,7 @@ Having done this, will make all persons that are marked with the `export` keywor

The final step is to adjust the cross-reference resolution by overriding the `DefaultScopeProvider.getScope(…)` function:

```typescript
```ts
export class HelloWorldScopeProvider extends DefaultScopeProvider {
override getScope(context: ReferenceInfo): Scope {
switch(context.container.$type as keyof HelloWorldAstType) {
Expand All @@ -111,7 +111,7 @@ export class HelloWorldScopeProvider extends DefaultScopeProvider {

Do not forget to add the new service to the `HelloWorldModule`:

```typescript
```ts
export const HelloWorldModule: Module<HelloWorldServices, PartialLangiumServices & HelloWorldAddedServices> = {
//...
references: {
Expand All @@ -125,7 +125,7 @@ You noticed the two missing functions? Here is what they have to do.

The first function (`getExportedPersonsFromGlobalScope(context)`) will take a look at the global scope and return all exported persons respecting the files that were touched by the file imports. Note that we are outputting all persons that are marked with the `export` keyword. The actual name resolution is done internally later by the linker.

```typescript
```ts
private getExportedPersonsFromGlobalScope(context: ReferenceInfo): Scope {
//get document for current reference
const document = AstUtils.getDocument(context.container);
Expand Down Expand Up @@ -154,7 +154,7 @@ private getExportedPersonsFromGlobalScope(context: ReferenceInfo): Scope {

The second function (`getImportedPersonsFromCurrentFile(context)`) will take a look at the current file and return all persons that are imported from other files.

```typescript
```ts
private getImportedPersonsFromCurrentFile(context: ReferenceInfo) {
//get current document of reference
const document = AstUtils.getDocument(context.container);
Expand Down
6 changes: 3 additions & 3 deletions hugo/content/docs/recipes/validation/dependency-loops.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ npm install graphology graphology-components graphology-dag

Open the `hello-world-validator.ts` and add another validator for `Model`. It is important to say that we do not create a check on the `Greeting` level, because we need the overview over all greetings. The complete overview is given for the `Model` AST node. It would be possible to just calculate cycles for a single greeting or person, but that is more complex and less performant!

```typescript
```ts
const checks: ValidationChecks<HelloWorldAstType> = {
Model: validator.checkGreetingCycles, // new!!!
Person: validator.checkPersonStartsWithCapital
Expand All @@ -163,7 +163,7 @@ const checks: ValidationChecks<HelloWorldAstType> = {

And here is the implementation:

```typescript
```ts
checkGreetingCycles(model: Model, accept: ValidationAcceptor): void {
//arrange the graph
const graph = new DirectedGraph<{}, {greeting: Greeting}>();
Expand Down Expand Up @@ -225,7 +225,7 @@ Here is the screenshot of VS Code with the error:

The topological sort can be done like this:

```typescript
```ts
import { topologicalSort } from 'graphology-dag';

//resolvedOrder is an array of person names!
Expand Down
22 changes: 11 additions & 11 deletions hugo/content/docs/reference/configuration-services.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ The [arithmetics example](https://github.com/eclipse-langium/langium/tree/main/e

First, we need to register the new implementation of `ScopeProvider` inside of the `ArithmeticsModule`:

```Typescript
```ts
export const ArithmeticsModule: Module<ArithmeticsServices, PartialLangiumServices & ArithmeticsAddedServices> = {
references: {
ScopeProvider: (services) => new ArithmeticsScopeProvider(services)
Expand Down Expand Up @@ -62,7 +62,7 @@ export class ArithmeticsScopeProvider extends DefaultScopeProvider {
The functions `createScope` and `getGlobalScope` are already defined in `DefaultScopeProvider` but needed to be overridden to add the option `{caseInsensitive: true}`. This is achieved through inheritance: By using the keyword `extends`, `ArithmeticsScopeProvider` inherits from `DefaultScopeProvider`, which means that it can access properties and methods as well as override methods declared in the superclass.

In the `DefaultScopeProvider`, those two methods are declared as:
```Typescript
```ts
protected createScope(elements: Stream<AstNodeDescription>, outerScope: Scope): Scope {
return new StreamScope(elements, outerScope);
}
Expand All @@ -79,15 +79,15 @@ Of course it is also possible to replace the default implementation with a compl
### Adding New Services
To add services that are not available by default in Langium, e.g. application specific ones, we first need to edit the type `ArithmeticsAddedService`.
By default, the Yeoman-based generator adds a validator service where you can implement validation rules specific to your language. New services are added as properties to the type declaration:
```Typescript
```ts
export type ArithmeticsAddedServices = {
ArithmeticsValidator: ArithmeticsValidator
}
```
The `ArithmeticsAddedService` type now has a property `ArithmeticsValidator` of type `ArithmeticsValidator`.
For the sake of organization and clarity, the services can be nested inside of other properties acting as "groups":
```Typescript
```ts
export type ArithmeticsAddedServices = {
validation: {
ArithmeticsValidator: ArithmeticsValidator
Expand All @@ -104,7 +104,7 @@ export type ArithmeticsAddedServices = {
```
Now that we have declared our new services inside of the `ArithmeticsAddedServices` type definition, we need to specify to the module how we want them to be implemented. To do so, we need to update the `ArithmeticsModule`:
```Typescript
```ts
export const ArithmeticsModule: Module<ArithmeticsServices, PartialLangiumServices & ArithmeticsAddedServices> = {
validation: {
ArithmeticsValidator: () => new ArithmeticsValidator()
Expand All @@ -114,13 +114,13 @@ export const ArithmeticsModule: Module<ArithmeticsServices, PartialLangiumServic
Similarly to [overridden services](#overriding-and-extending-services), the first access to the `ArithmeticsValidator` property will create a new instance of the class `ArithmeticsValidator`.

The `ArithmeticsValidator` service does not depend on other services, and no argument is passed during the instantiation of the class. If you implement a service that depends on other services, the constructor of your service should expect `<yourDslName>Services` as argument. The initializer function can expect that object as argument and pass it to your services constructor, such as:
```Typescript
```ts
export const ArithmeticsModule: Module<ArithmeticsServices, PartialLangiumServices & ArithmeticsAddedServices> = {
ServiceWithDependencies = (services) => new ServiceClass(services);
}
```
The services which `ServiceClass` depends on need to be registered in the constructor:
```Typescript
```ts
export class ServiceClass {
private readonly serviceOne: ServiceOne;
private readonly serviceTwo: ServiceTwo;
Expand All @@ -138,7 +138,7 @@ export class ServiceClass {
#### Resolving cyclic dependencies

In case one of the services the `ServiceClass` above depends on, also has a dependency back to the `ServiceClass`, your module will throw an error similar to this: `Cycle detected. Please make "ServiceClass" lazy.` Ideally, such cyclic dependencies between services should be avoided. Sometimes, cycles are unavoidable though. In order to make them lazy, assign a lambda function that returns the service in the constructor. You can then invoke this function in your service logic to get access to the depending service:
```Typescript
```ts
export class ServiceClass {
private readonly serviceOne: () => ServiceOne;

Expand All @@ -156,7 +156,7 @@ export class ServiceClass {
The `ArithmeticsValidator` needs to be registered inside of the `ValidationRegistry`. This done by [overriding](#overriding-and-extending-services) `ValidationRegistry` with `ArithmeticsValidationRegistry`.

Briefly, `ArithmeticsValidator` implements two checks, `checkDivByZero` and `checkNormalisable`:
```Typescript
```ts
export class ArithmeticsValidator {
checkDivByZero(binExpr: BinaryExpression, accept: ValidationAcceptor): void {
...
Expand All @@ -168,7 +168,7 @@ export class ArithmeticsValidator {
}
```
These two new checks need to be registered inside of the `ValidationRegistry`. We extend `ValidationRegistry` with `ArithmeticsValidationRegistry` to implement our new functionalities:
```Typescript
```ts
export class ArithmeticsValidationRegistry extends ValidationRegistry {
constructor(services: ArithmeticsServices) {
super(services);
Expand All @@ -184,7 +184,7 @@ export class ArithmeticsValidationRegistry extends ValidationRegistry {
Inside of the `ArithmeticsValidationRegistry`, we obtain our `ArithmeticsValidator` with `const validator = services.validation.ArithmeticsValidator`, which will create a new instance of `ArithmeticsValidator`. Then we declare the `checks` to be registered and register them inside of the registry via the function `register` which is declared in the superclass. The `ArithmeticsValidationRegistry` only adds validation checks to the `ValidationRegistry`, but does not override any functionality from it.

The implementation of `ArithmeticsValidationRegistry` needs to be registered in `ArithmeticsModule`. The complete `ArithmeticsModule` is:
```Typescript
```ts
export const ArithmeticsModule: Module<ArithmeticsServices, PartialLangiumServices & ArithmeticsAddedServices> = {
references: {
ScopeProvider: (services) => new ArithmeticsScopeProvider(services)
Expand Down
2 changes: 1 addition & 1 deletion hugo/content/playground/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
******************************************************************************/

export const LangiumTextMateContent = {
"name": "Langium",
"name": "langium",
"scopeName": "source.langium",
"fileTypes": [
"langium"
Expand Down
20 changes: 20 additions & 0 deletions hugo/static/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@
--footer-link-color-visited: #ffcc5c;
}

:root[color-mode="light"] .shiki,
:root[color-mode="light"] .shiki span {
color: var(--shiki-light) !important;
}

@media (prefers-color-scheme: light) {
:root {
--header-background: #4ec58a;
Expand Down Expand Up @@ -86,6 +91,11 @@
fill: var(--header-font-color) !important;
stroke: #000000 !important;
}

.shiki,
.shiki span {
color: var(--shiki-light) !important;
}
}

/* Dark mode theming */
Expand Down Expand Up @@ -121,6 +131,11 @@
--footer-link-color-visited: rgb(213, 104, 231);
}

:root[color-mode="dark"] .shiki,
:root[color-mode="dark"] .shiki span {
color: var(--shiki-dark) !important;
}

@media (prefers-color-scheme: dark) {
:root {
--header-background: rgb(23, 23, 23);
Expand Down Expand Up @@ -169,6 +184,11 @@
fill: var(--header-font-color) !important;
stroke: var((--body-font-color)) !important;
}

.shiki,
.shiki span {
color: var(--shiki-dark) !important;
}
}

:root .chroma .err {
Expand Down
29 changes: 0 additions & 29 deletions hugo/static/prism/langium-prism.js

This file was deleted.

Loading

0 comments on commit 7f4ff28

Please sign in to comment.