Compare commits
3 commits
Author | SHA1 | Date | |
---|---|---|---|
9622219679 |
|||
828c62a0a6 |
|||
6e09ffe4ff |
3 changed files with 54 additions and 30 deletions
15
.forgejo/workflows/release.yml
Normal file
15
.forgejo/workflows/release.yml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
name: Release
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write # to be able to publish a GitHub release
|
||||||
|
issues: write # to be able to comment on released issues
|
||||||
|
pull-requests: write # to be able to comment on released pull requests
|
||||||
|
id-token: write # to enable use of OIDC for npm provenance
|
||||||
|
steps:
|
||||||
|
- name: Create Release
|
||||||
|
uses: https://git.kjan.de/actions/semantic-release@main
|
||||||
|
with:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
|
@ -1,7 +1,6 @@
|
||||||
--- JQuote: A Neovim plugin for cycling through quote characters
|
--- JQuote: A Neovim plugin for cycling through quote characters
|
||||||
--- @module jquote
|
--- @module jquote
|
||||||
--- @author Author Name
|
--- @author Jan
|
||||||
--- @version 1.0.0
|
|
||||||
--- @license MIT
|
--- @license MIT
|
||||||
|
|
||||||
local M = {}
|
local M = {}
|
||||||
|
@ -24,7 +23,6 @@ M.options = vim.deepcopy(DEFAULT_OPTIONS)
|
||||||
|
|
||||||
--- Plugin metadata
|
--- Plugin metadata
|
||||||
--- @type table
|
--- @type table
|
||||||
M._version = "1.0.0"
|
|
||||||
M._name = "jquote"
|
M._name = "jquote"
|
||||||
|
|
||||||
--- Validates if a character is one of the configured quote characters
|
--- Validates if a character is one of the configured quote characters
|
||||||
|
@ -35,7 +33,7 @@ local function is_defined_quote_char(char)
|
||||||
if type(char) ~= "string" or #char ~= 1 then
|
if type(char) ~= "string" or #char ~= 1 then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
for _, quote_char in ipairs(M.options.quote_chars) do
|
for _, quote_char in ipairs(M.options.quote_chars) do
|
||||||
if char == quote_char then
|
if char == quote_char then
|
||||||
return true
|
return true
|
||||||
|
@ -58,14 +56,14 @@ local function find_quoted_string_at_cursor(line, cursor_col)
|
||||||
|
|
||||||
--- @type table[] Array of quote position records
|
--- @type table[] Array of quote position records
|
||||||
local quote_positions = {}
|
local quote_positions = {}
|
||||||
|
|
||||||
-- Scan line for quote characters and record their positions
|
-- Scan line for quote characters and record their positions
|
||||||
for i = 1, #line do
|
for i = 1, #line do
|
||||||
local char = line:sub(i, i)
|
local char = line:sub(i, i)
|
||||||
if is_defined_quote_char(char) then
|
if is_defined_quote_char(char) then
|
||||||
table.insert(quote_positions, {
|
table.insert(quote_positions, {
|
||||||
char = char,
|
char = char,
|
||||||
index = i - 1 -- Convert to 0-based indexing
|
index = i - 1 -- Convert to 0-based indexing
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -75,13 +73,13 @@ local function find_quoted_string_at_cursor(line, cursor_col)
|
||||||
local start_quote = quote_positions[i]
|
local start_quote = quote_positions[i]
|
||||||
for j = i + 1, #quote_positions do
|
for j = i + 1, #quote_positions do
|
||||||
local end_quote = quote_positions[j]
|
local end_quote = quote_positions[j]
|
||||||
|
|
||||||
-- Match opening and closing quotes of same type
|
-- Match opening and closing quotes of same type
|
||||||
if start_quote.char == end_quote.char then
|
if start_quote.char == end_quote.char then
|
||||||
if cursor_col >= start_quote.index and cursor_col <= end_quote.index then
|
if (cursor_col >= start_quote.index and cursor_col <= end_quote.index) or (cursor_col <= start_quote.index and cursor_col <= end_quote.index) then
|
||||||
return start_quote.index, end_quote.index, start_quote.char
|
return start_quote.index, end_quote.index, start_quote.char
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Skip to next pair to avoid nested matches
|
-- Skip to next pair to avoid nested matches
|
||||||
i = j
|
i = j
|
||||||
goto continue_outer_loop
|
goto continue_outer_loop
|
||||||
|
@ -101,9 +99,9 @@ local function get_next_quote_char(current_char)
|
||||||
if type(current_char) ~= "string" then
|
if type(current_char) ~= "string" then
|
||||||
return M.options.quote_chars[1]
|
return M.options.quote_chars[1]
|
||||||
end
|
end
|
||||||
|
|
||||||
local quote_count = #M.options.quote_chars
|
local quote_count = #M.options.quote_chars
|
||||||
|
|
||||||
for i = 1, quote_count do
|
for i = 1, quote_count do
|
||||||
if M.options.quote_chars[i] == current_char then
|
if M.options.quote_chars[i] == current_char then
|
||||||
-- Cycle to next character (wrapping around to first if at end)
|
-- Cycle to next character (wrapping around to first if at end)
|
||||||
|
@ -111,7 +109,7 @@ local function get_next_quote_char(current_char)
|
||||||
return M.options.quote_chars[next_index]
|
return M.options.quote_chars[next_index]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Fallback to first quote character if current not found
|
-- Fallback to first quote character if current not found
|
||||||
return M.options.quote_chars[1]
|
return M.options.quote_chars[1]
|
||||||
end
|
end
|
||||||
|
@ -125,13 +123,13 @@ function M.toggle_quotes()
|
||||||
vim.notify("JQuote: Failed to get current line", vim.log.levels.ERROR)
|
vim.notify("JQuote: Failed to get current line", vim.log.levels.ERROR)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
local success_cursor, cursor_pos = pcall(vim.api.nvim_win_get_cursor, 0)
|
local success_cursor, cursor_pos = pcall(vim.api.nvim_win_get_cursor, 0)
|
||||||
if not success_cursor or type(cursor_pos) ~= "table" or #cursor_pos < 2 then
|
if not success_cursor or type(cursor_pos) ~= "table" or #cursor_pos < 2 then
|
||||||
vim.notify("JQuote: Failed to get cursor position", vim.log.levels.ERROR)
|
vim.notify("JQuote: Failed to get cursor position", vim.log.levels.ERROR)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
local cursor_row, cursor_col = cursor_pos[1], cursor_pos[2]
|
local cursor_row, cursor_col = cursor_pos[1], cursor_pos[2]
|
||||||
local start_idx, end_idx, current_char = find_quoted_string_at_cursor(current_line, cursor_col)
|
local start_idx, end_idx, current_char = find_quoted_string_at_cursor(current_line, cursor_col)
|
||||||
|
|
||||||
|
@ -160,7 +158,7 @@ function M.toggle_quotes()
|
||||||
vim.notify("JQuote: Failed to update line", vim.log.levels.ERROR)
|
vim.notify("JQuote: Failed to update line", vim.log.levels.ERROR)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Restore cursor position
|
-- Restore cursor position
|
||||||
pcall(vim.api.nvim_win_set_cursor, 0, { cursor_row, cursor_col })
|
pcall(vim.api.nvim_win_set_cursor, 0, { cursor_row, cursor_col })
|
||||||
return true
|
return true
|
||||||
|
@ -175,27 +173,27 @@ local function validate_options(options)
|
||||||
if type(options) ~= "table" then
|
if type(options) ~= "table" then
|
||||||
return false, "Options must be a table"
|
return false, "Options must be a table"
|
||||||
end
|
end
|
||||||
|
|
||||||
if options.hotkey and type(options.hotkey) ~= "string" then
|
if options.hotkey and type(options.hotkey) ~= "string" then
|
||||||
return false, "hotkey must be a string"
|
return false, "hotkey must be a string"
|
||||||
end
|
end
|
||||||
|
|
||||||
if options.quote_chars then
|
if options.quote_chars then
|
||||||
if type(options.quote_chars) ~= "table" then
|
if type(options.quote_chars) ~= "table" then
|
||||||
return false, "quote_chars must be a table"
|
return false, "quote_chars must be a table"
|
||||||
end
|
end
|
||||||
|
|
||||||
if #options.quote_chars == 0 then
|
if #options.quote_chars == 0 then
|
||||||
return false, "quote_chars cannot be empty"
|
return false, "quote_chars cannot be empty"
|
||||||
end
|
end
|
||||||
|
|
||||||
for i, char in ipairs(options.quote_chars) do
|
for i, char in ipairs(options.quote_chars) do
|
||||||
if type(char) ~= "string" or #char ~= 1 then
|
if type(char) ~= "string" or #char ~= 1 then
|
||||||
return false, string.format("quote_chars[%d] must be a single character string", i)
|
return false, string.format("quote_chars[%d] must be a single character string", i)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return true, nil
|
return true, nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -204,23 +202,23 @@ end
|
||||||
--- @return boolean success Whether setup completed successfully
|
--- @return boolean success Whether setup completed successfully
|
||||||
function M.setup(user_options)
|
function M.setup(user_options)
|
||||||
user_options = user_options or {}
|
user_options = user_options or {}
|
||||||
|
|
||||||
-- Validate user options
|
-- Validate user options
|
||||||
local is_valid, error_msg = validate_options(user_options)
|
local is_valid, error_msg = validate_options(user_options)
|
||||||
if not is_valid then
|
if not is_valid then
|
||||||
vim.notify(string.format("JQuote setup error: %s", error_msg), vim.log.levels.ERROR)
|
vim.notify(string.format("JQuote setup error: %s", error_msg), vim.log.levels.ERROR)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Merge with defaults using safe deep extend
|
-- Merge with defaults using safe deep extend
|
||||||
local success, merged_options = pcall(vim.tbl_deep_extend, "force", vim.deepcopy(DEFAULT_OPTIONS), user_options)
|
local success, merged_options = pcall(vim.tbl_deep_extend, "force", vim.deepcopy(DEFAULT_OPTIONS), user_options)
|
||||||
if not success then
|
if not success then
|
||||||
vim.notify("JQuote: Failed to merge configuration options", vim.log.levels.ERROR)
|
vim.notify("JQuote: Failed to merge configuration options", vim.log.levels.ERROR)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
M.options = merged_options
|
M.options = merged_options
|
||||||
|
|
||||||
-- Defensive check for quote_chars integrity
|
-- Defensive check for quote_chars integrity
|
||||||
if not M.options.quote_chars or #M.options.quote_chars == 0 then
|
if not M.options.quote_chars or #M.options.quote_chars == 0 then
|
||||||
vim.notify("JQuote: quote_chars corrupted, restoring defaults", vim.log.levels.WARN)
|
vim.notify("JQuote: quote_chars corrupted, restoring defaults", vim.log.levels.WARN)
|
||||||
|
@ -239,7 +237,7 @@ function M.setup(user_options)
|
||||||
vim.notify(string.format("JQuote: Failed to set keymap for '%s'", M.options.hotkey), vim.log.levels.ERROR)
|
vim.notify(string.format("JQuote: Failed to set keymap for '%s'", M.options.hotkey), vim.log.levels.ERROR)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
vim.notify(string.format("JQuote: Initialized with hotkey '%s'", M.options.hotkey), vim.log.levels.INFO)
|
vim.notify(string.format("JQuote: Initialized with hotkey '%s'", M.options.hotkey), vim.log.levels.INFO)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
@ -248,13 +246,12 @@ end
|
||||||
--- @return table health_info Plugin health information
|
--- @return table health_info Plugin health information
|
||||||
function M.health()
|
function M.health()
|
||||||
local health_info = {
|
local health_info = {
|
||||||
version = M._version,
|
|
||||||
options = M.options,
|
options = M.options,
|
||||||
quote_chars_count = M.options.quote_chars and #M.options.quote_chars or 0,
|
quote_chars_count = M.options.quote_chars and #M.options.quote_chars or 0,
|
||||||
hotkey_configured = M.options.hotkey ~= nil,
|
hotkey_configured = M.options.hotkey ~= nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
return health_info
|
return health_info
|
||||||
end
|
end
|
||||||
|
|
||||||
return M
|
return M
|
||||||
|
|
12
release.config.cjs
Normal file
12
release.config.cjs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
module.exports = {
|
||||||
|
|
||||||
|
branches: ['main'],
|
||||||
|
plugins: [
|
||||||
|
'@semantic-release/commit-analyzer',
|
||||||
|
'@semantic-release/release-notes-generator',
|
||||||
|
'@semantic-release/changelog',
|
||||||
|
["@saithodev/semantic-release-gitea", {
|
||||||
|
"giteaUrl": "https://git.kjan.de"
|
||||||
|
}],
|
||||||
|
],
|
||||||
|
};
|
Loading…
Add table
Add a link
Reference in a new issue