refactor: rename scl_lsp → tia_lsp (project umbrella for future STL/LAD/FBD)
Rename the project from scl_lsp to tia_lsp to future-proof for additional
TIA Portal languages (STL/AWL, LAD, FBD). The 'scl' language name is kept
as-is for the SCL filetype and tree-sitter parser; future languages get
their own names (stl, lad, fbd).
Project-wide changes:
- lua/scl_lsp/ → lua/tia_lsp/ (plugin entry point)
- lua/scl/ → lua/tia/ (language modules, shared across TIA langs)
- require('scl.*') → require('tia.*')
- require('scl_lsp') → require('tia_lsp')
- LSP client name: 'scl_lsp' → 'tia_lsp'
- Diagnostic source: 'scl_lsp' → 'tia_lsp' (src/diagnostics.lua)
- package.json name: 'scl-language-server' → 'tia-lsp'
lua/tia_lsp/init.lua:
- Add vim.fn.exepath('tia-lsp') detection so the plugin prefers the
mason-installed executable and falls back to { 'lua', server_path }
for manual installs.
- Add opts.ts_parser_url to configure the tree-sitter parser source.
- Remove hardcoded ~/dev/scl_lsp paths in favor of ~/dev/tia-lsp and
the new ts_parser_url option.
Cleanup:
- Delete lua/tia/init.lua (dead code, unreferenced duplicate of tia_lsp).
- Delete scl_lsp.sh (replaced by the mason-installed bin/tia-lsp wrapper).
- Update README.md and AGENTS.md to reflect the two-repo split
(tia-lsp server + tia-lsp.nvim plugin) and document Mason installation.
Unchanged (intentional):
- grammar.js, src/grammar.json, src/parser.c: tree-sitter language name
remains 'scl' (it's the language, not the project).
- Filetype patterns ('scl', 'udt', 'db') in autocmds.
- :SCL* command names (per-filetype prefix; future :STL* etc.).
Tests pass with the same pre-existing failures as before the rename
(formatter VAR_INPUT test, udt_parser line 199 const-variable bug,
plc_json reference-project-missing). No new failures introduced.
This commit is contained in:
@@ -1,6 +1,9 @@
|
|||||||
# AGENTS.md - SCL Language Server
|
# AGENTS.md - tia-lsp
|
||||||
|
|
||||||
A Neovim/LazyVim plugin for Siemens SCL language support providing LSP, linting, formatting, syntax highlighting, and auto-completion.
|
A Neovim/LazyVim plugin and standalone LSP server for Siemens TIA Portal languages. Currently supports **SCL**; planned support for STL/AWL, LAD, FBD. The project is split into two repos:
|
||||||
|
|
||||||
|
- **`tia-lsp`** (this repo) — LSP server (`src/`) + tree-sitter grammar (`grammar.js`). Editor-agnostic.
|
||||||
|
- **`tia-lsp.nvim`** — Neovim plugin (`lua/`) that launches the server and adds editor features.
|
||||||
|
|
||||||
## Build/Lint/Test Commands
|
## Build/Lint/Test Commands
|
||||||
|
|
||||||
@@ -17,7 +20,7 @@ tree-sitter parse <file.scl> # Parse single SCL file
|
|||||||
|
|
||||||
# Lua Linting
|
# Lua Linting
|
||||||
luacheck src/ # Lint LSP server code
|
luacheck src/ # Lint LSP server code
|
||||||
luacheck lua/scl/ # Lint plugin modules
|
luacheck lua/tia/ # Lint plugin modules
|
||||||
|
|
||||||
# Unit & Integration Tests
|
# Unit & Integration Tests
|
||||||
lua test/run_tests.lua # Run all tests
|
lua test/run_tests.lua # Run all tests
|
||||||
@@ -36,18 +39,17 @@ lua test/test_integration.lua # Run integration tests
|
|||||||
## Project Structure
|
## Project Structure
|
||||||
|
|
||||||
```
|
```
|
||||||
scl_lsp/
|
tia-lsp/
|
||||||
├── src/ # LSP server (uses dofile)
|
├── src/ # LSP server (uses dofile)
|
||||||
│ ├── main.lua # Entry point, JSON-RPC protocol
|
│ ├── main.lua # Entry point, JSON-RPC protocol
|
||||||
│ ├── parser.lua # SCL parser
|
│ ├── parser.lua # SCL parser (will become parser_scl.lua + dispatch)
|
||||||
│ ├── diagnostics.lua # Linter
|
│ ├── diagnostics.lua # Linter (source = "tia_lsp")
|
||||||
│ ├── formatter.lua # Document formatter
|
│ ├── formatter.lua # Document formatter
|
||||||
│ ├── treesitter.lua # Tree-sitter integration
|
│ ├── treesitter.lua # Tree-sitter integration
|
||||||
│ ├── plc_json.lua # External UDT/DB loading
|
│ ├── plc_json.lua # External UDT/DB loading (language-agnostic)
|
||||||
│ ├── builtin_instructions.lua # TIA Portal built-in types
|
│ ├── builtin_instructions.lua # TIA Portal built-in types
|
||||||
│ └── json.lua # JSON encoder/decoder
|
│ └── json.lua # JSON encoder/decoder
|
||||||
├── lua/scl/ # Neovim plugin (uses require)
|
├── lua/tia/ # Neovim plugin (uses require)
|
||||||
│ ├── init.lua # Main plugin setup
|
|
||||||
│ ├── udt_parser.lua # UDT parser
|
│ ├── udt_parser.lua # UDT parser
|
||||||
│ ├── db_parser.lua # Global DB parser
|
│ ├── db_parser.lua # Global DB parser
|
||||||
│ ├── fb_parser.lua # Function Block parser
|
│ ├── fb_parser.lua # Function Block parser
|
||||||
@@ -56,13 +58,24 @@ scl_lsp/
|
|||||||
│ ├── multiline_params.lua
|
│ ├── multiline_params.lua
|
||||||
│ ├── auto_prefix.lua
|
│ ├── auto_prefix.lua
|
||||||
│ └── attr_toggle.lua
|
│ └── attr_toggle.lua
|
||||||
├── queries/ # Tree-sitter queries
|
├── lua/tia_lsp/ # Plugin entry point
|
||||||
└── grammar.js # Tree-sitter grammar
|
│ ├── init.lua # Main plugin setup (vim.lsp.start)
|
||||||
|
│ └── plugins/scl.lua # LazyVim plugin spec
|
||||||
|
├── queries/ # Tree-sitter queries (per-language: queries/scl/)
|
||||||
|
└── grammar.js # Tree-sitter grammar (language name: 'scl')
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Naming Convention
|
||||||
|
|
||||||
|
- **Project name** (repo, Lua module, LSP server, mason package): `tia-lsp` / `tia_lsp` — umbrella for all TIA languages.
|
||||||
|
- **Language name** (filetype, tree-sitter parser, grammar): `scl` — stays as-is. Future languages (`stl`, `lad`, `fbd`) get their own names.
|
||||||
|
- **LSP client name**: `tia_lsp` (one client handles all TIA languages; dispatches by `filetype` / `languageId`).
|
||||||
|
- **Diagnostic source**: `tia_lsp`.
|
||||||
|
- **Commands**: `:SCLFormat`, `:SCLShowVariables`, etc. — per-filetype prefix. Future: `:STLFormat`, etc.
|
||||||
|
|
||||||
## Filetype Detection
|
## Filetype Detection
|
||||||
|
|
||||||
Required in Neovim config (ftdetect/scl.vim):
|
After the split, `ftdetect/scl.vim` will live in `tia-lsp.nvim`. Currently required in Neovim config:
|
||||||
```vim
|
```vim
|
||||||
au BufRead,BufNewFile *.scl set filetype=scl
|
au BufRead,BufNewFile *.scl set filetype=scl
|
||||||
au BufRead,BufNewFile *.udt set filetype=scl
|
au BufRead,BufNewFile *.udt set filetype=scl
|
||||||
@@ -93,12 +106,13 @@ return M
|
|||||||
- Booleans: prefix with `is_`, `has_` (e.g., `is_udt`, `has_members`)
|
- Booleans: prefix with `is_`, `has_` (e.g., `is_udt`, `has_members`)
|
||||||
|
|
||||||
### Imports
|
### Imports
|
||||||
- `lua/scl/` modules: `require("scl.module_name")`
|
- `lua/tia/` modules: `require("tia.module_name")`
|
||||||
|
- `lua/tia_lsp/` entry: `require("tia_lsp")`
|
||||||
- `src/` modules: `dofile(script_path .. "/module.lua")`
|
- `src/` modules: `dofile(script_path .. "/module.lua")`
|
||||||
- External dependencies: wrap in `pcall()` for safety
|
- External dependencies: wrap in `pcall()` for safety
|
||||||
|
|
||||||
### Code Formatting
|
### Code Formatting
|
||||||
- `lua/scl/`: 2 spaces indentation
|
- `lua/tia/` and `lua/tia_lsp/`: 2 spaces indentation
|
||||||
- `src/`: tab-based indentation
|
- `src/`: tab-based indentation
|
||||||
- Max line length: 120 characters
|
- Max line length: 120 characters
|
||||||
- No trailing whitespace
|
- No trailing whitespace
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
# SCL Language Server - Unified Plugin for Siemens SCL
|
# tia-lsp - Language Server for Siemens TIA Portal
|
||||||
|
|
||||||
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.
|
A Neovim/LazyVim plugin and standalone LSP server providing **Language Server Protocol (LSP)**, **Linting**, **Formatting**, and **Syntax Highlighting** for Siemens TIA Portal languages. Currently supports **SCL** (Structured Control Language), with planned support for **STL/AWL**, **LAD**, and **FBD**.
|
||||||
|
|
||||||
|
The project is split into two repos:
|
||||||
|
|
||||||
|
- **`tia-lsp`** (this repo) — the standalone LSP server (`src/`) plus the tree-sitter grammar (`grammar.js`, `src/parser.c`). Speaks JSON-RPC over stdio. Editor-agnostic: usable from Neovim, VS Code, or any LSP client.
|
||||||
|
- **`tia-lsp.nvim`** — the Neovim plugin (`lua/`) that launches the server via `vim.lsp.start()` and adds editor-specific features (auto-prefix, blink.cmp source, workspace UDT scanning, attribute toggle, multiline params).
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
@@ -58,11 +63,13 @@ A comprehensive Neovim/LazyVim plugin providing **Language Server Protocol (LSP)
|
|||||||
|
|
||||||
## Installation
|
## 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. See [Mason installation](#mason-installation) below for the recommended path.
|
||||||
|
|
||||||
### LazyVim
|
### LazyVim
|
||||||
```lua
|
```lua
|
||||||
-- ~/.config/nvim/lua/plugins/scl.lua
|
-- ~/.config/nvim/lua/plugins/tia-lsp.lua
|
||||||
return {
|
return {
|
||||||
"lazar/scl_lsp",
|
"lazar/tia-lsp.nvim",
|
||||||
ft = "scl",
|
ft = "scl",
|
||||||
lazy = true,
|
lazy = true,
|
||||||
dependencies = {
|
dependencies = {
|
||||||
@@ -71,7 +78,7 @@ return {
|
|||||||
"saghen/blink.cmp",
|
"saghen/blink.cmp",
|
||||||
},
|
},
|
||||||
config = function()
|
config = function()
|
||||||
require("scl_lsp").setup({
|
require("tia_lsp").setup({
|
||||||
-- LSP options
|
-- LSP options
|
||||||
lsp = {
|
lsp = {
|
||||||
on_attach = function(client, bufnr)
|
on_attach = function(client, bufnr)
|
||||||
@@ -90,19 +97,59 @@ return {
|
|||||||
### Manual Setup
|
### Manual Setup
|
||||||
```lua
|
```lua
|
||||||
-- In your init.lua or plugin file
|
-- In your init.lua or plugin file
|
||||||
require("scl_lsp").setup({
|
require("tia_lsp").setup({
|
||||||
server_path = "/path/to/scl_lsp/src/main.lua",
|
server_path = "/path/to/tia-lsp/src/main.lua", -- only used if tia-lsp is not on PATH
|
||||||
|
ts_parser_url = "https://your-gitea/tia-lsp.git", -- tree-sitter parser source
|
||||||
cmp = true,
|
cmp = true,
|
||||||
workspace_types = true,
|
workspace_types = true,
|
||||||
auto_prefix = true,
|
auto_prefix = true,
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Mason installation
|
||||||
|
|
||||||
|
`tia-lsp` can be installed via [mason.nvim](https://github.com/mason-org/mason.nvim) using a custom registry. The setup below uses a `file:` registry sourced from a Gitea-hosted `tia-mason-registry` repo (cloned by lazy.nvim), and falls back to the official mason registry for any other packages.
|
||||||
|
|
||||||
|
1. Clone the registry repo as a lazy.nvim plugin:
|
||||||
|
```lua
|
||||||
|
-- ~/.config/nvim/lua/plugins/tia-mason-registry.lua
|
||||||
|
return {
|
||||||
|
url = "https://your-gitea/tia-mason-registry.git",
|
||||||
|
name = "tia-mason-registry",
|
||||||
|
lazy = false, -- must be available before mason setup
|
||||||
|
}
|
||||||
|
```
|
||||||
|
2. Register the registry with mason:
|
||||||
|
```lua
|
||||||
|
-- ~/.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. Install `yq` (one-time prerequisite for mason's `file:` registry):
|
||||||
|
```
|
||||||
|
:MasonInstall yq
|
||||||
|
```
|
||||||
|
4. Install the server:
|
||||||
|
```
|
||||||
|
:MasonInstall tia-lsp
|
||||||
|
```
|
||||||
|
5. Verify: open a `.scl` file and run `:LspInfo` — `tia_lsp` should be attached, and `vim.fn.exepath("tia-lsp")` should resolve to `~/.local/share/nvim/mason/bin/tia-lsp`.
|
||||||
|
|
||||||
|
To upgrade: tag a new `vX.Y.Z` release on the `tia-lsp` Gitea repo, bump `source.id` in `tia-mason-registry/packages/tia-lsp/package.yaml`, push the registry repo, then `:MasonInstall tia-lsp` again.
|
||||||
|
|
||||||
## Configuration Options
|
## Configuration Options
|
||||||
|
|
||||||
| Option | Type | Default | Description |
|
| Option | Type | Default | Description |
|
||||||
|--------|------|---------|-------------|
|
|--------|------|---------|-------------|
|
||||||
| `server_path` | string | `~/dev/scl_lsp/src/main.lua` | Path to LSP server |
|
| `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.on_attach` | function | `nil` | Custom LSP attach callback |
|
||||||
| `lsp.formatting` | boolean | `false` | Enable format command |
|
| `lsp.formatting` | boolean | `false` | Enable format command |
|
||||||
| `cmp` | boolean | `true` | Enable blink.cmp integration |
|
| `cmp` | boolean | `true` | Enable blink.cmp integration |
|
||||||
@@ -185,7 +232,7 @@ The LSP automatically scans for SCL files in `data_types/` folder and extracts T
|
|||||||
|
|
||||||
### Option 3: Generate `.plc.json`
|
### Option 3: Generate `.plc.json`
|
||||||
```bash
|
```bash
|
||||||
lua /home/lazar/dev/scl_lsp/src/plc_json.lua --generate
|
lua ~/dev/tia-lsp/src/plc_json.lua --generate
|
||||||
```
|
```
|
||||||
|
|
||||||
## Global Data Block Support
|
## Global Data Block Support
|
||||||
@@ -218,37 +265,40 @@ The plugin automatically scans for `.db` files in the workspace and provides aut
|
|||||||
### Project Structure
|
### Project Structure
|
||||||
|
|
||||||
```
|
```
|
||||||
scl_lsp/
|
tia-lsp/
|
||||||
├── README.md # This file
|
├── README.md # This file
|
||||||
├── package.json # NPM scripts (tree-sitter)
|
├── package.json # NPM scripts (tree-sitter)
|
||||||
├── Makefile # Build commands
|
├── Makefile # Build commands
|
||||||
├── grammar.js # Tree-sitter grammar
|
├── grammar.js # Tree-sitter grammar (SCL language)
|
||||||
├── tree-sitter.json # Parser config
|
├── tree-sitter.json # Parser config
|
||||||
├── queries/ # Tree-sitter queries
|
├── queries/ # Tree-sitter queries
|
||||||
|
│ └── scl/ # Per-language query dir (SCL)
|
||||||
│ ├── highlights.scm # Syntax highlighting
|
│ ├── highlights.scm # Syntax highlighting
|
||||||
│ ├── indents.scm # Indentation
|
│ ├── indents.scm # Indentation
|
||||||
│ ├── folds.scm # Code folding
|
│ ├── folds.scm # Code folding
|
||||||
│ ├── locals.scm # Variable scoping
|
│ ├── locals.scm # Variable scoping
|
||||||
│ └── tags.scm # Navigation tags
|
│ └── tags.scm # Navigation tags
|
||||||
├── src/ # LSP server
|
├── src/ # LSP server
|
||||||
│ ├── main.lua # Main entry point
|
│ ├── main.lua # Main entry point (JSON-RPC over stdio)
|
||||||
│ ├── parser.lua # Regex-based parser
|
│ ├── parser.lua # SCL parser (will become parser_scl.lua + dispatch)
|
||||||
│ ├── treesitter.lua # Tree-sitter integration
|
│ ├── treesitter.lua # Tree-sitter integration
|
||||||
│ ├── json.lua # JSON encoder/decoder
|
│ ├── json.lua # JSON encoder/decoder
|
||||||
│ ├── plc_json.lua # External UDT loading
|
│ ├── plc_json.lua # External UDT loading (language-agnostic)
|
||||||
│ ├── diagnostics.lua # Linter diagnostics
|
│ ├── diagnostics.lua # Linter diagnostics
|
||||||
│ └── formatter.lua # Document formatter
|
│ └── formatter.lua # Document formatter
|
||||||
└── lua/
|
└── lua/
|
||||||
└── scl_lsp/
|
├── tia_lsp/ # Neovim plugin
|
||||||
├── init.lua # Main plugin setup
|
│ ├── init.lua # Main plugin setup
|
||||||
├── plugins/
|
│ └── plugins/
|
||||||
│ └── scl.lua # LazyVim plugin spec
|
│ └── scl.lua # LazyVim plugin spec (SCL filetype)
|
||||||
└── scl/ # Syntax/completion modules
|
└── tia/ # Language modules (shared across TIA languages)
|
||||||
├── init.lua
|
|
||||||
├── auto_prefix.lua
|
├── auto_prefix.lua
|
||||||
|
├── attr_toggle.lua
|
||||||
├── blink_cmp_source.lua
|
├── blink_cmp_source.lua
|
||||||
|
├── builtin_instructions.lua
|
||||||
├── db_parser.lua
|
├── db_parser.lua
|
||||||
├── fb_parser.lua
|
├── fb_parser.lua
|
||||||
|
├── multiline_params.lua
|
||||||
├── udt_parser.lua
|
├── udt_parser.lua
|
||||||
├── variables.lua
|
├── variables.lua
|
||||||
└── workspace_types.lua
|
└── workspace_types.lua
|
||||||
@@ -294,7 +344,7 @@ The plugin uses a standalone LSP server (`src/main.lua`) that communicates via J
|
|||||||
- Completion, hover, go-to-definition
|
- Completion, hover, go-to-definition
|
||||||
- Semantic tokens
|
- Semantic tokens
|
||||||
|
|
||||||
The Neovim plugin (`lua/scl_lsp/init.lua`) manages:
|
The Neovim plugin (`lua/tia_lsp/init.lua`) manages:
|
||||||
- LSP client lifecycle via `vim.lsp.start()`
|
- LSP client lifecycle via `vim.lsp.start()`
|
||||||
- FileType autocmd for lazy loading
|
- FileType autocmd for lazy loading
|
||||||
- blink.cmp integration
|
- blink.cmp integration
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "scl-language-server",
|
"name": "tia-lsp",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"description": "Language Server Protocol implementation for Siemens SCL",
|
"description": "Language Server Protocol implementation for Siemens TIA Portal languages (SCL, with planned STL/AWL, LAD, FBD support)",
|
||||||
"main": "src/main.lua",
|
"main": "src/main.lua",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "lua src/main.lua",
|
"start": "lua src/main.lua",
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
cd /home/lazar/dev/scl_lsp
|
|
||||||
lua src/main.lua
|
|
||||||
+4
-4
@@ -122,7 +122,7 @@ function M.validate_diagnostics(content, workspace_types, root_dir)
|
|||||||
severity = DiagnosticSeverity.Error,
|
severity = DiagnosticSeverity.Error,
|
||||||
message = string.format("Undefined variable: %s", var_name),
|
message = string.format("Undefined variable: %s", var_name),
|
||||||
code = "SCL001",
|
code = "SCL001",
|
||||||
source = "scl_lsp",
|
source = "tia_lsp",
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -141,7 +141,7 @@ function M.validate_diagnostics(content, workspace_types, root_dir)
|
|||||||
severity = DiagnosticSeverity.Error,
|
severity = DiagnosticSeverity.Error,
|
||||||
message = "Variable declarations should NOT have '#' prefix in VAR section",
|
message = "Variable declarations should NOT have '#' prefix in VAR section",
|
||||||
code = "SCL002",
|
code = "SCL002",
|
||||||
source = "scl_lsp",
|
source = "tia_lsp",
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -210,7 +210,7 @@ function M.validate_diagnostics(content, workspace_types, root_dir)
|
|||||||
severity = DiagnosticSeverity.Warning,
|
severity = DiagnosticSeverity.Warning,
|
||||||
message = string.format("Unknown data type: %s", base_type),
|
message = string.format("Unknown data type: %s", base_type),
|
||||||
code = "SCL003",
|
code = "SCL003",
|
||||||
source = "scl_lsp",
|
source = "tia_lsp",
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -229,7 +229,7 @@ function M.validate_diagnostics(content, workspace_types, root_dir)
|
|||||||
severity = DiagnosticSeverity.Error,
|
severity = DiagnosticSeverity.Error,
|
||||||
message = "Cannot use '#' prefix for variables in VAR section",
|
message = "Cannot use '#' prefix for variables in VAR section",
|
||||||
code = "SCL004",
|
code = "SCL004",
|
||||||
source = "scl_lsp",
|
source = "tia_lsp",
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user