Tools

Editors

Use the Appling language server in any LSP capable editor, embed it in your own tool, or reuse its syntax highlighting.

@appling/lang ships a language server, appling-language-server, that speaks the Language Server Protocol. Any editor with an LSP client can use it for diagnostics, navigation and canonical formatting of .appling files. The same server runs inside the IDE.

Install

npm install --global @appling/lang
appling-language-server --stdio

Or, without a global install:

npx -p @appling/lang appling-language-server --stdio

The server talks over stdin and stdout with --stdio. It is built on vscode-languageserver, so the other transports of that library, --node-ipc and --socket=<port>, work as well.

Features

FeatureWhat you get
DiagnosticsSyntax errors, unresolved references (also across modules and files), layer rules, expression types and migration checks: the same rules as appling check
CompletionKeywords and the names visible at the cursor
Go to definitionFrom any reference to its declaration, also in another file
Find referencesEvery reference to an element
RenameThe declaration and its references
Document highlightOther occurrences of the element under the cursor
Document symbolsThe outline of a file
FoldingBlocks such as modules, entities and actions
HoverThe element’s kind, qualified name and layer, such as Field `sales.Order.status`, domain layer, followed by its doc comment
FormattingRewrites the whole document into canonical form, the same as appling fmt; skipped while the file has syntax errors

A doc comment is a /** ... */ comment directly before an element:

module sales {
  /** An order placed by a customer. */
  entity Order {
    reference: String unique
  }
}

The server loads every .appling file in the workspace folders the editor sends at startup, so references to files you have not opened resolve. Open your editor at the project root, the folder that contains all model files.

NOTE

Rename in the language server changes the declaration and its references. It does not follow names inside expressions (total in { total >= 0 }), export lists, transitions over enum values or message keys. The rename edit operation, used by the IDE inspector and the AI tools, follows all of them.

Connect an editor

Every LSP client needs the same four facts:

SettingValue
Commandappling-language-server --stdio
Language idappling
File pattern*.appling
RootThe folder with appling.config.json, or your repository root

Register .appling as a file type first if your editor does not know it, then point its LSP client at the command. Turn on format on save if you want files to stay canonical.

Neovim

Neovim 0.11 and later configure language servers with vim.lsp.config. Put this in your init.lua:

vim.filetype.add({ extension = { appling = 'appling' } })

vim.lsp.config('appling', {
  cmd = { 'appling-language-server', '--stdio' },
  filetypes = { 'appling' },
  root_markers = { 'appling.config.json', '.git' },
})
vim.lsp.enable('appling')

Format with vim.lsp.buf.format(), rename with vim.lsp.buf.rename(), and hover with K.

VS Code

The Appling extension for VS Code bundles the language server and a TextMate grammar generated from the Appling grammar, so it needs no global install. It starts when the workspace contains a .appling file and loads every model file in the workspace folders. Build and install it from the repository:

pnpm --filter @appling/lang build
pnpm --filter appling-vscode build
pnpm --filter appling-vscode package
code --install-extension packages/vscode/out/appling.vsix

Turn on editor.formatOnSave for [appling] to keep files canonical.

Embed the language server

@appling/lang/lsp exports the services with Langium’s LSP features plus the Appling formatter and hover. Use it to run the server over any connection, for example a websocket:

import { startLanguageServer } from 'langium/lsp';
import { NodeFileSystem } from 'langium/node';
import { createApplingLspServices } from '@appling/lang/lsp';

startLanguageServer(createApplingLspServices({ connection, ...NodeFileSystem }).shared);

connection is a vscode-languageserver connection. The IDE creates one per websocket with vscode-ws-jsonrpc and starts one server for each page.

Export of @appling/lang/lspPurpose
createApplingLspServices(context)The Appling services with Langium’s LSP services; returns { shared, Appling }
ApplingLspModuleThe Appling specific LSP services, to inject into your own module
ApplingFormatterFormats a document into canonical form
ApplingHoverProviderHover with kind, qualified name, layer and doc comment

Without a connection in the context, createApplingLspServices marks its configuration as initialized, so you can use the LSP services directly in tests or tools.

Syntax highlighting with Monarch

@appling/lang/monarch exports a Monarch grammar generated from the Appling grammar, for Monaco and other editors that read Monarch definitions:

import * as monaco from 'monaco-editor';
import monarch from '@appling/lang/monarch';

monaco.languages.register({ id: 'appling', extensions: ['.appling'] });
monaco.languages.setMonarchTokensProvider('appling', monarch as monaco.languages.IMonarchLanguage);

It produces the tokens keyword, string, number, comment and operator, so a Monaco theme can color them. Comments use // and /* ... */.

The package also ships the same grammar in TextMate form, src/syntaxes/appling.tmLanguage.json with the scope source.appling, for editors and highlighters that read TextMate grammars.