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",
|
"ORGANIZATION_BLOCK", "END_ORGANIZATION_BLOCK",
|
||||||
"FUNCTION_BLOCK", "END_FUNCTION_BLOCK",
|
"FUNCTION_BLOCK", "END_FUNCTION_BLOCK",
|
||||||
"FUNCTION", "END_FUNCTION",
|
"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
|
-- Check if word is a keyword
|
||||||
local function is_keyword(word)
|
local function is_keyword(word)
|
||||||
for _, kw in ipairs(keywords) do
|
for _, kw in ipairs(keywords) do
|
||||||
@@ -393,6 +408,74 @@ local function on_dot_typed()
|
|||||||
end
|
end
|
||||||
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
|
-- Setup auto-prefixing on specific triggers
|
||||||
function M.setup()
|
function M.setup()
|
||||||
local augroup = vim.api.nvim_create_augroup("SCLAutoPrefix", { clear = true })
|
local augroup = vim.api.nvim_create_augroup("SCLAutoPrefix", { clear = true })
|
||||||
@@ -414,9 +497,15 @@ function M.setup()
|
|||||||
vim.api.nvim_create_autocmd("InsertLeave", {
|
vim.api.nvim_create_autocmd("InsertLeave", {
|
||||||
group = augroup,
|
group = augroup,
|
||||||
callback = function()
|
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()
|
auto_prefix_current_line()
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -424,14 +513,20 @@ function M.setup()
|
|||||||
vim.api.nvim_create_autocmd("TextChangedI", {
|
vim.api.nvim_create_autocmd("TextChangedI", {
|
||||||
group = augroup,
|
group = augroup,
|
||||||
callback = function()
|
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 line = vim.api.nvim_get_current_line()
|
||||||
local cursor_col = vim.api.nvim_win_get_cursor(0)[2]
|
local cursor_col = vim.api.nvim_win_get_cursor(0)[2]
|
||||||
|
|
||||||
if cursor_col > 0 and line:sub(cursor_col, cursor_col) == " " then
|
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()
|
auto_prefix_current_line()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -484,6 +579,38 @@ function M.setup()
|
|||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|
||||||
-- Manual trigger function
|
-- Manual trigger function
|
||||||
|
|||||||
Reference in New Issue
Block a user