Skip to content

Commit

Permalink
Merge pull request #98 from monaqa/feat-match_before_cursor
Browse files Browse the repository at this point in the history
feat: add `match_before_cursor` field to constant augend
  • Loading branch information
monaqa authored Nov 19, 2024
2 parents ed4d6a5 + 18bfb51 commit 46b4375
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 5 deletions.
8 changes: 8 additions & 0 deletions doc/dial.jax
Original file line number Diff line number Diff line change
Expand Up @@ -981,6 +981,10 @@ CONSTANT *dial-augends-constant*
word = false,
cyclic = true,
},
augend.constant.new{
elements = {"let", "const"},
match_before_cursor = true,
},
},
}
<
Expand All @@ -999,6 +1003,10 @@ CONSTANT *dial-augends-constant*
pattern_regexp (string, default: `\C\V\<\(%s\)\>`)
文字列検索を行う際の正規表現。 elements に指定した文字列を
`%s` に指定します。
match_before_cursor (boolean, default: false)
true のとき、カーソルが対象の単語より後ろにある場合でもマッチ
します。ただし、カーソル上またはカーソルの後に他の有効な被加数が
存在すればそちらが優先されます。

注意: `&&``||` のように、記号からなる文字列を相互変換するときは `cyclic`
を false にしてください。
Expand Down
8 changes: 8 additions & 0 deletions doc/dial.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1014,6 +1014,10 @@ Predefined sequence of strings. You can use this rule with
word = false,
cyclic = true,
},
augend.constant.new{
elements = {"let", "const"},
match_before_cursor = true,
},
},
}
<
Expand All @@ -1033,6 +1037,10 @@ The argument table of `augend.constant.new` can take the following keys:
pattern_regexp (string, default: `\C\V\<\(%s\)\>`)
A regular expression used in search. `%s` represents the string
specified in `elements.`
match_before_cursor (boolean, default: false)
If true, it matches even when the cursor is positioned after
the target word. In that case, however, any other valid augend
on or after the cursor will take precedence.

NOTE: Set `cyclic` to false when cross-converting strings consisting of
symbols, such as `&&` and `||`.
Expand Down
16 changes: 14 additions & 2 deletions lua/dial/augend/common.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ local M = {}

---augend の find field を簡単に実装する。
---@param ptn string
---@param allow_match_before_cursor? boolean
---@return findf
function M.find_pattern(ptn)
function M.find_pattern(ptn, allow_match_before_cursor)
---@param line string
---@param cursor? integer
---@return textrange?
local function f(line, cursor)
local match_before_cursor = nil
local idx_start = 1
while idx_start <= #line do
local s, e = line:find(ptn, idx_start)
Expand All @@ -21,6 +23,7 @@ function M.find_pattern(ptn)
-- cursor が終了文字より後ろにあったら終了
return { from = s, to = e }
else
match_before_cursor = { from = s, to = e }
-- 終了文字の後ろから探し始める
idx_start = e + 1
end
Expand All @@ -29,19 +32,24 @@ function M.find_pattern(ptn)
break
end
end
if allow_match_before_cursor then
return match_before_cursor
end
return nil
end
return f
end

-- augend の find field を簡単に実装する。
---@param ptn string
---@param allow_match_before_cursor? boolean
---@return findf
function M.find_pattern_regex(ptn)
function M.find_pattern_regex(ptn, allow_match_before_cursor)
---@param line string
---@param cursor? integer
---@return textrange?
local function f(line, cursor)
local match_before_cursor = nil
local idx_start = 1
while idx_start <= #line do
local s, e = vim.regex(ptn):match_str(line:sub(idx_start))
Expand All @@ -55,6 +63,7 @@ function M.find_pattern_regex(ptn)
-- cursor が終了文字より後ろにあったら終了
return { from = s, to = e }
else
match_before_cursor = { from = s, to = e }
-- 終了文字の後ろから探し始める
idx_start = e + 1
end
Expand All @@ -63,6 +72,9 @@ function M.find_pattern_regex(ptn)
break
end
end
if allow_match_before_cursor then
return match_before_cursor
end
return nil
end
return f
Expand Down
10 changes: 7 additions & 3 deletions lua/dial/augend/constant.lua
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
local util = require "dial.util"
local common = require "dial.augend.common"

---@alias AugendConstantConfig { elements: string[], cyclic: boolean, pattern_regexp: string, preserve_case: boolean }
---@alias AugendConstantConfig { elements: string[], cyclic: boolean, pattern_regexp: string, preserve_case: boolean, match_before_cursor: boolean }

---@class AugendConstant
---@implement Augend
Expand Down Expand Up @@ -33,7 +33,7 @@ local function preserve_case(word)
return nil
end

---@param config { elements: string[], word?: boolean, cyclic?: boolean, pattern_regexp?: string, preserve_case?: boolean }
---@param config { elements: string[], word?: boolean, cyclic?: boolean, pattern_regexp?: string, preserve_case?: boolean, match_before_cursor?: boolean }
---@return Augend
function M.new(config)
util.validate_list("config.elements", config.elements, "string")
Expand All @@ -43,10 +43,14 @@ function M.new(config)
cyclic = { config.cyclic, "boolean", true },
pattern_regexp = { config.pattern_regexp, "string", true },
preserve_case = { config.preserve_case, "boolean", true },
match_before_cursor = { config.match_before_cursor, "boolean", true },
}
if config.preserve_case == nil then
config.preserve_case = false
end
if config.match_before_cursor == nil then
config.match_before_cursor = false
end
if config.pattern_regexp == nil then
local case_sensitive_flag = util.if_expr(config.preserve_case, [[\c]], [[\C]])
local word = util.unwrap_or(config.word, true)
Expand All @@ -70,7 +74,7 @@ function AugendConstant:find(line, cursor)
return vim.fn.escape(e, [[/\]])
end, self.config.elements)
local vim_regex_ptn = self.config.pattern_regexp:format(table.concat(escaped_elements, [[\|]]))
return common.find_pattern_regex(vim_regex_ptn)(line, cursor)
return common.find_pattern_regex(vim_regex_ptn, self.config.match_before_cursor)(line, cursor)
end

---@param text string
Expand Down
21 changes: 21 additions & 0 deletions tests/dial/augend/constant_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,25 @@ local constant = require("dial.augend").constant

describe("Test of constant between two words", function()
local augend = constant.new { elements = { "true", "false" } }

describe("find function", function()
it("can find a completely matching word", function()
assert.are.same(augend:find("enable = true", 1), { from = 10, to = 13 })
assert.are.same(augend:find("enable = false", 1), { from = 10, to = 14 })
end)
it("does not find a word including element words", function()
assert.are.same(augend:find("mistakenly construed", 1), nil)
end)
it("does not find a word before the cursor when match_before_cursor = false", function()
assert.are.same(augend:find("true negative", 5), nil)
end)
end)

augend = constant.new { elements = { "true", "false" }, match_before_cursor = true }

describe("find function", function()
it("does find a word before the cursor when match_before_cursor = true", function()
assert.are.same(augend:find("true positive", 5), { from = 1, to = 4 })
end)
end)
end)

0 comments on commit 46b4375

Please sign in to comment.