feat: improve tree-sitter syntax highlighting with named nodes
- Add aliases for keywords (VAR_INPUT, BEGIN, IF, etc.) as named nodes - Add aliases for built-in types (INT, BOOL, STRING, etc.) as type_builtin - Add aliases for constants (TRUE, FALSE) - Add aliases for operators (AND, OR, NOT, MOD) - Add prefix node for # variable prefix highlighting - Highlight FB instance names in calls - Highlight FB parameter names as properties - Update README with detailed syntax highlighting features - Update .gitignore for *.wasm files
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
local M = {}
|
||||
|
||||
M.FUNCTIONS = {
|
||||
ADD = true,
|
||||
SUB = true,
|
||||
MUL = true,
|
||||
DIV = true,
|
||||
MIN = true,
|
||||
MAX = true,
|
||||
LIMIT = true,
|
||||
MOVE = true,
|
||||
CONVERT = true,
|
||||
ROUND = true,
|
||||
TRUNC = true,
|
||||
CEIL = true,
|
||||
FLOOR = true,
|
||||
SQR = true,
|
||||
SQRT = true,
|
||||
SIN = true,
|
||||
COS = true,
|
||||
TAN = true,
|
||||
ASIN = true,
|
||||
ACOS = true,
|
||||
ATAN = true,
|
||||
LEN = true,
|
||||
CONCAT = true,
|
||||
LEFT = true,
|
||||
RIGHT = true,
|
||||
MID = true,
|
||||
AND = true,
|
||||
OR = true,
|
||||
XOR = true,
|
||||
SHL = true,
|
||||
SHR = true,
|
||||
ROL = true,
|
||||
ROR = true,
|
||||
BCD_I = true,
|
||||
I_BCD = true,
|
||||
}
|
||||
|
||||
M.FUNCTION_BLOCKS = {
|
||||
TON = true,
|
||||
TOF = true,
|
||||
TP = true,
|
||||
TONR = true,
|
||||
CTU = true,
|
||||
CTD = true,
|
||||
CTUD = true,
|
||||
IEC_TIMER = true,
|
||||
IEC_TON = true,
|
||||
IEC_TOF = true,
|
||||
IEC_TP = true,
|
||||
IEC_COUNTER = true,
|
||||
IEC_CTU = true,
|
||||
IEC_CTD = true,
|
||||
IEC_CTUD = true,
|
||||
R_TRIG = true,
|
||||
F_TRIG = true,
|
||||
SR = true,
|
||||
RS = true,
|
||||
SCHEDULE = true,
|
||||
BPM = true,
|
||||
LOG = true,
|
||||
DATALOG = true,
|
||||
}
|
||||
|
||||
M.PARAMETERS = {
|
||||
TON = { inputs = { { name = "IN", type = "BOOL" }, { name = "PT", type = "TIME" } }, outputs = { { name = "Q", type = "BOOL" }, { name = "ET", type = "TIME" } } },
|
||||
TOF = { inputs = { { name = "IN", type = "BOOL" }, { name = "PT", type = "TIME" } }, outputs = { { name = "Q", type = "BOOL" }, { name = "ET", type = "TIME" } } },
|
||||
TP = { inputs = { { name = "IN", type = "BOOL" }, { name = "PT", type = "TIME" } }, outputs = { { name = "Q", type = "BOOL" }, { name = "ET", type = "TIME" } } },
|
||||
TONR = { inputs = { { name = "IN", type = "BOOL" }, { name = "PT", type = "TIME" }, { name = "R", type = "BOOL" } }, outputs = { { name = "Q", type = "BOOL" }, { name = "ET", type = "TIME" } } },
|
||||
CTU = { inputs = { { name = "CU", type = "BOOL" }, { name = "R", type = "BOOL" }, { name = "PV", type = "INT" } }, outputs = { { name = "Q", type = "BOOL" }, { name = "CV", type = "INT" } } },
|
||||
CTD = { inputs = { { name = "CD", type = "BOOL" }, { name = "LD", type = "BOOL" }, { name = "PV", type = "INT" } }, outputs = { { name = "Q", type = "BOOL" }, { name = "CV", type = "INT" } } },
|
||||
CTUD = { inputs = { { name = "CU", type = "BOOL" }, { name = "CD", type = "BOOL" }, { name = "R", type = "BOOL" }, { name = "LD", type = "BOOL" }, { name = "PV", type = "INT" } }, outputs = { { name = "QU", type = "BOOL" }, { name = "QD", type = "BOOL" }, { name = "CV", type = "INT" } } },
|
||||
R_TRIG = { inputs = { { name = "CLK", type = "BOOL" } }, outputs = { { name = "Q", type = "BOOL" } } },
|
||||
F_TRIG = { inputs = { { name = "CLK", type = "BOOL" } }, outputs = { { name = "Q", type = "BOOL" } } },
|
||||
SR = { inputs = { { name = "S", type = "BOOL" }, { name = "R1", type = "BOOL" } }, outputs = { { name = "Q1", type = "BOOL" } } },
|
||||
RS = { inputs = { { name = "S1", type = "BOOL" }, { name = "R", type = "BOOL" } }, outputs = { { name = "Q1", type = "BOOL" } } },
|
||||
IEC_TIMER = { inputs = { { name = "IN", type = "BOOL" }, { name = "PT", type = "TIME" } }, outputs = { { name = "Q", type = "BOOL" }, { name = "ET", type = "TIME" } } },
|
||||
IEC_TON = { inputs = { { name = "IN", type = "BOOL" }, { name = "PT", type = "TIME" } }, outputs = { { name = "Q", type = "BOOL" }, { name = "ET", type = "TIME" } } },
|
||||
IEC_TOF = { inputs = { { name = "IN", type = "BOOL" }, { name = "PT", type = "TIME" } }, outputs = { { name = "Q", type = "BOOL" }, { name = "ET", type = "TIME" } } },
|
||||
IEC_TP = { inputs = { { name = "IN", type = "BOOL" }, { name = "PT", type = "TIME" } }, outputs = { { name = "Q", type = "BOOL" }, { name = "ET", type = "TIME" } } },
|
||||
IEC_COUNTER = { inputs = { { name = "CU", type = "BOOL" }, { name = "CD", type = "BOOL" }, { name = "R", type = "BOOL" }, { name = "LD", type = "BOOL" }, { name = "PV", type = "INT" } }, outputs = { { name = "QU", type = "BOOL" }, { name = "QD", type = "BOOL" }, { name = "CV", type = "INT" } } },
|
||||
IEC_CTU = { inputs = { { name = "CU", type = "BOOL" }, { name = "R", type = "BOOL" }, { name = "PV", type = "INT" } }, outputs = { { name = "Q", type = "BOOL" }, { name = "CV", type = "INT" } } },
|
||||
IEC_CTD = { inputs = { { name = "CD", type = "BOOL" }, { name = "LD", type = "BOOL" }, { name = "PV", type = "INT" } }, outputs = { { name = "Q", type = "BOOL" }, { name = "CV", type = "INT" } } },
|
||||
IEC_CTUD = { inputs = { { name = "CU", type = "BOOL" }, { name = "CD", type = "BOOL" }, { name = "R", type = "BOOL" }, { name = "LD", type = "BOOL" }, { name = "PV", type = "INT" } }, outputs = { { name = "QU", type = "BOOL" }, { name = "QD", type = "BOOL" }, { name = "CV", type = "INT" } } },
|
||||
ADD = { inputs = { { name = "IN1" }, { name = "IN2" } }, outputs = { { name = "OUT" } } },
|
||||
SUB = { inputs = { { name = "IN1" }, { name = "IN2" } }, outputs = { { name = "OUT" } } },
|
||||
MUL = { inputs = { { name = "IN1" }, { name = "IN2" } }, outputs = { { name = "OUT" } } },
|
||||
DIV = { inputs = { { name = "IN1" }, { name = "IN2" } }, outputs = { { name = "OUT" } } },
|
||||
MIN = { inputs = { { name = "IN1" }, { name = "IN2" } }, outputs = { { name = "OUT" } } },
|
||||
MAX = { inputs = { { name = "IN1" }, { name = "IN2" } }, outputs = { { name = "OUT" } } },
|
||||
LIMIT = { inputs = { { name = "MN" }, { name = "IN" }, { name = "MX" } }, outputs = { { name = "OUT" } } },
|
||||
MOVE = { inputs = { { name = "IN" } }, outputs = { { name = "OUT" } } },
|
||||
CONVERT = { inputs = { { name = "IN" } }, outputs = { { name = "OUT" } } },
|
||||
ROUND = { inputs = { { name = "IN" } }, outputs = { { name = "OUT" } } },
|
||||
TRUNC = { inputs = { { name = "IN" } }, outputs = { { name = "OUT" } } },
|
||||
CEIL = { inputs = { { name = "IN" } }, outputs = { { name = "OUT" } } },
|
||||
FLOOR = { inputs = { { name = "IN" } }, outputs = { { name = "OUT" } } },
|
||||
SQR = { inputs = { { name = "IN" } }, outputs = { { name = "OUT" } } },
|
||||
SQRT = { inputs = { { name = "IN" } }, outputs = { { name = "OUT" } } },
|
||||
SIN = { inputs = { { name = "IN" } }, outputs = { { name = "OUT" } } },
|
||||
COS = { inputs = { { name = "IN" } }, outputs = { { name = "OUT" } } },
|
||||
TAN = { inputs = { { name = "IN" } }, outputs = { { name = "OUT" } } },
|
||||
ASIN = { inputs = { { name = "IN" } }, outputs = { { name = "OUT" } } },
|
||||
ACOS = { inputs = { { name = "IN" } }, outputs = { { name = "OUT" } } },
|
||||
ATAN = { inputs = { { name = "IN" } }, outputs = { { name = "OUT" } } },
|
||||
LEN = { inputs = { { name = "IN" } }, outputs = { { name = "OUT" } } },
|
||||
CONCAT = { inputs = { { name = "IN1" }, { name = "IN2" } }, outputs = { { name = "OUT" } } },
|
||||
LEFT = { inputs = { { name = "IN" }, { name = "L" } }, outputs = { { name = "OUT" } } },
|
||||
RIGHT = { inputs = { { name = "IN" }, { name = "L" } }, outputs = { { name = "OUT" } } },
|
||||
MID = { inputs = { { name = "IN" }, { name = "L" }, { name = "P" } }, outputs = { { name = "OUT" } } },
|
||||
AND = { inputs = { { name = "IN1" }, { name = "IN2" } }, outputs = { { name = "OUT" } } },
|
||||
OR = { inputs = { { name = "IN1" }, { name = "IN2" } }, outputs = { { name = "OUT" } } },
|
||||
XOR = { inputs = { { name = "IN1" }, { name = "IN2" } }, outputs = { { name = "OUT" } } },
|
||||
SHL = { inputs = { { name = "IN" }, { name = "N" } }, outputs = { { name = "OUT" } } },
|
||||
SHR = { inputs = { { name = "IN" }, { name = "N" } }, outputs = { { name = "OUT" } } },
|
||||
ROL = { inputs = { { name = "IN" }, { name = "N" } }, outputs = { { name = "OUT" } } },
|
||||
ROR = { inputs = { { name = "IN" }, { name = "N" } }, outputs = { { name = "OUT" } } },
|
||||
BCD_I = { inputs = { { name = "IN" } }, outputs = { { name = "OUT" } } },
|
||||
I_BCD = { inputs = { { name = "IN" } }, outputs = { { name = "OUT" } } },
|
||||
}
|
||||
|
||||
function M.get_parameters(name)
|
||||
return M.PARAMETERS[name:upper()]
|
||||
end
|
||||
|
||||
function M.is_known_function_block(name)
|
||||
return M.FUNCTION_BLOCKS[name:upper()] or false
|
||||
end
|
||||
|
||||
function M.is_known_function(name)
|
||||
return M.FUNCTIONS[name:upper()] or false
|
||||
end
|
||||
|
||||
return M
|
||||
+31
-14
@@ -6,23 +6,40 @@ local M = {}
|
||||
function M.setup(opts)
|
||||
opts = opts or {}
|
||||
|
||||
-- Add plugin to runtime path
|
||||
vim.opt.runtimepath:prepend(vim.fn.stdpath("data") .. "/lazy/scl_lsp")
|
||||
|
||||
M.create_commands()
|
||||
|
||||
-- Treesitter parser config
|
||||
local has_ts, ts = pcall(require, "nvim-treesitter.parsers")
|
||||
if has_ts and ts.get_parser_configs then
|
||||
local ok, parser_config = pcall(ts.get_parser_configs)
|
||||
if ok and parser_config then
|
||||
parser_config.scl = {
|
||||
install_info = {
|
||||
files = { "src/parser.c" },
|
||||
generate_requires_npm = false,
|
||||
requires_generate_from_grammar = false,
|
||||
},
|
||||
filetype = "scl",
|
||||
}
|
||||
end
|
||||
-- Treesitter setup for Neovim 0.11+
|
||||
local function setup_treesitter()
|
||||
local lang = vim.treesitter.language
|
||||
local parser_path = "/home/lazar/dev/scl_lsp/src/parser.so"
|
||||
|
||||
-- Register the SCL language
|
||||
lang.add("scl", {
|
||||
path = parser_path,
|
||||
filetype = "scl",
|
||||
})
|
||||
end
|
||||
|
||||
pcall(setup_treesitter)
|
||||
|
||||
-- Install queries
|
||||
local queries_src = "/home/lazar/dev/scl_lsp/queries/highlights.scm"
|
||||
local queries_dest = vim.fn.stdpath("data") .. "/site/queries/scl/highlights.scm"
|
||||
if vim.fn.filereadable(queries_src) == 1 then
|
||||
vim.fn.mkdir(vim.fn.stdpath("data") .. "/site/queries/scl", "p")
|
||||
vim.fn.writefile(vim.fn.readfile(queries_src), queries_dest)
|
||||
end
|
||||
|
||||
-- Enable treesitter manually for SCL files - bypass LazyVim
|
||||
vim.api.nvim_create_autocmd("FileType", {
|
||||
pattern = "scl",
|
||||
callback = function(args)
|
||||
vim.treesitter.start(args.buf, "scl")
|
||||
end,
|
||||
})
|
||||
|
||||
-- Register blink.cmp source
|
||||
if opts.cmp then
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
local M = {}
|
||||
|
||||
local function get_builtin_interface(var_type)
|
||||
local builtin = require("scl.builtin_instructions")
|
||||
local clean_type = var_type:gsub('"', ''):gsub("#", ""):upper()
|
||||
local params_info = builtin.get_parameters(clean_type)
|
||||
if params_info then
|
||||
return {
|
||||
inputs = params_info.inputs or {},
|
||||
outputs = params_info.outputs or {},
|
||||
inouts = {},
|
||||
}
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function get_fb_interface(var_type)
|
||||
local fb_parser = require("scl.fb_parser")
|
||||
local clean_type = var_type:gsub('"', '')
|
||||
@@ -49,44 +63,69 @@ function M.fill_multiline_params()
|
||||
local line_before_cursor = line:sub(1, col)
|
||||
|
||||
local known_vars = get_known_variables(bufnr)
|
||||
local builtin = require("scl.builtin_instructions")
|
||||
|
||||
local fb_name = nil
|
||||
local fb_prefix = ""
|
||||
local is_builtin_function = false
|
||||
|
||||
local prefix, var_name = line_before_cursor:match("(#?)([%w_]+)%s*%(%s*$")
|
||||
if var_name and known_vars[var_name] then
|
||||
fb_prefix = prefix or ""
|
||||
fb_name = var_name
|
||||
end
|
||||
|
||||
if not fb_name then
|
||||
prefix, var_name = line_before_cursor:match("(#?)([%w_]+)%s*%([^)]-,%s*$")
|
||||
if var_name and known_vars[var_name] then
|
||||
if var_name then
|
||||
if known_vars[var_name] then
|
||||
fb_prefix = prefix or ""
|
||||
fb_name = var_name
|
||||
elseif builtin.is_known_function(var_name) then
|
||||
fb_prefix = prefix or ""
|
||||
fb_name = var_name
|
||||
is_builtin_function = true
|
||||
end
|
||||
end
|
||||
|
||||
if not fb_name then
|
||||
vim.notify("No FB instance found before cursor", vim.log.levels.WARN)
|
||||
prefix, var_name = line_before_cursor:match("(#?)([%w_]+)%s*%([^)]-,%s*$")
|
||||
if var_name then
|
||||
if known_vars[var_name] then
|
||||
fb_prefix = prefix or ""
|
||||
fb_name = var_name
|
||||
elseif builtin.is_known_function(var_name) then
|
||||
fb_prefix = prefix or ""
|
||||
fb_name = var_name
|
||||
is_builtin_function = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not fb_name then
|
||||
vim.notify("No FB instance or known function found before cursor", vim.log.levels.WARN)
|
||||
return
|
||||
end
|
||||
|
||||
local var_type = get_variable_type(fb_name, bufnr)
|
||||
if not var_type then
|
||||
vim.notify("Cannot find type for: " .. fb_name, vim.log.levels.WARN)
|
||||
return
|
||||
local fb_interface = nil
|
||||
|
||||
if is_builtin_function then
|
||||
fb_interface = get_builtin_interface(fb_name)
|
||||
else
|
||||
local var_type = get_variable_type(fb_name, bufnr)
|
||||
if not var_type then
|
||||
vim.notify("Cannot find type for: " .. fb_name, vim.log.levels.WARN)
|
||||
return
|
||||
end
|
||||
|
||||
local clean_type = var_type:gsub('"', '')
|
||||
|
||||
fb_interface = get_builtin_interface(clean_type)
|
||||
|
||||
if not fb_interface then
|
||||
if not is_fb_type(clean_type) then
|
||||
vim.notify(clean_type .. " is not an FB/Function type", vim.log.levels.WARN)
|
||||
return
|
||||
end
|
||||
fb_interface = get_fb_interface(clean_type)
|
||||
end
|
||||
end
|
||||
|
||||
local clean_type = var_type:gsub('"', '')
|
||||
if not is_fb_type(clean_type) then
|
||||
vim.notify(clean_type .. " is not an FB/Function type", vim.log.levels.WARN)
|
||||
return
|
||||
end
|
||||
|
||||
local fb_interface = get_fb_interface(clean_type)
|
||||
if not fb_interface then
|
||||
vim.notify("Cannot get interface for: " .. clean_type, vim.log.levels.WARN)
|
||||
vim.notify("Cannot get interface for: " .. (clean_type or fb_name), vim.log.levels.WARN)
|
||||
return
|
||||
end
|
||||
|
||||
@@ -102,7 +141,7 @@ function M.fill_multiline_params()
|
||||
end
|
||||
|
||||
if #params == 0 then
|
||||
vim.notify("No parameters found for: " .. clean_type, vim.log.levels.WARN)
|
||||
vim.notify("No parameters found for: " .. (clean_type or fb_name), vim.log.levels.WARN)
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user