feat: auto-uppercase keywords and auto-semicolon for END_* keywords
- Auto-uppercase SCL keywords (IF, CASE, FOR, NOT, AND, etc.) when typing space - Auto-add semicolon after END_* keywords (END_IF, END_FOR, etc.) when: - Leaving insert mode on a line ending with END_* - Pressing Enter after typing END_* - Added complete keyword list including TYPE, STRUCT, DATA_BLOCK, etc. - Works for .scl, .udt, and .db files
This commit is contained in:
+130
-3
@@ -33,9 +33,24 @@ local keywords = {
|
||||
"ORGANIZATION_BLOCK", "END_ORGANIZATION_BLOCK",
|
||||
"FUNCTION_BLOCK", "END_FUNCTION_BLOCK",
|
||||
"FUNCTION", "END_FUNCTION",
|
||||
"RETURN",
|
||||
"RETURN", "TYPE", "END_TYPE", "STRUCT", "END_STRUCT",
|
||||
"DATA_BLOCK", "END_DATA_BLOCK",
|
||||
"CONSTANT", "RETAIN", "NON_RETAIN",
|
||||
}
|
||||
|
||||
-- Keywords that need semicolon after them (when at end of statement)
|
||||
local end_keywords = {
|
||||
"END_IF", "END_FOR", "END_WHILE", "END_REPEAT", "END_CASE",
|
||||
"END_VAR", "END_FUNCTION", "END_FUNCTION_BLOCK", "END_ORGANIZATION_BLOCK",
|
||||
"END_TYPE", "END_STRUCT", "END_DATA_BLOCK", "END_REGION",
|
||||
}
|
||||
|
||||
-- Map lowercase to uppercase for auto-conversion
|
||||
local keyword_map = {}
|
||||
for _, kw in ipairs(keywords) do
|
||||
keyword_map[kw:lower()] = kw
|
||||
end
|
||||
|
||||
-- Check if word is a keyword
|
||||
local function is_keyword(word)
|
||||
for _, kw in ipairs(keywords) do
|
||||
@@ -393,6 +408,74 @@ local function on_dot_typed()
|
||||
end
|
||||
end
|
||||
|
||||
-- Auto-uppercase keywords when typing space
|
||||
local function auto_uppercase_keyword()
|
||||
-- Only in SCL files
|
||||
local ft = vim.bo.filetype
|
||||
if ft ~= "scl" and ft ~= "udt" and ft ~= "db" then
|
||||
return
|
||||
end
|
||||
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
local row = vim.api.nvim_win_get_cursor(0)[1]
|
||||
local col = vim.api.nvim_win_get_cursor(0)[2]
|
||||
local line = vim.api.nvim_buf_get_lines(bufnr, row - 1, row, false)[1]
|
||||
|
||||
-- Check if we just typed a space
|
||||
if col < 1 or line:sub(col, col) ~= " " then
|
||||
return
|
||||
end
|
||||
|
||||
-- Find word before the space
|
||||
local word_end = col - 1
|
||||
local word_start = word_end
|
||||
while word_start > 0 and line:sub(word_start, word_start):match("[%w_]") do
|
||||
word_start = word_start - 1
|
||||
end
|
||||
word_start = word_start + 1
|
||||
|
||||
if word_start > word_end then
|
||||
return
|
||||
end
|
||||
|
||||
local word = line:sub(word_start, word_end)
|
||||
local lower_word = word:lower()
|
||||
|
||||
-- Check if it's a keyword that needs uppercase
|
||||
if keyword_map[lower_word] and word ~= keyword_map[lower_word] then
|
||||
local upper_word = keyword_map[lower_word]
|
||||
vim.api.nvim_buf_set_text(bufnr, row - 1, word_start - 1, row - 1, word_end, { upper_word })
|
||||
end
|
||||
end
|
||||
|
||||
-- Auto-add semicolon after END_* keywords
|
||||
local function auto_add_semicolon()
|
||||
-- Only in SCL files
|
||||
local ft = vim.bo.filetype
|
||||
if ft ~= "scl" and ft ~= "udt" and ft ~= "db" then
|
||||
return
|
||||
end
|
||||
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
local row = vim.api.nvim_win_get_cursor(0)[1]
|
||||
local line = vim.api.nvim_buf_get_lines(bufnr, row - 1, row, false)[1]
|
||||
local trimmed = line:match("^%s*(.-)%s*$")
|
||||
|
||||
-- Check if line ends with an END_* keyword (without semicolon)
|
||||
for _, end_kw in ipairs(end_keywords) do
|
||||
if trimmed:upper() == end_kw then
|
||||
-- Check if already has semicolon
|
||||
if not line:match(";%s*$") then
|
||||
local new_line = line .. ";"
|
||||
vim.api.nvim_buf_set_lines(bufnr, row - 1, row, false, { new_line })
|
||||
-- Move cursor to end of line
|
||||
vim.api.nvim_win_set_cursor(0, { row, #new_line })
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Setup auto-prefixing on specific triggers
|
||||
function M.setup()
|
||||
local augroup = vim.api.nvim_create_augroup("SCLAutoPrefix", { clear = true })
|
||||
@@ -414,9 +497,15 @@ function M.setup()
|
||||
vim.api.nvim_create_autocmd("InsertLeave", {
|
||||
group = augroup,
|
||||
callback = function()
|
||||
if vim.bo.filetype == "scl" then
|
||||
local ft = vim.bo.filetype
|
||||
if ft == "scl" or ft == "udt" or ft == "db" then
|
||||
-- Auto-add semicolon after END_* keywords
|
||||
auto_add_semicolon()
|
||||
-- Variable prefixing (only for scl)
|
||||
if ft == "scl" then
|
||||
auto_prefix_current_line()
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
@@ -424,14 +513,20 @@ function M.setup()
|
||||
vim.api.nvim_create_autocmd("TextChangedI", {
|
||||
group = augroup,
|
||||
callback = function()
|
||||
if vim.bo.filetype == "scl" then
|
||||
local ft = vim.bo.filetype
|
||||
if ft == "scl" or ft == "udt" or ft == "db" then
|
||||
local line = vim.api.nvim_get_current_line()
|
||||
local cursor_col = vim.api.nvim_win_get_cursor(0)[2]
|
||||
|
||||
if cursor_col > 0 and line:sub(cursor_col, cursor_col) == " " then
|
||||
-- Auto-uppercase keywords
|
||||
auto_uppercase_keyword()
|
||||
-- Variable prefixing (only for scl)
|
||||
if ft == "scl" then
|
||||
auto_prefix_current_line()
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
@@ -484,6 +579,38 @@ function M.setup()
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
-- Auto-add semicolon when pressing Enter after END_* keyword
|
||||
vim.api.nvim_create_autocmd("TextChangedI", {
|
||||
group = augroup,
|
||||
callback = function()
|
||||
local ft = vim.bo.filetype
|
||||
if ft ~= "scl" and ft ~= "udt" and ft ~= "db" then
|
||||
return
|
||||
end
|
||||
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
local row = vim.api.nvim_win_get_cursor(0)[1]
|
||||
local line = vim.api.nvim_buf_get_lines(bufnr, row - 1, row, false)[1]
|
||||
|
||||
-- Check if we're on a new/empty line (Enter was pressed)
|
||||
if line and line:match("^%s*$") and row > 1 then
|
||||
local prev_line = vim.api.nvim_buf_get_lines(bufnr, row - 2, row - 1, false)[1]
|
||||
if prev_line then
|
||||
local trimmed = prev_line:match("^%s*(.-)%s*$")
|
||||
-- Check if previous line is an END_* keyword without semicolon
|
||||
for _, end_kw in ipairs(end_keywords) do
|
||||
if trimmed:upper() == end_kw and not prev_line:match(";%s*$") then
|
||||
-- Add semicolon to previous line
|
||||
local new_prev = prev_line .. ";"
|
||||
vim.api.nvim_buf_set_lines(bufnr, row - 2, row - 1, false, { new_prev })
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
-- Manual trigger function
|
||||
|
||||
Reference in New Issue
Block a user