feat: match like 'smartcase' (#177)

* feat: match like 'smartcase'

Fix #36

* docs: add note for 'smartcase'

* docs: emphasize requirements
This commit is contained in:
JINNOUCHI Yasushi 2024-02-25 14:25:40 +09:00 committed by GitHub
parent 4f3e007ec2
commit 771726f7d6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 80 additions and 3 deletions

View File

@ -77,7 +77,7 @@ directories provided by the language server.
## Requirements ## Requirements
- [telescope.nvim](https://github.com/nvim-telescope/telescope.nvim) (required) - [telescope.nvim](https://github.com/nvim-telescope/telescope.nvim) **(required)**
- [nvim-web-devicons](https://github.com/kyazdani42/nvim-web-devicons) (optional) - [nvim-web-devicons](https://github.com/kyazdani42/nvim-web-devicons) (optional)
- [ripgrep](https://github.com/BurntSushi/ripgrep) or [fd](https://github.com/sharkdp/fd) (optional) - [ripgrep](https://github.com/BurntSushi/ripgrep) or [fd](https://github.com/sharkdp/fd) (optional)
@ -142,6 +142,20 @@ Filter tags are applied by typing the `:tag:` name (adding surrounding colons)
in the finder query. Entering `:<Tab>` will trigger omnicompletion for in the finder query. Entering `:<Tab>` will trigger omnicompletion for
available tags. available tags.
### Dealing with upper case letters
In default, the sorter always ignores upper case letters in your input string.
But when [`'smartcase'`][smartcase] is ON and input string includes one upper case letter at
least, it matches against exact the same as you input.
| input string | `'smartcase'` is ON | `'smartcase'` is OFF |
|--------------|-----------------------------|-----------------------------|
| `abc` | matches `abc`, `ABC`, `aBc` | matches `abc`, `ABC`, `aBc` |
| `aBc` | matches `aBc` | no match |
| `ABC` | matches `ABC` | no match |
[smartcase]: https://neovim.io/doc/user/options.html#'smartcase'
## Configuration ## Configuration
See [default configuration](https://github.com/nvim-telescope/telescope.nvim#telescope-defaults) for full details on configuring Telescope. See [default configuration](https://github.com/nvim-telescope/telescope.nvim#telescope-defaults) for full details on configuring Telescope.

View File

@ -1,11 +1,11 @@
local State = require "frecency.state" local State = require "frecency.state"
local Finder = require "frecency.finder" local Finder = require "frecency.finder"
local sorters = require "frecency.sorters"
local log = require "plenary.log" local log = require "plenary.log"
local Path = require "plenary.path" --[[@as PlenaryPath]] local Path = require "plenary.path" --[[@as PlenaryPath]]
local actions = require "telescope.actions" local actions = require "telescope.actions"
local config_values = require("telescope.config").values local config_values = require("telescope.config").values
local pickers = require "telescope.pickers" local pickers = require "telescope.pickers"
local sorters = require "telescope.sorters"
local utils = require "telescope.utils" --[[@as TelescopeUtils]] local utils = require "telescope.utils" --[[@as TelescopeUtils]]
local uv = vim.loop or vim.uv local uv = vim.loop or vim.uv
@ -110,7 +110,7 @@ function Picker:start(opts)
prompt_title = "Frecency", prompt_title = "Frecency",
finder = finder, finder = finder,
previewer = config_values.file_previewer(opts), previewer = config_values.file_previewer(opts),
sorter = sorters.get_substr_matcher(), sorter = sorters.get_frecency_matcher(),
on_input_filter_cb = self:on_input_filter_cb(opts), on_input_filter_cb = self:on_input_filter_cb(opts),
attach_mappings = function(prompt_bufnr) attach_mappings = function(prompt_bufnr)
return self:attach_mappings(prompt_bufnr) return self:attach_mappings(prompt_bufnr)

63
lua/frecency/sorters.lua Normal file
View File

@ -0,0 +1,63 @@
local sorters = require "telescope.sorters"
local util = require "telescope.utils"
local M = {}
---@param prompt string
---@return boolean
local function has_upper_case(prompt)
return not not prompt:match "%u"
end
---@param prompt string
---@param display string
---@return { start: integer, finish: integer }[]
local function highlighter(_, prompt, display)
---@type { start: integer, finish: integer }[]
local highlights = {}
display = has_upper_case(prompt) and display or display:lower()
local search_terms = util.max_split(prompt, "%s")
local hl_start, hl_end
for _, word in ipairs(search_terms) do
hl_start, hl_end = display:find(word, 1, true)
if hl_start then
table.insert(highlights, { start = hl_start, finish = hl_end })
end
end
return highlights
end
---@param prompt string
---@param entry FrecencyEntry
---@return integer
local function scoring_function(_, prompt, _, entry)
if #prompt == 0 then
return 1
end
local display = has_upper_case(prompt) and entry.ordinal or entry.ordinal:lower()
local search_terms = util.max_split(prompt, "%s")
for _, word in ipairs(search_terms) do
if not display:find(word, 1, true) then
return -1
end
end
return entry.index
end
---This is a sorter similar to telescope.sorters.get_substr_matcher. telescope's
---one always ignore cases, but this sorter deal with them like 'smartcase' way.
function M.get_frecency_matcher()
return vim.o.smartcase
and sorters.Sorter:new {
highlighter = highlighter,
scoring_function = scoring_function,
}
or sorters.get_substr_matcher()
end
return M