diff --git a/lua/cheaty/init.lua b/lua/cheaty/init.lua index b9b1815..0c23941 100644 --- a/lua/cheaty/init.lua +++ b/lua/cheaty/init.lua @@ -1,15 +1,23 @@ +---@class cheaty local M = {} -- stylua: ignore start +---@class cheatyOpts +---@field width? number +---@field height? number +---@field save_file? string +---@field cheatsheet? string[] local defaults = { width = 0.6, height = 0.6, + save_file = vim.fs.joinpath(vim.fn.stdpath("data"), "cheaty.md"), cheatsheet = { "# This is a sample cheatsheet!", "Tailor it to your liking in the config!" } } -- stylua: ignore end -M.config = {} +M.config = {} ---@type cheatyOpts +---@param opts? cheatyOpts function M.setup(opts) M.config = vim.tbl_deep_extend("force", defaults, opts or {}) diff --git a/lua/cheaty/window.lua b/lua/cheaty/window.lua index 9e1e203..5fddf41 100644 --- a/lua/cheaty/window.lua +++ b/lua/cheaty/window.lua @@ -1,25 +1,48 @@ +local uv = vim.uv or vim.loop + +---@class cheaty.Window local M = {} -local win_id = nil -local buf_id = nil +local win_id, buf_id = nil, nil ---@type integer|nil, integer|nil +local fd, stat = nil, nil ---@type integer|nil, uv.fs_stat.result|nil + +---@param cfg cheatyOpts +---@param flags? uv.fs_open.flags +local function open_file(cfg, flags) + if not cfg.save_file or cfg.save_file == "" then + error("No valid path!", vim.log.levels.ERROR) + end + + if vim.fn.filereadable(cfg.save_file) ~= 1 then + vim.fn.writefile(cfg.cheatsheet or {}, cfg.save_file) + end + stat = uv.fs_stat(cfg.save_file) + fd = uv.fs_open(cfg.save_file, flags or "r", tonumber("644", 8)) +end + +---@param cfg cheatyOpts local function create_window(cfg) buf_id = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(buf_id, 0, -1, false, cfg.cheatsheet) + open_file(cfg, "r") - -- Buffer options - local buffer = vim.bo[buf_id] + local contents = cfg.cheatsheet + if fd and stat then + contents = vim.split(uv.fs_read(fd, stat.size), "\n", { trimempty = false }) + uv.fs_close(fd) + end - buffer.buftype = "nofile" - buffer.bufhidden = "wipe" - buffer.modifiable = false - buffer.swapfile = false - buffer.filetype = "markdown" + vim.api.nvim_buf_set_lines(buf_id, 0, -1, false, contents) - vim.api.nvim_buf_call(buf_id, function() - vim.cmd("doautocmd FileType markdown") - end) + -- Buffer options + local opts = { buf = buf_id } ---@type vim.api.keyset.option + vim.api.nvim_set_option_value("buftype", "nofile", opts) + -- vim.api.nvim_set_option_value("bufhidden", "wipe", opts) + vim.api.nvim_set_option_value("modified", false, opts) + vim.api.nvim_set_option_value("modifiable", true, opts) + vim.api.nvim_set_option_value("swapfile", false, opts) + vim.api.nvim_set_option_value("filetype", "markdown", opts) local width = math.floor(vim.o.columns * cfg.width) local height = math.floor(vim.o.lines * cfg.height) @@ -29,6 +52,9 @@ local function create_window(cfg) win_id = vim.api.nvim_open_win(buf_id, true, { relative = "editor", + noautocmd = false, + title = "Cheaty", + title_pos = "center", row = row, col = col, width = width, @@ -36,23 +62,52 @@ local function create_window(cfg) style = "minimal", border = "rounded", }) + + vim.keymap.set("n", "q", M.close, { buffer = buf_id }) + + local augroup = vim.api.nvim_create_augroup("cheaty", { clear = true }) + vim.api.nvim_create_autocmd({ "TextChanged", "TextChangedI" }, { + group = augroup, + buffer = buf_id, + callback = function() + if not (buf_id and vim.api.nvim_buf_is_valid(buf_id)) then + return + end + + open_file(cfg, "w") + if not fd then + return + end + + local content = vim.api.nvim_buf_get_lines(buf_id, 0, -1, true) + uv.fs_write(fd, table.concat(content, "\n")) + uv.fs_close(fd) + end, + }) end function M.close() - if win_id and vim.api.nvim_win_is_valid(win_id) then - vim.api.nvim_win_close(win_id, true) + if not (buf_id or win_id) then + return end + pcall(vim.api.nvim_buf_delete, buf_id, { force = true }) + pcall(vim.api.nvim_win_close, win_id, true) + + fd = nil + stat = nil win_id = nil buf_id = nil end +---@param cfg cheatyOpts function M.toggle(cfg) - if win_id and vim.api.nvim_win_is_valid(win_id) then + if win_id and buf_id then M.close() - else - create_window(cfg) + return end + + create_window(cfg) end return M