Compare commits

..
4 Commits
Author SHA1 Message Date
lazar 3776ce33ff refactor: change the default path for local dev env 2026-07-20 17:01:37 +02:00
lazar 1acac2b73c docs: rewrite installation with architecture overview, troubleshooting, and cross-references 2026-07-19 15:09:58 +02:00
lazar 03548dab7d feat: comprehensive query files for all block types and VAR sections (Phase 3)
Update all 5 tree-sitter query files to cover the full grammar:

highlights.scm:
- Add highlights for new literals (binary, octal, date, bool, typed_int,
  wstring, char)
- Add highlights for block names (organization_block, function_block,
  function, data_block, type_definition)
- Add highlights for return_statement, goto_statement, title_statement
- Add highlights for bit_access, method_callee
- Add compound assignment operators (+=, -=, *=, /=, etc.)

indents.scm:
- Add function, type_definition, data_block to @indent.begin
- Add all var_*_declaration variants to @indent.begin
- Add struct_type to @indent.begin
- Add END_FUNCTION, END_TYPE, END_DATA_BLOCK, END_STRUCT to @indent.end

folds.scm:
- Add function, type_definition, data_block to @fold
- Add all var_*_declaration variants to @fold
- Add struct_type to @fold

locals.scm:
- Add function, type_definition, data_block as @local.scope
- Add all var_*_declaration variants as @local.scope
- Add struct_type as @local.scope
- Add block name definitions (@definition.function, @definition.class,
  @definition.type)
- Narrow @reference to prefixed_identifier only (reduces noise)

tags.scm:
- Add function, data_block, type_definition tags
- Add FB call references
- Add region_statement as @definition.module
2026-07-18 19:20:33 +02:00
lazar aebffc34e7 fix: load compiled parser.so via vim.treesitter.language.add
nvim-treesitter's :TSInstall reloads the parsers module from source
(package.loaded['nvim-treesitter.parsers'] = nil), which wipes runtime
config modifications. The old get_parser_configs() approach no longer
works for registering custom parsers with :TSInstall.

New approach:
- The mason build script now compiles parser.c into parser.so during
  :MasonInstall tia-lsp (requires cc/gcc)
- The plugin's setup_syntax finds parser.so via:
  1. opts.ts_parser_path (explicit override)
  2. Mason package dir (resolved from exepath('tia-lsp'))
  3. ~/dev/tia-lsp/parser.so (local dev fallback)
- Loads it with vim.treesitter.language.add('scl', { path = parser.so })
- Starts highlighting via vim.treesitter.start(bufnr, 'scl') in the
  FileType autocmd
- Falls back to notifying the user if no parser.so is found
- Still registers with nvim-treesitter's parsers table as best-effort
  for :TSInstall support (won't survive reload, but works in-session)
2026-07-18 18:01:32 +02:00
7 changed files with 621 additions and 346 deletions
+95 -41
View File
@@ -15,26 +15,52 @@ A Neovim/LazyVim plugin that launches the [`tia-lsp`](https://gitea.l-tech.rs/la
| **Attribute Block Toggle** | Interactive expand/collapse of `{...}` blocks with `<Leader>xa` | | **Attribute Block Toggle** | Interactive expand/collapse of `{...}` blocks with `<Leader>xa` |
| **Tree-sitter Highlighting** | Syntax highlighting via tree-sitter queries | | **Tree-sitter Highlighting** | Syntax highlighting via tree-sitter queries |
## Architecture
This plugin is part of a three-repo ecosystem:
```
tia-lsp.nvim ← Neovim plugin (you are here) — launches the LSP client,
│ adds editor features (auto-# prefix, blink.cmp source,
│ attribute toggle, workspace scanning, ...)
tia-lsp ← Standalone LSP server — reads JSON-RPC over stdio,
│ provides hover, completion, diagnostics, formatting
│ Requires: lua src/main.lua + compiled parser.so
tia-mason-registry ← mason.nvim recipe — tells mason how to download tia-lsp,
compile parser.so, and create the tia-lsp executable
```
- **tia-lsp** ([repo](https://gitea.l-tech.rs/lazar/tia-lsp)) — the actual language server, editor-agnostic
- **tia-mason-registry** ([repo](https://gitea.l-tech.rs/lazar/tia-mason-registry)) — a single `package.yaml` for mason
- **tia-lsp.nvim** (this repo) — the Neovim-specific integration
## 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. The plugin auto-detects the mason-installed `tia-lsp` executable via `vim.fn.exepath("tia-lsp")`. If not found, it falls back to running `lua <server_path>` (configurable).
### LazyVim + Mason (Recommended) ### LazyVim + Mason (Recommended)
1. Add the mason registry as a lazy.nvim plugin: Mason downloads and builds the `tia-lsp` server; this plugin configures the LSP client.
```lua
-- ~/.config/nvim/lua/plugins/tia-mason-registry.lua **Step 1: Add the mason registry as a lazy.nvim plugin**
return {
mason needs a local copy of the registry to read the install recipe. Adding it as a lazy.nvim plugin gets it cloned automatically:
```lua
-- ~/.config/nvim/lua/plugins/tia-mason-registry.lua
return {
url = "https://gitea.l-tech.rs/lazar/tia-mason-registry.git", url = "https://gitea.l-tech.rs/lazar/tia-mason-registry.git",
name = "tia-mason-registry", name = "tia-mason-registry",
lazy = false, -- must be available before mason setup }
} ```
```
2. Register the registry with mason: **Step 2: Register the registry with mason**
```lua
-- ~/.config/nvim/lua/plugins/mason.lua ```lua
return { -- ~/.config/nvim/lua/plugins/mason.lua
return {
"mason-org/mason.nvim", "mason-org/mason.nvim",
opts = { opts = {
registries = { registries = {
@@ -42,50 +68,67 @@ The plugin auto-detects the mason-installed `tia-lsp` executable via `vim.fn.exe
"github:mason-org/mason-registry", "github:mason-org/mason-registry",
}, },
}, },
} }
``` ```
3. Add the plugin: > **Why this works:** lazy.nvim clones `tia-mason-registry` to `~/.local/share/nvim/lazy/tia-mason-registry`. The `file:` registry path points mason to that directory, where it finds `packages/tia-lsp/package.yaml`. Mason needs [`yq`](https://github.com/mikefarah/yq) to parse YAML custom registries — install it once: `:MasonInstall yq`
```lua
-- ~/.config/nvim/lua/plugins/tia-lsp.lua **Step 3: Install the LSP server**
return {
"lazar/tia-lsp.nvim", ```
:MasonInstall tia-lsp
```
This clones `tia-lsp` from the source repo, compiles `parser.so` (tree-sitter), and places the `tia-lsp` executable on PATH.
**Step 4: Add this plugin**
```lua
-- ~/.config/nvim/lua/plugins/tia-lsp.lua
return {
"https://gitea.l-tech.rs/lazar/tia-lsp.nvim",
ft = "scl", ft = "scl",
lazy = true, lazy = true,
dependencies = { dependencies = {
"neovim/nvim-lspconfig", "neovim/nvim-lspconfig",
"nvim-treesitter/nvim-treesitter", "nvim-treesitter/nvim-treesitter",
"saghen/blink.cmp", "saghen/blink.cmp", -- optional, for completion
}, },
config = function() opts = {
require("tia_lsp").setup({
lsp = { lsp = {
on_attach = function(client, bufnr) -- on_attach = function(client, bufnr) ... end,
-- custom keymaps
end,
}, },
cmp = true, -- Enable blink.cmp integration cmp = true, -- enable blink.cmp integration
workspace_types = true, -- Enable workspace UDT scanning workspace_types = true, -- scan project for UDTs and DBs
auto_prefix = true, -- Enable auto-# prefixing auto_prefix = true, -- auto-# prefix for local variables
debug = false, },
}) }
end, ```
}
```
4. Install: **Step 5: Verify**
```
:MasonInstall yq " one-time prerequisite for file: registry
:MasonInstall tia-lsp " installs the LSP server
```
5. Verify: open a `.scl` file and run `:LspInfo` — `tia_lsp` should be attached. Open a `.scl` file and run `:LspInfo`. `tia_lsp` should be attached. Run `:checkhealth` for detailed diagnostics.
---
### Manual Setup (without Mason) ### Manual Setup (without Mason)
Clone and build the server manually, then point the plugin at it.
```bash
# 1. Clone the LSP server
git clone --depth 1 https://gitea.l-tech.rs/lazar/tia-lsp.git ~/tia-lsp
# 2. Compile the tree-sitter parser (required for parsing SCL)
cc -fPIC -I ~/tia-lsp/src/tree_sitter -c ~/tia-lsp/src/parser.c -o ~/tia-lsp/parser.o
cc -shared ~/tia-lsp/parser.o -o ~/tia-lsp/parser.so
```
Then configure the plugin. The plugin first looks for `tia-lsp` on PATH; if not found, it falls back to running `lua <server_path>`. The tree-sitter parser is loaded from `parser.so` adjacent to the server.
```lua ```lua
require("tia_lsp").setup({ require("tia_lsp").setup({
server_path = "/path/to/tia-lsp/src/main.lua", -- only used if tia-lsp is not on PATH server_path = "~/tia-lsp/src/main.lua", -- fallback if tia-lsp not on PATH
ts_parser_url = "https://gitea.l-tech.rs/lazar/tia-lsp.git", ts_parser_url = "https://gitea.l-tech.rs/lazar/tia-lsp.git",
cmp = true, cmp = true,
workspace_types = true, workspace_types = true,
@@ -97,7 +140,7 @@ require("tia_lsp").setup({
| Option | Type | Default | Description | | Option | Type | Default | Description |
|--------|------|---------|-------------| |--------|------|---------|-------------|
| `server_path` | string | `~/dev/tia-lsp/src/main.lua` | Path to LSP server (only used if `tia-lsp` is not on PATH) | | `server_path` | string | `~/dev/tia-lsp/src/main.lua` | Path to LSP server (fallback when `tia-lsp` not on PATH; change for manual installs) |
| `ts_parser_url` | string | `file://~/dev/tia-lsp` | URL passed to nvim-treesitter for the SCL parser source | | `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 |
@@ -211,6 +254,17 @@ tia-lsp.nvim/
- **blink.cmp** — Optional, for completion - **blink.cmp** — Optional, for completion
- **Lua 5.1+** — LSP server runtime - **Lua 5.1+** — LSP server runtime
## Troubleshooting
| Symptom | Likely Cause | Fix |
|---------|-------------|-----|
| `:MasonInstall tia-lsp` fails with "unknown package" | Custom registry not registered with mason | Check the `registries` list in your mason config includes the `file:` path to the cloned registry |
| `:MasonInstall tia-lsp` fails with "yq: command not found" | Mason needs `yq` to parse the YAML registry | Run `:MasonInstall yq` to install it, then retry `:MasonInstall tia-lsp` |
| `tia_lsp` not attached after opening `.scl` | Server not on PATH or `server_path` points to wrong location | Run `:LspInfo` to see what server is configured. Check `vim.fn.exepath("tia-lsp")` returns a path |
| LSP starts but no syntax highlighting | Tree-sitter parser (`parser.so`) not found | mason install generates it automatically. For manual setups, run the `cc` commands in the Manual Setup section |
| `parser.so` load error at startup | Compiled for wrong architecture or Lua version | Recompile: clean the old `.so` and run the `cc` build commands again |
| LSP starts but no completions/hover | Server can't find its modules | Mason installs to a managed directory. If using manual setup, ensure `src/` contents are present next to `main.lua` |
## Testing ## Testing
```bash ```bash
+111 -17
View File
@@ -13,16 +13,17 @@ function M.setup(opts)
setup_package_path() setup_package_path()
opts = opts or {} opts = opts or {}
local server_path = opts.server_path or vim.fn.expand("~/dev/tia-lsp/src/main.lua") local server_path = opts.server_path or vim.fn.expand("~/Documents/lua/tia-lsp/src/main.lua")
local root_patterns = { ".git", "data_types", "plc.data.json" } local root_patterns = { ".git", "data_types", "plc.data.json" }
local function start_lsp(bufnr) local function start_lsp(bufnr)
local fname = vim.api.nvim_buf_get_name(bufnr) local fname = vim.api.nvim_buf_get_name(bufnr)
if fname == "" then return end if fname == "" then
return
end
local root_dir = vim.fs.root(fname, root_patterns) local root_dir = vim.fs.root(fname, root_patterns) or vim.fn.fnamemodify(fname, ":p:h")
or vim.fn.fnamemodify(fname, ":p:h")
-- Prefer the mason-installed executable (vim.fn.exepath resolves on each -- Prefer the mason-installed executable (vim.fn.exepath resolves on each
-- buffer enter, so a :MasonInstall mid-session is picked up without restart). -- buffer enter, so a :MasonInstall mid-session is picked up without restart).
@@ -53,6 +54,9 @@ function M.setup(opts)
pattern = "scl", pattern = "scl",
callback = function(args) callback = function(args)
start_lsp(args.buf) start_lsp(args.buf)
M.notify_parser_install_if_needed(args.buf)
-- Start tree-sitter highlighting if the parser is registered
pcall(vim.treesitter.start, args.buf, "scl")
end, end,
}) })
@@ -65,6 +69,8 @@ function M.setup(opts)
for _, bufnr in ipairs(vim.api.nvim_list_bufs()) do for _, bufnr in ipairs(vim.api.nvim_list_bufs()) do
if vim.bo[bufnr].filetype == "scl" and vim.api.nvim_buf_is_loaded(bufnr) then if vim.bo[bufnr].filetype == "scl" and vim.api.nvim_buf_is_loaded(bufnr) then
start_lsp(bufnr) start_lsp(bufnr)
M.notify_parser_install_if_needed(bufnr)
pcall(vim.treesitter.start, bufnr, "scl")
end end
end end
@@ -78,16 +84,87 @@ function M.setup(opts)
end end
end end
-- Find a compiled tree-sitter parser (.so) for SCL.
-- Looks in: opts.ts_parser_path, mason package dir, ~/dev/tia-lsp.
-- Returns the path to parser.so, or nil if not found.
function M.find_parser_so(opts)
-- 1. Explicit path from opts
if opts.ts_parser_path and vim.fn.filereadable(opts.ts_parser_path) == 1 then
return opts.ts_parser_path
end
-- 2. Mason install: resolve exepath("tia-lsp") -> real bin -> package dir
local tia_bin = vim.fn.exepath("tia-lsp")
if tia_bin ~= "" then
local real_bin = vim.fn.resolve(vim.fn.fnamemodify(tia_bin, ":p"))
local pkg_dir = vim.fn.fnamemodify(real_bin, ":h:h")
local so = pkg_dir .. "/parser.so"
if vim.fn.filereadable(so) == 1 then
return so
end
end
-- 3. Local dev path
local dev_so = vim.fn.expand("~/dev/tia-lsp/parser.so")
if vim.fn.filereadable(dev_so) == 1 then
return dev_so
end
return nil
end
-- Notify the user once per session if the tree-sitter parser isn't available.
local parser_notified = false
function M.notify_parser_install_if_needed(bufnr)
if parser_notified then
return
end
if vim.bo[bufnr].filetype ~= "scl" then
return
end
local ok = pcall(vim.treesitter.get_parser, bufnr, "scl")
if ok then
return
end
parser_notified = true
vim.schedule(function()
local msg = "SCL: Tree-sitter parser not found. "
if vim.fn.exepath("tia-lsp") ~= "" then
msg = msg .. "Run :MasonInstall tia-lsp to install it."
else
msg = msg .. "Install tia-lsp via mason or compile parser.so manually."
end
vim.notify(msg, vim.log.levels.INFO)
end)
end
function M.setup_syntax(opts) function M.setup_syntax(opts)
local has_ts, ts = pcall(require, "nvim-treesitter.parsers") -- Load the compiled tree-sitter parser (.so) via Neovim's built-in API.
if has_ts and ts.get_parser_configs then -- This bypasses nvim-treesitter's install system, which reloads its
local ok, parser_config = pcall(ts.get_parser_configs) -- parsers module from source on :TSInstall and wipes runtime config.
if ok and parser_config then local parser_so = M.find_parser_so(opts)
if parser_so then
local ok, err = pcall(vim.treesitter.language.add, "scl", { path = parser_so })
if not ok then
vim.notify(
"SCL: Failed to load tree-sitter parser from " .. parser_so .. ": " .. tostring(err),
vim.log.levels.WARN
)
end
end
-- Also register with nvim-treesitter (best-effort, for :TSInstall support
-- in sessions where the user wants to install from source).
local has_ts, parsers = pcall(require, "nvim-treesitter.parsers")
if has_ts and type(parsers) == "table" then
local parser_config
if type(parsers.get_parser_configs) == "function" then
parser_config = parsers.get_parser_configs()
else
parser_config = parsers
end
if type(parser_config) == "table" then
parser_config.scl = { parser_config.scl = {
install_info = { install_info = {
-- Override via setup({ ts_parser_url = "https://your-gitea/tia-lsp.git" }). url = opts.ts_parser_url or "https://gitea.l-tech.rs/lazar/tia-lsp.git",
url = opts.ts_parser_url
or "https://gitea.l-tech.rs/lazar/tia-lsp.git",
files = { "src/parser.c" }, files = { "src/parser.c" },
generate_requires_npm = false, generate_requires_npm = false,
requires_generate_from_grammar = false, requires_generate_from_grammar = false,
@@ -237,15 +314,32 @@ function M.rescan_workspace_types()
local udt_result = ws.scan_project_udts() local udt_result = ws.scan_project_udts()
local fb_result = ws.scan_project_fbs() local fb_result = ws.scan_project_fbs()
vim.notify("Scanned UDTs: " .. udt_result.parsed_count .. "/" .. udt_result.total_files .. vim.notify(
", FBs: " .. fb_result.parsed_count .. "/" .. fb_result.total_files, vim.log.levels.INFO) "Scanned UDTs: "
.. udt_result.parsed_count
.. "/"
.. udt_result.total_files
.. ", FBs: "
.. fb_result.parsed_count
.. "/"
.. fb_result.total_files,
vim.log.levels.INFO
)
end end
function M.create_commands() function M.create_commands()
vim.api.nvim_create_user_command("SCLShowVariables", function() M.show_variables() end, {}) vim.api.nvim_create_user_command("SCLShowVariables", function()
vim.api.nvim_create_user_command("SCLShowWorkspaceTypes", function() M.show_workspace_types() end, {}) M.show_variables()
vim.api.nvim_create_user_command("SCLRescanWorkspaceTypes", function() M.rescan_workspace_types() end, {}) end, {})
vim.api.nvim_create_user_command("SCLPrefixWord", function() M.prefix_current_word() end, {}) vim.api.nvim_create_user_command("SCLShowWorkspaceTypes", function()
M.show_workspace_types()
end, {})
vim.api.nvim_create_user_command("SCLRescanWorkspaceTypes", function()
M.rescan_workspace_types()
end, {})
vim.api.nvim_create_user_command("SCLPrefixWord", function()
M.prefix_current_word()
end, {})
-- Attribute toggle commands -- Attribute toggle commands
vim.api.nvim_create_user_command("SCLToggleAttrBlock", function() vim.api.nvim_create_user_command("SCLToggleAttrBlock", function()
+9
View File
@@ -3,12 +3,21 @@
[ [
(organization_block) (organization_block)
(function_block) (function_block)
(function)
(type_definition)
(data_block)
(var_declaration) (var_declaration)
(var_temp_declaration)
(var_constant_declaration)
(var_retain_declaration)
(var_non_retain_declaration)
(var_db_specific_declaration)
(if_statement) (if_statement)
(case_statement) (case_statement)
(for_statement) (for_statement)
(while_statement) (while_statement)
(repeat_statement) (repeat_statement)
(region_statement) (region_statement)
(struct_type)
(block_comment) (block_comment)
] @fold ] @fold
+58 -11
View File
@@ -1,66 +1,99 @@
; SCL highlights ; SCL highlights
; Comments
(line_comment) @comment (line_comment) @comment
(block_comment) @comment (block_comment) @comment
(c_style_comment) @comment (c_style_comment) @comment
; Literals
(number) @number (number) @number
(hex_number) @number (hex_number) @number
(string) @string (binary_number) @number
(octal_number) @number
(time_value) @number (time_value) @number
(date_literal) @number
(bool_literal) @constant.builtin
(typed_int_literal) @number
(wstring_literal) @string
(char_literal) @character
(string) @string
; Prefix
(prefix) @punctuation.special (prefix) @punctuation.special
; Variables and identifiers
(identifier) @variable (identifier) @variable
; FB instance calls - highlight instance name as type ; FB instance calls
(fb_call (fb_call
instance: (prefixed_identifier instance: (prefixed_identifier
(identifier) @type)) (identifier) @type))
(fb_call (fb_call
instance: (identifier) @type) instance: (identifier) @type)
; FB parameter names (IN :=, PT :=, etc.) ; FB parameter names
(fb_parameter (fb_parameter
name: (identifier) @property) name: (identifier) @property)
; Function call names ; Function call names
(function_call (function_call
(identifier) @function) (identifier) @function)
(function_call
(string) @function)
; Method call names
(method_callee
(identifier) @function)
; Variable declarations ; Variable declarations
(var_item (var_item
name: (identifier) @variable) name: (identifier) @variable)
; Type references in declarations ; Type references
(type (type
(identifier) @type) (identifier) @type)
(type_builtin) @type.builtin (type_builtin) @type.builtin
; Keywords and operators
(keyword) @keyword (keyword) @keyword
(constant) @constant.builtin (constant) @constant.builtin
(operator) @operator (operator) @operator
(assignment) @operator ; Block names
(binary_expression) @operator (organization_block
(unary_expression) @operator name: (string) @type)
(function_block
name: (string) @type)
(function
name: (string) @function)
(data_block
name: (string) @type)
(type_definition
name: (string) @type)
; Access
(field_access (field_access
"." "."
(identifier) @property) (identifier) @property)
(array_access) @property (array_access) @property
(bit_access) @property
; Attributes
(attribute_list) @attribute (attribute_list) @attribute
(attribute) @attribute (attribute) @attribute
(attribute_value) @string (attribute_value) @string
(var_item) @property ; Statements
(assignment) @operator
(binary_expression) @operator
(unary_expression) @operator
(chained_assignment) @operator
; Function/FB calls
(function_call) @function.call (function_call) @function.call
(fb_call) @function.call (fb_call) @function.call
; Control flow
(if_statement) @conditional (if_statement) @conditional
(elsif_clause) @conditional (elsif_clause) @conditional
(else_clause) @conditional (else_clause) @conditional
@@ -71,6 +104,13 @@
(while_statement) @repeat (while_statement) @repeat
(repeat_statement) @repeat (repeat_statement) @repeat
(return_statement) @keyword
(goto_statement) @keyword
; Title
(title_statement) @comment
; Punctuation
";" @punctuation.delimiter ";" @punctuation.delimiter
":" @punctuation.delimiter ":" @punctuation.delimiter
"," @punctuation.delimiter "," @punctuation.delimiter
@@ -80,15 +120,22 @@
"]" @punctuation.bracket "]" @punctuation.bracket
"." @punctuation.delimiter "." @punctuation.delimiter
; Operators
":=" @operator ":=" @operator
"=>" @operator "=>" @operator
"+=" @operator
"-=" @operator
"*=" @operator
"/=" @operator
"&=" @operator
"|=" @operator
"^=" @operator
"=" @operator "=" @operator
"<>" @operator "<>" @operator
"<" @operator "<" @operator
">" @operator ">" @operator
"<=" @operator "<=" @operator
">=" @operator ">=" @operator
"+" @operator "+" @operator
"-" @operator "-" @operator
"*" @operator "*" @operator
+26 -2
View File
@@ -1,10 +1,26 @@
; Indentation rules for SCL ; Indentation rules for SCL
; Indent after block keywords ; Indent after block definitions
[ [
(organization_block) (organization_block)
(function_block) (function_block)
(function)
(type_definition)
(data_block)
] @indent.begin
; Indent after VAR sections
[
(var_declaration) (var_declaration)
(var_temp_declaration)
(var_constant_declaration)
(var_retain_declaration)
(var_non_retain_declaration)
(var_db_specific_declaration)
] @indent.begin
; Indent after control structures
[
(if_statement) (if_statement)
(case_statement) (case_statement)
(for_statement) (for_statement)
@@ -13,12 +29,16 @@
(region_statement) (region_statement)
] @indent.begin ] @indent.begin
; Indent after THEN, DO, etc. ; Indent after STRUCT in UDTs and inline structs
(struct_type) @indent.begin
; Indent after THEN, DO, ELSE, ELSIF, BEGIN
[ [
"THEN" "THEN"
"DO" "DO"
"ELSE" "ELSE"
"ELSIF" "ELSIF"
(keyword) @indent.branch
] @indent.branch ] @indent.branch
; Outdent at end keywords ; Outdent at end keywords
@@ -30,8 +50,12 @@
"END_WHILE" "END_WHILE"
"END_REPEAT" "END_REPEAT"
"END_REGION" "END_REGION"
"END_STRUCT"
"END_ORGANIZATION_BLOCK" "END_ORGANIZATION_BLOCK"
"END_FUNCTION_BLOCK" "END_FUNCTION_BLOCK"
"END_FUNCTION"
"END_TYPE"
"END_DATA_BLOCK"
] @indent.end ] @indent.end
; Outdent for ELSE and ELSIF ; Outdent for ELSE and ELSIF
+30 -6
View File
@@ -1,15 +1,39 @@
; Local variable scoping for SCL - matches grammar.js structure ; Local variable scoping for SCL
; Variable declarations define local variables ; Variable declarations define local variables
(var_item (var_item
name: (identifier) @definition.var) name: (identifier) @definition.var)
; Variable sections create scopes
(var_declaration) @local.scope
; Blocks create scopes ; Blocks create scopes
(organization_block) @local.scope (organization_block) @local.scope
(function_block) @local.scope (function_block) @local.scope
(function) @local.scope
(type_definition) @local.scope
(data_block) @local.scope
; Identifiers are references ; VAR sections create scopes
(identifier) @reference (var_declaration) @local.scope
(var_temp_declaration) @local.scope
(var_constant_declaration) @local.scope
(var_retain_declaration) @local.scope
(var_non_retain_declaration) @local.scope
(var_db_specific_declaration) @local.scope
; Struct types create scopes
(struct_type) @local.scope
; Block names are definitions
(organization_block
name: (string) @definition.function)
(function_block
name: (string) @definition.function)
(function
name: (string) @definition.function)
(data_block
name: (string) @definition.class)
(type_definition
name: (string) @definition.type)
; References
(prefixed_identifier
(identifier) @reference)
+24 -1
View File
@@ -1,4 +1,4 @@
; Tag queries for SCL - matches grammar.js structure ; Tag queries for SCL - symbol navigation
; Organization blocks ; Organization blocks
(organization_block (organization_block
@@ -8,6 +8,18 @@
(function_block (function_block
name: (string) @name) @definition.function name: (string) @name) @definition.function
; Functions
(function
name: (string) @name) @definition.function
; Data blocks
(data_block
name: (string) @name) @definition.class
; Type definitions (UDTs)
(type_definition
name: (string) @name) @definition.type
; Variable definitions within blocks ; Variable definitions within blocks
(var_item (var_item
name: (identifier) @name name: (identifier) @name
@@ -25,3 +37,14 @@
(function_call (function_call
(string) @name) @reference.call (string) @name) @reference.call
; FB calls (references)
(fb_call
instance: (identifier) @name) @reference.call
(fb_call
instance: (prefixed_identifier
(identifier) @name)) @reference.call
; Region statements
(region_statement) @definition.module