Skip to content
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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,17 @@ artifacts/
.npm-cache/
.eslintcache
.pre-commit-cache/
.emacs-test/
.nvim-demo/
.nvim-test/

# Logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
*.log
.nvimlog

# OS/editor noise
.DS_Store
Expand Down
7 changes: 7 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,10 @@ repos:
language: system
pass_filenames: false
always_run: true
- id: all-tests-pre-push
name: all-tests-pre-push
entry: env PRE_COMMIT_HOME=.pre-commit-cache npm run test:all
language: system
pass_filenames: false
always_run: true
stages: [pre-push]
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ When modifying code or tests:
* Preserve formatting and style.
* Avoid refactoring unless explicitly asked.
* Do not modify large unrelated regions of code.
* Do not use `git commit --no-verify` unless the user gives explicit permission in the current conversation.
* After completing any new feature, update the Allium specs in `docs/project/specs/` so they reflect the current system behaviour before finishing the work.

### Tests
Expand Down
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,26 @@ npm install -g @allium/cli

See [AGENTS.md](AGENTS.md) for development rules and the [Project Roadmap](docs/project/plan.md) for build instructions and priorities.

### Git Hooks

This repository uses `pre-commit` hooks for local quality gates.

Install hooks:

```bash
npm install
```

Run the full test matrix locally:

```bash
npm run test:all
```

`test:all` runs fastest-to-slowest: `test`, `test:nvim`, `test:emacs`, `test:nvim:integration`, `test:emacs:integration`.

The `pre-push` hook runs `npm run test:all` before allowing a push.

## Licence

[MIT](LICENSE)
39 changes: 39 additions & 0 deletions docs/editors/neovim.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,45 @@ Run the following command in Neovim to check the health of the Allium integratio

This will verify that the `allium-lsp` binary is found and that the Tree-sitter parser is correctly installed.

## Quick Isolated Demo

From the monorepo root, you can launch a repo-local Neovim demo session that
does not use your normal Neovim config/state:

```bash
npm run demo:nvim-allium
```

Tree-sitter variant:

```bash
npm run demo:nvim-allium:ts
```

The demo stores runtime data in `.nvim-demo/`.

## Plugin Tests

Run repo-local Neovim plugin tests in headless mode:

```bash
npm run test:nvim
```

The test suite uses `nvim -u NONE` and stubs external dependencies for fast, deterministic checks.

Install repo-local integration test dependencies once:

```bash
npm run test:nvim:install
```

Run integration tests with real `nvim-lspconfig`, real `nvim-treesitter`, and real `allium-lsp`:

```bash
npm run test:nvim:integration
```

## Feature Reference

| Feature | Description | Standard Keymap |
Expand Down
18 changes: 18 additions & 0 deletions docs/project/specs/allium-development-workflow-behaviour.allium
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module allium_development_workflow_behaviour

rule FullTestMatrixRunsInOrderedPipeline {
when: CommandInvoked(command: "npm run test:all")

ensures: TestSuiteExecuted(name: workspace_unit_tests)
ensures: TestSuiteExecuted(name: nvim_plugin_unit)
ensures: TestSuiteExecuted(name: emacs_mode_unit)
ensures: TestSuiteExecuted(name: nvim_plugin_integration)
ensures: TestSuiteExecuted(name: emacs_mode_integration)
ensures: TestSuitesExecutedInOrder(names: [workspace_unit_tests, nvim_plugin_unit, emacs_mode_unit, nvim_plugin_integration, emacs_mode_integration])
}

rule PrePushUsesFullTestMatrixCommand {
when: GitHookInvoked(type: pre_push)

ensures: CommandInvoked(command: "npm run test:all")
}
150 changes: 150 additions & 0 deletions docs/project/specs/allium-emacs-mode-behaviour.allium
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
module allium_emacs_mode_behaviour

entity EmacsModeBuffer {
major_mode: allium_mode | allium_ts_mode
comment_start: String
comment_end: String
}

entity EmacsLspRegistration {
client: eglot | lsp_mode
mode: allium_mode | allium_ts_mode
command: List<String>
}

rule AlliumModeConfiguresCoreBufferDefaults {
when: AlliumModeActivated(buffer)

ensures: EmacsModeBuffer.created(
major_mode: allium_mode,
comment_start: "-- ",
comment_end: ""
)
}

rule AlliumModeRespectsCustomIndentOffset {
when: AlliumModeActivated(buffer)
requires: AlliumIndentOffsetConfigured(spaces: 2)

ensures: BlockContentIndentedBy(spaces: 2)
}

rule AlliumModeRegistersEglotServerProgram {
when: FeatureLoaded(feature: eglot)
requires: AlliumModeLoaded()

ensures: EmacsLspRegistration.created(
client: eglot,
mode: allium_mode,
command: ["allium-lsp", "--stdio"]
)
}

rule AlliumTsModeRegistersEglotServerProgram {
when: FeatureLoaded(feature: eglot)
requires: AlliumModeLoaded()

ensures: EmacsLspRegistration.created(
client: eglot,
mode: allium_ts_mode,
command: ["allium-lsp", "--stdio"]
)
}

rule AlliumModeRegistersLspModeClient {
when: FeatureLoaded(feature: lsp_mode)
requires: AlliumModeLoaded()

ensures: EmacsLspRegistration.created(
client: lsp_mode,
mode: allium_mode,
command: ["allium-lsp", "--stdio"]
)
}

rule AlliumModeLspModeRegistrationHonorsCustomServerCommand {
when: FeatureLoaded(feature: lsp_mode)
requires: AlliumModeLoaded()
requires: AlliumLspServerCommandConfigured(command: ["node", "allium-lsp.js", "--stdio"])

ensures: EmacsLspRegistration.created(
client: lsp_mode,
mode: allium_mode,
command: ["node", "allium-lsp.js", "--stdio"]
)
}

rule AlliumModesMapToAlliumLanguageIdForLspMode {
when: FeatureLoaded(feature: lsp_mode)
requires: AlliumModeLoaded()

ensures: LspLanguageIdConfigured(mode: allium_mode, language_id: "allium")
ensures: LspLanguageIdConfigured(mode: allium_ts_mode, language_id: "allium")
}

rule EmacsModeBatchTestsRunInCiStyleEnvironment {
when: CommandInvoked(command: "npm run test:emacs")

ensures: EmacsBatchRun(startup: "-Q")
ensures: ErtSuitesExecuted(package: "allium-mode")
}

rule EmacsModeIntegrationTestsExerciseRealServer {
when: CommandInvoked(command: "npm run test:emacs:integration")

ensures: EmacsBatchRun(startup: "-Q")
ensures: AlliumLspBinaryBuilt(path: "packages/allium-lsp/dist/bin.js")
ensures: LspSessionEstablished(client: eglot, transport: stdio)
ensures: LspSessionEstablished(client: lsp_mode, transport: stdio)
ensures: LspSessionEstablished(client: eglot, mode: allium_ts_mode, transport: stdio)
ensures: HoverRequestRoundTrip(client: eglot)
ensures: HoverRequestRoundTrip(client: lsp_mode)
ensures: ReferencesRequestRoundTrip(client: eglot)
ensures: DefinitionRequestRoundTrip(client: eglot)
ensures: CrossFileDefinitionRequestRoundTrip(client: eglot)
ensures: RenameRequestRoundTrip(client: eglot)
ensures: FormatRequestRoundTrip(client: eglot)
ensures: CodeActionsRequested(client: eglot)
}

rule EmacsModeTestDependenciesCanBeInstalledLocally {
when: CommandInvoked(command: "npm run test:emacs:install")

ensures: PackageElInitialized()
ensures: TestPackagesInstalled(path: ".emacs-test/elpa")
ensures: TreeSitterGrammarLibraryBuilt(path: ".emacs-test/tree-sitter/libtree-sitter-allium")
ensures: RepositoryFileNotTracked(path: ".emacs-test")
}

rule EmacsModeClassicDemoRunsInIsolatedSession {
when: CommandInvoked(command: "npm run demo:allium-mode")

ensures: EmacsBatchRun(startup: "-Q")
ensures: PackageElInitialized()
ensures: TestPackagesInstalled(path: ".emacs-test/elpa")
ensures: LspSessionEstablished(client: eglot, transport: stdio)
}

rule EmacsModeTreeSitterDemoRunsWithRepoGrammar {
when: CommandInvoked(command: "npm run demo:allium-mode:ts")

ensures: EmacsBatchRun(startup: "-Q")
ensures: TreeSitterGrammarLoadedFrom(path: ".emacs-test/tree-sitter")
ensures: EmacsModeBuffer.created(major_mode: allium_ts_mode)
}

rule AlliumTsModeUsesTreeSitterGrammarWhenAvailable {
when: AlliumTsModeActivated(buffer)
requires: TreeSitterGrammarInstalled(language: allium)

ensures: TreeSitterParserCreated(language: allium)
ensures: TreeSitterGrammarLoadedFrom(path: ".emacs-test/tree-sitter")
}

rule AlliumTsModeFallsBackGracefullyWhenParserUnavailable {
when: AlliumTsModeActivated(buffer)
requires: TreeSitterParserCreateFails(language: allium)

ensures: EmacsModeBuffer.created(major_mode: allium_ts_mode)
ensures: TreeSitterSetupNotApplied()
}
50 changes: 50 additions & 0 deletions docs/project/specs/allium-neovim-mode-behaviour.allium
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
module allium_neovim_mode_behaviour

rule NeovimClassicDemoRunsInIsolatedSession {
when: CommandInvoked(command: "npm run demo:nvim-allium")

ensures: NeovimSessionStarted()
ensures: ConfigIsolatedUnder(path: ".nvim-demo/xdg/config")
ensures: DataIsolatedUnder(path: ".nvim-demo/xdg/data")
ensures: StateIsolatedUnder(path: ".nvim-demo/xdg/state")
ensures: CacheIsolatedUnder(path: ".nvim-demo/xdg/cache")
ensures: NvimPluginLoaded(path: "packages/nvim-allium")
ensures: LspSessionEstablished(client: nvim_lsp, transport: stdio)
}

rule NeovimTreeSitterDemoRunsWithLocalGrammar {
when: CommandInvoked(command: "npm run demo:nvim-allium:ts")

ensures: NeovimSessionStarted()
ensures: NvimTreeSitterConfigured(language: allium)
ensures: TreeSitterGrammarLoadedFrom(path: "packages/tree-sitter-allium")
}

rule NeovimPluginUnitTestsRunHeadless {
when: CommandInvoked(command: "npm run test:nvim")

ensures: NeovimSessionStarted(mode: headless)
ensures: NvimPluginLoaded(path: "packages/nvim-allium")
ensures: TestSuiteExecuted(name: nvim_allium_unit)
}

rule NeovimPluginIntegrationTestsRunWithRealDependencies {
when: CommandInvoked(command: "npm run test:nvim:integration")

ensures: NeovimSessionStarted(mode: headless)
ensures: NvimPluginLoaded(path: "packages/nvim-allium")
ensures: NvimLspconfigLoaded()
ensures: NvimTreeSitterLoaded()
ensures: LspSessionEstablished(client: nvim_lsp, transport: stdio)
ensures: HoverRequestSupported()
ensures: DefinitionRequestSupported()
ensures: CrossFileDefinitionRequestSupported()
ensures: ReferencesRequestSupported()
ensures: CrossFileReferencesRequestSupported()
ensures: RenameRequestSupported()
ensures: CrossFileRenameWorkspaceEditSupported()
ensures: FormattingRequestSupported()
ensures: CodeActionRequestSupported()
ensures: DiagnosticsPublishedForInvalidSpec()
ensures: HealthCheckReportAvailable()
}
Loading