lazar 8255db7f64 chore: adjust for plugin-only scope after split
After splitting from the original scl_lsp repo, update for plugin-only scope:

- README.md: focused on Neovim plugin installation, configuration,
  commands, keybindings, and editor features
- AGENTS.md: plugin-only project structure and conventions
- test/run_tests.lua: run only plugin tests (udt, db, fb, integration)
- test/test_integration.lua: remove plc_json dependency (server module)
- queries/: move from queries/*.scm to queries/scl/*.scm (nvim-treesitter
  per-language convention)
- ftdetect/scl.vim: add filetype detection for .scl/.udt/.db files
2026-07-18 11:46:18 +02:00

tia-lsp.nvim - Neovim Plugin for Siemens TIA Portal

A Neovim/LazyVim plugin that launches the tia-lsp language server and adds editor-specific features for Siemens TIA Portal languages. Currently supports SCL (Structured Control Language), with planned support for STL/AWL, LAD, and FBD.

Features

Feature Description
Auto-Prefix Automatically adds # prefix to local variables (like TIA Portal)
Multiline Parameters Fill FB/Function call parameters across multiple lines with <Space>mp or :SCLMultilineParams
Tab Navigation Jump between parameters with <Tab> in insert mode
Workspace UDT Scanner Scans project for user-defined types (.udt files)
Workspace Global DB Scanner Scans project for global data blocks (.db files)
blink.cmp Integration Smart completion source for blink.cmp
Attribute Block Toggle Interactive expand/collapse of {...} blocks with <Leader>xa
Tree-sitter Highlighting Syntax highlighting via tree-sitter queries

Installation

The plugin auto-detects the mason-installed tia-lsp executable via vim.fn.exepath("tia-lsp") and falls back to lua <server_path> for manual installs.

  1. Add the mason registry as a lazy.nvim plugin:

    -- ~/.config/nvim/lua/plugins/tia-mason-registry.lua
    return {
      url = "https://gitea.l-tech.rs/lazar/tia-mason-registry.git",
      name = "tia-mason-registry",
      lazy = false,  -- must be available before mason setup
    }
    
  2. Register the registry with mason:

    -- ~/.config/nvim/lua/plugins/mason.lua
    return {
      "mason-org/mason.nvim",
      opts = {
        registries = {
          "file:" .. vim.fn.expand("~/.local/share/nvim/lazy/tia-mason-registry"),
          "github:mason-org/mason-registry",
        },
      },
    }
    
  3. Add the plugin:

    -- ~/.config/nvim/lua/plugins/tia-lsp.lua
    return {
      "lazar/tia-lsp.nvim",
      ft = "scl",
      lazy = true,
      dependencies = {
        "neovim/nvim-lspconfig",
        "nvim-treesitter/nvim-treesitter",
        "saghen/blink.cmp",
      },
      config = function()
        require("tia_lsp").setup({
          lsp = {
            on_attach = function(client, bufnr)
              -- custom keymaps
            end,
          },
          cmp = true,              -- Enable blink.cmp integration
          workspace_types = true,  -- Enable workspace UDT scanning
          auto_prefix = true,      -- Enable auto-# prefixing
          debug = false,
        })
      end,
    }
    
  4. Install:

    :MasonInstall yq       " one-time prerequisite for file: registry
    :MasonInstall tia-lsp  " installs the LSP server
    
  5. Verify: open a .scl file and run :LspInfotia_lsp should be attached.

Manual Setup (without Mason)

require("tia_lsp").setup({
  server_path = "/path/to/tia-lsp/src/main.lua",  -- only used if tia-lsp is not on PATH
  ts_parser_url = "https://gitea.l-tech.rs/lazar/tia-lsp.git",
  cmp = true,
  workspace_types = true,
  auto_prefix = true,
})

Configuration Options

Option Type Default Description
server_path string ~/dev/tia-lsp/src/main.lua Path to LSP server (only used if tia-lsp is not on PATH)
ts_parser_url string file://~/dev/tia-lsp URL passed to nvim-treesitter for the SCL parser source
lsp.on_attach function nil Custom LSP attach callback
lsp.formatting boolean false Enable format command
cmp boolean true Enable blink.cmp integration
workspace_types boolean true Enable workspace UDT scanning
auto_prefix boolean true Enable auto-# prefixing
project_root string nil Custom project root
library_paths table {} Additional library paths
debug boolean false Enable debug logging

Commands

Command Description
:SCLShowVariables Show local variables in current file
:SCLShowWorkspaceTypes Show workspace UDTs, FBs, and Global DBs count
:SCLRescanWorkspaceTypes Rescan workspace for types and DBs
:SCLPrefixWord Manually prefix current word with #
:SCLMultilineParams Fill multiline parameters for FB/Function call
:SCLFormat Format current SCL file
:SCLToggleAttrBlock Toggle attribute block under cursor
:SCLExpandAllAttrBlocks Expand all {...} blocks in buffer
:SCLCollapseAllAttrBlocks Collapse all matching attribute blocks

Keybindings

Key Action
K Hover (show variable info)
gd Go to Definition
<leader>s Document Symbols
<leader>w Workspace Symbols
<Space>mp Fill multiline FB/Function parameters (insert mode)
<Tab> Jump to next parameter (insert mode)
<Leader>xa Toggle attribute block under cursor
<Leader>xae Expand all attribute blocks
<Leader>xac Collapse all attribute blocks
<leader>fw Workspace Symbols (Telescope)
<leader>ca Code Actions

Attribute Block Toggle

Interactive expand/collapse of SCL variable attribute blocks:

-- Before: Verbose attributes
statCounter{EXTERNALACCESSIBLE := 'false'; EXTERNALVISIBLE := 'false'} : Int;

-- After: Collapsed
statCounter{...} : Int;

Usage:

  • Place cursor inside any {...} block
  • Press <Leader>xa to toggle expand/collapse
  • Use <Leader>xae to expand all blocks in buffer
  • Use <Leader>xac to collapse all blocks

Note: Collapsed blocks are automatically expanded before saving to preserve full content on disk.

Filetype Detection

The plugin includes ftdetect/scl.vim which registers the following file extensions as scl filetype:

  • *.scl — SCL source files
  • *.udt — User-defined type files
  • *.db — Data block files

Project Structure

tia-lsp.nvim/
├── lua/
│   ├── tia_lsp/                 # Plugin entry point
│   │   ├── init.lua             # Main setup (vim.lsp.start, exepath detection)
│   │   └── plugins/
│   │       └── scl.lua          # LazyVim plugin spec (SCL filetype)
│   └── tia/                     # Language modules (shared across TIA languages)
│       ├── auto_prefix.lua      # Auto-# prefixing
│       ├── attr_toggle.lua      # Attribute block expand/collapse
│       ├── blink_cmp_source.lua # blink.cmp completion source
│       ├── builtin_instructions.lua
│       ├── db_parser.lua        # Global DB parser
│       ├── fb_parser.lua        # Function Block parser
│       ├── multiline_params.lua # Multiline parameter filling
│       ├── udt_parser.lua       # UDT parser
│       ├── variables.lua        # Variable extraction
│       └── workspace_types.lua  # Workspace scanning
├── queries/
│   └── scl/                     # Tree-sitter queries (per-language)
│       ├── highlights.scm       # Syntax highlighting
│       ├── indents.scm          # Indentation
│       ├── folds.scm            # Code folding
│       ├── locals.scm           # Variable scoping
│       └── tags.scm             # Navigation tags
├── ftdetect/
│   └── scl.vim                  # Filetype detection
└── test/                        # Plugin tests
    ├── run_tests.lua
    ├── test_harness.lua
    ├── test_udt.lua
    ├── test_db.lua
    ├── test_fb.lua
    └── test_integration.lua

Requirements

  • Neovim 0.11+ (uses vim.lsp.start())
  • tia-lsp — the LSP server (install via mason or manually)
  • nvim-treesitter — Syntax highlighting
  • blink.cmp — Optional, for completion
  • Lua 5.1+ — LSP server runtime

Testing

lua test/run_tests.lua

Tests use files from a reference project (override with SCL_REF_PROJECT=/path/to/ref lua test/run_tests.lua).

S
Description
No description provided
Readme
177 KiB
Languages
Lua 96.7%
Tree-sitter Query 3.2%