| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- local M = {}
- -- Helper function to detect clipboard command
- local function detect_clipboard_cmd()
- -- Check for Wayland
- if vim.fn.executable("wl-copy") == 1 then
- return "wl-copy --type image/png"
- end
- -- Check for X11
- if vim.fn.executable("xclip") == 1 then
- return "xclip -selection clipboard -t image/png"
- end
- -- Check for macOS
- if vim.fn.executable("pbcopy") == 1 then
- return "pbcopy"
- end
- -- Default fallback (Wayland)
- return "wl-copy --type image/png"
- end
- -- Configuration
- local config = {
- freeze_cmd = "freeze",
- clipboard_cmd = detect_clipboard_cmd(),
- }
- -- Helper function to detect visual selection
- local function get_visual_selection()
- local mode = vim.fn.mode()
-
- -- If we're in visual mode, capture directly from visual marks
- if mode:match("[vV]") then
- local v_pos = vim.fn.getpos("v") -- Start of visual selection
- local dot_pos = vim.fn.getpos(".") -- Current cursor position (end of selection)
-
- if v_pos[2] > 0 and dot_pos[2] > 0 then
- return math.min(v_pos[2], dot_pos[2]), math.max(v_pos[2], dot_pos[2])
- end
- end
-
- return nil, nil
- end
- -- Helper function to get language from filetype
- local function get_language_from_filetype()
- local filetype = vim.bo.filetype
- if filetype == "" then
- return nil
- end
- return filetype
- end
- -- Helper function to validate yes/no input
- local function parse_yes_no(input, default)
- if not input or input == "" then
- return default
- end
- local lower = string.lower(input)
- if lower == "y" or lower == "yes" then
- return true
- elseif lower == "n" or lower == "no" then
- return false
- end
- return default
- end
- -- Helper function to build freeze command
- local function build_freeze_command(filepath, output, opts)
- local cmd = config.freeze_cmd .. " " .. vim.fn.shellescape(filepath)
- if opts.language then
- cmd = cmd .. " --language " .. vim.fn.shellescape(opts.language)
- end
- if opts.show_line_numbers then
- cmd = cmd .. " --show-line-numbers"
- end
- if opts.window then
- cmd = cmd .. " --window"
- end
- if opts.start_line and opts.end_line then
- cmd = cmd .. " --lines " .. opts.start_line .. "," .. opts.end_line
- end
- cmd = cmd .. " -o " .. vim.fn.shellescape(output)
- return cmd
- end
- -- Helper function to execute freeze and copy to clipboard
- local function execute_freeze(cmd, output)
- vim.fn.system(cmd)
- local clipboard_cmd = config.clipboard_cmd .. " < " .. vim.fn.shellescape(output)
- vim.fn.system(clipboard_cmd)
- vim.fn.delete(output)
- end
- local function freeze_screenshot(start_line, end_line)
- local filepath = vim.fn.expand("%:p")
- if filepath == "" then
- vim.notify("No file to screenshot", vim.log.levels.ERROR)
- return
- end
- -- Auto-detect visual selection if not provided
- if not start_line or not end_line then
- start_line, end_line = get_visual_selection()
- end
- local output = vim.fn.tempname() .. ".png"
- local cmd = config.freeze_cmd .. " " .. vim.fn.shellescape(filepath) .. " --show-line-numbers -o " .. vim.fn.shellescape(output)
- if start_line and end_line then
- cmd = cmd .. " --lines " .. start_line .. "," .. end_line
- end
- execute_freeze(cmd, output)
- local msg = start_line and string.format("Screenshot of lines %d–%d copied", start_line, end_line)
- or "Screenshot of entire file copied"
- vim.notify(msg, vim.log.levels.INFO)
- end
- local function freeze_interactive(start_line, end_line)
- local filepath = vim.fn.expand("%:p")
- if filepath == "" then
- vim.notify("No file to screenshot", vim.log.levels.ERROR)
- return
- end
- -- Check if snacks.nvim is available
- local ok, snacks = pcall(require, "snacks")
- if not ok or not snacks or not snacks.input then
- vim.notify("snacks.nvim is required for interactive mode", vim.log.levels.ERROR)
- return
- end
- -- Auto-detect visual selection if not provided
- if not start_line or not end_line then
- start_line, end_line = get_visual_selection()
- end
- local opts = {
- show_line_numbers = true, -- default: yes
- window = false, -- default: no
- language = get_language_from_filetype(),
- start_line = start_line,
- end_line = end_line,
- }
- -- First prompt: show line numbers
- snacks.input.input({
- prompt = "Mostrar números de línea? (y/n)",
- default = "y",
- }, function(value)
- if value then
- opts.show_line_numbers = parse_yes_no(value, true)
- end
- -- Second prompt: show window controls
- snacks.input.input({
- prompt = "Mostrar controles de ventana? (y/n)",
- default = "n",
- }, function(value2)
- if value2 then
- opts.window = parse_yes_no(value2, false)
- end
- -- Execute freeze with selected options
- local output = vim.fn.tempname() .. ".png"
- local cmd = build_freeze_command(filepath, output, opts)
- execute_freeze(cmd, output)
- local msg = start_line and string.format("Screenshot of lines %d–%d copied", start_line, end_line)
- or "Screenshot copied to clipboard"
- vim.notify(msg, vim.log.levels.INFO)
- end)
- end)
- end
- function M.setup(opts)
- opts = opts or {}
-
- -- Configure freeze command path
- if opts.freeze_cmd then
- config.freeze_cmd = opts.freeze_cmd
- end
-
- -- Configure clipboard command
- if opts.clipboard_cmd then
- config.clipboard_cmd = opts.clipboard_cmd
- end
- end
- -- Wrapper functions that properly handle visual mode
- -- These should be used in keymaps to ensure selection is captured correctly
- local function freeze_screenshot_wrapper()
- -- Try to get visual selection - this will work if called from visual mode keymap
- local start_line, end_line = get_visual_selection()
- freeze_screenshot(start_line, end_line)
- end
- local function freeze_interactive_wrapper()
- -- Try to get visual selection - this will work if called from visual mode keymap
- local start_line, end_line = get_visual_selection()
- freeze_interactive(start_line, end_line)
- end
- M.freeze_screenshot = freeze_screenshot
- M.freeze_interactive = freeze_interactive
- M.freeze_screenshot_wrapper = freeze_screenshot_wrapper
- M.freeze_interactive_wrapper = freeze_interactive_wrapper
- return M
|