first commit
This commit is contained in:
271
README.md
271
README.md
@@ -1 +1,270 @@
|
|||||||
# memos.nvim
|
# memos.nvim
|
||||||
|
|
||||||
|
English | [简体中文](./README.md#memosnvim-简体中文)
|
||||||
|
|
||||||
|
A Neovim plugin to interact with [Memos](https://github.com/usememos/memos) right inside the editor. List, create, edit, and delete your memos without leaving Neovim.
|
||||||
|
|
||||||
|
## ✨ Features
|
||||||
|
|
||||||
|
- **List Memos**: View, search, and paginate through your memos in a floating window.
|
||||||
|
- **Create & Edit**: Create new memos or edit existing ones in a dedicated buffer with `markdown` filetype support.
|
||||||
|
- **Delete Memos**: Delete memos directly from the list.
|
||||||
|
- **Customizable**: Configure API endpoints, keymaps, and more.
|
||||||
|
|
||||||
|
## 📦 Installation
|
||||||
|
|
||||||
|
Requires [plenary.nvim](https://github.com/nvim-lua/plenary.nvim).
|
||||||
|
|
||||||
|
Install with [lazy.nvim](https://github.com/folke/lazy.nvim):
|
||||||
|
|
||||||
|
```lua
|
||||||
|
-- lua/plugins/memos.lua
|
||||||
|
|
||||||
|
return {
|
||||||
|
-- Memos.nvim: A plugin to interact with Memos from within Neovim
|
||||||
|
{
|
||||||
|
-- IMPORTANT: Replace with your actual GitHub username/repo
|
||||||
|
"your-github-username/memos.nvim",
|
||||||
|
|
||||||
|
-- Optional, but good for identification in Lazy UI
|
||||||
|
name = "memos.nvim",
|
||||||
|
|
||||||
|
dependencies = { "nvim-lua/plenary.nvim" },
|
||||||
|
|
||||||
|
-- Load the plugin on these commands
|
||||||
|
cmd = { "Memos", "MemosCreate" },
|
||||||
|
|
||||||
|
config = function()
|
||||||
|
require("memos").setup({
|
||||||
|
-- REQUIRED: Your Memos host URL
|
||||||
|
host = "https://your-memos-host.com",
|
||||||
|
|
||||||
|
-- REQUIRED: Your Memos API token (Open API)
|
||||||
|
token = "your-super-secret-token",
|
||||||
|
|
||||||
|
-- Optional: Customize keymaps
|
||||||
|
keymaps = {
|
||||||
|
-- Keymaps for the editing/creating buffer
|
||||||
|
buffer = {
|
||||||
|
save = "<leader>ms", -- Save the current memo
|
||||||
|
},
|
||||||
|
-- Keymaps for the memo list window
|
||||||
|
list = {
|
||||||
|
add_memo = "a", -- Add a new memo
|
||||||
|
edit_memo = "<CR>", -- Edit selected memo
|
||||||
|
-- ... other keymaps can be configured here
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Plenary is a required dependency
|
||||||
|
{
|
||||||
|
"nvim-lua/plenary.nvim",
|
||||||
|
lazy = true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🚀 Usage
|
||||||
|
|
||||||
|
### Commands
|
||||||
|
|
||||||
|
- `:Memos`: Opens a floating window to list and search your memos.
|
||||||
|
- `:MemosCreate`: Opens a new buffer to create a new memo.
|
||||||
|
- `:MemosSave`: (Available in the memo buffer) Saves the memo you are currently creating or editing.
|
||||||
|
|
||||||
|
### Default Keymaps
|
||||||
|
|
||||||
|
#### In the Memo List Window
|
||||||
|
|
||||||
|
| Key | Action |
|
||||||
|
| ------------------ | ------------------------------------ |
|
||||||
|
| `a` | Add a new memo |
|
||||||
|
| `d` or `dd` | Delete the selected memo |
|
||||||
|
| `<CR>` | Edit the selected memo |
|
||||||
|
| `<Tab>` | Edit the selected memo in a vsplit |
|
||||||
|
| `s` | Search your memos |
|
||||||
|
| `r` | Refresh the memo list |
|
||||||
|
| `.` | Load the next page of memos |
|
||||||
|
| `q` | Quit the list window |
|
||||||
|
|
||||||
|
#### In the Edit/Create Buffer
|
||||||
|
|
||||||
|
| Key | Action |
|
||||||
|
| ------------------ | ------------------------------------ |
|
||||||
|
| `<leader>ms` | Save the current memo |
|
||||||
|
|
||||||
|
## ⚙️ Configuration
|
||||||
|
|
||||||
|
You can override the default settings by passing a table to the `setup()` function.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
require("memos").setup({
|
||||||
|
-- REQUIRED: Your Memos host URL
|
||||||
|
host = "https://your-memos-host.com",
|
||||||
|
|
||||||
|
-- REQUIRED: Your Memos API token (Open API)
|
||||||
|
token = "your-super-secret-token",
|
||||||
|
|
||||||
|
-- Number of memos to fetch per page
|
||||||
|
pageSize = 50,
|
||||||
|
|
||||||
|
-- Set to false or nil to disable a keymap
|
||||||
|
keymaps = {
|
||||||
|
-- Keymaps for the memo list window
|
||||||
|
list = {
|
||||||
|
add_memo = "a",
|
||||||
|
delete_memo = "d",
|
||||||
|
delete_memo_visual = "dd",
|
||||||
|
edit_memo = "<CR>",
|
||||||
|
vsplit_edit_memo = "<Tab>",
|
||||||
|
search_memos = "s",
|
||||||
|
refresh_list = "r",
|
||||||
|
next_page = ".",
|
||||||
|
quit = "q",
|
||||||
|
},
|
||||||
|
-- Keymaps for the editing/creating buffer
|
||||||
|
buffer = {
|
||||||
|
save = "<leader>ms",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# memos.nvim (简体中文)
|
||||||
|
|
||||||
|
[English](./README.md#memosnvim) | 简体中文
|
||||||
|
|
||||||
|
一个 Neovim 插件,让你在编辑器内部直接与 [Memos](https://github.com/usememos/memos) 进行交互。无需离开 Neovim 即可列表、创建、编辑和删除你的 memos。
|
||||||
|
|
||||||
|
## ✨ 功能
|
||||||
|
|
||||||
|
- **列表 Memos**: 在浮动窗口中查看、搜索和翻页你的 memos。
|
||||||
|
- **创建与编辑**: 在专用的、支持 `markdown` 文件类型的缓冲区中创建新 memo 或编辑现有 memo。
|
||||||
|
- **删除 Memos**: 直接从列表中删除 memo。
|
||||||
|
- **可定制**: 可配置 API 地址、快捷键等。
|
||||||
|
|
||||||
|
## 📦 安装
|
||||||
|
|
||||||
|
需要 [plenary.nvim](https://github.com/nvim-lua/plenary.nvim) 插件。
|
||||||
|
|
||||||
|
使用 [lazy.nvim](https://github.com/folke/lazy.nvim) 安装:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
-- lua/plugins/memos.lua
|
||||||
|
|
||||||
|
return {
|
||||||
|
-- Memos.nvim: 一个在 Neovim 中与 Memos 交互的插件
|
||||||
|
{
|
||||||
|
-- 重要: 请将这里替换为你的 GitHub 用户名/仓库名
|
||||||
|
"your-github-username/memos.nvim",
|
||||||
|
|
||||||
|
-- 可选,但在 Lazy 管理界面中易于识别
|
||||||
|
name = "memos.nvim",
|
||||||
|
|
||||||
|
dependencies = { "nvim-lua/plenary.nvim" },
|
||||||
|
|
||||||
|
-- 在执行这些命令时加载插件
|
||||||
|
cmd = { "Memos", "MemosCreate" },
|
||||||
|
|
||||||
|
config = function()
|
||||||
|
require("memos").setup({
|
||||||
|
-- 必填: 你的 Memos 服务地址
|
||||||
|
host = "https://your-memos-host.com",
|
||||||
|
|
||||||
|
-- 必填: 你的 Memos API 令牌 (Open API)
|
||||||
|
token = "your-super-secret-token",
|
||||||
|
|
||||||
|
-- 可选: 自定义快捷键
|
||||||
|
keymaps = {
|
||||||
|
-- 编辑/创建窗口的快捷键
|
||||||
|
buffer = {
|
||||||
|
save = "<leader>ms", -- 保存当前 memo
|
||||||
|
},
|
||||||
|
-- memo 列表窗口的快捷键
|
||||||
|
list = {
|
||||||
|
add_memo = "a", -- 新增 memo
|
||||||
|
edit_memo = "<CR>", -- 编辑所选 memo
|
||||||
|
-- ... 其他快捷键也可以在这里配置
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Plenary 是一个必要的依赖
|
||||||
|
{
|
||||||
|
"nvim-lua/plenary.nvim",
|
||||||
|
lazy = true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🚀 使用方法
|
||||||
|
|
||||||
|
### 命令
|
||||||
|
|
||||||
|
- `:Memos`: 打开一个浮动窗口,列出并搜索你的 memos。
|
||||||
|
- `:MemosCreate`: 打开一个新的缓冲区来创建 memo。
|
||||||
|
- `:MemosSave`: (在 memo 编辑缓冲区中可用) 保存你正在创建或编辑的 memo。
|
||||||
|
|
||||||
|
### 默认快捷键
|
||||||
|
|
||||||
|
#### 在 Memo 列表窗口中
|
||||||
|
|
||||||
|
| 按键 | 功能 |
|
||||||
|
| ------------------ | ---------------------------------- |
|
||||||
|
| `a` | 新增一个 memo |
|
||||||
|
| `d` 或 `dd` | 删除所选的 memo |
|
||||||
|
| `<CR>` | 编辑所选的 memo |
|
||||||
|
| `<Tab>` | 在垂直分屏中编辑所选的 memo |
|
||||||
|
| `s` | 搜索你的 memos |
|
||||||
|
| `r` | 刷新 memo 列表 |
|
||||||
|
| `.` | 加载下一页 memos |
|
||||||
|
| `q` | 退出列表窗口 |
|
||||||
|
|
||||||
|
#### 在编辑/创建缓冲区中
|
||||||
|
|
||||||
|
| 按键 | 功能 |
|
||||||
|
| ------------------ | ---------------------------------- |
|
||||||
|
| `<leader>ms` | 保存当前 memo |
|
||||||
|
|
||||||
|
## ⚙️ 配置
|
||||||
|
|
||||||
|
你可以通过向 `setup()` 函数传递一个 table 来覆盖默认设置。
|
||||||
|
|
||||||
|
```lua
|
||||||
|
require("memos").setup({
|
||||||
|
-- 必填: 你的 Memos 服务地址
|
||||||
|
host = "https://your-memos-host.com",
|
||||||
|
|
||||||
|
-- 必填: 你的 Memos API 令牌 (Open API)
|
||||||
|
token = "your-super-secret-token",
|
||||||
|
|
||||||
|
-- 每页获取的 memo 数量
|
||||||
|
pageSize = 50,
|
||||||
|
|
||||||
|
-- 设置为 false 或 nil 可以禁用某个快捷键
|
||||||
|
keymaps = {
|
||||||
|
-- memo 列表窗口的快捷键
|
||||||
|
list = {
|
||||||
|
add_memo = "a",
|
||||||
|
delete_memo = "d",
|
||||||
|
delete_memo_visual = "dd",
|
||||||
|
edit_memo = "<CR>",
|
||||||
|
vsplit_edit_memo = "<Tab>",
|
||||||
|
search_memos = "s",
|
||||||
|
refresh_list = "r",
|
||||||
|
next_page = ".",
|
||||||
|
quit = "q",
|
||||||
|
},
|
||||||
|
-- 编辑/创建窗口的快捷键
|
||||||
|
buffer = {
|
||||||
|
save = "<leader>ms",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|||||||
133
doc/memos.nvim.txt
Normal file
133
doc/memos.nvim.txt
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
*memos.nvim.txt* For Neovim | English and 简体中文
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
CONTENTS *memos.nvim-contents*
|
||||||
|
|
||||||
|
1. About....................................|memos-about|
|
||||||
|
2. Features.................................|memos-features|
|
||||||
|
3. Installation.............................|memos-installation|
|
||||||
|
4. Usage....................................|memos-usage|
|
||||||
|
5. Configuration............................|memos-configuration|
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
1. About *memos-about*
|
||||||
|
|
||||||
|
A Neovim plugin to interact with Memos (https://github.com/usememos/memos)
|
||||||
|
right inside the editor. List, create, edit, and delete your memos without
|
||||||
|
leaving Neovim.
|
||||||
|
|
||||||
|
一个 Neovim 插件,让你在编辑器内部直接与 Memos 进行交互。无需离开 Neovim
|
||||||
|
即可列表、创建、编辑和删除你的 memos。
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
2. Features *memos-features*
|
||||||
|
|
||||||
|
- *List Memos*: View, search, and paginate through your memos in a floating
|
||||||
|
window.
|
||||||
|
- *Create & Edit*: Create new memos or edit existing ones in a dedicated
|
||||||
|
buffer with `markdown` filetype support.
|
||||||
|
- *Delete Memos*: Delete memos directly from the list.
|
||||||
|
- *Lazy Loading*: The plugin is loaded only when you run one of its commands.
|
||||||
|
- *Customizable*: Configure API endpoints, keymaps, and more.
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
3. Installation *memos-installation*
|
||||||
|
|
||||||
|
Requires |plenary.nvim|.
|
||||||
|
|
||||||
|
Install with |lazy.nvim|:
|
||||||
|
>lua
|
||||||
|
-- lua/plugins/memos.lua
|
||||||
|
return {
|
||||||
|
{
|
||||||
|
"your-github-username/memos.nvim",
|
||||||
|
name = "memos.nvim",
|
||||||
|
dependencies = { "nvim-lua/plenary.nvim" },
|
||||||
|
cmd = { "Memos", "MemosCreate" },
|
||||||
|
config = function()
|
||||||
|
require("memos").setup({
|
||||||
|
host = "https://your-memos-host.com",
|
||||||
|
token = "your-super-secret-token",
|
||||||
|
})
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nvim-lua/plenary.nvim",
|
||||||
|
lazy = true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
<
|
||||||
|
==============================================================================
|
||||||
|
4. Usage *memos-usage*
|
||||||
|
|
||||||
|
COMMANDS *memos-commands*
|
||||||
|
|
||||||
|
*:Memos*
|
||||||
|
Opens a floating window to list and search your memos.
|
||||||
|
|
||||||
|
*:MemosCreate*
|
||||||
|
Opens a new buffer to create a new memo.
|
||||||
|
|
||||||
|
*:MemosSave*
|
||||||
|
(Available in the memo buffer) Saves the memo you are currently
|
||||||
|
creating or editing.
|
||||||
|
|
||||||
|
DEFAULT KEYMAPS *memos-keymaps*
|
||||||
|
|
||||||
|
*In the Memo List Window:*
|
||||||
|
| Key | Action |
|
||||||
|
|--------------------|--------------------------------------|
|
||||||
|
| `a` | Add a new memo |
|
||||||
|
| `d` or `dd` | Delete the selected memo |
|
||||||
|
| `<CR>` | Edit the selected memo |
|
||||||
|
| `<Tab>` | Edit the selected memo in a vsplit |
|
||||||
|
| `s` | Search your memos |
|
||||||
|
| `r` | Refresh the memo list |
|
||||||
|
| `.` | Load the next page of memos |
|
||||||
|
| `q` | Quit the list window |
|
||||||
|
|
||||||
|
*In the Edit/Create Buffer:*
|
||||||
|
| Key | Action |
|
||||||
|
|--------------------|--------------------------------------|
|
||||||
|
| `<leader>ms` | Save the current memo |
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
5. Configuration *memos-configuration*
|
||||||
|
|
||||||
|
You can override the default settings by passing a table to the `setup()`
|
||||||
|
function.
|
||||||
|
|
||||||
|
Default configuration:
|
||||||
|
>lua
|
||||||
|
require("memos").setup({
|
||||||
|
-- REQUIRED: Your Memos host URL
|
||||||
|
host = "https://your-memos-host.com",
|
||||||
|
|
||||||
|
-- REQUIRED: Your Memos API token (Open API)
|
||||||
|
token = "your-super-secret-token",
|
||||||
|
|
||||||
|
-- Number of memos to fetch per page
|
||||||
|
pageSize = 50,
|
||||||
|
|
||||||
|
-- Set to false or nil to disable a keymap
|
||||||
|
keymaps = {
|
||||||
|
-- Keymaps for the memo list window
|
||||||
|
list = {
|
||||||
|
add_memo = "a",
|
||||||
|
delete_memo = "d",
|
||||||
|
delete_memo_visual = "dd",
|
||||||
|
edit_memo = "<CR>",
|
||||||
|
vsplit_edit_memo = "<Tab>",
|
||||||
|
search_memos = "s",
|
||||||
|
refresh_list = "r",
|
||||||
|
next_page = ".",
|
||||||
|
quit = "q",
|
||||||
|
},
|
||||||
|
-- Keymaps for the editing/creating buffer
|
||||||
|
buffer = {
|
||||||
|
save = "<leader>ms",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
<
|
||||||
|
vim:tw=78:ts=8:ft=help:norl:
|
||||||
92
lua/memos/api.lua
Normal file
92
lua/memos/api.lua
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
local Job = require('plenary.job')
|
||||||
|
local config = require('memos').config
|
||||||
|
|
||||||
|
local M = {}
|
||||||
|
|
||||||
|
local function run_curl(args, on_exit)
|
||||||
|
table.insert(args, '-H')
|
||||||
|
table.insert(args, 'Authorization: Bearer ' .. config.token)
|
||||||
|
Job:new({ command = 'curl', args = args, on_exit = on_exit }):start()
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.get_current_user(callback)
|
||||||
|
run_curl({
|
||||||
|
'-s', '--fail', '-X', 'POST', config.host .. '/api/v1/auth/status',
|
||||||
|
}, function(job, return_val)
|
||||||
|
if return_val == 0 then
|
||||||
|
local result_string = table.concat(job:result(), "")
|
||||||
|
local data = vim.json.decode(result_string)
|
||||||
|
callback(data or nil)
|
||||||
|
else
|
||||||
|
vim.schedule(function() vim.notify("Failed to get user info.", vim.log.levels.ERROR) end)
|
||||||
|
callback(nil)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.list_memos(parent, filter, pageSize, pageToken, callback)
|
||||||
|
local list_url = config.host .. '/api/v1/memos'
|
||||||
|
local params = {}
|
||||||
|
table.insert(params, "parent=" .. parent)
|
||||||
|
table.insert(params, "pageSize=" .. tostring(pageSize))
|
||||||
|
if pageToken and pageToken ~= "" then table.insert(params, "pageToken=" .. pageToken) end
|
||||||
|
if filter and filter ~= '' then
|
||||||
|
table.insert(params, 'filter=content.contains("' .. vim.fn.escape(filter, '\\"') .. '")')
|
||||||
|
end
|
||||||
|
list_url = list_url .. "?" .. table.concat(params, "&")
|
||||||
|
|
||||||
|
run_curl({
|
||||||
|
'-s', '--fail', '-X', 'GET', list_url,
|
||||||
|
}, function(job, return_val)
|
||||||
|
if return_val == 0 then
|
||||||
|
local result_string = table.concat(job:result(), "")
|
||||||
|
local data = vim.json.decode(result_string)
|
||||||
|
callback({ memos = data.memos or {}, nextPageToken = data.nextPageToken or "" })
|
||||||
|
else
|
||||||
|
vim.schedule(function() vim.notify("Failed to fetch memos.", vim.log.levels.ERROR) end)
|
||||||
|
callback(nil)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 【修改】让 create_memo 的回调函数返回新创建的 memo 对象
|
||||||
|
function M.create_memo(content, callback)
|
||||||
|
local create_url = config.host .. '/api/v1/memos'
|
||||||
|
local json_data = vim.json.encode({ content = content })
|
||||||
|
run_curl({
|
||||||
|
'-s', '--fail', '-X', 'POST', create_url,
|
||||||
|
'-H', 'Content-Type: application/json',
|
||||||
|
'--data', json_data,
|
||||||
|
}, function(job, return_val)
|
||||||
|
if return_val == 0 then
|
||||||
|
local result_string = table.concat(job:result(), "")
|
||||||
|
local new_memo = vim.json.decode(result_string)
|
||||||
|
callback(new_memo)
|
||||||
|
else
|
||||||
|
callback(nil)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.update_memo(memo_name, content, callback)
|
||||||
|
local update_url = config.host .. '/api/v1/' .. memo_name
|
||||||
|
local json_data = vim.json.encode({ content = content })
|
||||||
|
run_curl({
|
||||||
|
'-s', '--fail', '-X', 'PATCH', update_url,
|
||||||
|
'-H', 'Content-Type: application/json',
|
||||||
|
'--data', json_data,
|
||||||
|
}, function(job, return_val)
|
||||||
|
callback(return_val == 0)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.delete_memo(memo_name, callback)
|
||||||
|
local delete_url = config.host .. '/api/v1/' .. memo_name
|
||||||
|
run_curl({
|
||||||
|
'-s', '--fail', '-X', 'DELETE', delete_url,
|
||||||
|
}, function(job, return_val)
|
||||||
|
callback(return_val == 0)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
||||||
43
lua/memos/init.lua
Normal file
43
lua/memos/init.lua
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
local M = {}
|
||||||
|
|
||||||
|
M.config = {
|
||||||
|
host = nil,
|
||||||
|
token = nil,
|
||||||
|
pageSize = 50,
|
||||||
|
keymaps = {
|
||||||
|
-- 在列表窗口中的快捷键
|
||||||
|
list = {
|
||||||
|
add_memo = "a",
|
||||||
|
delete_memo = "d",
|
||||||
|
delete_memo_visual = "dd", -- 和 d 功能一样,为了符合习惯
|
||||||
|
edit_memo = "<CR>",
|
||||||
|
vsplit_edit_memo = "<Tab>",
|
||||||
|
search_memos = "s",
|
||||||
|
refresh_list = "r",
|
||||||
|
next_page = ".",
|
||||||
|
quit = "q",
|
||||||
|
},
|
||||||
|
-- 在编辑和创建窗口中的快捷键
|
||||||
|
buffer = {
|
||||||
|
save = "<leader>ms",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
function M.setup(opts)
|
||||||
|
-- 使用 "force" 策略,并将默认配置放在前面,用户的配置在后面
|
||||||
|
M.config = vim.tbl_deep_extend("force", M.config, opts or {})
|
||||||
|
if not M.config.host or not M.config.token then
|
||||||
|
vim.notify("Memos: `host` and `token` must be configured.", vim.log.levels.ERROR)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.create_memo()
|
||||||
|
require("memos.ui").create_memo_in_buffer()
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.show_list()
|
||||||
|
require("memos.ui").show_memos_list()
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
||||||
251
lua/memos/ui.lua
Normal file
251
lua/memos/ui.lua
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
local api = require('memos.api')
|
||||||
|
local config = require('memos').config
|
||||||
|
|
||||||
|
local M = {}
|
||||||
|
|
||||||
|
-- 存放状态的变量
|
||||||
|
local memos_cache = {}
|
||||||
|
local buf_id = nil
|
||||||
|
local current_page_token = nil
|
||||||
|
local current_user = nil
|
||||||
|
local current_filter = nil
|
||||||
|
|
||||||
|
-- ===================================================================
|
||||||
|
-- 首先定义所有会被其他函数调用的 local "辅助" 函数
|
||||||
|
-- ===================================================================
|
||||||
|
|
||||||
|
-- 渲染 Memos 列表到 buffer
|
||||||
|
local function render_memos(data, append)
|
||||||
|
vim.schedule(function()
|
||||||
|
if not buf_id or not vim.api.nvim_buf_is_valid(buf_id) then return end
|
||||||
|
local new_memos = data.memos or {}
|
||||||
|
current_page_token = data.nextPageToken or ""
|
||||||
|
if append then
|
||||||
|
memos_cache = vim.list_extend(memos_cache, new_memos)
|
||||||
|
else
|
||||||
|
memos_cache = new_memos
|
||||||
|
end
|
||||||
|
local lines = {}
|
||||||
|
local k = config.keymaps.list
|
||||||
|
if #memos_cache == 0 then
|
||||||
|
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)
|
||||||
|
else
|
||||||
|
for i, memo in ipairs(memos_cache) do
|
||||||
|
local first_line = memo.content:match("^[^\n]*")
|
||||||
|
local display_time = memo.displayTime:sub(1, 10)
|
||||||
|
table.insert(lines, string.format("%d. [%s] %s", i, display_time, first_line))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if current_page_token ~= "" then
|
||||||
|
table.insert(lines, "...")
|
||||||
|
table.insert(lines, string.format("(Press '%s' to load more)", k.next_page))
|
||||||
|
end
|
||||||
|
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_option(buf_id, 'modifiable', false)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 设置编辑 buffer 的通用函数
|
||||||
|
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'
|
||||||
|
|
||||||
|
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
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 打开一个已存在的 Memo
|
||||||
|
local function open_memo_for_edit(memo, open_cmd)
|
||||||
|
vim.cmd(open_cmd)
|
||||||
|
local first_line = memo.content:match("^[^\n]*")
|
||||||
|
local buffer_name = "memos/" .. memo.name:gsub("memos/", "") .. "/" .. first_line:gsub("[/\\]", "_"):sub(1, 50) .. ".md"
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
-- ===================================================================
|
||||||
|
-- 然后定义所有对外暴露的 M.xxx 函数,确保它们能访问到上面的 local 函数
|
||||||
|
-- ===================================================================
|
||||||
|
|
||||||
|
-- 【修正】将此函数移到 render_memos 定义之后,解决报错
|
||||||
|
function M.refresh_list_silently()
|
||||||
|
if not current_user or not current_user.name then return end
|
||||||
|
api.list_memos(current_user.name, current_filter, config.pageSize, nil, function(data)
|
||||||
|
render_memos(data, false)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.save_or_create_dispatcher()
|
||||||
|
local memo_name = vim.b.memos_memo_name
|
||||||
|
local content = table.concat(vim.api.nvim_buf_get_lines(0, 0, -1, false), '\n')
|
||||||
|
|
||||||
|
if content == '' then
|
||||||
|
vim.notify("Memo is empty, not sending.", vim.log.levels.WARN)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if memo_name then
|
||||||
|
api.update_memo(memo_name, content, function(success)
|
||||||
|
if success then
|
||||||
|
vim.schedule(function() vim.notify("✅ Memo updated successfully!") end)
|
||||||
|
M.refresh_list_silently()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
api.create_memo(content, function(new_memo)
|
||||||
|
if new_memo and new_memo.name then
|
||||||
|
vim.schedule(function()
|
||||||
|
vim.notify("✅ Memo created successfully!")
|
||||||
|
vim.cmd('bdelete!') -- 强制关闭临时的 new_memo buffer
|
||||||
|
open_memo_for_edit(new_memo, 'enew') -- 用新 memo 的信息打开一个标准的编辑窗口
|
||||||
|
M.refresh_list_silently()
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
vim.schedule(function() vim.notify("❌ Failed to create memo.", vim.log.levels.ERROR) end)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.create_memo_in_buffer()
|
||||||
|
vim.cmd('enew')
|
||||||
|
vim.b.memos_memo_name = nil
|
||||||
|
vim.api.nvim_buf_set_name(0, "memos/new_memo.md")
|
||||||
|
setup_buffer_for_editing()
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.show_memos_list(filter)
|
||||||
|
current_filter = filter
|
||||||
|
local should_create_buf = true
|
||||||
|
if buf_id and vim.api.nvim_buf_is_valid(buf_id) then
|
||||||
|
should_create_buf = false
|
||||||
|
else
|
||||||
|
buf_id = vim.api.nvim_create_buf(true, true) -- listed = true, scratch = true
|
||||||
|
vim.api.nvim_buf_set_name(buf_id, " Memos")
|
||||||
|
vim.bo[buf_id].buftype = 'nofile'
|
||||||
|
vim.bo[buf_id].swapfile = false
|
||||||
|
vim.bo[buf_id].filetype = 'memos_list'
|
||||||
|
vim.bo[buf_id].modifiable = false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 【修正】确保跳转到列表窗口,并且是在当前窗口打开
|
||||||
|
local win_id = vim.fn.bufwinid(buf_id)
|
||||||
|
if win_id ~= -1 then
|
||||||
|
vim.api.nvim_set_current_win(win_id)
|
||||||
|
else
|
||||||
|
vim.api.nvim_set_current_buf(buf_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
vim.schedule(function() vim.notify("Getting user info...") end)
|
||||||
|
api.get_current_user(function(user)
|
||||||
|
if user and user.name then
|
||||||
|
current_user = user
|
||||||
|
vim.schedule(function() vim.notify("Fetching memos for " .. user.name .. "...") end)
|
||||||
|
api.list_memos(user.name, current_filter, config.pageSize, nil, function(data)
|
||||||
|
render_memos(data, false)
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
vim.schedule(function() vim.notify("Could not get user, aborting fetch.", vim.log.levels.ERROR) end)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
local function set_keymap(key, command)
|
||||||
|
if key and key ~= "" then
|
||||||
|
vim.api.nvim_buf_set_keymap(buf_id, 'n', key, command, { noremap = true, silent = true })
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if config.keymaps and config.keymaps.list then
|
||||||
|
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.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.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.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.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>')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.load_next_page()
|
||||||
|
if not current_page_token or current_page_token == "" then
|
||||||
|
vim.notify("No more pages to load.", vim.log.levels.INFO)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if not current_user or not current_user.name then
|
||||||
|
vim.notify("User info not available.", vim.log.levels.WARN)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
vim.schedule(function() vim.notify("Loading next page...") end)
|
||||||
|
api.list_memos(current_user.name, current_filter, config.pageSize, current_page_token, function(data)
|
||||||
|
render_memos(data, true)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.edit_selected_memo()
|
||||||
|
local line_num = vim.api.nvim_win_get_cursor(0)[1]
|
||||||
|
local selected_memo = memos_cache[line_num]
|
||||||
|
if selected_memo then
|
||||||
|
open_memo_for_edit(selected_memo, 'enew')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.edit_selected_memo_in_vsplit()
|
||||||
|
local line_num = vim.api.nvim_win_get_cursor(0)[1]
|
||||||
|
local selected_memo = memos_cache[line_num]
|
||||||
|
if selected_memo then
|
||||||
|
open_memo_for_edit(selected_memo, 'vsplit | enew')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.confirm_delete_memo()
|
||||||
|
local line_num = vim.api.nvim_win_get_cursor(0)[1]
|
||||||
|
local selected_memo = memos_cache[line_num]
|
||||||
|
if not selected_memo then return end
|
||||||
|
local choice = vim.fn.confirm("Delete this memo?\n[" .. selected_memo.content:sub(1, 50) .. "...]", "&Yes\n&No", 2)
|
||||||
|
if choice == 1 then
|
||||||
|
api.delete_memo(selected_memo.name, function(success)
|
||||||
|
if success then
|
||||||
|
vim.schedule(function()
|
||||||
|
vim.notify("✅ Memo deleted.")
|
||||||
|
M.show_memos_list(current_filter)
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
vim.schedule(function() vim.notify("❌ Failed to delete memo.", vim.log.levels.ERROR) end)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.search_memos()
|
||||||
|
vim.ui.input({ prompt = "Search Memos: " }, function(input)
|
||||||
|
M.show_memos_list(input or "")
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
||||||
23
plugin/memos.lua
Normal file
23
plugin/memos.lua
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
-- 创建新 Memo 的命令
|
||||||
|
vim.api.nvim_create_user_command(
|
||||||
|
'MemosCreate',
|
||||||
|
function()
|
||||||
|
require('memos').create_memo()
|
||||||
|
end,
|
||||||
|
{
|
||||||
|
nargs = 0,
|
||||||
|
desc = "Create a new Memos entry"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
-- 【新增】查看 Memos 列表的命令
|
||||||
|
vim.api.nvim_create_user_command(
|
||||||
|
'Memos',
|
||||||
|
function()
|
||||||
|
require('memos').show_list()
|
||||||
|
end,
|
||||||
|
{
|
||||||
|
nargs = 0,
|
||||||
|
desc = "List and search your Memos"
|
||||||
|
}
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user