Skip to content

Commit 47ce327

Browse files
committed
feat(link)!: wrap link actions (normal/visual)
refactor: remove `expr` in kmp
1 parent cb5e435 commit 47ce327

8 files changed

+139
-57
lines changed

README.md

+6-13
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,18 @@
77
```
88

99
## Config
10+
see `config.lua`
1011
```lua
11-
{
12+
local default_opts = {
1213
ft = { "markdown", "typst" },
1314
line = "<c- >",
1415
codeblock = "<c-e>",
1516
listdn = "o",
1617
listup = "O",
17-
},
18+
img_link = "<leader>zi",
19+
raw_link = "<leader>zj",
20+
}
1821
```
1922

2023
## API
21-
```lua
22-
vim.api.nvim_create_autocmd("Filetype", {
23-
pattern = { "markdown" },
24-
callback = function()
25-
vim.keymap.set({ "x", "n" }, "<c- >", require("mder").line, { buffer = 0 })
26-
vim.keymap.set({ "x" }, "<c-e>", require("mder").codeblock, { buffer = 0 })
27-
vim.keymap.set({ "n" }, "o", require("mder").listdn, { expr = true, buffer = 0 })
28-
vim.keymap.set({ "n" }, "O", require("mder").listup, { expr = true, buffer = 0 })
29-
end,
30-
})
31-
```
24+
see `commands.lua`

lua/mder/autolist.lua

+17-8
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,31 @@
1+
local M = {}
2+
13
-- auto list item
24
local autolist = function(c)
35
return function()
46
local row = vim.api.nvim_win_get_cursor(0)[1]
57
local line = vim.api.nvim_buf_get_lines(0, row - 1, row, false)[1]
6-
for it, pat in pairs {
8+
for it, p in pairs {
79
["-"] = "%-",
810
["+"] = "%+",
911
["*"] = "%*",
1012
["="] = "%=",
1113
} do
12-
if line:find("^%s*" .. pat .. " %[ %]") then return c .. it .. " [ ] " end
13-
if line:find("^%s*" .. pat .. " ") then return c .. it .. " " end
14+
if line:find("^%s*" .. p .. " %[x%]") then
15+
vim.api.nvim_feedkeys(c .. it .. " [x] ", "n", false)
16+
return
17+
end
18+
if line:find("^%s*" .. p .. " %[ %]") then
19+
vim.api.nvim_feedkeys(c .. it .. " [ ] ", "n", false)
20+
return
21+
end
22+
if line:find("^%s*" .. p .. " ") then vim.api.nvim_feedkeys(c .. it .. " ", "n", false) end
1423
end
15-
return c
24+
vim.api.nvim_feedkeys(c, "n", false)
1625
end
1726
end
1827

19-
return {
20-
listup = autolist "O",
21-
listdn = autolist "o",
22-
}
28+
M.listup = autolist "O"
29+
M.listdn = autolist "o"
30+
31+
return M

lua/mder/codeblock.lua

+3-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
local k = require("mder.utils").k
2-
31
-- surround codeblock with correct indent
42
local wrap_codeblock = function()
53
local vs, ve = vim.fn.getpos(".")[2], vim.fn.getpos("v")[2]
@@ -12,11 +10,11 @@ local wrap_codeblock = function()
1210
lines[#lines + 1] = "```"
1311
vim.api.nvim_buf_set_lines(0, vs, ve, false, lines)
1412

15-
vim.api.nvim_feedkeys(k "<esc>", "x", false)
13+
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("<esc>", true, true, true), "x", false)
1614
vim.api.nvim_win_set_cursor(0, { vs + 1, 3 })
17-
vim.api.nvim_feedkeys(k "A", "n", false)
15+
vim.api.nvim_feedkeys("A", "n", false)
1816
end
1917

2018
return {
21-
codeblock = wrap_codeblock,
19+
wrap_codeblock = wrap_codeblock,
2220
}

lua/mder/commands.lua

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
return {
2-
codeblock = function() return require("mder.codeblock").codeblock() end,
3-
line = function() return require("mder.line").line() end,
2+
codeblock = function() return require("mder.codeblock").wrap_codeblock() end,
3+
line = function() return require("mder.line").toggle_lines() end,
44
listdn = function() return require("mder.autolist").listdn() end,
55
listup = function() return require("mder.autolist").listup() end,
6+
img_link = function() return require("mder.link").wrap_or_paste_img() end,
7+
raw_link = function() return require("mder.link").wrap_or_paste_raw() end,
68
}

lua/mder/config.lua

+27-18
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,31 @@
1+
local M = {}
2+
13
local default_opts = {
24
ft = { "markdown", "typst" },
3-
line = "<c- >",
4-
codeblock = "<c-e>",
5-
listdn = "o",
6-
listup = "O",
5+
keymap = {
6+
line = "<c- >",
7+
codeblock = "<c-e>",
8+
listdn = "o",
9+
listup = "O",
10+
img_link = "<leader>zi",
11+
raw_link = "<leader>zj",
12+
},
713
}
814

9-
return {
10-
setup = function(opts)
11-
opts = vim.tbl_deep_extend("force", default_opts, opts or {})
12-
vim.api.nvim_create_autocmd("Filetype", {
13-
pattern = opts.ft,
14-
callback = function()
15-
vim.keymap.set({ "x", "n" }, opts.line, require("mder").line, { buffer = 0 })
16-
vim.keymap.set({ "x" }, opts.codeblock, require("mder").codeblock, { buffer = 0 })
17-
vim.keymap.set({ "n" }, opts.listdn, require("mder").listdn, { expr = true, buffer = 0 })
18-
vim.keymap.set({ "n" }, opts.listup, require("mder").listup, { expr = true, buffer = 0 })
19-
end,
20-
})
21-
end,
22-
}
15+
M.setup = function(opts)
16+
opts = vim.tbl_deep_extend("force", default_opts, opts or {})
17+
vim.api.nvim_create_autocmd("Filetype", {
18+
pattern = opts.ft,
19+
callback = function()
20+
local map = function(mode, act) vim.keymap.set(mode, opts.keymap[act], require("mder")[act], { buffer = 0 }) end
21+
map({ "n", "x" }, "line")
22+
map({ "x" }, "codeblock")
23+
map({ "n" }, "listdn")
24+
map({ "n" }, "listup")
25+
map({ "n", "x" }, "img_link")
26+
map({ "n", "x" }, "raw_link")
27+
end,
28+
})
29+
end
30+
31+
return M

lua/mder/line.lua

+3-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
local getvpos = require("mder.utils").getvpos
2-
31
local check = "%[x%]"
42
local empty = "%[ %]"
53

@@ -39,13 +37,13 @@ local toggle_line = function(line)
3937
return make_box(line)
4038
end
4139

42-
local line = function()
43-
local vs, ve = getvpos()
40+
local toggle_lines = function()
41+
local vs, ve = require("mder.utils").visual_region()
4442
local lines = vim.api.nvim_buf_get_lines(0, vs, ve, false)
4543
vim.api.nvim_buf_set_lines(0, vs, ve, false, vim.iter(lines):map(toggle_line):totable())
4644
end
4745

4846
return {
49-
line = line,
47+
toggle_lines = toggle_lines,
5048
toggle_line = toggle_line,
5149
}

lua/mder/link.lua

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
local M = {}
2+
3+
-- wrap url, then paste it
4+
local paste = function(wrap_cb, url)
5+
if not url then
6+
local text = vim.fn.getreg "+"
7+
if text == nil then return end
8+
-- TODO: whatever, treat it as url now
9+
url = text:gsub("\n", "")
10+
end
11+
url = wrap_cb(url)
12+
vim.api.nvim_paste(url, true, 1)
13+
end
14+
15+
-- return line with wrapped url, or nil if no url in line
16+
-- TODO: also skip if wrapped url exist
17+
-- TODO: two or more url
18+
local wrap_line = function(cb, line)
19+
-- https://github.com/sportshead/gx.nvim/blob/77241c1508883882c027aa971b98cd0631ff2a10/lua/gx/helper.lua?plain=1#L49-L60
20+
local url_patterns = {
21+
"(https?://[a-zA-Z%d_/%%%-%.~@\\+#=?&:]+)",
22+
"([a-zA-Z%d_/%-%.~@\\+#]+%.[a-zA-Z%d_/%%%-%.~@\\+#=?&:]+)",
23+
}
24+
local s, e
25+
for _, p in ipairs(url_patterns) do
26+
s, e = line:find(p)
27+
if s then break end
28+
end
29+
if not s then return nil end
30+
local url = line:sub(s, e) -- NOTE: may not contain 'https?://'
31+
url = cb(url)
32+
line = line:sub(1, s - 1) .. url .. line:sub(e + 1)
33+
return line
34+
end
35+
36+
-- normal mode only
37+
local wrap_or_paste = function(cb)
38+
local line = vim.api.nvim_get_current_line()
39+
local wrapped = wrap_line(cb, line)
40+
if not wrapped then return paste(cb) end
41+
vim.api.nvim_set_current_line(wrapped)
42+
end
43+
44+
local wrap_lines = function(cb)
45+
-- normal: wrap or paste
46+
local mode = vim.api.nvim_get_mode().mode
47+
if mode == "n" then return wrap_or_paste(cb) end
48+
-- visual: linewise wrap
49+
local vs, ve = require("mder.utils").visual_region()
50+
local lines = vim.api.nvim_buf_get_lines(0, vs, ve, false)
51+
lines = vim.tbl_map(function(line) return wrap_line(cb, line) or line end, lines)
52+
vim.api.nvim_buf_set_lines(0, vs, ve, false, lines)
53+
end
54+
55+
-- wrap with pos inicator...
56+
local img_cb = function(url, prefix, name)
57+
prefix = prefix or "img:"
58+
name = name or ""
59+
return ("![%s%s](%s)"):format(prefix, name, url), #prefix + 3, #prefix + #name + 5
60+
end
61+
62+
local raw_cb = function(url) return "<" .. url .. ">", 2 end
63+
64+
local link_cb = function(url, prefix, name)
65+
prefix = prefix or "img:"
66+
name = name or ""
67+
return ("[%s%s](%s)"):format(prefix, name, url), #prefix + 2, #prefix + #name + 4
68+
end
69+
70+
M.wrap_or_paste_img = function() wrap_lines(img_cb) end
71+
M.wrap_or_paste_raw = function() wrap_lines(raw_cb) end
72+
M.wrap_or_paste_link = function() wrap_lines(link_cb) end
73+
74+
return M

lua/mder/utils.lua

+5-6
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1-
local getvpos = function()
2-
local vs, ve = vim.fn.getpos(".")[2], vim.fn.getpos("v")[2]
1+
-- 0-index, exclusive, linewise
2+
-- also "correct" in normal mode
3+
local visual_region = function()
4+
local vs, ve = vim.fn.line ".", vim.fn.line "v"
35
if vs > ve then
46
vs, ve = ve, vs
57
end
68
return vs - 1, ve
79
end
810

9-
local k = function(str) return vim.api.nvim_replace_termcodes(str, true, true, true) end
10-
1111
return {
12-
getvpos = getvpos,
13-
k = k,
12+
visual_region = visual_region,
1413
}

0 commit comments

Comments
 (0)