Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# flash-zh.nvim

基于[flash.nvim](https://github.com/folke/flash.nvim)以及小鹤双拼,neovim 中文跳转插件。
基于[flash.nvim](https://github.com/folke/flash.nvim)的 Neovim 中文跳转插件,支持小鹤双拼(默认)与拼音加加双拼

![iShot_2023-10-05_19 32 53](https://github.com/rainzm/flash-zh.nvim/assets/22927169/4c3ca124-0fee-48a2-b7c6-17391afe8d0e)

Expand Down Expand Up @@ -44,6 +44,19 @@ return {{

**如果想要跳转的地方没有 label 出现,接着输入即可,和查找一样。**

### 选择双拼方案

插件内置两套方案:

- `flypy`:小鹤双拼(默认)
- `pyjj`:拼音加加双拼

```lua
require("flash-zh").setup({
scheme = "pyjj",
})
```

### 自定义匹配字符

- 你可以覆盖、或是追加字符到默认的匹配字符集。
Expand Down Expand Up @@ -73,4 +86,3 @@ return {{
## 感谢

- [hop-zh-by-flypy](https://github.com/zzhirong/hop-zh-by-flypy)

54 changes: 54 additions & 0 deletions lua/flash-zh/char_map.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
local flypy = require("flash-zh.flypy")

local M = {}

---@class FlashZhCharMap
---@field comma table<string,string>
---@field escape table<string,string>
---@field char1patterns table<string,string>
---@field char2patterns table<string,string>

local current_name = "flypy"
---@type FlashZhCharMap
local current_map = flypy

---@type table<string, FlashZhCharMap>
local cache = {
flypy = flypy,
}

local function build(name)
if cache[name] then
return cache[name]
end
if name == "pyjj" then
local pyjj = require("flash-zh.pyjj")
cache.pyjj = pyjj.from_flypy(flypy)
return cache.pyjj
end
error("unknown scheme: " .. tostring(name))
end

---@return string
function M.name()
return current_name
end

---@return FlashZhCharMap
function M.get()
return current_map
end

---@param name string
function M.set(name)
name = name or "flypy"
current_map = build(name)
current_name = name
end

function M.available()
return { "flypy", "pyjj" }
end

return M

122 changes: 88 additions & 34 deletions lua/flash-zh/init.lua
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
local flash = require("flash")
local flypy = require("flash-zh.flypy")
local char_map = require("flash-zh.char_map")

local M = {}

function M.jump(opts)
opts = opts or {}

-- Allow per-jump override so users can verify schemes quickly,
-- and so it still works even if setup() was not called (common with lazy.nvim misconfig).
if opts.scheme then
require("flash-zh.char_map").set(opts.scheme)
opts.scheme = nil
end

local mode = M.mix_mode
if opts.chinese_only then
mode = M.zh_mode
Expand All @@ -16,10 +25,35 @@ function M.jump(opts)
labeler = function(_, state)
require("flash-zh.labeler").new(state):update()
end,
}, opts or {})
}, opts)
flash.jump(opts)
end

function M.remote(opts)
opts = opts or {}

-- Same behavior as jump(), but performs a remote operation (operator-pending).
if opts.scheme then
require("flash-zh.char_map").set(opts.scheme)
opts.scheme = nil
end

local mode = M.mix_mode
if opts.chinese_only then
mode = M.zh_mode
end
opts = vim.tbl_deep_extend("force", {
labels = "asdfghjklqwertyuiopzxcvbnm",
search = {
mode = mode,
},
labeler = function(_, state)
require("flash-zh.labeler").new(state):update()
end,
}, opts)
flash.remote(opts)
end

function M.mix_mode(str)
local all_possible_splits = M.parser(str)
local regexs = { [[\(]] }
Expand All @@ -33,38 +67,48 @@ function M.mix_mode(str)
end

function M.zh_mode(str)
local map = char_map.get()
local regexs = {}
while string.len(str) > 1 do
regexs[#regexs + 1] = flypy.char2patterns[string.sub(str, 1, 2)]
local orig = string.sub(str, 1, 2)
local k = orig:lower()
-- Be defensive: unknown keys should not crash the search.
regexs[#regexs + 1] = map.char2patterns[k] or ("[" .. orig:lower() .. orig:upper() .. "]")
str = string.sub(str, 3)
end
if string.len(str) == 1 then
regexs[#regexs + 1] = flypy.char1patterns[str]
local orig = str
local k = orig:lower()
regexs[#regexs + 1] = map.char1patterns[k] or ("[" .. orig:lower() .. orig:upper() .. "]")
end
local ret = table.concat(regexs)
return ret, ret
end

local nodes = {
alpha = function(str)
return "[" .. str .. string.upper(str) .. "]"
end,
pinyin = function(str)
return flypy.char2patterns[str]
end,
comma = function(str)
return flypy.comma[str]
end,
singlepin = function(str)
return flypy.char1patterns[str]
end,
other = function(str)
str = flypy.escape[str] or str
return str
end,
}
local function get_nodes(map)
return {
alpha = function(str)
return "[" .. str:lower() .. str:upper() .. "]"
end,
pinyin = function(str)
return map.char2patterns[str]
end,
comma = function(str)
return map.comma[str]
end,
singlepin = function(str)
return map.char1patterns[str]
end,
other = function(str)
str = map.escape[str] or str
return str
end,
}
end

function M.regex(parser)
local map = char_map.get()
local nodes = get_nodes(map)
local regexs = {}
for _, v in ipairs(parser) do
regexs[#regexs + 1] = nodes[v.type](v.str)
Expand All @@ -73,26 +117,28 @@ function M.regex(parser)
end

function M.parser(str, prefix)
local map = char_map.get()
prefix = prefix or {}
local firstchar = string.sub(str, 1, 1)
local chars = {}
for k, _ in pairs(flypy.comma) do
for k, _ in pairs(map.comma) do
table.insert(chars, k)
end
if firstchar == "" then
return { prefix }
elseif string.match(firstchar, "%l") then
elseif string.match(firstchar, "%a") then
local secondchar = string.sub(str, 2, 2)
if secondchar == "" then
local prefix2 = M.copy(prefix)
prefix[#prefix + 1] = { str = firstchar, type = "alpha" }
prefix2[#prefix2 + 1] = { str = firstchar, type = "singlepin" }
prefix2[#prefix2 + 1] = { str = firstchar:lower(), type = "singlepin" }
return { prefix, prefix2 }
elseif string.match(secondchar, "%a") then
if flypy.char2patterns[firstchar .. secondchar] then
local code = (firstchar .. secondchar):lower()
if map.char2patterns[code] then
local prefix2 = M.copy(prefix)
prefix2[#prefix2 + 1] = { str = firstchar, type = "alpha" }
prefix[#prefix + 1] = { str = firstchar .. secondchar, type = "pinyin" }
prefix[#prefix + 1] = { str = code, type = "pinyin" }
local str2 = string.sub(str, 2, -1)
str = string.sub(str, 3, -1)
return M.merge_table(M.parser(str, prefix), M.parser(str2, prefix2))
Expand Down Expand Up @@ -139,24 +185,32 @@ function M.copy(table)
end

-- @param opts table
-- @field[opt] opts.scheme string Choose the built-in shuangpin scheme. One of: "flypy", "pyjj".
-- @field opts.char_map table Char map for flypy.
-- @field[opt] opts.char_map.comma table Override the default comma map.
-- @field[opt] opts.char_map.append_comma table Append to the default comma map.
-- @field[opt] opts.char_map.append_char1 table Append to the default char1patterns map.
-- @field[opt] opts.char_map.append_char2 table Append to the default char2patterns map.
function M.setup(opts)
opts = opts or {}

if opts.scheme then
char_map.set(opts.scheme)
end

if not opts.char_map then
return
end

local map = char_map.get()
local to_escape = "\\^$*+?.%|[]()"
if opts.char_map.comma then
for k, v in pairs(opts.char_map.comma) do
if #k ~= 1 then
error("comma key must be a single character")
else
v = vim.fn.escape(v, to_escape)
flypy.comma[k] = "[" .. v .. "]"
map.comma[k] = "[" .. v .. "]"
end
end
end
Expand All @@ -165,9 +219,9 @@ function M.setup(opts)
if #k ~= 1 then
error("append_comma key must be a single character")
else
local chars = flypy.comma[k] or ""
local chars = map.comma[k] or ""
chars = string.sub(chars, 2, -2) .. vim.fn.escape(v, to_escape)
flypy.comma[k] = "[" .. chars .. "]"
map.comma[k] = "[" .. chars .. "]"
end
end
end
Expand All @@ -176,9 +230,9 @@ function M.setup(opts)
if #k ~= 1 then
error("append_char1 key must be a single character")
else
local chars = flypy.char1patterns[k] or ""
local chars = map.char1patterns[k] or ""
chars = string.sub(chars, 2, -2) .. vim.fn.escape(v, to_escape)
flypy.char1patterns[k] = "[" .. chars .. "]"
map.char1patterns[k] = "[" .. chars .. "]"
end
end
end
Expand All @@ -187,9 +241,9 @@ function M.setup(opts)
if #k ~= 2 then
error("append_char2 key must be two characters")
else
local chars = flypy.char2patterns[k] or ""
local chars = map.char2patterns[k] or ""
chars = string.sub(chars, 2, -2) .. vim.fn.escape(v, to_escape)
flypy.char2patterns[k] = "[" .. chars .. "]"
map.char2patterns[k] = "[" .. chars .. "]"
end
end
end
Expand Down
Loading