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:
+175
-3
@@ -335,6 +335,30 @@ function handlers.textDocument_hover(params)
|
||||
var_info.data_type or "unknown",
|
||||
var_info.line + 1
|
||||
)
|
||||
|
||||
if var_info.comment and var_info.comment ~= "" then
|
||||
detail = detail .. "\n\n" .. var_info.comment
|
||||
end
|
||||
|
||||
if var_info.data_type then
|
||||
local builtin_params = builtin.get_parameters(var_info.data_type)
|
||||
if builtin_params then
|
||||
detail = detail .. "\n\n**Members:**\n"
|
||||
if builtin_params.inputs and #builtin_params.inputs > 0 then
|
||||
detail = detail .. "*Inputs:*\n"
|
||||
for _, inp in ipairs(builtin_params.inputs) do
|
||||
detail = detail .. string.format(" - `%s`: %s\n", inp.name, inp.type or "ANY")
|
||||
end
|
||||
end
|
||||
if builtin_params.outputs and #builtin_params.outputs > 0 then
|
||||
detail = detail .. "*Outputs:*\n"
|
||||
for _, out in ipairs(builtin_params.outputs) do
|
||||
detail = detail .. string.format(" - `%s`: %s\n", out.name, out.type or "ANY")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
contents = { kind = "markdown", value = detail },
|
||||
range = {
|
||||
@@ -348,10 +372,17 @@ function handlers.textDocument_hover(params)
|
||||
for type_name, type_info in pairs(doc.types) do
|
||||
if type_name == word then
|
||||
local detail = string.format("**Type**: `%s`\nKind: %s", type_name, type_info.kind)
|
||||
if type_info.comment and type_info.comment ~= "" then
|
||||
detail = detail .. "\n\n" .. type_info.comment
|
||||
end
|
||||
if type_info.kind == "struct" and type_info.fields then
|
||||
detail = detail .. "\n\n**Fields:**\n"
|
||||
for _, field in ipairs(type_info.fields) do
|
||||
detail = detail .. string.format("- `%s`: %s\n", field.name, field.type)
|
||||
if field.comment and field.comment ~= "" then
|
||||
detail = detail .. string.format("- `%s`: %s // %s\n", field.name, field.type, field.comment)
|
||||
else
|
||||
detail = detail .. string.format("- `%s`: %s\n", field.name, field.type)
|
||||
end
|
||||
end
|
||||
end
|
||||
return {
|
||||
@@ -365,6 +396,124 @@ function handlers.textDocument_hover(params)
|
||||
end
|
||||
end
|
||||
|
||||
if builtin.is_known_function_block(word) or builtin.is_known_function(word) then
|
||||
local params_info = builtin.get_parameters(word)
|
||||
local kind = builtin.is_known_function_block(word) and "Function Block" or "Function"
|
||||
local detail = string.format("**%s**: `%s`\n", kind, word)
|
||||
if params_info then
|
||||
detail = detail .. "\n**Parameters:**\n"
|
||||
if params_info.inputs and #params_info.inputs > 0 then
|
||||
detail = detail .. "*Inputs:*\n"
|
||||
for _, inp in ipairs(params_info.inputs) do
|
||||
detail = detail .. string.format(" - `%s`: %s\n", inp.name, inp.type or "ANY")
|
||||
end
|
||||
end
|
||||
if params_info.outputs and #params_info.outputs > 0 then
|
||||
detail = detail .. "*Outputs:*\n"
|
||||
for _, out in ipairs(params_info.outputs) do
|
||||
detail = detail .. string.format(" - `%s`: %s\n", out.name, out.type or "ANY")
|
||||
end
|
||||
end
|
||||
else
|
||||
detail = detail .. "\n_(No parameter info available)_"
|
||||
end
|
||||
return {
|
||||
contents = { kind = "markdown", value = detail },
|
||||
range = {
|
||||
start = { line = params.position.line, character = word_start - 1 },
|
||||
["end"] = { line = params.position.line, character = word_end - 1 },
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
local fb_param_info = nil
|
||||
|
||||
local function find_fb_call_start(lines, current_line_idx)
|
||||
for i = current_line_idx, 1, -1 do
|
||||
local l = lines[i]
|
||||
local fb_name = l:match("#([%w_]+)%s*%(") or l:match("([%w_]+)%s*%(")
|
||||
if fb_name and doc.variables and doc.variables[fb_name] then
|
||||
return fb_name, i
|
||||
end
|
||||
if l:match("%)%s*;%s*$") then
|
||||
break
|
||||
end
|
||||
end
|
||||
return nil, nil
|
||||
end
|
||||
|
||||
local fb_name_on_line, _ = find_fb_call_start(lines, line_idx)
|
||||
if fb_name_on_line then
|
||||
local fb_var = doc.variables[fb_name_on_line]
|
||||
if fb_var then
|
||||
local fb_type = fb_var.data_type
|
||||
if fb_type then
|
||||
local clean_type = fb_type:gsub('"', ""):gsub("#", "")
|
||||
local params_info = builtin.get_parameters(clean_type)
|
||||
|
||||
if not params_info then
|
||||
local workspace_types = plc_json.get_types(doc.root_dir)
|
||||
if workspace_types and workspace_types[clean_type] then
|
||||
local ws_type = workspace_types[clean_type]
|
||||
if ws_type.kind == "function_block" or ws_type.kind == "function" then
|
||||
local fields = {}
|
||||
for _, f in ipairs(ws_type.inputs or {}) do
|
||||
table.insert(fields, { name = f.name, type = f.type, comment = f.comment })
|
||||
end
|
||||
params_info = { inputs = fields, outputs = ws_type.outputs or {} }
|
||||
elseif ws_type.fields then
|
||||
local fields = {}
|
||||
for _, f in ipairs(ws_type.fields) do
|
||||
table.insert(fields, { name = f.name, type = f.type, comment = f.comment })
|
||||
end
|
||||
params_info = { inputs = fields, outputs = {} }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not params_info and doc.types and doc.types[clean_type] and doc.types[clean_type].fields then
|
||||
local fields = {}
|
||||
for _, f in ipairs(doc.types[clean_type].fields) do
|
||||
table.insert(fields, { name = f.name, type = f.type, comment = f.comment })
|
||||
end
|
||||
params_info = { inputs = fields, outputs = {} }
|
||||
end
|
||||
|
||||
if params_info then
|
||||
for _, inp in ipairs(params_info.inputs or {}) do
|
||||
if inp.name:upper() == word:upper() then
|
||||
fb_param_info = { name = inp.name, type = inp.type, direction = "input", comment = inp.comment }
|
||||
break
|
||||
end
|
||||
end
|
||||
if not fb_param_info then
|
||||
for _, out in ipairs(params_info.outputs or {}) do
|
||||
if out.name:upper() == word:upper() then
|
||||
fb_param_info = { name = out.name, type = out.type, direction = "output", comment = out.comment }
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if fb_param_info then
|
||||
local detail = string.format("**Parameter**: `%s`\nType: `%s`\nDirection: %s",
|
||||
fb_param_info.name, fb_param_info.type or "ANY", fb_param_info.direction)
|
||||
if fb_param_info.comment and fb_param_info.comment ~= "" then
|
||||
detail = detail .. "\n\n" .. fb_param_info.comment
|
||||
end
|
||||
return {
|
||||
contents = { kind = "markdown", value = detail },
|
||||
range = {
|
||||
start = { line = params.position.line, character = word_start - 1 },
|
||||
["end"] = { line = params.position.line, character = word_end - 1 },
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
@@ -432,9 +581,10 @@ function handlers.textDocument_completion(params)
|
||||
local var_info = doc.variables and doc.variables[var_name]
|
||||
local data_type = var_info and var_info.data_type
|
||||
|
||||
if data_type and doc.types then
|
||||
if data_type then
|
||||
local struct_name = data_type
|
||||
if doc.types[struct_name] and doc.types[struct_name].fields then
|
||||
|
||||
if doc.types and doc.types[struct_name] and doc.types[struct_name].fields then
|
||||
for _, field in ipairs(doc.types[struct_name].fields) do
|
||||
table.insert(items, {
|
||||
label = field.name,
|
||||
@@ -444,6 +594,28 @@ function handlers.textDocument_completion(params)
|
||||
insertTextFormat = 1,
|
||||
})
|
||||
end
|
||||
else
|
||||
local builtin_params = builtin.get_parameters(struct_name)
|
||||
if builtin_params then
|
||||
for _, inp in ipairs(builtin_params.inputs or {}) do
|
||||
table.insert(items, {
|
||||
label = inp.name,
|
||||
kind = 13,
|
||||
detail = struct_name .. "." .. inp.name .. ": " .. (inp.type or "ANY"),
|
||||
insertText = inp.name,
|
||||
insertTextFormat = 1,
|
||||
})
|
||||
end
|
||||
for _, out in ipairs(builtin_params.outputs or {}) do
|
||||
table.insert(items, {
|
||||
label = out.name,
|
||||
kind = 13,
|
||||
detail = struct_name .. "." .. out.name .. ": " .. (out.type or "ANY"),
|
||||
insertText = out.name,
|
||||
insertTextFormat = 1,
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user