diff --git a/lua/convert/convert_all.lua b/lua/convert/convert_all.lua index a12eb63..59cc793 100644 --- a/lua/convert/convert_all.lua +++ b/lua/convert/convert_all.lua @@ -22,31 +22,21 @@ local convert_all = function(bufnr, from, to) end local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false) - - local num_lines = #lines - local start_row = 1 - - local selection = utils.get_selection() - - if selection ~= nil then - start_row = selection.start_row - num_lines = #selection.lines - end - - for row = start_row, num_lines + start_row - 1, 1 do - local line = lines[row] - local found_unit = utils.find_unit_in_line(line, row) - - if found_unit ~= nil and found_unit.unit == from then - local converted = calculator.convert(from, to, found_unit.val) - - vim.api.nvim_buf_set_text( - bufnr, - found_unit.pos.row - 1, - found_unit.pos.start_col - 1, - found_unit.pos.row - 1, - found_unit.pos.end_col, - { converted }) + local all_units = utils.find_all_units_in_line(line, row) + if all_units ~= nil and #all_units > 0 and all_units[1].unit == from then + for i = #all_units, 1, -1 do + local found = all_units[i] + local converted = calculator.convert(from, to, found.val) + + vim.api.nvim_buf_set_text( + bufnr, + found.pos.row - 1, + found.pos.start_col - 1, + found.pos.row - 1, + found.pos.end_col, + { converted } + ) + end end end end diff --git a/lua/convert/init.lua b/lua/convert/init.lua index 0c2a022..4cd9d0d 100644 --- a/lua/convert/init.lua +++ b/lua/convert/init.lua @@ -25,12 +25,12 @@ M.find_next = function() for row = next_row, #lines, 1 do local line = lines[row] - local found_unit = utils.find_unit_in_line(line, row) + local found_units = utils.find_all_units_in_line(line, row) - if found_unit ~= nil then - vim.api.nvim_win_set_cursor(current_win, { row, found_unit.pos.start_col - 1 }) - ui.open_win(found_unit) + if found_units ~= nil then + vim.api.nvim_win_set_cursor(current_win, { row, found_units[1].pos.start_col - 1 }) + ui.open_win(found_units) return end end @@ -46,11 +46,11 @@ M.find_current = function() line = string.rep(" ", #current_line - #line) .. line - local found_unit = utils.find_unit_in_line(line, cursor_pos.row) + local found_units = utils.find_all_units_in_line(line, cursor_pos.row) - if found_unit ~= nil then - vim.api.nvim_win_set_cursor(current_win, { cursor_pos.row, found_unit.pos.start_col - 1 }) - ui.open_win(found_unit) + if found_units ~= nil and #found_units > 0 then + vim.api.nvim_win_set_cursor(current_win, { cursor_pos.row, found_units[1].pos.start_col - 1 }) + ui.open_win(found_units) end end diff --git a/lua/convert/ui/open_popup.lua b/lua/convert/ui/open_popup.lua index cc23da9..17cd4ee 100644 --- a/lua/convert/ui/open_popup.lua +++ b/lua/convert/ui/open_popup.lua @@ -4,20 +4,20 @@ local utils = require("convert.utils") local config = require("convert.config") local size_units = { - 'px', - 'rem', - 'cm', - 'in', - 'mm', - 'pt', - 'pc' + 'px', + 'rem', + 'cm', + 'in', + 'mm', + 'pt', + 'pc' } local color_units = { - 'rgb', - 'hex', - 'hsl' + 'rgb', + 'hex', + 'hsl' } local number_units = { @@ -27,19 +27,19 @@ local number_units = { } local color_menu = { - Menu.item('rgb'), - Menu.item('hex'), - Menu.item('hsl'), + Menu.item('rgb'), + Menu.item('hex'), + Menu.item('hsl'), } local size_menu = { - Menu.item('px'), - Menu.item('rem'), - Menu.item('cm'), - Menu.item('in'), - Menu.item('mm'), - Menu.item('pt'), - Menu.item('pc'), + Menu.item('px'), + Menu.item('rem'), + Menu.item('cm'), + Menu.item('in'), + Menu.item('mm'), + Menu.item('pt'), + Menu.item('pc'), } local number_menu = { @@ -48,66 +48,81 @@ local number_menu = { Menu.item('octal'), } -local M = {} +--- Opens popup window for convert in a single line +---@param found_units matched[] +M.open_win = function(found_units) + if not found_units or #found_units == 0 then return end ----@param found_unit matched -M.open_win = function(found_unit) - local lines = nil + local from_unit = found_units[1].unit + local from_val = found_units[1].val - if utils.contains(color_units, found_unit.unit) then - lines = color_menu - end + local lines = nil - if utils.contains(size_units, found_unit.unit) then - lines = size_menu - end - - if utils.contains(number_units, found_unit.unit) then - lines = number_menu + if utils.contains(color_units, from_unit) then + lines = color_menu + elseif utils.contains(size_units, from_unit) then + lines = size_menu + else + return end - local popup_opts = { - relative = "cursor", - position = { - row = 2, - col = 1, - }, - size = { - width = 40, - height = #lines, - }, - border = { - style = "rounded", - text = { - top = "[Convert " .. found_unit.val .. " " .. found_unit.unit .. " To]", - top_align = "center" - }, - }, - buf_options = { - modifiable = false, - readonly = true, - }, - win_options = { - winhighlight = "Normal:Normal" - } - } - local menu = Menu(popup_opts, { - lines = lines, - - max_width = 100, - keymap = config.keymaps, - on_submit = function(item) - local from_unit = found_unit.unit - local to_unit = item.text - local from_val = found_unit.val - local converted = calculator.convert(from_unit, to_unit, from_val) - vim.api.nvim_buf_set_text(0, found_unit.pos.row - 1, found_unit.pos.start_col - 1, found_unit.pos.row - 1, found_unit.pos.end_col, - { converted }) - vim.api.nvim_win_set_cursor(0, { found_unit.pos.row, found_unit.pos.end_col + #to_unit }) - end - }) - - menu:mount() + local popup_opts = { + relative = "cursor", + position = { + row = 2, + col = 1, + }, + size = { + width = 40, + height = #lines, + }, + border = { + style = "rounded", + text = { + top = "[Convert " .. from_val .. " To]", + top_align = "center" + }, + }, + buf_options = { + modifiable = false, + readonly = true, + }, + win_options = { + winhighlight = "Normal:Normal" + } + } + local menu = Menu(popup_opts, { + lines = lines, + + max_width = 100, + keymap = config.keymaps, + on_submit = function(item) + local to_unit = item.text + local bufnr = 0 + + for i = #found_units, 1, -1 do + local match = found_units[i] + if match.unit == from_unit then + local converted = calculator.convert(from_unit, to_unit, match.val) + vim.api.nvim_buf_set_text( + bufnr, + match.pos.row - 1, + match.pos.start_col - 1, + match.pos.row - 1, + match.pos.end_col, + { converted } + ) + end + end + + -- Move cursor to end of last converted unit + local last = found_units[#found_units] + vim.api.nvim_win_set_cursor(0, { last.pos.row, last.pos.end_col + #to_unit }) + end + }) + + menu:mount() + end return M diff --git a/lua/convert/utils.lua b/lua/convert/utils.lua index 6ba4d4c..2bf0a2a 100644 --- a/lua/convert/utils.lua +++ b/lua/convert/utils.lua @@ -57,7 +57,62 @@ M.match_unit = function(line) return nil end ----@return matched | nil + +---@param line string +---@param cursor_row number +---@return matched[] | nil +M.find_all_units_in_line = function(line, cursor_row) + local results = {} + local matched_unit = nil + + for unit, pattern in pairs(units) do + local start_pos = 1 + while start_pos <= #line do + local s, e, val = string.find(line, pattern, start_pos) + if s == nil then break end + + if unit == 'rgb' or unit == 'hsl' then + val = line:match(pattern, start_pos) + end + + local num_val = tonumber(val) + if num_val then + -- If this is the first unit match, set it as the inferred from_unit + if not matched_unit then + matched_unit = unit + end + + -- Only collect matches for the same inferred unit + if unit == matched_unit then + table.insert(results, { + unit = unit, + val = num_val, + pos = { + row = cursor_row, + start_col = s, + end_col = e, + } + }) + end + end + + start_pos = e + 1 + end + + if matched_unit then + break -- only process one unit type (inferred one) + end + end + + if #results > 0 then + return results + end + + return nil +end + + +---@return matched[] | nil M.find_unit_in_line = function(line, cursor_row) local unit = M.match_unit(line) if unit then