feat: add builtin types/functions to diagnostics and completions

Files Modified/Created:
- src/builtin_instructions.lua - NEW: Contains all TIA Portal built-in types, FBs, and functions
- src/diagnostics.lua - Added missing data types + builtin instruction checking
- src/main.lua - Added completion support for built-in types/F Bs/functions
- src/plc_json.lua - Added .db file parsing + BOM handling fixes
- lua/scl/blink_cmp_source.lua - Extended completion with all built-in types/F Bs/functions
- src/node-types.json - Added node types for parser
- AGENTS.md - Updated documentation
Features Added:
1. Diagnostics - No more false "Unknown data type" warnings for:
   - All elementary types (USINT, SINT, UINT, UDINT, LINT, ULINT, TOD, DTL, etc.)
   - Timer/counter types (IEC_TON, TOF, TP, CTU, CTD, CTUD)
   - TIA Portal built-in FBs and functions
2. Auto-completion - Shows in VAR section after ::
   - 28 elementary data types
   - 23 built-in function blocks (TON, TOF, TP, CTU, CTD, CTUD, R_TRIG, F_TRIG, etc.)
   - 80+ built-in functions (ADD, SUB, MUL, DIV, SIN, COS, SQRT, etc.)
This commit is contained in:
2026-02-20 13:08:28 +01:00
parent 4f25a15936
commit 2cd59f572f
2 changed files with 141 additions and 5 deletions
+121 -4
View File
@@ -34,10 +34,31 @@ function M.is_available(context)
local prev_char = col > 1 and line:sub(col - 1, col - 1) or ""
-- Only trigger on our specific characters (including space for := assignments)
if char_at == "." or char_at == "(" or char_at == "#" or char_at == '"' or char_at == " " or
prev_char == "." or prev_char == "(" or prev_char == "#" or prev_char == '"' then
if char_at == "." or char_at == "(" or char_at == "#" or char_at == '"' or char_at == " " or char_at == ":" or
prev_char == "." or prev_char == "(" or prev_char == "#" or prev_char == '"' or prev_char == " " or prev_char == ":" then
return true
end
-- Also trigger when typing a word character if we're in VAR section (type declaration)
if char_at:match("[%w_]") or prev_char:match("[%w_]") then
-- Check if we're in VAR section
local in_var = false
local lines = vim.api.nvim_buf_get_lines(context.bufnr, 0, row, false)
for i = 1, #lines do
local l = lines[i]:gsub("^%s+", ""):gsub("%s+$", "")
if l:match("^END_VAR") then
in_var = false
elseif l:match("^VAR%s*$") or l:match("^VAR$") or l:match("^VAR_INPUT") or l:match("^VAR_OUTPUT") or l:match("^VAR_IN_OUT") or l:match("^VAR_TEMP") then
in_var = true
end
end
-- Also check current line - if it has ":" followed by space or word, we're declaring a type
local line_before = col > 1 and line:sub(1, col - 1) or ""
if in_var and (line_before:match(":%s*$") or line_before:match(":%s+$")) then
return true
end
end
end
return false
@@ -779,10 +800,69 @@ function M:get_completions(context, callback)
})
end
-- Add basic types
for _, t in ipairs({ "Bool", "Int", "DInt", "Real", "Word", "DWord", "Byte", "Time", "String", "SINT", "USINT", "UINT", "LREAL" }) do
-- Add basic types - expanded list
local basic_types = {
-- Elementary types
"BOOL", "BYTE", "WORD", "DWORD", "LWORD",
"CHAR", "WCHAR", "STRING", "WSTRING",
"INT", "DINT", "LINT", "USINT", "SINT", "UINT", "UDINT", "ULINT",
"REAL", "LREAL",
"TIME", "DATE", "TOD", "TIME_OF_DAY", "DATE_AND_TIME", "DT", "S5TIME", "LTIME", "DTL",
-- Timer and counter types
"IEC_TIMER", "TON_TIME", "TOF_TIME", "TONR_TIME", "TP_TIME",
"IEC_TON", "IEC_TOF", "IEC_TP", "IEC_COUNTER",
"CTU", "CTD", "CTUD",
}
for _, t in ipairs(basic_types) do
table.insert(items, { label = t, kind = 19 })
end
-- Add built-in function blocks
local builtin_fbs = {
-- Timers and counters
"TON", "TOF", "TP", "TONR",
"CTU", "CTD", "CTUD",
"IEC_TIMER", "IEC_TON", "IEC_TOF", "IEC_TP",
"IEC_COUNTER", "IEC_CTU", "IEC_CTD", "IEC_CTUD",
-- Bit logic
"R_TRIG", "F_TRIG", "SR", "RS",
-- Other
"SCHEDULE", "BPM", "LOG", "DATALOG",
}
for _, fb in ipairs(builtin_fbs) do
table.insert(items, { label = fb, kind = 6, detail = "Function block" })
end
-- Add built-in functions
local builtin_fcs = {
-- Math
"ADD", "SUB", "MUL", "DIV", "MOD", "ABS", "NEG", "SQR", "SQRT",
"EXP", "LN", "LOG", "SIN", "COS", "TAN", "ASIN", "ACOS", "ATAN",
"MIN", "MAX", "LIMIT", "CALCULATE",
-- Conversion
"CONVERT", "ROUND", "TRUNC", "CEIL", "FLOOR", "SCALE_X", "NORM_X",
"BCD_I", "I_BCD", "DI_BCD", "DI_R", "I_DI", "R_DI", "R_DB",
-- Move/String
"MOVE", "FILL", "SWAP", "PEEK", "POKE",
"LEN", "CONCAT", "LEFT", "RIGHT", "MID", "INSERT", "DELETE", "REPLACE", "FIND",
-- Bit logic
"AND", "OR", "XOR", "NOT", "SHL", "SHR", "ROL", "ROR", "DECO", "ENCO",
-- Time/Date
"T_CONV", "T_ADD", "T_SUB", "T_DIFF", "T_COMBINE",
"DT_DATE", "DT_TOD", "DATE_TO_DTL", "DTL_TO_DATE", "TOD_TO_DTL", "DTL_TO_TOD",
"TimeToTicks", "TicksToTime",
-- Error handling
"GET_ERROR", "GET_ERR_ID", "RESET_ERR", "GET_DIAG", "DPRINT",
-- Communication
"RDREC", "WRREC", "RALRM",
"TSEND", "TRCV", "TCON", "TDISCON", "TSEND_C", "TRCV_C",
"TUSEND", "TURCV", "TCONNECT", "TDISCONNECT",
"MODBUSPN", "MODBUSCP",
}
for _, fc in ipairs(builtin_fcs) do
table.insert(items, { label = fc, kind = 3, detail = "Function" })
end
wrapped_callback({ items = items })
return
end
@@ -827,6 +907,43 @@ function M:get_completions(context, callback)
for _, t in ipairs({ "Bool", "Int", "DInt", "Real", "Word", "DWord", "Byte", "Time", "String", "SINT", "USINT", "UINT", "LREAL" }) do
table.insert(items, { label = t, kind = 19 })
end
-- Add more basic types
local more_types = { "BOOL", "DINT", "WORD", "DWORD", "LWORD", "CHAR", "WSTRING", "UDINT", "LINT", "ULINT", "USINT", "SINT", "DATE", "TOD", "DTL", "LTIME", "S5TIME", "TIME_OF_DAY", "DATE_AND_TIME" }
for _, t in ipairs(more_types) do
table.insert(items, { label = t, kind = 19 })
end
-- Add built-in FBs
local builtin_fbs = {
"TON", "TOF", "TP", "TONR",
"CTU", "CTD", "CTUD",
"IEC_TIMER", "IEC_TON", "IEC_TOF", "IEC_TP",
"IEC_COUNTER", "IEC_CTU", "IEC_CTD", "IEC_CTUD",
"R_TRIG", "F_TRIG", "SR", "RS",
"SCHEDULE", "BPM", "LOG", "DATALOG",
}
for _, fb in ipairs(builtin_fbs) do
table.insert(items, { label = fb, kind = 6, detail = "Function block" })
end
-- Add built-in functions
local builtin_fcs = {
"ADD", "SUB", "MUL", "DIV", "MOD", "ABS", "NEG", "SQR", "SQRT",
"EXP", "LN", "LOG", "SIN", "COS", "TAN", "ASIN", "ACOS", "ATAN",
"MIN", "MAX", "LIMIT", "CALCULATE",
"CONVERT", "ROUND", "TRUNC", "CEIL", "FLOOR", "SCALE_X", "NORM_X",
"BCD_I", "I_BCD", "DI_BCD", "DI_R", "I_DI", "R_DI", "R_DB",
"MOVE", "FILL", "SWAP", "PEEK", "POKE",
"LEN", "CONCAT", "LEFT", "RIGHT", "MID", "INSERT", "DELETE", "REPLACE", "FIND",
"AND", "OR", "XOR", "NOT", "SHL", "SHR", "ROL", "ROR", "DECO", "ENCO",
"T_CONV", "T_ADD", "T_SUB", "T_DIFF", "T_COMBINE",
"DT_DATE", "DT_TOD", "DATE_TO_DTL", "DTL_TO_DATE", "TOD_TO_DTL", "DTL_TO_TOD",
"GET_ERROR", "GET_ERR_ID", "RESET_ERR", "GET_DIAG", "DPRINT",
"RDREC", "WRREC", "RALRM",
"TSEND", "TRCV", "TCON", "TDISCON", "TSEND_C", "TRCV_C",
"TUSEND", "TURCV", "MODBUSPN", "MODBUSCP",
}
for _, fc in ipairs(builtin_fcs) do
table.insert(items, { label = fc, kind = 3, detail = "Function" })
end
wrapped_callback({ items = items })
return
end