Files

167 lines
5.0 KiB
Markdown

# AGENTS.md - tia-lsp.nvim
Neovim plugin for Siemens TIA Portal languages. Currently supports **SCL**; planned support for STL/AWL, LAD, FBD. This repo is the plugin only (`lua/` + tree-sitter queries). The companion LSP server lives in `tia-lsp`.
## Build/Lint/Test Commands
```bash
# Lua Linting
luacheck lua/tia/ # Lint language modules
luacheck lua/tia_lsp/ # Lint plugin entry point
# Unit & Integration Tests
lua test/run_tests.lua # Run all plugin tests
lua test/test_udt.lua # Run UDT parser tests
lua test/test_db.lua # Run DB parser tests
lua test/test_fb.lua # Run FB parser tests
lua test/test_integration.lua # Run integration 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.nvim/
├── lua/tia/ # Language modules (uses require)
│ ├── udt_parser.lua # UDT parser
│ ├── db_parser.lua # Global DB parser
│ ├── fb_parser.lua # Function Block parser
│ ├── variables.lua # Variable extraction
│ ├── workspace_types.lua # Workspace scanning
│ ├── multiline_params.lua
│ ├── auto_prefix.lua
│ └── attr_toggle.lua
├── lua/tia_lsp/ # Plugin entry point
│ ├── init.lua # Main plugin setup (vim.lsp.start)
│ └── plugins/scl.lua # LazyVim plugin spec
├── queries/scl/ # Tree-sitter queries (per-language)
└── ftdetect/scl.vim # Filetype detection
```
## Naming Convention
- **Project name** (repo, Lua module): `tia-lsp.nvim` / `tia_lsp` — umbrella for all TIA languages.
- **Language name** (filetype, tree-sitter parser): `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`).
- **Commands**: `:SCLFormat`, `:SCLShowVariables`, etc. — per-filetype prefix. Future: `:STLFormat`, etc.
## Filetype Detection
`ftdetect/scl.vim` registers the following extensions as `scl` filetype:
```vim
au BufRead,BufNewFile *.scl set filetype=scl
au BufRead,BufNewFile *.udt set filetype=scl
au BufRead,BufNewFile *.db set filetype=scl
```
## 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
- `lua/tia/` modules: `require("tia.module_name")`
- `lua/tia_lsp/` entry: `require("tia_lsp")`
- External dependencies: wrap in `pcall()` for safety
### Code Formatting
- `lua/tia/` and `lua/tia_lsp/`: 2 spaces 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:
```
~/Documents/siemens/scl_lang_support_lazyvim_ref_project/
```
Contains `.scl`, `.db`, `.udt`, and `.xml` files for comprehensive testing of:
- Plugin features (auto-prefix, workspace scanning, attribute toggle)
- Workspace type scanning