Language Server (LSP)

BioLang includes a Language Server Protocol implementation for diagnostics, completion, and hover information. Start it with bl lsp from an LSP-compatible editor.

Features

  • Diagnostics — Real-time error and warning underlines produced by the current parser and checker.
  • Completion — Context-aware suggestions for language keywords, registered builtins, and symbols declared in the current document.
  • Hover — Hover over any builtin or current-document symbol to see the information available to the server.

VS Code Setup

This repository does not currently ship a VS Code extension. BioLang Desktop already integrates the language server. A third-party VS Code LSP client must launch bl lsp and associate it with .bl files.

Neovim Setup

Using nvim-lspconfig:

-- In your Neovim LSP configuration (e.g., init.lua)
local lspconfig = require('lspconfig')
local configs = require('lspconfig.configs')

-- Register the BioLang LSP
if not configs.biolang then
  configs.biolang = {
    default_config = {
      cmd = { 'bl', 'lsp' },
      filetypes = { 'biolang' },
      root_dir = lspconfig.util.root_pattern('biolang.toml', '.git'),
      settings = {},
    },
  }
end

lspconfig.biolang.setup({
  on_attach = function(client, bufnr)
    -- Enable completion triggered by <c-x><c-o>
    vim.api.nvim_buf_set_option(bufnr, 'omnifunc', 'v:lua.vim.lsp.omnifunc')

    -- Keybindings
    local opts = { noremap = true, silent = true, buffer = bufnr }
    vim.keymap.set('n', 'K', vim.lsp.buf.hover, opts)
  end,
})

For file type detection, add to ~/.config/nvim/ftdetect/biolang.lua:

vim.filetype.add({
  extension = {
    bl = 'biolang',
  },
})

Emacs Setup

Define a minimal major mode, then register bl lsp with lsp-mode or eglot:

With lsp-mode

(define-derived-mode biolang-mode prog-mode "BioLang")
(add-to-list 'auto-mode-alist '("\\.bl\\'" . biolang-mode))

;; Register the LSP server
(with-eval-after-load 'lsp-mode
  (add-to-list 'lsp-language-id-configuration '(biolang-mode . "biolang"))
  (lsp-register-client
   (make-lsp-client
    :new-connection (lsp-stdio-connection '("bl" "lsp"))
    :activation-fn (lsp-activate-on "biolang")
    :server-id 'biolang-ls)))

;; Enable LSP for BioLang files
(add-hook 'biolang-mode-hook #'lsp)

With eglot (Emacs 29+)

(add-to-list 'eglot-server-programs
             '(biolang-mode "bl" "lsp"))
(add-hook 'biolang-mode-hook #'eglot-ensure)

Helix Setup

Add to ~/.config/helix/languages.toml:

[[language]]
name = "biolang"
scope = "source.biolang"
file-types = ["bl"]
language-servers = ["biolang-lsp"]
indent = { tab-width = 2, unit = "  " }
comment-token = "#"

[language-server.biolang-lsp]
command = "bl"
args = ["lsp"]

Completion Details

The LSP provides rich completion across several categories:

# After typing "seq |> ", completions show:
gc_content(seq)          Float — GC content as fraction 0.0-1.0
reverse_complement(seq)  DNA — Reverse complement of sequence
complement(seq)          DNA — Complement without reversing
transcribe(seq)          RNA — Transcribe DNA to RNA
len(seq)                 Int — Sequence length
  slice(start, end)     DNA — Extract subsequence
validate(path)        Record — Validate a supported data file
kmer_count(seq, k)    Table — Count all k-mers

# After typing "ncbi_", completions show:
  ncbi_search(db, term)     — Search an NCBI database
  ncbi_fetch(ids, db)       — Fetch records by ID list
  ncbi_summary(db, id)      — Get document summary
  ncbi_gene(term)           — Quick gene lookup
  ncbi_sequence(id)         — Fetch sequence as FASTA text
  ncbi_pubmed(term)         — Search PubMed

Hover Information

Hovering over identifiers shows contextual information:

# Hovering over gc_content shows:
┌──────────────────────────────────────────────┐
│ gc_content(seq) -> Float                     │
│                                              │
│ Calculate the GC content (fraction of G+C    │
│ bases) of a DNA or RNA sequence.             │
│                                              │
│ Returns: Float between 0.0 and 1.0           │
│                                              │
│ Example:                                     │
│   dna"ATCGATCG" |> gc_content()  # => 0.5   │
└──────────────────────────────────────────────┘

# Hovering over a variable shows its inferred type:
┌──────────────────────────────────────────────┐
│ seq: DNA                                     │
│ Defined at line 3                            │
│ Value: dna"ATCGATCG"                         │
└──────────────────────────────────────────────┘

Diagnostics

The LSP and browser editors share lexer and parser diagnostics. They report malformed syntax in real time; name, type, file, and data-dependent failures remain execution errors and are shown when the cell or script runs.

# Missing closing bracket (red underline)
let values = [1, 2, 3
                      ^
error: expected ']'

# Incomplete expression (red underline)
let centre =
            ^
error: expected expression

Troubleshooting

Start bl lsp without additional flags and inspect the language-server output captured by your editor. The current CLI communicates over standard input and output and does not expose logging flags.

bl lsp