Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactoring #115

Merged
merged 2 commits into from
Jan 19, 2025
Merged
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
3 changes: 3 additions & 0 deletions lua/blink-ripgrep/highlighting.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
local M = {}

--- In the blink documentation window, when the context for the match is being
--- shown, highlight the match so that the user can easily see where the match
--- is.
---@param bufnr number
---@param match blink-ripgrep.RipgrepMatch
---@param highlight_ns_id number
Expand Down
42 changes: 2 additions & 40 deletions lua/blink-ripgrep/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -27,27 +27,6 @@ pcall(function()
end)
vim.api.nvim_set_hl(0, "BlinkRipgrepMatch", { link = "Search", default = true })

local word_pattern
do
-- match an ascii character as well as unicode continuation bytes.
-- Technically, unicode continuation bytes need to be applied in order to
-- construct valid utf-8 characters, but right now we trust that the user
-- only types valid utf-8 in their project.
local char = vim.lpeg.R("az", "AZ", "09", "\128\255")

local non_starting_word_character = vim.lpeg.P(1) - char
local word_character = char + vim.lpeg.P("_") + vim.lpeg.P("-")
local non_middle_word_character = vim.lpeg.P(1) - word_character

word_pattern = vim.lpeg.Ct(
(
non_starting_word_character ^ 0
* vim.lpeg.C(word_character ^ 1)
* non_middle_word_character ^ 0
) ^ 0
)
end

---@type blink-ripgrep.Options
RgSource.config = {
prefix_min_len = 3,
Expand All @@ -67,32 +46,15 @@ function RgSource.setup(options)
RgSource.config = vim.tbl_deep_extend("force", RgSource.config, options or {})
end

---@param text_before_cursor string "The text of the entire line before the cursor"
---@return string
function RgSource.match_prefix(text_before_cursor)
local matches = vim.lpeg.match(word_pattern, text_before_cursor)
local last_match = matches and matches[#matches]
return last_match or ""
end

---@param context blink.cmp.Context
---@return string
local function default_get_prefix(context)
local line = context.line
local col = context.cursor[2]
local text = line:sub(1, col)
local prefix = RgSource.match_prefix(text)
return prefix
end

---@param input_opts blink-ripgrep.Options
function RgSource.new(input_opts)
local self = setmetatable({}, RgSource)

RgSource.config =
vim.tbl_deep_extend("force", RgSource.config, input_opts or {})

self.get_prefix = RgSource.config.get_prefix or default_get_prefix
self.get_prefix = RgSource.config.get_prefix
or require("blink-ripgrep.search_prefix").default_get_prefix

self.get_command = RgSource.config.get_command

Expand Down
45 changes: 45 additions & 0 deletions lua/blink-ripgrep/search_prefix.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
local M = {}

--- The pattern that is used to match the prefix of a search query. The prefix
--- is the text before the cursor that is used to search for matching words in
--- the project.
local word_pattern
do
-- match an ascii character as well as unicode continuation bytes.
-- Technically, unicode continuation bytes need to be applied in order to
-- construct valid utf-8 characters, but right now we trust that the user
-- only types valid utf-8 in their project.
local char = vim.lpeg.R("az", "AZ", "09", "\128\255")

local non_starting_word_character = vim.lpeg.P(1) - char
local word_character = char + vim.lpeg.P("_") + vim.lpeg.P("-")
local non_middle_word_character = vim.lpeg.P(1) - word_character

word_pattern = vim.lpeg.Ct(
(
non_starting_word_character ^ 0
* vim.lpeg.C(word_character ^ 1)
* non_middle_word_character ^ 0
) ^ 0
)
end

---@param text_before_cursor string "The text of the entire line before the cursor"
---@return string
function M.match_prefix(text_before_cursor)
local matches = vim.lpeg.match(word_pattern, text_before_cursor)
local last_match = matches and matches[#matches]
return last_match or ""
end

---@param context blink.cmp.Context
---@return string
function M.default_get_prefix(context)
local line = context.line
local col = context.cursor[2]
local text = line:sub(1, col)
local prefix = M.match_prefix(text)
return prefix
end

return M
2 changes: 2 additions & 0 deletions lua/blink-ripgrep/visualization.lua
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ vim.api.nvim_set_hl(
{ link = "Search", default = true }
)

-- Temporarily flash the search prefix so that the user can see what searches
-- are being performed. Should be called in debug mode only.
---@param prefix string
function visualization.flash_search_prefix(prefix)
vim.api.nvim_buf_clear_namespace(0, ns_id, 0, -1)
Expand Down
146 changes: 73 additions & 73 deletions spec/blink-ripgrep/get_prefix_spec.lua
Original file line number Diff line number Diff line change
@@ -1,82 +1,82 @@
local assert = require("luassert")
local blink_ripgrep = require("blink-ripgrep")
local search_prefix = require("blink-ripgrep.search_prefix")

describe("match_prefix", function()
it("for simple strings", function()
assert.are_same(blink_ripgrep.match_prefix("hello"), "hello")
assert.are_same(blink_ripgrep.match_prefix("abc123"), "abc123")
assert.are_same(blink_ripgrep.match_prefix("abc-123"), "abc-123")
assert.are_same(blink_ripgrep.match_prefix("abc_123"), "abc_123")
assert.are_same(search_prefix.match_prefix("hello"), "hello")
assert.are_same(search_prefix.match_prefix("abc123"), "abc123")
assert.are_same(search_prefix.match_prefix("abc-123"), "abc-123")
assert.are_same(search_prefix.match_prefix("abc_123"), "abc_123")
end)

it(
"matches when there is one nonmatching piece of input in the beginning",
function()
assert.are_same(blink_ripgrep.match_prefix(".hello"), "hello")
assert.are_same(blink_ripgrep.match_prefix(",hello"), "hello")
assert.are_same(search_prefix.match_prefix(".hello"), "hello")
assert.are_same(search_prefix.match_prefix(",hello"), "hello")
assert.are_same(
blink_ripgrep.match_prefix(".,,!@!@$@%<<@$<hello"),
search_prefix.match_prefix(".,,!@!@$@%<<@$<hello"),
"hello"
)
assert.are_same(blink_ripgrep.match_prefix(" hello"), "hello")
assert.are_same(blink_ripgrep.match_prefix("random_text hello"), "hello")
assert.are_same(blink_ripgrep.match_prefix("-- hello"), "hello")
assert.are_same(blink_ripgrep.match_prefix("-- abc123"), "abc123")
assert.are_same(blink_ripgrep.match_prefix("-- abc-123"), "abc-123")
assert.are_same(blink_ripgrep.match_prefix("-- abc_123"), "abc_123")
assert.are_same(search_prefix.match_prefix(" hello"), "hello")
assert.are_same(search_prefix.match_prefix("random_text hello"), "hello")
assert.are_same(search_prefix.match_prefix("-- hello"), "hello")
assert.are_same(search_prefix.match_prefix("-- abc123"), "abc123")
assert.are_same(search_prefix.match_prefix("-- abc-123"), "abc-123")
assert.are_same(search_prefix.match_prefix("-- abc_123"), "abc_123")
end
)

it("matches when there is nonmatching input at the end", function()
assert.are_same(blink_ripgrep.match_prefix(".hello)"), "hello")
assert.are_same(blink_ripgrep.match_prefix(",hello)"), "hello")
assert.are_same(search_prefix.match_prefix(".hello)"), "hello")
assert.are_same(search_prefix.match_prefix(",hello)"), "hello")
assert.are_same(
blink_ripgrep.match_prefix(".,,!@!@$@%<<@$<hello)"),
search_prefix.match_prefix(".,,!@!@$@%<<@$<hello)"),
"hello"
)
assert.are_same(blink_ripgrep.match_prefix(" hello)"), "hello")
assert.are_same(blink_ripgrep.match_prefix("random_text hello)"), "hello")
assert.are_same(blink_ripgrep.match_prefix("-- hello)"), "hello")
assert.are_same(blink_ripgrep.match_prefix("-- abc123)"), "abc123")
assert.are_same(blink_ripgrep.match_prefix("-- abc-123)"), "abc-123")
assert.are_same(blink_ripgrep.match_prefix("-- abc_123)"), "abc_123")
assert.are_same(search_prefix.match_prefix(" hello)"), "hello")
assert.are_same(search_prefix.match_prefix("random_text hello)"), "hello")
assert.are_same(search_prefix.match_prefix("-- hello)"), "hello")
assert.are_same(search_prefix.match_prefix("-- abc123)"), "abc123")
assert.are_same(search_prefix.match_prefix("-- abc-123)"), "abc-123")
assert.are_same(search_prefix.match_prefix("-- abc_123)"), "abc_123")
end)

it("matches when word_characters are in the front", function()
assert.are_same(blink_ripgrep.match_prefix("--hello)"), "hello")
assert.are_same(blink_ripgrep.match_prefix("__hello)"), "hello")
assert.are_same(search_prefix.match_prefix("--hello)"), "hello")
assert.are_same(search_prefix.match_prefix("__hello)"), "hello")
end)

it(
"matches when there is nonmatching input at the beginning and at the end",
function()
assert.are_same(blink_ripgrep.match_prefix('"hello"'), "hello")
assert.are_same(search_prefix.match_prefix('"hello"'), "hello")
end
)

it(
"matches when there are multiple nonmatching pieces of input in the beginning",
function()
assert.are_same(blink_ripgrep.match_prefix(".hello.hello"), "hello")
assert.are_same(blink_ripgrep.match_prefix(",hello,hello"), "hello")
assert.are_same(search_prefix.match_prefix(".hello.hello"), "hello")
assert.are_same(search_prefix.match_prefix(",hello,hello"), "hello")
assert.are_same(
blink_ripgrep.match_prefix(".,,!@!@$@%<<@$<hello.,,!@!@$@%<<@$<hello"),
search_prefix.match_prefix(".,,!@!@$@%<<@$<hello.,,!@!@$@%<<@$<hello"),
"hello"
)
assert.are_same(blink_ripgrep.match_prefix(" hello hello"), "hello")
assert.are_same(search_prefix.match_prefix(" hello hello"), "hello")

assert.are_same(
blink_ripgrep.match_prefix("random_text hello hello"),
search_prefix.match_prefix("random_text hello hello"),
"hello"
)
assert.are_same(blink_ripgrep.match_prefix("-- hello hello"), "hello")
assert.are_same(blink_ripgrep.match_prefix("-- abc123 abc123"), "abc123")
assert.are_same(search_prefix.match_prefix("-- hello hello"), "hello")
assert.are_same(search_prefix.match_prefix("-- abc123 abc123"), "abc123")
assert.are_same(
blink_ripgrep.match_prefix("-- abc-123 abc-123"),
search_prefix.match_prefix("-- abc-123 abc-123"),
"abc-123"
)
assert.are_same(
blink_ripgrep.match_prefix("-- abc_123 abc_123"),
search_prefix.match_prefix("-- abc_123 abc_123"),
"abc_123"
)
end
Expand All @@ -85,72 +85,72 @@ describe("match_prefix", function()
it("for multipart strings", function()
-- three parts
assert.are_same(
blink_ripgrep.match_prefix("hello-world-today"),
search_prefix.match_prefix("hello-world-today"),
"hello-world-today"
)

-- three parts with numbers
assert.are_same(
blink_ripgrep.match_prefix("abc123-def456-ghi789"),
search_prefix.match_prefix("abc123-def456-ghi789"),
"abc123-def456-ghi789"
)

-- multiple parts with mixed dashes and underscores
assert.are_same(
blink_ripgrep.match_prefix("abc-123_def-456_ghi-789"),
search_prefix.match_prefix("abc-123_def-456_ghi-789"),
"abc-123_def-456_ghi-789"
)
end)

it("matches unicode characters", function()
-- umlauts and other special characters
assert.are_same(blink_ripgrep.match_prefix("yöllä"), "yöllä") -- Finnish word with 'ö' and 'ä'
assert.are_same(blink_ripgrep.match_prefix("über"), "über") -- German word with 'ü'
assert.are_same(blink_ripgrep.match_prefix("übermensch"), "übermensch") -- German compound word with 'ü'
assert.are_same(blink_ripgrep.match_prefix("mañana"), "mañana") -- Spanish word with 'ñ'
assert.are_same(blink_ripgrep.match_prefix("Ångström"), "Ångström") -- Swedish word with 'Å' and 'ö'
assert.are_same(blink_ripgrep.match_prefix("Straße"), "Straße") -- German word with 'ß'
assert.are_same(blink_ripgrep.match_prefix("český"), "český") -- Czech word with 'č'
assert.are_same(blink_ripgrep.match_prefix("naïve"), "naïve") -- French word with 'ï'
assert.are_same(blink_ripgrep.match_prefix("façade"), "façade") -- French word with 'ç'
assert.are_same(blink_ripgrep.match_prefix("résumé"), "résumé") -- French word with 'é'
assert.are_same(blink_ripgrep.match_prefix("космос"), "космос") -- Russian word with Cyrillic characters
assert.are_same(blink_ripgrep.match_prefix("你好"), "你好") -- Chinese characters
assert.are_same(blink_ripgrep.match_prefix("日本語"), "日本語") -- Japanese characters
assert.are_same(blink_ripgrep.match_prefix("한국어"), "한국어") -- Korean characters
assert.are_same(blink_ripgrep.match_prefix("τοπική"), "τοπική") -- Greek word with 'π' and 'ή'
assert.are_same(search_prefix.match_prefix("yöllä"), "yöllä") -- Finnish word with 'ö' and 'ä'
assert.are_same(search_prefix.match_prefix("über"), "über") -- German word with 'ü'
assert.are_same(search_prefix.match_prefix("übermensch"), "übermensch") -- German compound word with 'ü'
assert.are_same(search_prefix.match_prefix("mañana"), "mañana") -- Spanish word with 'ñ'
assert.are_same(search_prefix.match_prefix("Ångström"), "Ångström") -- Swedish word with 'Å' and 'ö'
assert.are_same(search_prefix.match_prefix("Straße"), "Straße") -- German word with 'ß'
assert.are_same(search_prefix.match_prefix("český"), "český") -- Czech word with 'č'
assert.are_same(search_prefix.match_prefix("naïve"), "naïve") -- French word with 'ï'
assert.are_same(search_prefix.match_prefix("façade"), "façade") -- French word with 'ç'
assert.are_same(search_prefix.match_prefix("résumé"), "résumé") -- French word with 'é'
assert.are_same(search_prefix.match_prefix("космос"), "космос") -- Russian word with Cyrillic characters
assert.are_same(search_prefix.match_prefix("你好"), "你好") -- Chinese characters
assert.are_same(search_prefix.match_prefix("日本語"), "日本語") -- Japanese characters
assert.are_same(search_prefix.match_prefix("한국어"), "한국어") -- Korean characters
assert.are_same(search_prefix.match_prefix("τοπική"), "τοπική") -- Greek word with 'π' and 'ή'
end)

it("matches emoji", function()
-- because why not 😄
assert.are_same(blink_ripgrep.match_prefix("👍👎"), "👍👎")
assert.are_same(blink_ripgrep.match_prefix("👍-👎"), "👍-👎")
assert.are_same(search_prefix.match_prefix("👍👎"), "👍👎")
assert.are_same(search_prefix.match_prefix("👍-👎"), "👍-👎")
end)

it("does not include punctuation characters", function()
assert.are_same(blink_ripgrep.match_prefix("!hello"), "hello")
assert.are_same(blink_ripgrep.match_prefix("?world"), "world")
assert.are_same(blink_ripgrep.match_prefix("#hashtag"), "hashtag")
assert.are_same(blink_ripgrep.match_prefix("$money"), "money")
assert.are_same(blink_ripgrep.match_prefix("%value"), "value")
assert.are_same(blink_ripgrep.match_prefix("&and"), "and")
assert.are_same(blink_ripgrep.match_prefix("*star"), "star")
assert.are_same(blink_ripgrep.match_prefix("@email"), "email")
assert.are_same(blink_ripgrep.match_prefix("~tilde"), "tilde")
assert.are_same(blink_ripgrep.match_prefix(";semicolon"), "semicolon")
assert.are_same(blink_ripgrep.match_prefix(":colon"), "colon")
assert.are_same(search_prefix.match_prefix("!hello"), "hello")
assert.are_same(search_prefix.match_prefix("?world"), "world")
assert.are_same(search_prefix.match_prefix("#hashtag"), "hashtag")
assert.are_same(search_prefix.match_prefix("$money"), "money")
assert.are_same(search_prefix.match_prefix("%value"), "value")
assert.are_same(search_prefix.match_prefix("&and"), "and")
assert.are_same(search_prefix.match_prefix("*star"), "star")
assert.are_same(search_prefix.match_prefix("@email"), "email")
assert.are_same(search_prefix.match_prefix("~tilde"), "tilde")
assert.are_same(search_prefix.match_prefix(";semicolon"), "semicolon")
assert.are_same(search_prefix.match_prefix(":colon"), "colon")
end)

it("does not include whitespace and control characters", function()
assert.are_same(blink_ripgrep.match_prefix(" hello"), "hello")
assert.are_same(blink_ripgrep.match_prefix("world "), "world")
assert.are_same(blink_ripgrep.match_prefix("\t\ttext"), "text")
assert.are_same(blink_ripgrep.match_prefix("\nnewline"), "newline")
assert.are_same(search_prefix.match_prefix(" hello"), "hello")
assert.are_same(search_prefix.match_prefix("world "), "world")
assert.are_same(search_prefix.match_prefix("\t\ttext"), "text")
assert.are_same(search_prefix.match_prefix("\nnewline"), "newline")
end)

it("includes symbols", function()
assert.are_same(blink_ripgrep.match_prefix("©copyright"), "©copyright")
assert.are_same(blink_ripgrep.match_prefix("®registered"), "®registered")
assert.are_same(blink_ripgrep.match_prefix("™trademark"), "™trademark")
assert.are_same(search_prefix.match_prefix("©copyright"), "©copyright")
assert.are_same(search_prefix.match_prefix("®registered"), "®registered")
assert.are_same(search_prefix.match_prefix("™trademark"), "™trademark")
end)
end)
Loading