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

App launcher refactor #198

Open
wants to merge 185 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
185 commits
Select commit Hold shift + click to select a range
52acaf5
Some renaming and use _ for unused vars
Kasper24 Feb 4, 2023
0790382
Use forced_num_col so I don't need to do dumb shit to get the actual …
Kasper24 Feb 4, 2023
611e382
I like page_forward being before backward
Kasper24 Feb 4, 2023
a8a865b
Auto detect terminal
Kasper24 Feb 4, 2023
6c57501
Pull these out of the function
Kasper24 Feb 4, 2023
61a21a1
Small changes
Kasper24 Feb 4, 2023
c6a2453
Use _role suffix
Kasper24 Feb 4, 2023
6f1198e
Add support for passing in a template for the app widget
Kasper24 Feb 5, 2023
d134719
At last
Kasper24 Feb 5, 2023
281fc89
Add support app launcher template
Kasper24 Feb 5, 2023
4cb5972
Not used
Kasper24 Feb 5, 2023
5b8282b
Refactor scrolling
Kasper24 Feb 5, 2023
4cbedd6
Make select and unselect part of the app_widget object
Kasper24 Feb 5, 2023
d272561
Make the scroll function accesiable + DRY it
Kasper24 Feb 5, 2023
cbf8960
Formatting
Kasper24 Feb 5, 2023
98fc2c9
Not needed anymore
Kasper24 Feb 5, 2023
c822f16
Formatting
Kasper24 Feb 5, 2023
f148d92
hmm
Kasper24 Feb 5, 2023
458cd3c
No need for ()
Kasper24 Feb 5, 2023
7a55852
whoops
Kasper24 Feb 5, 2023
3d3529c
More formatting
Kasper24 Feb 5, 2023
4499ede
Templates
Kasper24 Feb 5, 2023
ddd5b27
It might be empty
Kasper24 Feb 5, 2023
400bd98
Fix accessing the wrong self
Kasper24 Feb 7, 2023
ee9c8b1
Better naming
Kasper24 Feb 12, 2023
1e69421
Add method to dynamically update app launcher favorites
Kasper24 Feb 12, 2023
3cfff61
Refactor the icon theme helper
Kasper24 Feb 14, 2023
8de50ae
whoooopsi
Kasper24 Feb 14, 2023
8591059
Use get_id here, it's just suffixed with .desktop in the end
Kasper24 Feb 14, 2023
1ef57e3
return it
Kasper24 Feb 14, 2023
680fbb0
Makes more sense in this way
Kasper24 Feb 14, 2023
4445f0b
This can error out
Kasper24 Feb 14, 2023
c8552e5
Why there isn't an easier way to get a desktop file from a client
Kasper24 Feb 14, 2023
530619c
I swear this actually works now
Kasper24 Feb 14, 2023
8530b17
Nemo WM_CLASS='nemo' while it's desktop name prop='Files', but hey at…
Kasper24 Feb 16, 2023
eda3703
Use the start_new func
Kasper24 Feb 19, 2023
c975a0d
Reduce amount of configuration options
Kasper24 Feb 19, 2023
7a20f91
Rename prompt_color to prompt_bg_color
Kasper24 Feb 19, 2023
d4911c9
set raw to true
Kasper24 Feb 19, 2023
6e77e55
No need to recreate the timer
Kasper24 Feb 19, 2023
1f5cdbf
Add a default_value function to improve the syntax of setting defaults
Kasper24 Feb 19, 2023
a6c3376
Formatting
Kasper24 Feb 19, 2023
21f0bd2
Improve templates support
Kasper24 Feb 19, 2023
b8b3e8a
Refactor the prompt widget
Kasper24 Feb 20, 2023
eb7c1aa
It's the 1st widget in the layout, no need to search for it
Kasper24 Feb 20, 2023
e5deb85
Not used
Kasper24 Feb 20, 2023
68482b1
Just get it from helpers
Kasper24 Feb 20, 2023
8812678
Use the new prompt widget and improve widget_template support
Kasper24 Feb 20, 2023
594610a
Better defaults
Kasper24 Feb 20, 2023
5562030
Use state to know when to show the cursor or not
Kasper24 Feb 20, 2023
c01b586
Support icon prop in table form or in regular form
Kasper24 Feb 20, 2023
8b60520
Better defaults
Kasper24 Feb 20, 2023
33576c2
Fix scrolling and grid when using widget_template
Kasper24 Feb 20, 2023
1a70455
Remove animation support (can be done manually) + some very weird code?
Kasper24 Feb 20, 2023
87f50e7
Always_on for default prompt
Kasper24 Feb 20, 2023
38e3d03
Make use of the screen prop
Kasper24 Feb 20, 2023
3fb0836
Not working
Kasper24 Feb 20, 2023
0ae3c65
Hard code it
Kasper24 Feb 20, 2023
f984ca5
Remove old props from docs
Kasper24 Feb 20, 2023
2c65704
Update docs
Kasper24 Feb 20, 2023
9d5729c
Make it consistent with the rest of awesome API
Kasper24 Feb 20, 2023
e47fbd2
Just use set_text
Kasper24 Feb 20, 2023
2649d0e
Rename entry/entries to app/apps
Kasper24 Feb 21, 2023
582b3c4
Adding more props to the app table that this is obslete now, it's bet…
Kasper24 Feb 21, 2023
6cf48e9
Not used
Kasper24 Feb 21, 2023
fd3ee7a
Add more props to the app table
Kasper24 Feb 21, 2023
b957625
Add the desktop_app_info to the app table
Kasper24 Feb 21, 2023
04d7af4
Fix prompt disabling other keygrabbers
Kasper24 Feb 22, 2023
7f73fc3
Expose these methods in a nicer way for the app_template
Kasper24 Feb 24, 2023
0978c54
This should have been ipairs
Kasper24 Feb 24, 2023
d7f2309
This is a table-array like as well, use ipairs
Kasper24 Feb 24, 2023
24cdcb9
No need for the case_insensitive function, can just :lower() the stri…
Kasper24 Feb 24, 2023
7f34d48
Refactor the sorting function + split the sorting part into it's own …
Kasper24 Feb 24, 2023
097f007
Refresh the app list when settings the favorites
Kasper24 Feb 24, 2023
7207d97
Get the text from self, no need to pass it as well
Kasper24 Feb 24, 2023
7e33e62
Replace xclip dep using gtk clipboard
Kasper24 Feb 24, 2023
8765612
::press gets called consisntely when holding down a key and that will…
Kasper24 Feb 24, 2023
44af848
Define app once
Kasper24 Feb 24, 2023
8c8d967
Check if the returned table is nil
Kasper24 Feb 24, 2023
c449681
Convert the reset function into a public method + fix not respecting …
Kasper24 Feb 24, 2023
a4df7de
Add more helper functions + remove useless comments
Kasper24 Feb 24, 2023
f161aa2
Expose every useful private local function as a public method + add s…
Kasper24 Feb 24, 2023
c45e64b
Rename selected and unselected to select and unselect + add 'page::fo…
Kasper24 Feb 25, 2023
af15c9b
Add scroll signal
Kasper24 Feb 25, 2023
9e0c6fd
Pass the app launcher to the app_template
Kasper24 Feb 25, 2023
3c44c5c
Use app_info:launch() for non terminal apps to fix issues with launch…
Kasper24 Feb 25, 2023
47da489
Change class for terminal apps
Kasper24 Feb 25, 2023
282ce35
Rename spawn to run
Kasper24 Feb 25, 2023
a992a52
Rename AWESOME_SENSIBLE_TERMINASL_PATH TO AWESOME_SENSIBLE_TERMINAL_S…
Kasper24 Feb 25, 2023
86bef7a
Add function to run app as root
Kasper24 Feb 25, 2023
b300def
Formatting
Kasper24 Feb 25, 2023
6439e6d
Fix not passing self
Kasper24 Feb 25, 2023
69c5653
Add a proper refresh method
Kasper24 Feb 25, 2023
49c8156
Simplify and fix scrolling logic
Kasper24 Feb 25, 2023
c084c9b
Add a method to get the current page + pass the current page in the p…
Kasper24 Feb 27, 2023
0982fd6
Add method to get pages count + pass the pages count in the page signals
Kasper24 Feb 27, 2023
93327ae
Add a method to get the text + add a search signal
Kasper24 Feb 27, 2023
8f7ce8f
Add more methods + don't connect the button::press signals for templates
Kasper24 Mar 1, 2023
12478eb
Clearer naming
Kasper24 Mar 1, 2023
051c84b
Fix run_or_select + some renaming
Kasper24 Mar 1, 2023
a33bb8f
Try to collect garbage
Kasper24 Mar 1, 2023
c658173
Improve searching
Kasper24 Mar 1, 2023
468e4d9
Rename active_widget for selected_app_widget and a public method to r…
Kasper24 Mar 2, 2023
bf7db8a
Fix search timer
Kasper24 Mar 3, 2023
4e9f1d6
Use desktop app info search instead
Kasper24 Mar 3, 2023
b8dc4fa
Use gears cache for the app widgets
Kasper24 Mar 3, 2023
297ea25
Don't loop twice
Kasper24 Mar 3, 2023
6f5b50f
Break
Kasper24 Mar 3, 2023
68e6e7e
Has no effect
Kasper24 Mar 3, 2023
b6518e6
Handle vertical orientation
Kasper24 Mar 3, 2023
436b8eb
Use the correct methods for scrolling with the mouse wheel depending …
Kasper24 Mar 4, 2023
92b651b
Make it select the first index at the new page when scrolling with th…
Kasper24 Mar 4, 2023
12b94b5
Typo
Kasper24 Mar 4, 2023
216094d
gears.cache didn't work this, make the cache manually to stop it from…
Kasper24 Mar 5, 2023
2ad3c5d
Make the table weak
Kasper24 Mar 6, 2023
13d0f1c
Add an option to lazy load widgets (worse peformance, but less ram on…
Kasper24 Mar 6, 2023
4cdc4fb
Replace the prompt with a proper text input widget
Kasper24 Mar 7, 2023
4873f1e
Use simpler commands
Kasper24 Mar 7, 2023
f028cae
Fix some text input issues
Kasper24 Mar 10, 2023
881895e
Text filtering the right way
Kasper24 Mar 10, 2023
a99eb3f
Adjust some code + fix initial value not working
Kasper24 Mar 10, 2023
e1c556e
Add unfocus on client focus prop
Kasper24 Mar 10, 2023
6008922
pass in the text for the unfocus signal
Kasper24 Mar 10, 2023
301d23e
Fix text_color not customizable
Kasper24 Mar 10, 2023
26a03aa
Fix focusing the text input when releasing any mouse button
Kasper24 Mar 11, 2023
0239710
Don't emit the signal here, this is called by the user
Kasper24 Mar 12, 2023
35e8152
temp
Kasper24 Mar 12, 2023
4ba108d
Fix typo
Kasper24 Mar 12, 2023
ba8071b
Extract the scroller widget into it's own file + add scrollbar
Kasper24 Mar 12, 2023
c6e87c1
Unbork the default template + fixes some beautiful.colors refs
Kasper24 Mar 12, 2023
df2953f
Formatting
Kasper24 Mar 12, 2023
74f4834
15 is enough
Kasper24 Mar 12, 2023
45f858d
Fix not setting the text input color ond default template
Kasper24 Mar 12, 2023
020defb
Fix using wrong value
Kasper24 Mar 12, 2023
63d8f27
Fix not returning the value
Kasper24 Mar 12, 2023
9226d7c
Fix varius issues
Kasper24 Mar 12, 2023
fb688b2
Part of the rofi grid widget now
Kasper24 Mar 12, 2023
2e3da90
Fix default sorting + formatting
Kasper24 Mar 12, 2023
89a1a1f
These defaults makes more sense for the app launcher, but less if use…
Kasper24 Mar 12, 2023
aa629f6
Add text_input_selection_bg prop
Kasper24 Mar 12, 2023
df599e2
Rename text_input_color to text_input_text_color to avoid confusion
Kasper24 Mar 12, 2023
debaa44
Fix calling the method on the wrong object
Kasper24 Mar 12, 2023
996fc7c
Should check if true
Kasper24 Mar 12, 2023
ef7cba1
Fix checking for the wrong value
Kasper24 Mar 13, 2023
31934c1
Implement double click to select current word + triple click to selec…
Kasper24 Mar 13, 2023
98a3b31
Better naming
Kasper24 Mar 13, 2023
ad9c4d7
DesktopAppInfo sucks for sorting the matched apps for best results, u…
Kasper24 Mar 13, 2023
26588dc
Formatting
Kasper24 Mar 13, 2023
39a7b96
Is 0.05 enough?
Kasper24 Mar 13, 2023
ed287c8
Makes cache smarter when reloding the app list (only add/remove what'…
Kasper24 Mar 15, 2023
39dc721
Add back the set_selected_entry method with a new name 'scroll_to_index'
Kasper24 Mar 15, 2023
3180909
Add local pairs
Kasper24 Mar 15, 2023
1cec46b
Elseif it
Kasper24 Mar 15, 2023
a1c93c8
Fix not being able to do shift + key
Kasper24 Mar 15, 2023
26c6b2b
Remove print
Kasper24 Mar 15, 2023
8919812
Widgets might share the same entries, so don't have any method on the…
Kasper24 Mar 15, 2023
6c76dc9
Fix varius input handling issues with the text input widget
Kasper24 Mar 16, 2023
566a5a9
Add context to the unfocus signal
Kasper24 Mar 16, 2023
92df6d9
Fix getting the same value twice
Kasper24 Mar 16, 2023
0c6a1ca
Better handling for when clicked position it outsidd the bounds
Kasper24 Mar 16, 2023
070150e
Fix cursor blinking too fast sometimes
Kasper24 Mar 16, 2023
ff8af15
Fix #92df6d97958df14ca82b47e2de6df086be218969
Kasper24 Mar 16, 2023
6a52784
Hide scrollbar when grid is empty
Kasper24 Mar 16, 2023
d09bf3b
I was keeping the cache, but overriding the entries table which cause…
Kasper24 Mar 16, 2023
331712f
Handle favorites directly in the rofi grid widget
Kasper24 Mar 16, 2023
aa25cfd
Add default_search_sort_fn and default_search_fn to rofi grid
Kasper24 Mar 16, 2023
35611e4
Add context to the select signal
Kasper24 Mar 16, 2023
bbba4cd
Make use of #35611e
Kasper24 Mar 17, 2023
053cb47
Improve text selection handling when cursor it outside text extents
Kasper24 Mar 17, 2023
cbc6f46
Can't select text if empty
Kasper24 Mar 18, 2023
7d4afec
Change default click timeout to 0.1
Kasper24 Mar 18, 2023
36cd158
This wasn't working if the mouse left the text input before releasing…
Kasper24 Mar 18, 2023
86f5382
Only set the mode to overwrite if there was actual text being selected
Kasper24 Mar 19, 2023
69dd122
Increase click timeout
Kasper24 Mar 19, 2023
ee5438c
Fix cursor reblinking when already in insert mode and pressing the te…
Kasper24 Mar 19, 2023
80b9062
Implmement the select_or_exec function at the rofi grid widget level
Kasper24 Mar 26, 2023
92ff783
Remove whitespace
Kasper24 Mar 27, 2023
e80db42
Forgot to commit this
Kasper24 Apr 3, 2023
0452b69
Fix text obscure
Kasper24 Apr 3, 2023
d8897a2
Fix cursor position after overwriting text
Kasper24 Apr 3, 2023
c44dc01
Improve dragging handling
Kasper24 Apr 3, 2023
17d171e
Fix using the wrong key
Jun 28, 2023
f96d837
Refresh the app list everytime :show() is called
Jun 28, 2023
b4cb55a
Use uid instead of name to identify if an entry already exists
Jun 28, 2023
0f0a7f7
Fix crash caused by api change renaming some grid props
Kasper24 Oct 19, 2024
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
75 changes: 19 additions & 56 deletions docs/widgets/app_launcher.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ local app_launcher = bling.widget.app_launcher(args)

```lua
local args = {
terminal = "alacritty" -- Set default terminal
favorites = { "firefox", "wezterm" } -- Favorites are given priority and are bubbled to top of the list
search_commands = true -- Search by app name AND commandline command
skip_names = { "Discord" } -- List of apps to omit from launcher
Expand All @@ -59,71 +58,35 @@ local args = {
icon_size = 24 -- Set icon size

type = "dock" -- awful.popup type ("dock", "desktop", "normal"...). See awesomewm docs for more detail
show_on_focused_screen = true -- Should app launcher show on currently focused screen
screen = awful.screen -- Screen you want the launcher to launch to
placement = awful.placement.top_left -- Where launcher should be placed ("awful.placement.centered").
rubato = { x = rubato_animation_x, y = rubato_animation_y } -- Rubato animation to apply to launcher
shrink_width = true -- Automatically shrink width of launcher to fit varying numbers of apps in list (works on apps_per_column)
shrink_height = true -- Automatically shrink height of launcher to fit varying numbers of apps in list (works on apps_per_row)
background = "#FFFFFF" -- Set bg color
border_width = dpi(0) -- Set border width of popup
border_color = "#FFFFFF" -- Set border color of popup
shape = function(cr, width, height)
show_on_focused_screen = true -- Should the app launcher popup show on currently focused screen
screen = awful.screen -- Screen you want the launcher popup to open on
placement = awful.placement.top_left -- Where launcher popup should be placed
bg = "#FFFFFF" -- Set launcher popup bg color
border_width = dpi(0) -- Set launcher popup border width of popup
border_color = "#FFFFFF" -- Set launcher popup border color of popup
shape = function(cr, width, height) -- Set launcher popup shape
gears.shape.rectangle(cr, width, height)
end -- Set shape for launcher
prompt_height = dpi(50) -- Prompt height
prompt_margins = dpi(30) -- Prompt margins
prompt_paddings = dpi(15) -- Prompt padding
shape = function(cr, width, height)
gears.shape.rectangle(cr, width, height)
end -- Set shape for prompt
prompt_color = "#000000" -- Prompt background color
prompt_border_width = dpi(0) -- Prompt border width
prompt_border_color = "#000000" -- Prompt border color
prompt_text_halign = "center" -- Prompt text horizontal alignment
prompt_text_valign = "center" -- Prompt text vertical alignment
prompt_icon_text_spacing = dpi(10) -- Prompt icon text spacing
prompt_show_icon = true -- Should prompt show icon (?)
end

prompt_bg_color = "#000000" -- Prompt background color
prompt_icon_font = "Comic Sans" -- Prompt icon font
prompt_icon_color = "#000000" -- Prompt icon color
prompt_icon_size = 15 -- Prompt icon size
prompt_icon_color = "#FFFFFF" -- Prompt icon color
prompt_icon = "" -- Prompt icon
prompt_icon_markup = string.format(
"<span size='xx-large' foreground='%s'>%s</span>",
args.prompt_icon_color, args.prompt_icon
) -- Prompt icon markup
prompt_text = "<b>Search</b>:" -- Prompt text
prompt_start_text = "manager" -- Set string for prompt to start with
prompt_font = "Comic Sans" -- Prompt font
prompt_text_color = "#FFFFFF" -- Prompt text color
prompt_cursor_color = "#000000" -- Prompt cursor color
prompt_label_font = "Comic Sans" -- Prompt labe font
prompt_label_size = 15 -- Prompt labe font
prompt_label_color = "#FFFFFF" -- Prompt labe font
prompt_label = "Search" -- Prompt labe font
prompt_text_font = "Comic Sans" -- Prompt text font
prompt_text_size = 15 -- Prompt text font
prompt_text_color = "#FFFFFF" -- Prompt text font

apps_per_row = 3 -- Set how many apps should appear in each row
apps_per_column = 3 -- Set how many apps should appear in each column
apps_margin = {left = dpi(40), right = dpi(40), bottom = dpi(30)} -- Margin between apps
apps_spacing = dpi(10) -- Spacing between apps

expand_apps = true -- Should apps expand to fill width of launcher
app_width = dpi(400) -- Width of each app
app_height = dpi(40) -- Height of each app
app_shape = function(cr, width, height)
gears.shape.rectangle(cr, width, height)
end -- Shape of each app
app_normal_color = "#000000" -- App normal color
app_normal_hover_color = "#111111" -- App normal hover color
app_selected_color = "#FFFFFF" -- App selected color
app_selected_hover_color = "#EEEEEE" -- App selected hover color
app_content_padding = dpi(10) -- App content padding
app_content_spacing = dpi(10) -- App content spacing
app_show_icon = true -- Should show icon?
app_icon_halign = "center" -- App icon horizontal alignment
app_icon_width = dpi(70) -- App icon wigth
app_icon_height = dpi(70) -- App icon height
app_show_name = true -- Should show app name?
app_name_generic_name_spacing = dpi(0) -- Generic name spacing (If show_generic_name)
app_name_halign = "center" -- App name horizontal alignment
app_name_font = "Comic Sans" -- App name font
app_name_normal_color = "#FFFFFF" -- App name normal color
app_name_selected_color = "#000000" -- App name selected color
app_show_generic_name = true -- Should show generic app name?
}
```
275 changes: 275 additions & 0 deletions helpers/fzy.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
-- The lua implementation of the fzy string matching algorithm

local SCORE_GAP_LEADING = -0.005
local SCORE_GAP_TRAILING = -0.005
local SCORE_GAP_INNER = -0.01
local SCORE_MATCH_CONSECUTIVE = 1.0
local SCORE_MATCH_SLASH = 0.9
local SCORE_MATCH_WORD = 0.8
local SCORE_MATCH_CAPITAL = 0.7
local SCORE_MATCH_DOT = 0.6
local SCORE_MAX = math.huge
local SCORE_MIN = -math.huge
local MATCH_MAX_LENGTH = 1024

local fzy = {}

-- Check if `needle` is a subsequence of the `haystack`.
--
-- Usually called before `score` or `positions`.
--
-- Args:
-- needle (string)
-- haystack (string)
-- case_sensitive (bool, optional): defaults to false
--
-- Returns:
-- bool
function fzy.has_match(needle, haystack, case_sensitive)
if not case_sensitive then
needle = string.lower(needle)
haystack = string.lower(haystack)
end

local j = 1
for i = 1, string.len(needle) do
j = string.find(haystack, needle:sub(i, i), j, true)
if not j then
return false
else
j = j + 1
end
end

return true
end

local function is_lower(c)
return c:match("%l")
end

local function is_upper(c)
return c:match("%u")
end

local function precompute_bonus(haystack)
local match_bonus = {}

local last_char = "/"
for i = 1, string.len(haystack) do
local this_char = haystack:sub(i, i)
if last_char == "/" or last_char == "\\" then
match_bonus[i] = SCORE_MATCH_SLASH
elseif last_char == "-" or last_char == "_" or last_char == " " then
match_bonus[i] = SCORE_MATCH_WORD
elseif last_char == "." then
match_bonus[i] = SCORE_MATCH_DOT
elseif is_lower(last_char) and is_upper(this_char) then
match_bonus[i] = SCORE_MATCH_CAPITAL
else
match_bonus[i] = 0
end

last_char = this_char
end

return match_bonus
end

local function compute(needle, haystack, D, M, case_sensitive)
-- Note that the match bonuses must be computed before the arguments are
-- converted to lowercase, since there are bonuses for camelCase.
local match_bonus = precompute_bonus(haystack)
local n = string.len(needle)
local m = string.len(haystack)

if not case_sensitive then
needle = string.lower(needle)
haystack = string.lower(haystack)
end

-- Because lua only grants access to chars through substring extraction,
-- get all the characters from the haystack once now, to reuse below.
local haystack_chars = {}
for i = 1, m do
haystack_chars[i] = haystack:sub(i, i)
end

for i = 1, n do
D[i] = {}
M[i] = {}

local prev_score = SCORE_MIN
local gap_score = i == n and SCORE_GAP_TRAILING or SCORE_GAP_INNER
local needle_char = needle:sub(i, i)

for j = 1, m do
if needle_char == haystack_chars[j] then
local score = SCORE_MIN
if i == 1 then
score = ((j - 1) * SCORE_GAP_LEADING) + match_bonus[j]
elseif j > 1 then
local a = M[i - 1][j - 1] + match_bonus[j]
local b = D[i - 1][j - 1] + SCORE_MATCH_CONSECUTIVE
score = math.max(a, b)
end
D[i][j] = score
prev_score = math.max(score, prev_score + gap_score)
M[i][j] = prev_score
else
D[i][j] = SCORE_MIN
prev_score = prev_score + gap_score
M[i][j] = prev_score
end
end
end
end

-- Compute a matching score.
--
-- Args:
-- needle (string): must be a subequence of `haystack`, or the result is
-- undefined.
-- haystack (string)
-- case_sensitive (bool, optional): defaults to false
--
-- Returns:
-- number: higher scores indicate better matches. See also `get_score_min`
-- and `get_score_max`.
function fzy.score(needle, haystack, case_sensitive)
local n = string.len(needle)
local m = string.len(haystack)

if n == 0 or m == 0 or m > MATCH_MAX_LENGTH or n > m then
return SCORE_MIN
elseif n == m then
return SCORE_MAX
else
local D = {}
local M = {}
compute(needle, haystack, D, M, case_sensitive)
return M[n][m]
end
end

-- Compute the locations where fzy matches a string.
--
-- Determine where each character of the `needle` is matched to the `haystack`
-- in the optimal match.
--
-- Args:
-- needle (string): must be a subequence of `haystack`, or the result is
-- undefined.
-- haystack (string)
-- case_sensitive (bool, optional): defaults to false
--
-- Returns:
-- {int,...}: indices, where `indices[n]` is the location of the `n`th
-- character of `needle` in `haystack`.
-- number: the same matching score returned by `score`
function fzy.positions(needle, haystack, case_sensitive)
local n = string.len(needle)
local m = string.len(haystack)

if n == 0 or m == 0 or m > MATCH_MAX_LENGTH or n > m then
return {}, SCORE_MIN
elseif n == m then
local consecutive = {}
for i = 1, n do
consecutive[i] = i
end
return consecutive, SCORE_MAX
end

local D = {}
local M = {}
compute(needle, haystack, D, M, case_sensitive)

local positions = {}
local match_required = false
local j = m
for i = n, 1, -1 do
while j >= 1 do
if D[i][j] ~= SCORE_MIN and (match_required or D[i][j] == M[i][j]) then
match_required = (i ~= 1) and (j ~= 1) and (
M[i][j] == D[i - 1][j - 1] + SCORE_MATCH_CONSECUTIVE)
positions[i] = j
j = j - 1
break
else
j = j - 1
end
end
end

return positions, M[n][m]
end

-- Apply `has_match` and `positions` to an array of haystacks.
--
-- Args:
-- needle (string)
-- haystack ({string, ...})
-- case_sensitive (bool, optional): defaults to false
--
-- Returns:
-- {{idx, positions, score}, ...}: an array with one entry per matching line
-- in `haystacks`, each entry giving the index of the line in `haystacks`
-- as well as the equivalent to the return value of `positions` for that
-- line.
function fzy.filter(needle, haystacks, case_sensitive)
local result = {}

for i, line in ipairs(haystacks) do
if fzy.has_match(needle, line, case_sensitive) then
local p, s = fzy.positions(needle, line, case_sensitive)
table.insert(result, {i, p, s})
end
end

return result
end

-- The lowest value returned by `score`.
--
-- In two special cases:
-- - an empty `needle`, or
-- - a `needle` or `haystack` larger than than `get_max_length`,
-- the `score` function will return this exact value, which can be used as a
-- sentinel. This is the lowest possible score.
function fzy.get_score_min()
return SCORE_MIN
end

-- The score returned for exact matches. This is the highest possible score.
function fzy.get_score_max()
return SCORE_MAX
end

-- The maximum size for which `fzy` will evaluate scores.
function fzy.get_max_length()
return MATCH_MAX_LENGTH
end

-- The minimum score returned for normal matches.
--
-- For matches that don't return `get_score_min`, their score will be greater
-- than than this value.
function fzy.get_score_floor()
return MATCH_MAX_LENGTH * SCORE_GAP_INNER
end

-- The maximum score for non-exact matches.
--
-- For matches that don't return `get_score_max`, their score will be less than
-- this value.
function fzy.get_score_ceiling()
return MATCH_MAX_LENGTH * SCORE_MATCH_CONSECUTIVE
end

-- The name of the currently-running implmenetation, "lua" or "native".
function fzy.get_implementation_name()
return "lua"
end

return fzy
Loading