Files
tia-lsp/AGENTS.md
T
lazar 4429280524 docs(AGENTS.md): Update AGENTS.md
The new AGENTS.md includes:
- Reference project for testing
- Build/test commands (LSP and tree-sitter)
- Condensed project structure
- Code style guidelines (module pattern, naming, imports, comments)
- Parser module API convention
- Cache management patterns
- Error handling patterns (return pattern, pcall, validation)
- Completion system documentation
- Commands table
2026-02-18 10:25:35 +01:00

169 lines
5.1 KiB
Markdown

# AGENTS.md - SCL Language Server (Unified)
A unified Neovim/LazyVim plugin for Siemens SCL language support providing LSP, linting, formatting, syntax highlighting, and auto-completion.
## Reference Project for Testing
For manual testing and SCL/UDT/DB file examples, use:
```
~/dev/siemens/projects/scl_lang_support_lazyvim_ref_project
```
## Build/Lint/Test Commands
### LSP Server
```bash
make start # Start LSP server
make test # Run LSP in test mode
lua src/main.lua --test # Direct test mode execution
```
### Tree-sitter Parser
```bash
tree-sitter generate # Generate parser from grammar.js
tree-sitter test # Run tree-sitter tests
tree-sitter parse <file.scl> # Parse a single SCL file
```
## Project Structure
```
scl_lsp/
├── src/ # Standalone LSP server (uses dofile)
│ ├── main.lua # Entry point, JSON-RPC protocol
│ ├── parser.lua # Regex-based SCL parser
│ ├── diagnostics.lua # Linter diagnostics
│ └── formatter.lua # Document formatter
├── lua/scl/ # Neovim plugin modules (uses require)
│ ├── blink_cmp_source.lua # blink.cmp completion source
│ ├── udt_parser.lua # UDT (.udt) parser
│ ├── db_parser.lua # Global DB (.db) parser
│ ├── fb_parser.lua # Function Block parser
│ ├── variables.lua # Local variable extraction
│ ├── workspace_types.lua # Workspace scanning
│ └── multiline_params.lua # FB parameter filling
└── queries/ # Tree-sitter queries
```
## Code Style Guidelines
### Module Pattern
All modules follow the standard Lua module pattern:
```lua
-- Module description comment at top
local M = {}
-- Private module-level cache
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`, `var_types`)
- Constants: `UPPER_SNAKE_CASE` (e.g., `PROJECT_MARKERS`)
- Private functions: declare as `local function` before public functions
- Boolean variables: prefix with `is_`, `has_` (e.g., `is_udt`, `has_members`)
### Imports
- `lua/scl/` modules: use `require("scl.module_name")`
- `src/` modules: use `dofile(script_path .. "/module.lua")`
- External dependencies: wrap in `pcall()` for safety
### Comments
- Every file must have a header comment explaining its purpose
- All functions should have a brief comment describing what they do
- Complex logic requires inline comments explaining the "why"
- Non-obvious regex patterns must have explanatory comments
### Parser Module API Convention
All parser modules (udt_parser, db_parser, fb_parser) must implement:
- `parse_*_file(filepath)` - Parse a file and cache result
- `parse_*_content(content, filename)` - Parse string content
- `get_*(name)` - Get single cached item by name
- `get_all_*_names()` - Return list of all cached names
- `get_*_members(name)` - Get members/fields for a type
- `is_*_type(name)` - Check if name is a known type
- `clear_cache()` - Clear all cached data
- `get_cache_count()` - Return number of cached items
### Cache Management
- Use module-level local tables for caching: `local cache = {}`
- Clear caches by iterating and setting to nil, not by reassigning:
```lua
function M.clear_cache()
for k in pairs(cache) do
cache[k] = nil
end
end
```
## Error Handling
### Return Pattern
Functions that can fail return `nil, "error message"`:
```lua
function M.parse_file(filepath)
local file = io.open(filepath, "r")
if not file then
return nil, "Cannot open file: " .. filepath
end
-- ... parse logic
return result
end
```
### External Dependencies
Always wrap external requires in `pcall()`:
```lua
local ok, module = pcall(require, "some_module")
if ok and module then
module.do_something()
end
```
### Validation
Check required parameters early and return sensible defaults:
```lua
function M.get_members(type_name)
if not type_name then
return {}
end
-- ... continue
end
```
## Completion System
### Trigger Characters
- `#` - Local variables (after BEGIN)
- `.` - Member access (UDT/DB members)
- `"` - Global DB names
- `(` - FB/Function parameters
- ` ` (space) - General completion
### Active Portion Detection
When matching patterns in completion, use the "active portion" of the line (after the last operator) to correctly handle expressions like:
```scl
"DB1".member := "DB2".member
```
Find the last `:=`, `=>`, `=`, `<>`, `>=`, `<=`, `>`, `<`, `AND`, `OR`, `NOT` and only match patterns after it.
## 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 |
| `:LspSCLFormat` | Format current SCL file |
| `:SCLGeneratePlcJson` | Generate plc.data.json from data_types/ |