Inintal commit
This commit is contained in:
@@ -0,0 +1,228 @@
|
||||
# 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
|
||||
```lua
|
||||
-- ~/.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
|
||||
```lua
|
||||
-- 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`
|
||||
```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`
|
||||
```bash
|
||||
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
|
||||
|
||||
```bash
|
||||
# Generate parser from grammar.js
|
||||
npm run build
|
||||
# or: tree-sitter generate
|
||||
|
||||
# Run tests
|
||||
npm test
|
||||
# or: tree-sitter test
|
||||
```
|
||||
|
||||
## SCL Code Example
|
||||
|
||||
```pascal
|
||||
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
|
||||
Reference in New Issue
Block a user