diff --git a/Aux-Addon.toc b/Aux-Addon.toc index 6d439e2..9bf83c1 100644 --- a/Aux-Addon.toc +++ b/Aux-Addon.toc @@ -20,5 +20,5 @@ about.xml list.xml -completion.lua +completion.xml diff --git a/buy.lua b/buy.lua index a877291..e139fc0 100644 --- a/buy.lua +++ b/buy.lua @@ -419,21 +419,12 @@ function AuxBuyTooltipButton_OnClick() local pattern = AuxBuyTooltipInputBox:GetText() if pattern ~= '' then Aux.util.set_add(tooltip_patterns, pattern) - end - AuxBuyTooltipInputBox:SetText('') - if DropDownList1:IsVisible() then + if DropDownList1:IsVisible() then + Aux.buy.toggle_tooltip_dropdown() + end Aux.buy.toggle_tooltip_dropdown() end - Aux.buy.toggle_tooltip_dropdown() -end - -function AuxBuyTooltipRemoveButton_OnClick() - Aux.util.set_remove(tooltip_patterns, AuxBuyTooltipInputBox:GetText()) AuxBuyTooltipInputBox:SetText('') - if DropDownList1:IsVisible() then - Aux.buy.toggle_tooltip_dropdown() - end - Aux.buy.toggle_tooltip_dropdown() end function AuxBuyTooltipDropDown_Initialize() @@ -442,6 +433,7 @@ function AuxBuyTooltipDropDown_Initialize() text = pattern, value = pattern, func = AuxBuyTooltipDropDown_OnClick, + notCheckable = true, } end end diff --git a/buy.xml b/buy.xml index 0c3f6a4..ad50f51 100644 --- a/buy.xml +++ b/buy.xml @@ -231,12 +231,19 @@ - - Aux.util.item_name_autocomplete() - + + Aux.completion.make_suggestions(this) + + + Aux.completion.highlight_next(this) + - this:ClearFocus() - Aux.buy.SearchButton_onclick() + if Aux.completion.highlighted() then + Aux.completion.select(this) + else + this:ClearFocus() + Aux.buy.SearchButton_onclick() + end diff --git a/completion.lua b/completion.lua index 53dbbed..f33d6d3 100644 --- a/completion.lua +++ b/completion.lua @@ -1,44 +1,127 @@ +Aux.completion = {} + local NUM_MATCHES = 5 +local leven, fuzzy, populate_dropdown, toggle_dropdown, suggestions, highlight + local item_names = {} -for item_id=1,100 do + +local current_suggestions = {} +local selected_index + + +for item_id=1,30000 do local name = GetItemInfo(item_id) - tinsert(item_names, name) + if name then + tinsert(item_names, name) + end end -function leven(s,t) - if s == '' then return strlen(t) end - if t == '' then return strlen(s) end - - local s1 = string.sub(s, 2, -1) - local t1 = string.sub(t, 2, -1) - - if string.sub(s, 0, 1) == string.sub(t, 0, 1) then - return leven(s1, t1) - end - - return 1 + math.min( - leven(s1, t1), - leven(s, t1), - leven(s1, t) - ) +function fuzzy(input) + local uppercase_input = strupper(input) + local pattern = '(.*)' + for i=1,strlen(uppercase_input) do + pattern = pattern .. string.sub(uppercase_input, i, i) .. '(.*)' + end + return function(input) + local match = { string.find(strupper(input), pattern) } + if match[1] then + local rating = 1 + for i=3,getn(match) do + rating = rating * max(strlen(match[i]), 1) + end + return rating + end + end end -function get_matches(input) - local closest = {} - for _, name in pairs(item_names) do - local edit_distance = leven(input, name) - if getn(closest) < NUM_MATCHES then - tinsert(closest, { name=name, edit_distance=edit_distance }) +function update_highlighting() + for i=1,32 do + local highlight = getglobal('DropDownList1Button' .. i .. 'Highlight') + if i == selected_index then + highlight:Show() else - sort(closest, function(a, b) return a.edit_distance > b.edit_distance end) - if closest[1].edit_distance > edit_distance then - closest[1] = { name=name, edit_distance=edit_distance } + highlight:Hide() + end + end +end + +function suggestions(input) + local matcher = fuzzy(input) + + local best = {} + for _, name in ipairs(item_names) do + local rating = matcher(name) + if rating then + if getn(best) < NUM_MATCHES then + tinsert(best, { name=name, rating=rating }) + sort(best, function(a, b) return a.rating < b.rating end) + else + if best[1].rating > rating then + best[1] = { name=name, rating=rating } + sort(best, function(a, b) return a.rating < b.rating end) + end end end end - for _, winner in ipairs(closest) do - Aux.log(winner.name) + return Aux.util.map(best, function(match) return match.name end) +end + +function Aux.completion.make_suggestions(input_box) + selected_index = nil + update_highlighting() + local input = input_box:GetText() + if input == '' then + current_suggestions = {} + else + current_suggestions = suggestions(input) + UIDropDownMenu_Initialize(AuxCompletionDropDown, function() populate_dropdown(input_box, current_suggestions) end) end + + if DropDownList1:IsVisible() then + toggle_dropdown(input_box) + end + toggle_dropdown(input_box) +end + +function Aux.completion.highlight_next(input_box) + if getn(current_suggestions) > 0 then + selected_index = selected_index and math.mod(selected_index, getn(current_suggestions)) + 1 or 1 + end + update_highlighting() +end + +function Aux.completion.highlighted() + return selected_index ~= nil +end + +function Aux.completion.select(input_box) + Aux.completion.set_quietly(input_box, current_suggestions[selected_index]) + selected_index = nil + update_highlighting() + CloseDropDownMenus(1) +end + +function Aux.completion.set_quietly(edit_box, text) + local orig = edit_box:GetScript('OnTextChanged') + edit_box:SetScript('OnTextChanged', function() edit_box:SetScript('OnTextChanged', orig) end) + edit_box:SetText(text) +end + +function populate_dropdown(input_box, suggestions) + for _, suggestion in ipairs(suggestions) do + UIDropDownMenu_AddButton{ + text = suggestion, + value = suggestion, + notCheckable = true, + func = function() + Aux.completion.set_quietly(input_box, this.value) + end, + } + end +end + +function toggle_dropdown(input_box) + ToggleDropDownMenu(1, nil, AuxCompletionDropDown, input_box, -12, 4) end \ No newline at end of file diff --git a/completion.xml b/completion.xml new file mode 100644 index 0000000..c1338bc --- /dev/null +++ b/completion.xml @@ -0,0 +1,8 @@ + + +