local M = {} local function get_fb_interface(var_type) local fb_parser = require("scl.fb_parser") local clean_type = var_type:gsub('"', '') if fb_parser.get_cache_count() == 0 then local ws = require("scl.workspace_types") ws.scan_project_fbs(vim.api.nvim_get_current_buf()) end return fb_parser.get_fb_interface(clean_type) end local function is_fb_type(var_type) local fb_parser = require("scl.fb_parser") local clean_type = var_type:gsub('"', '') if fb_parser.get_cache_count() == 0 then local ws = require("scl.workspace_types") ws.scan_project_fbs(vim.api.nvim_get_current_buf()) end return fb_parser.is_fb_type(clean_type) end local function get_known_variables(bufnr) local scl_vars = require("scl.variables") local variables = scl_vars.extract_variables(bufnr) local known = {} for _, v in ipairs(variables) do known[v.name] = true end return known end local function get_variable_type(var_name, bufnr) local scl_vars = require("scl.variables") return scl_vars.get_variable_type(var_name, bufnr) end function M.fill_multiline_params() local bufnr = vim.api.nvim_get_current_buf() local cursor = vim.api.nvim_win_get_cursor(0) local row = cursor[1] local col = cursor[2] local line = vim.api.nvim_get_current_line() local line_before_cursor = line:sub(1, col) local known_vars = get_known_variables(bufnr) local fb_name = nil local fb_prefix = "" 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 fb_prefix = prefix or "" fb_name = var_name end end if not fb_name then vim.notify("No FB instance 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 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) return end local params = {} for _, inp in ipairs(fb_interface.inputs or {}) do table.insert(params, inp.name .. " := ") end for _, inout in ipairs(fb_interface.inouts or {}) do table.insert(params, inout.name .. " := ") end for _, out in ipairs(fb_interface.outputs or {}) do table.insert(params, out.name .. " => ") end if #params == 0 then vim.notify("No parameters found for: " .. clean_type, vim.log.levels.WARN) return end local indent = line:match("^%s*") or "" local continuation_indent = indent .. string.rep(" ", #fb_name + 2) local lines_to_insert = {} local first_line = indent .. fb_prefix .. fb_name .. "(" .. params[1] .. "," table.insert(lines_to_insert, first_line) for i = 2, #params do local p = params[i] local closing = (i == #params) and ");" or "," local line_content = continuation_indent .. p .. closing table.insert(lines_to_insert, line_content) end vim.api.nvim_buf_set_lines(bufnr, row - 1, row, false, lines_to_insert) local new_cursor_row = row local new_cursor_col = #indent + #fb_prefix + #fb_name + 1 + #params[1] vim.api.nvim_win_set_cursor(0, { new_cursor_row, new_cursor_col }) end local function is_inside_fb_call(bufnr, cursor_row, cursor_col) local function get_line_text(rownum) return vim.api.nvim_buf_get_lines(bufnr, rownum - 1, rownum, false)[1] or "" end local known_vars = get_known_variables(bufnr) local paren_depth = 0 local found_fb_call_start = false for i = cursor_row, 1, -1 do local line = get_line_text(i) local line_to_cursor = (i == cursor_row) and line:sub(1, cursor_col) or line for j = #line_to_cursor, 1, -1 do local char = line_to_cursor:sub(j, j) if char == ")" then paren_depth = paren_depth + 1 elseif char == "(" then if paren_depth > 0 then paren_depth = paren_depth - 1 else local before_paren = line_to_cursor:sub(1, j - 1) local var_match = before_paren:match("#?([%w_]+)%s*$") if var_match and known_vars[var_match] then return true end found_fb_call_start = true break end end end if found_fb_call_start then break end if line:match("^%s*END_") or line:match("^%s*BEGIN") then break end end return false end function M.jump_to_next_param() local cursor = vim.api.nvim_win_get_cursor(0) local row = cursor[1] local col = cursor[2] local bufnr = vim.api.nvim_get_current_buf() if not is_inside_fb_call(bufnr, row, col) then return false end local total_lines = vim.api.nvim_buf_line_count(bufnr) local function get_line_text(rownum) return vim.api.nvim_buf_get_lines(bufnr, rownum - 1, rownum, false)[1] or "" end local function find_next_param_on_line(start_row) for i = start_row, total_lines do local line = get_line_text(i) local param_match = line:match("[%w_]+%s*:=") or line:match("[%w_]+%s*=>") if param_match then local op_end = line:find(":=") or line:find("=>") vim.api.nvim_win_set_cursor(0, { i, op_end + 2 }) return true end if line:match("%)") then break end end return false end local current_line = get_line_text(row) local text_after_cursor = current_line:sub(col + 1) local next_param = text_after_cursor:match("([%w_]+)%s*:=") or text_after_cursor:match("([%w_]+)%s*=>") if next_param then local op_end = text_after_cursor:find(":=") or text_after_cursor:find("=>") local new_col = col + op_end + 2 vim.api.nvim_win_set_cursor(0, { row, new_col }) return true end if not find_next_param_on_line(row + 1) then local all_params = {} local all_text = "" for i = row, total_lines do local l = get_line_text(i) all_text = all_text .. l .. "\n" if l:match("%)") then break end end for param in all_text:gmatch("([%w_]+)%s*:=") do table.insert(all_params, param) end for param in all_text:gmatch("([%w_]+)%s*=>") do table.insert(all_params, param) end if #all_params > 0 then vim.api.nvim_feedkeys("> ", "m", false) return true end else return true end return false end return M