# AGENTS.md - tia-lsp A standalone LSP server for Siemens TIA Portal languages. Currently supports **SCL**; planned support for STL/AWL, LAD, FBD. This repo is the server only (`src/` + tree-sitter grammar). The companion Neovim plugin lives in `tia-lsp.nvim`. ## Build/Lint/Test Commands ```bash # LSP Server make start # Start LSP server make test # Run LSP in test mode lua src/main.lua --test # Direct test execution # Tree-sitter Parser tree-sitter generate # Generate parser from grammar.js tree-sitter test # Run all parser tests tree-sitter parse # Parse single SCL file # Lua Linting luacheck src/ # Lint LSP server code # Unit Tests lua test/run_tests.lua # Run all server tests lua test/test_formatter.lua # Run formatter tests lua test/test_plc_json.lua # Run plc_json tests # Reference Project # Tests use files from: ~/Documents/siemens/scl_lang_support_lazyvim_ref_project/ # Override with: SCL_REF_PROJECT=/path/to/ref lua tests/run_tests.lua ``` ## Project Structure ``` tia-lsp/ ├── src/ # LSP server (uses dofile) │ ├── main.lua # Entry point, JSON-RPC protocol │ ├── parser.lua # SCL parser (will become parser_scl.lua + dispatch) │ ├── diagnostics.lua # Linter (source = "tia_lsp") │ ├── formatter.lua # Document formatter │ ├── treesitter.lua # Tree-sitter integration │ ├── plc_json.lua # External UDT/DB loading (language-agnostic) │ ├── builtin_instructions.lua # TIA Portal built-in types │ └── json.lua # JSON encoder/decoder ├── grammar.js # Tree-sitter grammar (language name: 'scl') └── test/ # Server tests ``` ## Naming Convention - **Project name** (repo, 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`. ## Code Style Guidelines ### Module Pattern ```lua local M = {} local cache = {} function M.public_function() end local function private_function() end return M ``` ### Naming Conventions - Functions/variables: `snake_case` (e.g., `get_udt_members`) - Constants: `UPPER_SNAKE_CASE` (e.g., `PROJECT_MARKERS`) - Private functions: declare as `local function` before public functions - Booleans: prefix with `is_`, `has_` (e.g., `is_udt`, `has_members`) ### Imports - `src/` modules: `dofile(script_path .. "/module.lua")` - External dependencies: wrap in `pcall()` for safety ### Code Formatting - `src/`: tab-based indentation - Max line length: 120 characters - No trailing whitespace ### Comments Add comments to explain non-obvious code sections, complex logic, and public API functions. Keep comments concise and relevant. ### Parser Module API All parser modules must implement: - `parse_*_file(filepath)` - Parse and cache - `parse_*_content(content, filename)` - Parse string - `get_*(name)` - Get cached item - `get_all_*_names()` - List all cached names - `get_*_members(name)` - Get members/fields - `is_*_type(name)` - Check if known type - `clear_cache()` - Clear cached data - `get_cache_count()` - Return cache size ### Cache Management ```lua local cache = {} function M.clear_cache() for k in pairs(cache) do cache[k] = nil end end ``` ### Error Handling ```lua function M.parse_file(filepath) local file = io.open(filepath, "r") if not file then return nil, "Cannot open file: " .. filepath end return result end -- External dependencies local ok, module = pcall(require, "some_module") if ok and module then module.do_something() end ``` ## Lua Reserved Keywords Cannot use reserved keywords as table keys directly: ```lua -- WRONG local range = { start = pos1, end = pos2 } -- CORRECT local range = { start = pos1, ["end"] = pos2 } ``` Critical for LSP range objects with `end` field. ## Type System The LSP validates data types and provides warnings for unknown types: - **Elementary**: BOOL, BYTE, WORD, DWORD, INT, DINT, REAL, TIME, STRING, etc. - **Timer/counter**: IEC_TIMER, TON_TIME, TOF_TIME, CTU, CTD, CTUD - **Built-in FBs**: TON, TOF, TP, R_TRIG, F_TRIG, etc. - **Built-in functions**: ADD, SUB, MUL, DIV, SIN, COS, SQRT, etc. - **Workspace types**: UDTs from `.udt` files, DBs from `.db` files ## Testing Use the reference project for testing: ``` ~/Documenta/siemens/scl_lang_support_lazyvim_ref_project/ ``` Contains `.scl`, `.db`, `.udt`, and `.xml` files for comprehensive testing of: - LSP features (hover, completion, go-to-definition) - Formatter - Workspace type scanning