local popup = require'plenary.popup' local utils = require'presser.utils' local gcm = require('presser.context_manager') local api = vim.api local presser = {} -- list of functions to be exported -- :@Dev: close all Presser windows that may be open for all contexts presser.close = function () gcm.flush() -- invoke the context manager to flush the table end -- @Description: Construct a new instance of a window and buffer using the 'plenary.popup' module. -- @Params: -- + `_type` ~ string denoting which context manager is owner of the window. -- + `placeholder` ~ string allowing for placeholder text to be placed within the buffer when constructed. -- + `opts` ~ a table of additional options to be provided when constructing the window. -- @Returns: nil. Constructs a new window and stores the window's ID in a global table. -- -- @Dev: This function is to be as generic for creating a window whilst allowing for as much customisation over the -- window/buffer which are to be constructed. Users are to access this function so is not part of the module export. -- However, it's used by all internal built-ins which are meant to be used by users. Consider a class constructor in -- C++, this function is akin to that behaviour and is responsible for constructing the window/buffer and ensuring it -- can be tracked by Vim itself. local new = function ( _ctx, label, opts ) local opts = opts or {} if not opts.placeholder then opts["placeholder"] = "" end local buf_opts = { minwidth = 80, -- getwin_w() / 2 - ((getwin_w() % 2) / 2), borderchars = { "─", "│", "─", "│", "╭", "╮", "╯", "╰" }, } if opts.window then for k,v in pairs( opts.window ) do buf_opts[k] = v end end local obj = popup.create( opts.placeholder, buf_opts ) gcm.update( _ctx, { id = obj, what = label, allowed = opts.allowed } ) -- :TODO: call update function in context manager -- table.insert( manager[_type], obj ) -- g.presser_buf_ctx = manager -- :@Dev: handle for keybindings (TODO: any future stuff below here once window is made) local buf_id = function () return api.nvim_win_get_buf(obj) end -- handle for key bindings if opts.keybinds then for mode, mode_map in pairs( opts.keybinds ) do mode = string.lower(mode) for key_bind, key_action in pairs(mode_map) do local key_bind = api.nvim_replace_termcodes(key_bind, true, false, true), api.nvim_buf_set_keymap(buf_id(), mode, key_bind, key_action, { noremap = true, silent = true } ) end end end end presser.move_next_buffer = function () local ctxs = 0 local c = vim.g.presser_buf_ctx local buf = api.nvim_get_current_buf() for _, v in pairs( c ) do for idx, _ in pairs( v ) do ctxs = idx end end for ctx, ctx_obj in pairs( c ) do for idx, obj in pairs( ctx_obj ) do if api.nvim_win_get_buf( obj.id ) == buf then -- get the next window, and put cursor there local s = idx repeat local win = ctx_obj[(idx % ctxs) + 1] if win.allowed then api.nvim_set_current_win( ctx_obj[(idx % ctxs) + 1].id ) break end idx = (idx % ctxs) + 1 until s == idx end end end end local read_buffer = function () local c = vim.g.presser_buf_ctx local b = {} for ctx, ctx_obj in pairs( c ) do for idx, obj in pairs( ctx_obj ) do if obj.allowed then local buf = api.nvim_win_get_buf( obj.id ) table.insert(b, utils.clean_buf( api.nvim_buf_get_lines( buf, 0, -1, false )[1] )) end end end return b end presser.execute = function () local result = read_buffer() presser.close() local cmd = ":%s/" .. result[1] .. "/" .. result[2] .. "/g" api.nvim_exec( cmd, false ) end local start_buffer = function ( label ) for ctx, ctx_obj in pairs( vim.g.presser_buf_ctx ) do for idx, record in pairs( ctx_obj ) do if record.what == label then api.nvim_set_current_win( record.id ) end end end end -- @Description: Find and replace words within the current buffer. -- @Params: -- @Returns: nil. -- -- @Dev: function is responsible to creating all required buffers to allow full user interaction. -- -- @Future: implementation may allow for greater user customisation similar to what's found with -- extensions such as Telescope. For now, it should provide a concrete UI for purpose of design. function presser.find_replace() -- define the context which these windows will belong to in the context manager. local ctx = "find_replace" gcm.create( ctx ) local keymap = { n = { [""] = "lua require'presser'.close()", [""] = "lua require'presser'.execute()", }, i = { [""] = "lua require'presser'.move_next_buffer()", [""] = "lua require'presser'.execute()", } } -- get the centre of the current buffer local c_cols = math.floor( api.nvim_win_get_width(0) / 2 ) local c_lines = math.floor( api.nvim_win_get_height(0) / 2 ) -- print(c_cols, c_lines) -- options for the title buffer of the built-in local opts = { placeholder = "Find & Replace", allowed = false, window = { line = c_lines - 3, border = false, minwidth = 82, padding = { 0, 1, 1, 1 } }, } local tab_title = new( ctx, "presser_fr_title", opts ) -- options for the replace buffer local opts = { window = { line = c_lines, title = "Find", }, keybinds = keymap, } local find = new ( ctx, "find_buf", opts ) -- modify options for find buffer opts["window"]["line"] = c_lines+3 opts["window"]["title"] = "Replace" local replace = new( ctx, "replace_buf", opts ) local result = start_buffer( "find_buf" ) api.nvim_feedkeys('A', 'n', false) end --presser.find_replace() return presser