fix bugs about create and save new memo

This commit is contained in:
Elflare
2025-07-06 21:26:21 +08:00
parent 267e31d533
commit cb9fadd5eb

View File

@@ -1,326 +1,318 @@
local api = require('memos.api') local api = require("memos.api")
local config = require('memos').config local config = require("memos").config
local M = {} local M = {}
-- 存放状态的变量
local memos_cache = {} local memos_cache = {}
local buf_id = nil local buf_id = nil
local current_page_token = nil local current_page_token = nil
local current_user = nil local current_user = nil
local current_filter = nil local current_filter = nil
-- =================================================================== function M.render_memos(data, append)
-- 首先定义所有会被其他函数调用的 local "辅助" 函数 vim.schedule(function()
-- =================================================================== if not buf_id or not vim.api.nvim_buf_is_valid(buf_id) then
return
-- 渲染 Memos 列表到 buffer end
local function render_memos(data, append) local new_memos = data.memos or {}
vim.schedule(function() current_page_token = data.nextPageToken or ""
if not buf_id or not vim.api.nvim_buf_is_valid(buf_id) then if append then
return memos_cache = vim.list_extend(memos_cache, new_memos)
end else
local new_memos = data.memos or {} memos_cache = new_memos
current_page_token = data.nextPageToken or "" end
if append then local lines = {}
memos_cache = vim.list_extend(memos_cache, new_memos) local k = config.keymaps.list
else if #memos_cache == 0 then
memos_cache = new_memos local help = string.format(
end "No memos found. Press '%s' to refresh, '%s' to add, or '%s' to quit.",
local lines = {} k.refresh_list,
local k = config.keymaps.list k.add_memo,
if #memos_cache == 0 then k.quit
local help = string.format("No memos found. Press '%s' to refresh, '%s' to add, or '%s' to quit.", )
k.refresh_list, k.add_memo, k.quit) table.insert(lines, help)
table.insert(lines, help) else
else for i, memo in ipairs(memos_cache) do
for i, memo in ipairs(memos_cache) do local first_line = memo.content:match("^[^\n]*")
local first_line = memo.content:match("^[^\n]*") local display_time = memo.displayTime:sub(1, 10)
local display_time = memo.displayTime:sub(1, 10) table.insert(lines, string.format("%d. [%s] %s", i, display_time, first_line))
table.insert(lines, string.format("%d. [%s] %s", i, display_time, first_line)) end
end end
end if current_page_token ~= "" then
if current_page_token ~= "" then table.insert(lines, "...")
table.insert(lines, "...") table.insert(lines, string.format("(Press '%s' to load more)", k.next_page))
table.insert(lines, string.format("(Press '%s' to load more)", k.next_page)) end
end vim.api.nvim_buf_set_option(buf_id, "modifiable", true)
vim.api.nvim_buf_set_option(buf_id, 'modifiable', true) vim.api.nvim_buf_set_lines(buf_id, 0, -1, false, lines)
vim.api.nvim_buf_set_lines(buf_id, 0, -1, false, lines) vim.api.nvim_buf_set_option(buf_id, "modifiable", false)
vim.api.nvim_buf_set_option(buf_id, 'modifiable', false) end)
end) end
function M.setup_buffer_for_editing()
vim.bo.buftype = "nofile"
vim.bo.bufhidden = "wipe"
vim.bo.swapfile = false
vim.bo.buflisted = true
vim.bo.filetype = "markdown"
vim.b.memos_original_content = table.concat(vim.api.nvim_buf_get_lines(0, 0, -1, false), "\n")
local save_key_string = ""
if config.keymaps.buffer.save and config.keymaps.buffer.save ~= "" then
save_key_string = string.format(" or %s", config.keymaps.buffer.save)
end
if vim.b.memos_memo_name then
vim.notify("Editing memo. Use :MemosSave" .. save_key_string .. " to save.")
else
vim.notify("📝 New memo. Use :MemosSave" .. save_key_string .. " to create.")
end
vim.api.nvim_buf_create_user_command(0, "MemosSave", 'lua require("memos.ui").save_or_create_dispatcher()', {})
if config.keymaps.buffer.save and config.keymaps.buffer.save ~= "" then
vim.api.nvim_buf_set_keymap(
0,
"n",
config.keymaps.buffer.save,
"<Cmd>MemosSave<CR>",
{ noremap = true, silent = true }
)
end
if config.auto_save then
local group = vim.api.nvim_create_augroup("MemosAutoSave", { clear = true })
vim.api.nvim_create_autocmd("InsertLeave", {
group = group,
buffer = 0,
callback = function()
M.check_and_auto_save()
end,
})
vim.api.nvim_create_autocmd("CursorHold", {
group = group,
buffer = 0,
callback = function()
M.check_and_auto_save()
end,
})
end
end
function M.open_memo_for_edit(memo, open_cmd)
local first_line = memo.content:match("^[^\n]*")
local buffer_name = "memos/"
.. memo.name:gsub("memos/", "")
.. "/"
.. first_line:gsub("[/\\]", "_"):sub(1, 50)
.. ".md"
local existing_bufnr = vim.fn.bufnr(buffer_name)
if existing_bufnr ~= -1 and vim.api.nvim_buf_is_loaded(existing_bufnr) then
local win_id = vim.fn.bufwinid(existing_bufnr)
if win_id ~= -1 then
vim.api.nvim_set_current_win(win_id)
else
vim.api.nvim_set_current_buf(existing_bufnr)
end
else
vim.cmd(open_cmd)
vim.api.nvim_buf_set_name(0, buffer_name)
vim.api.nvim_buf_set_lines(0, 0, -1, false, vim.split(memo.content, "\n"))
vim.b.memos_memo_name = memo.name
M.setup_buffer_for_editing()
end
end end
-- 设置编辑 buffer 的通用函数
-- 【新增】检查内容是否变化并自动保存的函数
function M.check_and_auto_save() function M.check_and_auto_save()
-- 检查是否存在原始内容快照 if vim.b.memos_original_content == nil then
if vim.b.memos_original_content == nil then return end return
end
local current_content = table.concat(vim.api.nvim_buf_get_lines(0, 0, -1, false), '\n') local current_content = table.concat(vim.api.nvim_buf_get_lines(0, 0, -1, false), "\n")
if vim.b.memos_original_content ~= current_content then if vim.b.memos_original_content ~= current_content then
M.save_or_create_dispatcher() M.save_or_create_dispatcher()
end end
end end
-- 【修改】setup_buffer_for_editing 现在使用全新的自动保存逻辑
local function setup_buffer_for_editing()
vim.bo.buftype = 'nofile'
vim.bo.bufhidden = 'wipe'
vim.bo.swapfile = false
vim.bo.buflisted = true
vim.bo.filetype = 'markdown'
-- 【新增】在 buffer 打开时,立即创建内容快照
vim.b.memos_original_content = table.concat(vim.api.nvim_buf_get_lines(0, 0, -1, false), '\n')
local save_key_string = ""
if config.keymaps.buffer.save and config.keymaps.buffer.save ~= "" then
save_key_string = string.format(" or %s", config.keymaps.buffer.save)
end
if vim.b.memos_memo_name then
vim.notify("Editing memo. Use :MemosSave" .. save_key_string .. " to save.")
else
vim.notify("📝 New memo. Use :MemosSave" .. save_key_string .. " to create.")
end
vim.api.nvim_buf_create_user_command(0, 'MemosSave', 'lua require("memos.ui").save_or_create_dispatcher()', {})
if config.keymaps.buffer.save and config.keymaps.buffer.save ~= "" then
vim.api.nvim_buf_set_keymap(0, 'n', config.keymaps.buffer.save, '<Cmd>MemosSave<CR>', { noremap = true, silent = true })
end
-- 【修改】设置新的自动命令
if config.auto_save then
local group = vim.api.nvim_create_augroup('MemosAutoSave', { clear = true })
-- 离开插入模式时检查
vim.api.nvim_create_autocmd('InsertLeave', {
group = group,
buffer = 0,
callback = M.check_and_auto_save,
})
-- 光标静止时检查
vim.api.nvim_create_autocmd('CursorHold', {
group = group,
buffer = 0,
callback = M.check_and_auto_save,
})
end
end
-- 【修改】保存成功后,需要更新内容快照
function M.save_or_create_dispatcher() function M.save_or_create_dispatcher()
local memo_name = vim.b.memos_memo_name local bufnr_to_save = vim.api.nvim_get_current_buf()
local current_content = table.concat(vim.api.nvim_buf_get_lines(0, 0, -1, false), '\n') local memo_name = vim.b.memos_memo_name
local content = table.concat(vim.api.nvim_buf_get_lines(bufnr_to_save, 0, -1, false), "\n")
if current_content == '' then if content == "" then
vim.notify("Memo is empty, not sending.", vim.log.levels.WARN) vim.notify("Memo is empty, not sending.", vim.log.levels.WARN)
return return
end end
if memo_name then if memo_name then
api.update_memo(memo_name, current_content, function(success) -- 更新逻辑 (保持不变,工作正常)
if success then api.update_memo(memo_name, content, function(success)
vim.schedule(function() if success then
vim.notify("✅ Memo updated successfully!") vim.schedule(function()
-- 更新快照为最新内容 vim.notify("✅ Memo updated successfully!")
vim.b.memos_original_content = current_content if vim.api.nvim_buf_is_valid(bufnr_to_save) then
end) vim.b[bufnr_to_save].memos_original_content = content
M.refresh_list_silently() end
end end)
end) M.refresh_list_silently()
else end
api.create_memo(current_content, function(new_memo) end)
if new_memo and new_memo.name then else
vim.schedule(function() api.create_memo(content, function(new_memo)
vim.notify("✅ Memo created successfully!") if new_memo and new_memo.name then
vim.cmd('bdelete!') vim.schedule(function()
open_memo_for_edit(new_memo, 'enew') vim.notify("✅ Memo created successfully!")
M.refresh_list_silently() M.show_memos_list(current_filter)
end) -- 立即重新打开刚刚创建的 memo进入编辑模式
else vim.schedule(function()
vim.schedule(function() vim.notify("❌ Failed to create memo.", vim.log.levels.ERROR) end) M.open_memo_for_edit(new_memo, "enew")
end end)
end) end)
end else
vim.schedule(function()
vim.notify("❌ Failed to create memo.", vim.log.levels.ERROR)
end)
end
end)
end
end end
-- 打开一个已存在的 Memo
local function open_memo_for_edit(memo, open_cmd)
-- 1. 根据 memo 信息,构造一个唯一的 buffer 名称
local first_line = memo.content:match("^[^\n]*")
local buffer_name = "memos/" .. memo.name:gsub("memos/", "") .. "/" .. first_line:gsub("[/\\]", "_"):sub(1, 50) ..
".md"
-- 2. 检查这个名字的 buffer 是否已经存在
local existing_bufnr = vim.fn.bufnr(buffer_name)
if existing_bufnr ~= -1 and vim.api.nvim_buf_is_loaded(existing_bufnr) then
-- 3. 如果已存在,则找到它所在的窗口并跳转过去
local win_id = vim.fn.bufwinid(existing_bufnr)
if win_id ~= -1 then
vim.api.nvim_set_current_win(win_id)
else
-- 如果窗口已关闭但 buffer 仍在,则在当前窗口打开它
vim.api.nvim_set_current_buf(existing_bufnr)
end
else
-- 4. 如果不存在,才执行我们之前的创建新窗口的逻辑
vim.cmd(open_cmd)
vim.api.nvim_buf_set_name(0, buffer_name)
vim.api.nvim_buf_set_lines(0, 0, -1, false, vim.split(memo.content, '\n'))
vim.b.memos_memo_name = memo.name
setup_buffer_for_editing()
end
end
-- ===================================================================
-- 然后定义所有对外暴露的 M.xxx 函数,确保它们能访问到上面的 local 函数
-- ===================================================================
-- 【修正】将此函数移到 render_memos 定义之后,解决报错
function M.refresh_list_silently() function M.refresh_list_silently()
if not current_user or not current_user.name then if not current_user or not current_user.name then
return return
end end
api.list_memos(current_user.name, current_filter, config.pageSize, nil, function(data) api.list_memos(current_user.name, current_filter, config.pageSize, nil, function(data)
render_memos(data, false) M.render_memos(data, false)
end) end)
end end
function M.create_memo_in_buffer() function M.create_memo_in_buffer()
vim.cmd('enew') vim.cmd("enew")
vim.b.memos_memo_name = nil vim.b.memos_memo_name = nil
vim.api.nvim_buf_set_name(0, "memos/new_memo.md") -- 使用一个带时间戳的、独一无二的临时名字,防止冲突
setup_buffer_for_editing() vim.api.nvim_buf_set_name(0, "memos/new_memo_" .. vim.fn.strftime("%s"))
M.setup_buffer_for_editing()
end end
function M.show_memos_list(filter) function M.show_memos_list(filter)
current_filter = filter current_filter = filter
local should_create_buf = true local should_create_buf = true
if buf_id and vim.api.nvim_buf_is_valid(buf_id) then if buf_id and vim.api.nvim_buf_is_valid(buf_id) then
should_create_buf = false should_create_buf = false
else else
buf_id = vim.api.nvim_create_buf(true, true) -- listed = true, scratch = true buf_id = vim.api.nvim_create_buf(true, true)
vim.api.nvim_buf_set_name(buf_id, " Memos") vim.api.nvim_buf_set_name(buf_id, " Memos")
vim.bo[buf_id].buftype = 'nofile' vim.bo[buf_id].buftype = "nofile"
vim.bo[buf_id].swapfile = false vim.bo[buf_id].swapfile = false
vim.bo[buf_id].filetype = 'memos_list' vim.bo[buf_id].filetype = "memos_list"
vim.bo[buf_id].modifiable = false vim.bo[buf_id].modifiable = false
end end
-- 【修正】确保跳转到列表窗口,并且是在当前窗口打开 local win_id = vim.fn.bufwinid(buf_id)
local win_id = vim.fn.bufwinid(buf_id) if win_id ~= -1 then
if win_id ~= -1 then vim.api.nvim_set_current_win(win_id)
vim.api.nvim_set_current_win(win_id) else
else vim.api.nvim_set_current_buf(buf_id)
vim.api.nvim_set_current_buf(buf_id) end
end
vim.schedule(function() vim.schedule(function()
vim.notify("Getting user info...") vim.notify("Getting user info...")
end) end)
api.get_current_user(function(user) api.get_current_user(function(user)
if user and user.name then if user and user.name then
current_user = user current_user = user
vim.schedule(function() vim.schedule(function()
vim.notify("Fetching memos for " .. user.name .. "...") vim.notify("Fetching memos for " .. user.name .. "...")
end) end)
api.list_memos(user.name, current_filter, config.pageSize, nil, function(data) api.list_memos(user.name, current_filter, config.pageSize, nil, function(data)
render_memos(data, false) M.render_memos(data, false)
end) end)
else else
vim.schedule(function() vim.schedule(function()
vim.notify("Could not get user, aborting fetch.", vim.log.levels.ERROR) vim.notify("Could not get user, aborting fetch.", vim.log.levels.ERROR)
end) end)
end end
end) end)
local function set_keymap(key, command) local function set_keymap(key, command)
if key and key ~= "" then if key and key ~= "" then
vim.api.nvim_buf_set_keymap(buf_id, 'n', key, command, { vim.api.nvim_buf_set_keymap(buf_id, "n", key, command, { noremap = true, silent = true })
noremap = true, end
silent = true end
})
end
end
if config.keymaps and config.keymaps.list then if config.keymaps and config.keymaps.list then
local list_keymaps = config.keymaps.list local list_keymaps = config.keymaps.list
set_keymap(list_keymaps.edit_memo, '<Cmd>lua require("memos.ui").edit_selected_memo()<CR>') set_keymap(list_keymaps.edit_memo, '<Cmd>lua require("memos.ui").edit_selected_memo()<CR>')
set_keymap(list_keymaps.vsplit_edit_memo, '<Cmd>lua require("memos.ui").edit_selected_memo_in_vsplit()<CR>') set_keymap(list_keymaps.vsplit_edit_memo, '<Cmd>lua require("memos.ui").edit_selected_memo_in_vsplit()<CR>')
set_keymap(list_keymaps.quit, '<Cmd>bdelete!<CR>') set_keymap(list_keymaps.quit, "<Cmd>bdelete!<CR>")
set_keymap(list_keymaps.search_memos, '<Cmd>lua require("memos.ui").search_memos()<CR>') set_keymap(list_keymaps.search_memos, '<Cmd>lua require("memos.ui").search_memos()<CR>')
set_keymap(list_keymaps.refresh_list, '<Cmd>lua require("memos.ui").show_memos_list()<CR>') set_keymap(list_keymaps.refresh_list, '<Cmd>lua require("memos.ui").show_memos_list()<CR>')
set_keymap(list_keymaps.next_page, '<Cmd>lua require("memos.ui").load_next_page()<CR>') set_keymap(list_keymaps.next_page, '<Cmd>lua require("memos.ui").load_next_page()<CR>')
set_keymap(list_keymaps.add_memo, '<Cmd>lua require("memos.ui").create_memo_in_buffer()<CR>') set_keymap(list_keymaps.add_memo, '<Cmd>lua require("memos.ui").create_memo_in_buffer()<CR>')
set_keymap(list_keymaps.delete_memo, '<Cmd>lua require("memos.ui").confirm_delete_memo()<CR>') set_keymap(list_keymaps.delete_memo, '<Cmd>lua require("memos.ui").confirm_delete_memo()<CR>')
set_keymap(list_keymaps.delete_memo_visual, '<Cmd>lua require("memos.ui").confirm_delete_memo()<CR>') set_keymap(list_keymaps.delete_memo_visual, '<Cmd>lua require("memos.ui").confirm_delete_memo()<CR>')
end end
end end
function M.load_next_page() function M.load_next_page()
if not current_page_token or current_page_token == "" then if not current_page_token or current_page_token == "" then
vim.notify("No more pages to load.", vim.log.levels.INFO) vim.notify("No more pages to load.", vim.log.levels.INFO)
return return
end end
if not current_user or not current_user.name then if not current_user or not current_user.name then
vim.notify("User info not available.", vim.log.levels.WARN) vim.notify("User info not available.", vim.log.levels.WARN)
return return
end end
vim.schedule(function() vim.schedule(function()
vim.notify("Loading next page...") vim.notify("Loading next page...")
end) end)
api.list_memos(current_user.name, current_filter, config.pageSize, current_page_token, function(data) api.list_memos(current_user.name, current_filter, config.pageSize, current_page_token, function(data)
render_memos(data, true) M.render_memos(data, true)
end) end)
end end
function M.edit_selected_memo() function M.edit_selected_memo()
local line_num = vim.api.nvim_win_get_cursor(0)[1] local line_num = vim.api.nvim_win_get_cursor(0)[1]
local selected_memo = memos_cache[line_num] local selected_memo = memos_cache[line_num]
if selected_memo then if selected_memo then
open_memo_for_edit(selected_memo, 'enew') M.open_memo_for_edit(selected_memo, "enew")
end end
end end
function M.edit_selected_memo_in_vsplit() function M.edit_selected_memo_in_vsplit()
local line_num = vim.api.nvim_win_get_cursor(0)[1] local line_num = vim.api.nvim_win_get_cursor(0)[1]
local selected_memo = memos_cache[line_num] local selected_memo = memos_cache[line_num]
if selected_memo then if selected_memo then
open_memo_for_edit(selected_memo, 'vsplit | enew') M.open_memo_for_edit(selected_memo, "vsplit | enew")
end end
end end
function M.confirm_delete_memo() function M.confirm_delete_memo()
local line_num = vim.api.nvim_win_get_cursor(0)[1] local line_num = vim.api.nvim_win_get_cursor(0)[1]
local selected_memo = memos_cache[line_num] local selected_memo = memos_cache[line_num]
if not selected_memo then if not selected_memo then
return return
end end
local choice = vim.fn.confirm("Delete this memo?\n[" .. selected_memo.content:sub(1, 50) .. "...]", "&Yes\n&No", 2) local choice = vim.fn.confirm("Delete this memo?\n[" .. selected_memo.content:sub(1, 50) .. "...]", "&Yes\n&No", 2)
if choice == 1 then if choice == 1 then
api.delete_memo(selected_memo.name, function(success) api.delete_memo(selected_memo.name, function(success)
if success then if success then
vim.schedule(function() vim.schedule(function()
vim.notify("✅ Memo deleted.") vim.notify("✅ Memo deleted.")
M.show_memos_list(current_filter) M.show_memos_list(current_filter)
end) end)
else else
vim.schedule(function() vim.schedule(function()
vim.notify("❌ Failed to delete memo.", vim.log.levels.ERROR) vim.notify("❌ Failed to delete memo.", vim.log.levels.ERROR)
end) end)
end end
end) end)
end end
end end
function M.search_memos() function M.search_memos()
vim.ui.input({ vim.ui.input({ prompt = "Search Memos: " }, function(input)
prompt = "Search Memos: " M.show_memos_list(input or "")
}, function(input) end)
M.show_memos_list(input or "")
end)
end end
return M return M