Skip to content

Commit

Permalink
feat: add autocomplete and computed grammar (#199)
Browse files Browse the repository at this point in the history
* feat: add autocomplete for some Given statement examples

* chore: change to  snippet completition

* feat: autogenerate list of autocomplete statements

* ci: now grammar build is not automatic with packages installation

* fix: include missing file

* chore: add missing license headers

* add pnpm build to build:grammar

* feat: add case Insensitive grammar and syntax highlighting

* chore: make autocomplete case insensitive

* fix: fix error in then autocomplete

* chore: add autocomplete for then statements

* fix: add G for complete Given statements

* fix(grammar): add missing single quotes

* ci(grammar): use correct command to build grammar package

* chore: apply prettier to grammar code

---------

Co-authored-by: FilippoTrotter <[email protected]>
  • Loading branch information
matteo-cristino and FilippoTrotter authored Sep 17, 2024
1 parent 51a25b5 commit b710a04
Show file tree
Hide file tree
Showing 20 changed files with 1,247 additions and 707 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/grammar.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ jobs:
steps:
- name: 🛠️ Prepare pnpm workspace
uses: dyne/pnpm@main
with:
build: pnpm build:grammar
- name: 📦 Releases
working-directory: ./grammar
run: npx semantic-release
Expand Down
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -79,5 +79,6 @@ node_modules
!/grammar/.releaserc
!/grammar/src/syntax.grammar.terms.d.ts
!/grammar/src/tokens.js


!/grammar/src/complete.ts
!/grammar/utils/package.json
!/grammar/utils/prepare_complete.mjs
4 changes: 4 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,7 @@ pkg/*/node_modules/
!/pkg/**/*.test.ts

!docs/.vitepress/config.mts

# grammar
!/grammar/src/index.ts
!/grammar/utils/prepare_complete.mjs
7 changes: 4 additions & 3 deletions grammar/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"description": "Slangroom lezer grammar for syntax highlighting on Codemirror",
"scripts": {
"test": "mocha test/test.js",
"prepare": "rollup -c"
"build": "pnpm -C utils run grammar-prepare && rollup -c"
},
"author": {
"name": "Filippo Trotter"
Expand Down Expand Up @@ -42,10 +42,11 @@
"mocha": "^9.0.1",
"rollup": "^2.60.2",
"rollup-plugin-dts": "^4.0.1",
"rollup-plugin-ts": "^3.0.2",
"semantic-release": "^24.1.0",
"semantic-release-commit-filter": "^1.0.2",
"typescript": "^4.3.4"
"typescript": "^4.3.4",
"@rollup/plugin-typescript": "^11.1.6",
"@rollup/plugin-json": "^6.0.0"
},
"license": "AGPL-3.0-or-later"
}
25 changes: 15 additions & 10 deletions grammar/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,20 @@
//
// SPDX-License-Identifier: AGPL-3.0-or-later

import typescript from "rollup-plugin-ts"
import {lezer} from "@lezer/generator/rollup"
import typescript from '@rollup/plugin-typescript';
import { lezer } from '@lezer/generator/rollup';

export default {
input: "src/index.ts",
external: id => id != "tslib" && !/^(\.?\/|\w:)/.test(id),
output: [
{file: "dist/index.cjs", format: "cjs"},
{dir: "./dist", format: "es"}
],
plugins: [lezer(), typescript()]
}
input: 'src/index.ts',
external: (id) => id != 'tslib' && !/^(\.?\/|\w:)/.test(id),
output: [
{ file: 'dist/index.cjs', format: 'cjs' },
{ dir: './dist', format: 'es' },
],
plugins: [
typescript({
exclude: ['./utils/*'],
}),
lezer(),
],
};
59 changes: 59 additions & 0 deletions grammar/src/complete.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// SPDX-FileCopyrightText: 2024 Dyne.org foundation
//
// SPDX-License-Identifier: AGPL-3.0-or-later

import { CompletionContext, snippetCompletion } from '@codemirror/autocomplete';
import { fullStatementTemplates } from './complete_statement';

// Helper function to strip quotes from matched strings
function stripQuotes(s: string) {
return s.replace(/^'|'$/g, '');
}

const fullStatementSnippets = fullStatementTemplates.map((x) => {
let n = 1;
return snippetCompletion(
x.label.replace(/''/g, () => `'\${${n++}:}'`),
x,
);
});

export function completeStatement(context: CompletionContext) {
const line = context.state.doc.lineAt(context.pos);
let textBefore = context.state.sliceDoc(line.from, context.pos);
const triggerMatch = /^[GT].*$/i.exec(textBefore);

if (triggerMatch) {
const strings = textBefore.match(/'([^']*)'/g);
textBefore = textBefore.toLowerCase();
if (!strings) {
return {
from: context.pos - triggerMatch[0].length,
options: fullStatementSnippets,
validFor: /^.*$/,
};
}

const strippedStrings = strings.map(stripQuotes);

const templateOption = fullStatementTemplates.map((x) => {
let n = 1;
let m = 0;
return snippetCompletion(
x.label.replace(/''/g, () => `'\${${n}:${strippedStrings[n++ - 1] || ''}}'`),
{
label: x.label.replace(/''/g, () => `${strings[m++] || "''"}`),
type: x.type,
},
);
});

return {
from: context.pos - textBefore.length,
options: templateOption,
validFor: /^.*$/,
};
}

return null;
}
69 changes: 36 additions & 33 deletions grammar/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,52 +2,55 @@
//
// SPDX-License-Identifier: AGPL-3.0-or-later

import { parser } from "./syntax.grammar"
import { LRLanguage, LanguageSupport, HighlightStyle, syntaxHighlighting } from "@codemirror/language"
import { styleTags, tags as t } from "@lezer/highlight"
import { completeFromList } from "@codemirror/autocomplete"
import { parser } from './syntax.grammar';
import {
LRLanguage,
LanguageSupport,
HighlightStyle,
syntaxHighlighting,
} from '@codemirror/language';
import { styleTags, tags as t } from '@lezer/highlight';
import { completeStatement } from './complete';

const syntax_colors = syntaxHighlighting(
HighlightStyle.define(
[
{ tag: t.heading, color: "purple" },
{ tag: t.heading1, color: "gray" },
{tag: t.variableName, color: "red"},
{ tag: t.keyword, color: "green" },
{tag: t.string, color: "blue"},
{tag: t.lineComment, color: "gray"},
{tag: t.heading2, color: "black"}
],
{ all: { color: "black" } }
)
);
[
{ tag: t.heading, color: 'purple' },
{ tag: t.heading1, color: 'gray' },
{ tag: t.variableName, color: 'red' },
{ tag: t.keyword, color: 'green' },
{ tag: t.string, color: 'blue' },
{ tag: t.lineComment, color: 'gray' },
{ tag: t.heading2, color: 'black' },
],
{ all: { color: 'black' } },
),
);

export const SlangroomLanguage = LRLanguage.define({
parser: parser.configure({
props: [
styleTags({
"Given Then When and in inside If EndIf Foreach EndForeach" : t.variableName,
"have send open connect print output" : t.keyword,
"Rule VersionRule! UnknownIgnoreRule! GenericRule!": t.heading,
" Scenario ScenarioType/... ScenarioComment!": t.heading1,
"DbAction! EthereumAction! FsAction! GitAction! HelpersAction! HttpAction! JsonSchemaAction! OAuthAction! PocketbaseAction! QrCodeAction! RedisAction! ShellAction! TimestampAction! WalletAction! ZencodeAction!": t.heading2,
'given then when and in inside if endif foreach endforeach': t.variableName,
'have send open connect print output': t.keyword,
'rule VersionRule! GenericRule!': t.heading,
'scenario ScenarioType/... ScenarioComment!': t.heading1,
'DbAction! EthereumAction! FsAction! GitAction! HelpersAction! HttpAction! JsonSchemaAction! OAuthAction! PocketbaseAction! QrCodeAction! RedisAction! ShellAction! TimestampAction! WalletAction! ZencodeAction!':
t.heading2,
StringLiteral: t.string,
Comment: t.lineComment,
})
]
}),
],
}),
languageData: {
commentTokens: { line: "#" }
}
})
commentTokens: { line: '#' },
},
});

const ac = SlangroomLanguage.data.of({
autocomplete: completeFromList([
{ label: "given", type: "keyword" },
{ label: "then", type: "keyword" },
{ label: "when", type: "keyword" }
])
})
autocomplete: completeStatement,
});

export function Slangroom() {
return new LanguageSupport(SlangroomLanguage, [syntax_colors, ac])
return new LanguageSupport(SlangroomLanguage, [syntax_colors, ac]);
}
Loading

0 comments on commit b710a04

Please sign in to comment.