2026-02-14 15:05:12 +01:00
2026-02-14 15:05:12 +01:00
2026-02-14 15:05:12 +01:00
2026-02-14 15:05:12 +01:00
2026-02-14 15:05:12 +01:00
2026-02-14 15:05:12 +01:00

SCL Language Server - Unified Plugin for Siemens SCL

A comprehensive Neovim/LazyVim plugin providing Language Server Protocol (LSP), Linting, Formatting, and Syntax Highlighting for Siemens SCL (Structured Control Language) used in Siemens TIA Portal.

Features

LSP (Language Server Protocol)

Feature Description
Hover Press K to see variable type and struct fields
Completion # for variables, . for struct fields, ( for functions
Go to Definition gd jump to variable declaration
Document Symbols Shows functions, variables, types
Workspace Symbols Search across all .scl files with fuzzy matching
Semantic Tokens Keywords, variables highlighted
Inlay Hints Shows variable types after declaration
External UDT Load types from .plc.json or data_types/ folder

Linter (Diagnostics)

Feature Description
Undefined Variables Detects variables used without declaration
Invalid # Prefix Detects # prefix in VAR sections
Unknown Types Warns about unknown data types
Type Validation Basic type checking

Formatter

Feature Description
Document Formatting Format entire SCL files
Indentation Proper block indentation
Keyword Casing Maintains SCL keyword casing

Syntax Highlighting

  • Full SCL syntax support via tree-sitter
  • ORGANIZATION_BLOCK, FUNCTION_BLOCK, FUNCTION definitions
  • Variable declarations (VAR_INPUT, VAR_OUTPUT, VAR_IN_OUT, VAR_TEMP, etc.)
  • Control structures (IF/THEN/ELSE, CASE, FOR, WHILE, REPEAT)
  • Code regions and comments
  • All SCL data types and operators

Additional Features

Feature Description
Auto-Prefix Automatically adds # prefix to local variables (like TIA Portal)
Workspace UDT Scanner Scans project for user-defined types
blink.cmp Integration Smart completion source for blink.cmp

Installation

LazyVim

-- ~/.config/nvim/lua/plugins/scl.lua
return {
  "lazar/scl_lsp",
  ft = "scl",
  lazy = true,
  dependencies = {
    "neovim/nvim-lspconfig",
    "nvim-treesitter/nvim-treesitter",
    "saghen/blink.cmp",
  },
  config = function()
    require("scl_lsp").setup({
      -- LSP options
      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,
}

Manual Setup

-- In your init.lua or plugin file
require("scl_lsp").setup({
  server_path = "/path/to/scl_lsp/src/main.lua",
  cmp = true,
  workspace_types = true,
  auto_prefix = true,
})

Configuration Options

Option Type Default Description
server_path string ~/dev/scl_lsp/src/main.lua Path to LSP server
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 and FB count
:SCLRescanWorkspaceTypes Rescan workspace for types
:SCLPrefixWord Manually prefix current word with #
:LspSCLFormat Format current SCL file
:SCLGeneratePlcJson Generate plc.data.json from data_types/

Keybindings

Key Action
K Hover (show variable info)
gd Go to Definition
<leader>s Document Symbols
<leader>w Workspace Symbols
<leader>fw Workspace Symbols (Telescope)
<leader>ca Code Actions

External UDT Support

Option 1: Create .plc.json

{
  "dataTypes": [
    {
      "name": "equipmentData",
      "struct": [
        {"name": "id", "dataTypeName": "INT"},
        {"name": "status", "dataTypeName": "BOOL"},
        {"name": "temperature", "dataTypeName": "REAL"}
      ]
    }
  ]
}

Option 2: Auto-scan data_types/ folder

The LSP automatically scans for SCL files in data_types/ folder and extracts TYPE definitions.

Option 3: Generate .plc.json

lua /home/lazar/dev/scl_lsp/src/plc_json.lua --generate

Project Structure

scl_lsp/
├── README.md                    # This file
├── package.json                 # NPM scripts (tree-sitter)
├── Makefile                     # Build commands
├── grammar.js                   # Tree-sitter grammar
├── tree-sitter.json            # Parser config
├── queries/                    # Tree-sitter queries
│   ├── highlights.scm         # Syntax highlighting
│   ├── indents.scm            # Indentation
│   ├── folds.scm              # Code folding
│   ├── locals.scm             # Variable scoping
│   └── tags.scm               # Navigation tags
├── src/                        # LSP server
│   ├── main.lua               # Main entry point
│   ├── parser.lua             # Regex-based parser
│   ├── treesitter.lua         # Tree-sitter integration
│   ├── json.lua               # JSON encoder/decoder
│   ├── plc_json.lua           # External UDT loading
│   ├── diagnostics.lua        # Linter diagnostics
│   └── formatter.lua          # Document formatter
└── lua/
    └── scl_lsp/
        ├── init.lua           # Main plugin setup
        ├── plugins/
        │   └── scl.lua        # LazyVim plugin spec
        └── scl/               # Syntax/completion modules
            ├── init.lua
            ├── auto_prefix.lua
            ├── blink_cmp_source.lua
            ├── fb_parser.lua
            ├── udt_parser.lua
            ├── variables.lua
            └── workspace_types.lua

Building Tree-sitter Parser

# Generate parser from grammar.js
npm run build
# or: tree-sitter generate

# Run tests
npm test
# or: tree-sitter test

SCL Code Example

FUNCTION_BLOCK "Em101Sequence"
VAR
    x : INT;
    myVar : equipmentData;  // User-defined type
END_VAR

IF x > 5 THEN
    myVar.id := 10;
END_IF

myVar.status := TRUE;
myVar.temperature := 25.5;

END_FUNCTION_BLOCK

Requirements

  • Neovim 0.9+
  • nvim-lspconfig - LSP client
  • nvim-treesitter - Syntax highlighting
  • blink.cmp - Optional, for completion
  • Lua 5.1+ - LSP server runtime
S
Description
No description provided
Readme
177 KiB
Languages
Lua 96.7%
Tree-sitter Query 3.2%