Skip to content
Open
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.todo.md
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,10 @@ require("dial.config").augends:register_group{
|`augend.constant.alias.alpha` |Lowercase alphabet letter (word) |`a`, `b`, `c`, ..., `z` |
|`augend.constant.alias.Alpha` |Uppercase alphabet letter (word) |`A`, `B`, `C`, ..., `Z` |
|`augend.semver.alias.semver` |Semantic version |`0.3.0`, `1.22.1`, `3.9.1`, ... |
|`augend.ordinal.alias.en` |English shortform ordinal numbers |`0th`, `1st`, `2nd`, `3rd`, `4th`, ... |
|`augend.ordinal.alias.en_neg` |English shortform ordinal numbers including negatives |..., `-1st`, `0th`, `1st`, `2nd`, `3rd`, `4th`, ... |
|`augend.ordinal.alias.en_old` |English shortform ordinal numbers - archaic |`0th`, `1st`, `2d`, `3d`, `4th`, ... |
|`augend.misc.alias.markdown_header` |ATX-Style markdown headings |`# This is a title`, `### Notes` |


If you don't specify any settings, the following augends is set as the value of the `default` group.
Expand Down
6 changes: 6 additions & 0 deletions doc/dial.txt
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ for a particular filetype.
},
markdown = {
augend.integer.alias.decimal,
augend.ordinal.alias.en,
augend.misc.alias.markdown_header,
}
}
Expand Down Expand Up @@ -337,6 +338,11 @@ The following aliases are provided by default (See |dial-augends| for detail):
`augend.paren.alias.lua_str_literal`
`augend.paren.alias.rust_str_literal`

ordinal:
`augend.ordinal.alias.en`
`augend.ordinal.alias.en_neg`
`augend.ordinal.alias.en_old`

misc:
`augend.misc.alias.markdown_header`

Expand Down
2 changes: 2 additions & 0 deletions lua/dial/augend.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ local date = require "dial.augend.date"
local decimal_fraction = require "dial.augend.decimal_fraction"
local hexcolor = require "dial.augend.hexcolor"
local integer = require "dial.augend.integer"
local ordinal = require "dial.augend.ordinal"
local semver = require "dial.augend.semver"
local user = require "dial.augend.user"
local paren = require "dial.augend.paren"
Expand All @@ -16,6 +17,7 @@ return {
decimal_fraction = decimal_fraction,
hexcolor = hexcolor,
integer = integer,
ordinal = ordinal,
semver = semver,
user = user,
paren = paren,
Expand Down
53 changes: 39 additions & 14 deletions lua/dial/augend/common.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ local M = {}
---augend の find field を簡単に実装する。
---@param ptn string
---@param allow_match_before_cursor? boolean
---@param check_query? string
---@return findf
function M.find_pattern(ptn, allow_match_before_cursor)
function M.find_pattern(ptn, allow_match_before_cursor, check_query)
---@param line string
---@param cursor? integer
---@return textrange?
Expand All @@ -17,7 +18,22 @@ function M.find_pattern(ptn, allow_match_before_cursor)
local idx_start = 1
while idx_start <= #line do
local s, e = line:find(ptn, idx_start)
if s then
if not s then
-- 検索結果がなければそこで終了
break
end
local check_e
if check_query then
_, check_e = line:find(check_query, idx_start)
end
if check_e then
if (cursor == nil or cursor <= e) and check_e == e then
return { from = s, to = e }
else
match_before_cursor = { from = s, to = e }
idx_start = e + 1
end
else
-- 検索結果があったら
if cursor == nil or cursor <= e then
-- cursor が終了文字より後ろにあったら終了
Expand All @@ -27,9 +43,6 @@ function M.find_pattern(ptn, allow_match_before_cursor)
-- 終了文字の後ろから探し始める
idx_start = e + 1
end
else
-- 検索結果がなければそこで終了
break
end
end
if allow_match_before_cursor then
Expand All @@ -43,8 +56,9 @@ end
-- augend の find field を簡単に実装する。
---@param ptn string
---@param allow_match_before_cursor? boolean
---@param check_query? string
---@return findf
function M.find_pattern_regex(ptn, allow_match_before_cursor)
function M.find_pattern_regex(ptn, allow_match_before_cursor, check_query)
---@param line string
---@param cursor? integer
---@return textrange?
Expand All @@ -53,11 +67,25 @@ function M.find_pattern_regex(ptn, allow_match_before_cursor)
local idx_start = 1
while idx_start <= #line do
local s, e = vim.regex(ptn):match_str(line:sub(idx_start))

if s then
s = s + idx_start -- 上で得られた s は相対位置なので
e = e + idx_start - 1 -- 上で得られた s は相対位置なので

if not s then
-- 検索結果がなければそこで終了
break
end
local check_e
if check_query then
_, check_e = vim.regex(check_query):match_str(line:sub(idx_start))
end
s = s + idx_start -- 上で得られた s は相対位置なので
e = e + idx_start - 1 -- 上で得られた s は相対位置なので
if check_e then
check_e = check_e + idx_start - 1
if (cursor == nil or cursor <= e) and check_e == e then
return { from = s, to = e }
else
match_before_cursor = { from = s, to = e }
idx_start = e + 1
end
else
-- 検索結果があったら
if cursor == nil or cursor <= e then
-- cursor が終了文字より後ろにあったら終了
Expand All @@ -67,9 +95,6 @@ function M.find_pattern_regex(ptn, allow_match_before_cursor)
-- 終了文字の後ろから探し始める
idx_start = e + 1
end
else
-- 検索結果がなければそこで終了
break
end
end
if allow_match_before_cursor then
Expand Down
100 changes: 100 additions & 0 deletions lua/dial/augend/ordinal.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
local common = require "dial.augend.common"
local util = require "dial.util"

---@alias ordinalSuffix { default: string, special?: string[] }

---@alias AugendOrdinalConfig { natural?: boolean, suffix?: ordinalSuffix }

---@class AugendOrdinal: Augend
---@field natural boolean
---@field suffix ordinalSuffix
---@field query string
---@field check_query? string
local AugendOrdinal = {}

---@param line string
---@param cursor? integer
---@return textrange?
function AugendOrdinal:find(line, cursor)
return common.find_pattern_regex(self.query, false, self.check_query)(line, cursor)
end

---@param text string
---@param addend integer
---@param cursor? integer
---@return addresult
function AugendOrdinal:add(text, addend, cursor)
local ordinal_query = "%d+"

if not self.natural then
ordinal_query = "-?" .. ordinal_query
end

for ordinal in text:gmatch(ordinal_query) do
local cardinal = ordinal + addend

if (cardinal < 0) and self.natural then
cardinal = 0
end

local remainder = math.abs(cardinal) % 100

-- WARN: the following statement only works for the english language
local suffix = not vim.tbl_contains({ 11, 12, 13 }, remainder) and self.suffix.special[remainder % 10]
or self.suffix.default

text = cardinal .. suffix
end

cursor = 1

return { text = text, cursor = cursor }
end

local M = {}

---@param config AugendOrdinalConfig
---@return Augend
function M.new(config)
vim.validate("natural", config.natural, "boolean", true)
vim.validate("suffix", config.suffix, "table", true)

local natural = util.unwrap_or(config.natural, true)

local suffix = util.unwrap_or(config.suffix, {
default = "th",
special = {
"st",
"nd",
"rd",
},
})

-- WARN: the following queries only work for the english language
local query = ([[\V%s\d\+\a\{1,2}]]):format(util.if_expr(natural, "", [[-\?]]))
local check_query = ([[\V%s\d\+\a\+]]):format(util.if_expr(natural, "", [[-\?]]))

return setmetatable({
natural = natural,
suffix = suffix,
query = query,
check_query = check_query,
}, { __index = AugendOrdinal })
end

M.alias = {
en = M.new {},
en_neg = M.new { natural = false },
en_old = M.new {
suffix = {
default = "th",
special = {
"st",
"d",
"d",
},
},
},
}

return M
Loading