Documentation
¶
Overview ¶
Package lsp is the Go half of the tabnas language server: the same protocol-free pipeline as the canonical TypeScript package (ts/src/core.js) — diagnostics via ParseRecover, semantic tokens via the reconciled lex trace, outline via SubRuleDone, completion via Continuations — plus a minimal stdio JSON-RPC front-end (Serve).
TS is canonical; this port mirrors it by fixture parity (test/fixtures/, run by both runtimes), never by code sharing. It exists so the generator can emit static, single-binary language servers for grammars that live in Go — or for any pure-data GrammarSpec, which is runtime-independent (design §7).
Index ¶
- Constants
- Variables
- func EntryFromSpecJSON(languageID string, extensions []string, spec []byte) (*Entry, MakeInstance)
- func ExtOf(uri string) string
- func NewInstance(e *Entry) *tabnas.Tabnas
- func Serve(cfg Config) error
- func TokenType(name string, overrides map[string]string) string
- func UTF16Len(s string) int
- type Analysis
- type CompletionItem
- type Config
- type Diagnostic
- type Doc
- type DocumentStore
- type DocumentSymbol
- type Entry
- type Instances
- func (s *Instances) Get(e *Entry) (*tabnas.Tabnas, error)
- func (s *Instances) Invalidate(e *Entry)
- func (s *Instances) Parse(inst *tabnas.Tabnas, src string, c *collector) (any, []*tabnas.TabnasError, error)
- func (s *Instances) Quarantined(e *Entry) bool
- func (s *Instances) RecordFailure(e *Entry)
- func (s *Instances) WithParseLock(fn func())
- type MakeInstance
- type Position
- type Range
- type Registry
- type Resolution
- type SemanticTokens
- type Server
Constants ¶
const QuarantineLimit = 3
const VERSION = "0.1.4"
VERSION is this package's version.
Variables ¶
var DefaultOutlineRules = map[string]string{
"map": "Object",
"list": "Array",
}
DefaultOutlineRules maps structural rule names to symbol labels.
var DefaultTokenTypes = map[string]string{
"#ST": "string",
"#NR": "number",
"#CM": "comment",
"#VL": "keyword",
"#TX": "string",
"#OB": "operator",
"#CB": "operator",
"#OS": "operator",
"#CS": "operator",
"#CL": "operator",
"#CA": "operator",
}
DefaultTokenTypes maps engine-standard token names (railroad's CANON key set) to LSP semantic token types. #ID is per-plugin and comes from entry overrides.
var Legend = []string{
"string", "number", "comment", "keyword", "operator", "variable",
"macro", "type", "property",
}
Legend is the fixed superset legend (design §11).
Functions ¶
func EntryFromSpecJSON ¶
func EntryFromSpecJSON(languageID string, extensions []string, spec []byte) (*Entry, MakeInstance)
EntryFromSpecJSON builds an Entry plus a grammar loader from a serialized GrammarSpec — the L2 lane, and the only lane a Go server needs for pure-data grammars. The spec bytes are expected to have passed the generation-time firewall (the generator refuses poisoned specs); GrammarSpecFromJSON re-applies the engine's own gates (schema-version ceiling among them) at load time.
func NewInstance ¶
NewInstance builds a bare engine instance configured for LSP use: recovery on (multi-error diagnostics), the entry's sync groups applied when it declares any.
func Serve ¶
Serve runs the server until the client closes the stream or sends exit. It returns nil on an orderly shutdown.
Types ¶
type Analysis ¶
type Analysis struct {
Value any
Errors []*tabnas.TabnasError
Failed bool
Diagnostics []Diagnostic
SemanticTokens *SemanticTokens
Outline []*DocumentSymbol
}
Analysis is everything one parse yields.
type CompletionItem ¶
type CompletionItem struct {
Label string `json:"label"`
Kind int `json:"kind"`
Detail string `json:"detail,omitempty"`
InsertText string `json:"insertText,omitempty"`
}
CompletionItem is the LSP completion item.
type Config ¶
type Config struct {
// Entries are the served languages.
Entries []*Entry
// MakeInstance builds the engine instance for an entry. Generated
// servers pass the closure from EntryFromSpecJSON or their own
// plugin-applying loader.
MakeInstance MakeInstance
// In/Out default to stdin/stdout.
In io.Reader
Out io.Writer
// Logf receives server-side log lines; default: stderr.
Logf func(format string, args ...any)
}
Config configures Serve.
type Diagnostic ¶
type Diagnostic struct {
Range Range `json:"range"`
Severity int `json:"severity"`
Code string `json:"code,omitempty"`
Source string `json:"source"`
Message string `json:"message"`
CodeDescription *codeDescription `json:"codeDescription,omitempty"`
}
Diagnostic is an LSP diagnostic.
func Diagnostics ¶
func Diagnostics(errs []*tabnas.TabnasError, entry *Entry, doc *Doc) []Diagnostic
Diagnostics converts engine errors to LSP diagnostics through the structured-diagnostic JSON — the exact bytes TS consumes — so the two ports cannot disagree about codes, rows, or the `len` unit.
type Doc ¶
type Doc struct {
URI string
LanguageID string
Version int
Text string
// contains filtered or unexported fields
}
Doc is one open document.
func (*Doc) LineStarts ¶
LineStarts returns the byte offset of each line start.
func (*Doc) PosFromEngine ¶
PosFromEngine converts an engine (row, col) — 1-based, col in runes — to an LSP Position.
func (*Doc) PositionAt ¶
PositionAt converts a byte offset to an LSP Position.
type DocumentStore ¶
type DocumentStore struct {
// contains filtered or unexported fields
}
DocumentStore holds the open documents.
func NewDocumentStore ¶
func NewDocumentStore() *DocumentStore
func (*DocumentStore) Close ¶
func (s *DocumentStore) Close(uri string)
func (*DocumentStore) Get ¶
func (s *DocumentStore) Get(uri string) *Doc
type DocumentSymbol ¶
type DocumentSymbol struct {
Name string `json:"name"`
Kind int `json:"kind"`
Range Range `json:"range"`
SelectionRange Range `json:"selectionRange"`
Children []*DocumentSymbol `json:"children"`
// contains filtered or unexported fields
}
DocumentSymbol is the LSP hierarchical symbol. Children hold pointers so nesting never copies a subtree that later grows.
func Outline ¶
func Outline(events []ruleEvent, entry *Entry, doc *Doc) []*DocumentSymbol
Outline derives nested document symbols from one parse's rule events.
type Entry ¶
type Entry struct {
Name string
LanguageID string
Extensions []string
// PluginKind: grammar | compiler | modifier. Modifiers are never
// routing targets.
PluginKind string
// LexStream gates semantic tokens: only "clean" entries (no relex,
// no rewind) serve them. Default "clean".
LexStream string
// SemanticTokens maps engine token names to LSP token types,
// overriding the CANON defaults (core DefaultTokenTypes).
SemanticTokens map[string]string
// OutlineRules maps rule names to symbol labels, overriding the
// defaults (map -> Object, list -> Array).
OutlineRules map[string]string
// SyncGroups REPLACES the engine's recovery sync-group defaults
// when non-nil (mirrors the TS option's semantics).
SyncGroups []string
// Enabled follows the editor-collision policy; disabled entries
// are not routed.
Enabled bool
}
Entry describes one served language: the Go mirror of a registry entry (ts/src/registry.js). Generated servers construct these statically; there is no bundled fleet registry on the Go side — fleet grammars are npm modules, and only pure-data specs or Go plugin packages can serve from a Go binary.
type Instances ¶
type Instances struct {
// contains filtered or unexported fields
}
Instances caches engine instances per entry, serializes parses, and quarantines repeatedly failing grammars (design §6).
func NewInstances ¶
func NewInstances(makeInst MakeInstance) *Instances
func (*Instances) Get ¶
Get returns the cached instance for an entry, building it (and installing the permanent mux) on first use. nil when quarantined.
func (*Instances) Invalidate ¶
Invalidate drops an entry's cached instance (grammar hot-reload: rebuild, never re-apply — Grammar() prepends alternates).
func (*Instances) Parse ¶
func (s *Instances) Parse(inst *tabnas.Tabnas, src string, c *collector) (any, []*tabnas.TabnasError, error)
Parse runs one parse with the collector active. parseMu serializes parses across all instances, so the subscribers — which run synchronously inside the parsing goroutine — always see the one active collector. Continuations' internal parses (routed through Complete) hold the same lock with a nil collector, making the mux a no-op for them.
func (*Instances) Quarantined ¶
func (*Instances) RecordFailure ¶
func (*Instances) WithParseLock ¶
func (s *Instances) WithParseLock(fn func())
WithParseLock runs fn with the parse lock held and no collector active — the engine-call guard for non-analyze parses such as Continuations.
type MakeInstance ¶
MakeInstance builds (or rebuilds, on reload) the engine instance for an entry. Instances installs the single mux subscriber on whatever this returns — implementations must NOT install their own subscribers for the pipeline's events.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
func NewRegistry ¶
func (*Registry) Resolve ¶
func (r *Registry) Resolve(languageID, uri string) Resolution
type Resolution ¶
type Resolution struct {
Entry *Entry
Via string // "languageId" | "extension" | ""
Ambiguous []string
}
Resolution names the entry and how it was reached; Ambiguous lists competing languageIds when an extension is claimed more than once.
type SemanticTokens ¶
SemanticTokens is the LSP result plus the legend it indexes.
func SemanticTokensOf ¶
func SemanticTokensOf(events []tokenPoint, entry *Entry, doc *Doc) *SemanticTokens
SemanticTokensOf derives the delta-encoded token data (line and character deltas in UTF-16 units, per the negotiated encoding). Tokens spanning lines are split into line-local spans, mirroring the TS core: multiline semantic tokens are an optional client capability, and an unsplit one mis-highlights or is rejected by clients without it.