Skip to content

Commit

Permalink
fix selection
Browse files Browse the repository at this point in the history
  • Loading branch information
SirAppSec committed Sep 6, 2024
1 parent 592d222 commit b6f6821
Show file tree
Hide file tree
Showing 3 changed files with 170 additions and 98 deletions.
164 changes: 74 additions & 90 deletions lua/hacker-helper.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
-- utils
local selection_util = require("hacker-helper.selection_util")

-- main module file
local module = require("hacker-helper.module")

-- Notify the user if LuaSocket is not installed
local function check_luasocket_installed()
local ok, mime = pcall(require, "mime")
Expand All @@ -8,7 +12,10 @@ local function check_luasocket_installed()
"Hacker Helper Error: LuaSocket (luasocket) is not installed. Please install it using LuaRocks: luarocks install luasocket",
vim.log.levels.ERROR
)
vim.notify("Hacker Helper Error: sudo apt install luarocks", vim.log.levels.ERROR)
vim.notify(
"Hacker Helper Error: sudo apt install luarocks && sudo luarocks install luasocket",
vim.log.levels.ERROR
)
return nil
end
return mime
Expand All @@ -31,6 +38,10 @@ local config = {
opt = "Hello!",
}

local mime = check_luasocket_installed()
if not mime then
return
end -- Ensure LuaSocket is installed
---@class MyModule
local M = {}
---@type Config
Expand All @@ -41,10 +52,6 @@ M.config = config
---@param user_config Config? User-provided configuration
M.setup = function(user_config)
-- Check if luasocket is installed
local mime = check_luasocket_installed()
if not mime then
return
end -- Ensure LuaSocket is installed
-- Merge user configuration with defaults
M.config = vim.tbl_deep_extend("force", M.config, user_config or {})

Expand Down Expand Up @@ -72,97 +79,74 @@ M.setup = function(user_config)
{ noremap = true, silent = true, desc = "Decoder" }
)

-- Key mappings for encoding and decoding
vim.keymap.set("v", M.config.prefix .. M.config.keys.encode_prefix .. M.config.keys.encode_url, function()
M.transform_selection("url", "encode")
end, { noremap = true, silent = true, desc = "URL Encode" })
vim.keymap.set("v", M.config.prefix .. M.config.keys.encode_prefix .. M.config.keys.encode_base64, function()
M.transform_selection("base64", "encode")
end, { noremap = true, silent = true, desc = "Base64 Encode" })

vim.keymap.set("v", M.config.prefix .. M.config.keys.decode_prefix .. M.config.keys.decode_url, function()
M.transform_selection("url", "decode")
end, { noremap = true, silent = true, desc = "URL Decode" })
vim.keymap.set("v", M.config.prefix .. M.config.keys.decode_prefix .. M.config.keys.decode_base64, function()
M.transform_selection("base64", "decode")
end, { noremap = true, silent = true, desc = "Base64 Decode" })
end
-- Key mappings for Base64 and URL encoding/decoding using config prefixes

-- Base64 Encode
vim.keymap.set('v', M.config.prefix .. M.config.keys.encode_prefix .. M.config.keys.encode_base64, function()
selection_util.transform_selection(function(text, selection_type)
return M.transform_func(text, selection_type, "encode", "base64")
end)
end, { noremap = true, silent = true, desc = "Base64 Encode" })

-- Base64 Decode
vim.keymap.set('v', M.config.prefix .. M.config.keys.decode_prefix .. M.config.keys.decode_base64, function()
selection_util.transform_selection(function(text, selection_type)
return M.transform_func(text, selection_type, "decode", "base64")
end)
end, { noremap = true, silent = true, desc = "Base64 Decode" })

-- URL Encode
vim.keymap.set('v', M.config.prefix .. M.config.keys.encode_prefix .. M.config.keys.encode_url, function()
selection_util.transform_selection(function(text, selection_type)
return M.transform_func(text, selection_type, "encode", "url")
end)
end, { noremap = true, silent = true, desc = "URL Encode" })

-- URL Decode
vim.keymap.set('v', M.config.prefix .. M.config.keys.decode_prefix .. M.config.keys.decode_url, function()
selection_util.transform_selection(function(text, selection_type)
return M.transform_func(text, selection_type, "decode", "url")
end)
end, { noremap = true, silent = true, desc = "URL Decode" })
-- Function to handle encoding/decoding based on selection
M.transform_selection = function(type, mode)
local mime = check_luasocket_installed()
if not mime then
return
end -- Ensure LuaSocket is installed

-- Capture the selection
local start_pos = vim.fn.getpos("'<")
local end_pos = vim.fn.getpos("'>")

local start_line = start_pos[2]
local start_col = start_pos[3] - 1 -- 0-based index

local end_line = end_pos[2]
local end_col = end_pos[3] -- inclusive

-- Get selected lines
local lines = vim.fn.getline(start_line, end_line)

-- Handle full-line selection (V mode) and partial selection
if vim.fn.mode() == "V" then
-- Full line selection, transform entire lines
for i, line in ipairs(lines) do
lines[i] = M.transform_text(line, type, mode, mime)
end
-- Replace the entire range with transformed lines
vim.fn.setline(start_line, lines)
else
-- Partial selection within a single line
if start_line == end_line then
-- Handle partial selection on a single line
local line = lines[1]
local selection = string.sub(line, start_col + 1, end_col)
local transformed = M.transform_text(selection, type, mode, mime)
local new_line = string.sub(line, 1, start_col) .. transformed .. string.sub(line, end_col + 1)
vim.fn.setline(start_line, new_line)
else
-- Handle multi-line selection, applying the transformation to partial lines
lines[1] = string.sub(lines[1], 1, start_col)
.. M.transform_text(string.sub(lines[1], start_col + 1), type, mode, mime)
lines[#lines] = M.transform_text(string.sub(lines[#lines], 1, end_col), type, mode, mime)
.. string.sub(lines[#lines], end_col + 1)
for i = 2, #lines - 1 do
lines[i] = M.transform_text(lines[i], type, mode, mime)
end
-- Replace the entire range with transformed lines
vim.fn.setline(start_line, lines)
end
end
-- Base64 encoding and decoding utility functions
M.base64_encode = function(text)
return mime.b64(text)
end

M.base64_decode = function(text)
return mime.unb64(text)
end

-- URL encoding and decoding utility functions
M.url_encode = function(text)
return text:gsub("([^%w%.%-_])", function(c)
return string.format("%%%02X", string.byte(c))
end)
end

M.url_decode = function(text)
return text:gsub("%%(%x%x)", function(hex)
return string.char(tonumber(hex, 16))
end)
end

M.transform_text = function(text, mode, type, mime)
mime = mime or require("mime") -- Ensure LuaSocket's mime module is loaded

if type == "url" then
if mode == "encode" then
return text:gsub("([^%w%.%-_])", function(c)
return string.format("%%%02X", string.byte(c))
end)
elseif mode == "decode" then
return text:gsub("%%(%x%x)", function(hex)
return string.char(tonumber(hex, 16))
end)
-- Transform function for encoding or decoding text based on type and selection type
M.transform_func = function(text, selection_type, encode_or_decode, encoding_type)
if encoding_type == "base64" then
if encode_or_decode == "encode" then
return M.base64_encode(text)
elseif encode_or_decode == "decode" then
return M.base64_decode(text)
end
elseif type == "base64" then
if mode == "encode" then
local encoded = mime.b64(text) -- Use only the first return value
return encoded
elseif mode == "decode" then
local decoded = mime.unb64(text) -- Use only the first return value
return decoded
elseif encoding_type == "url" then
if encode_or_decode == "encode" then
return M.url_encode(text)
elseif encode_or_decode == "decode" then
return M.url_decode(text)
end
end

return text -- return the original text if no valid type or mode is provided
return text
end

M.hello = function()
Expand Down
61 changes: 61 additions & 0 deletions lua/hacker-helper/selection_util.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
-- lua/hacker-helper/selection_util.lua

local M = {}

-- Utility function to capture the visual selection, apply a transformation, and replace the selection
M.transform_selection = function(transform_func)
-- Reselect the current visual block to ensure the latest selection is active
vim.cmd("normal! gv")

-- Get the visual selection range using visual marks
local start_pos = vim.fn.getpos("'<") -- Start of the visual selection
local end_pos = vim.fn.getpos("'>") -- End of the visual selection

-- Determine start and end lines and columns
local start_line = math.min(start_pos[2], end_pos[2])
local end_line = math.max(start_pos[2], end_pos[2])
local start_col = start_pos[3] - 1 -- 0-based index for inline selection
local end_col = end_pos[3] -- inclusive for inline selection

-- Get the selected lines
local lines = vim.fn.getline(start_line, end_line)

-- Handle visual line selection (V) and inline selection (v)
if vim.fn.visualmode() == "V" then
-- Full line selection
for i, line in ipairs(lines) do
lines[i] = transform_func(line, "full_line")
end
-- Replace the selected lines with the transformed text
vim.fn.setline(start_line, lines)
else
-- Inline selection (v mode)
if start_line == end_line then
-- Handle inline selection on a single line
local line = lines[1]
-- Capture the selected part of the line
local selection = string.sub(line, start_col + 1, end_col)
-- Transform the selection and pass that it's a specific selection
local transformed = transform_func(selection, "specific_selection")
-- Replace the selected part with the transformed text
local new_line = string.sub(line, 1, start_col) .. transformed .. string.sub(line, end_col + 1)
vim.fn.setline(start_line, new_line)
else
-- Handle multi-line partial selection
local first_line = string.sub(lines[1], start_col + 1)
local last_line = string.sub(lines[#lines], 1, end_col)
lines[1] = string.sub(lines[1], 1, start_col) .. transform_func(first_line, "multi_line")
lines[#lines] = transform_func(last_line, "multi_line") .. string.sub(lines[#lines], end_col + 1)
for i = 2, #lines - 1 do
lines[i] = transform_func(lines[i], "multi_line")
end
-- Replace the selected lines with the transformed text
vim.fn.setline(start_line, lines)
end
end

-- Reselect the visual selection after transformation (optional)
vim.cmd("normal! gv")
end

return M
43 changes: 35 additions & 8 deletions tests/hacker-helper/hacker_helper_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,53 @@ describe("Base64 and URL encoding/decoding", function()
-- Test Base64 encoding and decoding
it("encodes Base64 correctly", function()
local text = "Hello, World!"
local encoded = plugin.transform_text(text, "encode", "base64")
assert(encoded == "SGVsbG8sIFdvcmxkIQ==", "Base64 encoding failed")
local encoded = plugin.transform_func(text, "specific_selection", "encode", "base64")
assert.are.equal("SGVsbG8sIFdvcmxkIQ==", encoded)
end)

it("decodes Base64 correctly", function()
local encoded_text = "SGVsbG8sIFdvcmxkIQ=="
local decoded = plugin.transform_text(encoded_text, "decode", "base64")
assert(decoded == "Hello, World!", "Base64 decoding failed")
local decoded = plugin.transform_func(encoded_text, "specific_selection", "decode", "base64")
assert.are.equal("Hello, World!", decoded)
end)

-- Test URL encoding and decoding
it("encodes URL correctly", function()
local text = "Hello, World!"
local encoded = plugin.transform_text(text, "encode", "url")
assert(encoded == "Hello%2C%20World%21", "URL encoding failed")
local encoded = plugin.transform_func(text, "specific_selection", "encode", "url")
assert.are.equal("Hello%2C%20World%21", encoded)
end)

it("decodes URL correctly", function()
local encoded_text = "Hello%2C%20World%21"
local decoded = plugin.transform_text(encoded_text, "decode", "url")
assert(decoded == "Hello, World!", "URL decoding failed")
local decoded = plugin.transform_func(encoded_text, "specific_selection", "decode", "url")
assert.are.equal("Hello, World!", decoded)
end)

-- Test full-line and multi-line selections for Base64
it("encodes a full line with Base64 correctly", function()
local text = "This is a full line."
local encoded = plugin.transform_func(text, "full_line", "encode", "base64")
assert.are.equal("VGhpcyBpcyBhIGZ1bGwgbGluZS4=", encoded)
end)

it("decodes multi-line Base64 correctly", function()
local text = "VGhpcyBpcyBhIGZ1bGwgbGluZS4="
local decoded = plugin.transform_func(text, "multi_line", "decode", "base64")
assert.are.equal("This is a full line.", decoded)
end)

-- Test handling of unknown encoding type
it("returns the same text if encoding type is unknown", function()
local text = "Hello, World!"
local result = plugin.transform_func(text, "specific_selection", "encode", "unknown")
assert.are.equal(text, result)
end)

-- Test handling of unknown action (not encode/decode)
it("returns the same text if the action is not encode or decode", function()
local text = "Hello, World!"
local result = plugin.transform_func(text, "specific_selection", "unknown_action", "base64")
assert.are.equal(text, result)
end)
end)

0 comments on commit b6f6821

Please sign in to comment.