docs: encourage adding comments; fix nested IF/ELSIF indentation
- Update AGENTS.md to encourage comments instead of forbidding them - Add docstrings to all public functions in src/ modules - Add module headers and function comments to lua/scl/ modules - Fix formatter to properly indent multi-line IF/ELSIF conditions - Fix FB call detection to not match IF statements with parentheses
This commit is contained in:
+56
-15
@@ -1,5 +1,6 @@
|
||||
-- SCL Formatter - Document formatting for the LSP server
|
||||
-- Stack-based implementation for proper nested structure handling
|
||||
|
||||
local M = {}
|
||||
|
||||
-- Default patterns for attribute blocks to collapse
|
||||
@@ -10,10 +11,20 @@ local DEFAULT_COLLAPSE_PATTERNS = {
|
||||
"^%s*{%s*%w+%s*:=",
|
||||
}
|
||||
|
||||
--- Create LSP Position object
|
||||
--- @param line number Line number
|
||||
--- @param character number Character offset
|
||||
--- @return table Position object
|
||||
local function position(line, character)
|
||||
return { line = line, character = character }
|
||||
end
|
||||
|
||||
--- Create LSP Range object
|
||||
--- @param start_line number Start line
|
||||
--- @param start_char number Start character
|
||||
--- @param end_line number End line
|
||||
--- @param end_char number End character
|
||||
--- @return table Range object
|
||||
local function range(start_line, start_char, end_line, end_char)
|
||||
return {
|
||||
start = position(start_line, start_char),
|
||||
@@ -89,6 +100,11 @@ local CONTINUATION_OPERATORS = {
|
||||
["MOD"] = true,
|
||||
}
|
||||
|
||||
--- Format SCL document content
|
||||
--- Handles indentation, attribute collapsing, and multiline FB calls
|
||||
--- @param content string The SCL source code
|
||||
--- @param options table Formatting options (insertSpaces, tabSize, collapseAttributes)
|
||||
--- @return table Array of TextEdit objects with range and newText
|
||||
function M.format_document(content, options)
|
||||
options = options or {}
|
||||
local use_spaces = options.insertSpaces or false
|
||||
@@ -147,6 +163,15 @@ function M.format_document(content, options)
|
||||
end
|
||||
|
||||
local function is_fb_call_start(trimmed)
|
||||
local first_word = trimmed:match("^(#?[%w_]+)")
|
||||
if not first_word then return false end
|
||||
|
||||
-- Don't treat control structure keywords as FB calls
|
||||
local control_keywords = { IF = true, ELSIF = true, FOR = true, WHILE = true, CASE = true, WITH = true }
|
||||
if control_keywords[first_word:upper()] then
|
||||
return false
|
||||
end
|
||||
|
||||
if not (trimmed:match("^#?%w+") or trimmed:match('^"')) then
|
||||
return false
|
||||
end
|
||||
@@ -341,10 +366,14 @@ function M.format_document(content, options)
|
||||
|
||||
-- Check if continuing condition (IF/ELSIF condition before THEN)
|
||||
if in_condition and not ends_assignment then
|
||||
local starts_with_operator = is_assignment_continuation(trimmed)
|
||||
local first_word = trimmed:match("^([%w_]+)")
|
||||
local is_then = first_word and first_word:upper() == "THEN"
|
||||
if starts_with_operator or is_then then
|
||||
local is_else = first_word and first_word:upper() == "ELSE"
|
||||
local is_elsif = first_word and first_word:upper() == "ELSIF"
|
||||
local is_ender = trimmed:match("^END_") ~= nil
|
||||
local starts_new_statement = is_then or is_else or is_elsif or is_ender
|
||||
|
||||
if not starts_new_statement then
|
||||
table.insert(formatted_lines, condition_indent .. trimmed)
|
||||
if is_then then
|
||||
in_condition = false
|
||||
@@ -474,19 +503,20 @@ function M.format_document(content, options)
|
||||
if SAME_LEVEL[kw] then
|
||||
local formatted
|
||||
if kw == "THEN" then
|
||||
local if_block = nil
|
||||
for i = #stack, 1, -1 do
|
||||
if stack[i].type == "IF" then
|
||||
if_block = stack[i]
|
||||
break
|
||||
end
|
||||
end
|
||||
if if_block then
|
||||
formatted = string.rep(indent_char, if_block.indent) .. trimmed
|
||||
local then_indent
|
||||
if in_condition and condition_indent ~= "" then
|
||||
then_indent = condition_indent
|
||||
else
|
||||
formatted = get_indent() .. trimmed
|
||||
local if_block = nil
|
||||
for i = #stack, 1, -1 do
|
||||
if stack[i].type == "IF" then
|
||||
if_block = stack[i]
|
||||
break
|
||||
end
|
||||
end
|
||||
then_indent = if_block and string.rep(indent_char, if_block.indent) or get_indent()
|
||||
end
|
||||
table.insert(formatted_lines, formatted)
|
||||
table.insert(formatted_lines, then_indent .. trimmed)
|
||||
table.insert(stack, { type = "THEN_CONTENT", indent = #stack, no_indent = true })
|
||||
in_condition = false
|
||||
elseif kw == "ELSE" or kw == "ELSIF" then
|
||||
@@ -507,6 +537,11 @@ function M.format_document(content, options)
|
||||
end
|
||||
table.insert(formatted_lines, formatted)
|
||||
table.insert(stack, { type = "THEN_CONTENT", indent = #stack, no_indent = true })
|
||||
-- Check if this is a multi-line condition (doesn't end with THEN on same line)
|
||||
if not trimmed:match("THEN%s*$") then
|
||||
in_condition = true
|
||||
condition_indent = string.rep(indent_char, (if_block and if_block.indent or 0) + 1)
|
||||
end
|
||||
else
|
||||
formatted = get_indent() .. trimmed
|
||||
table.insert(formatted_lines, formatted)
|
||||
@@ -540,8 +575,12 @@ function M.format_document(content, options)
|
||||
table.insert(formatted_lines, formatted)
|
||||
table.insert(stack, { type = kw, indent = current_level })
|
||||
if kw == "IF" or kw == "ELSIF" then
|
||||
in_condition = true
|
||||
condition_indent = string.rep(indent_char, current_level)
|
||||
-- Check if this is a multi-line condition (doesn't end with THEN on same line)
|
||||
if not trimmed:match("THEN%s*$") then
|
||||
in_condition = true
|
||||
-- Continuation lines should be indented one level deeper than IF/ELSIF
|
||||
condition_indent = string.rep(indent_char, current_level + 1)
|
||||
end
|
||||
end
|
||||
goto continue
|
||||
end
|
||||
@@ -587,6 +626,8 @@ function M.format_document(content, options)
|
||||
}
|
||||
end
|
||||
|
||||
--- Get default formatting options
|
||||
--- @return table Default options table
|
||||
function M.get_formatting_options()
|
||||
return {
|
||||
insertSpaces = false,
|
||||
|
||||
Reference in New Issue
Block a user