Fuzzy Search

This commit is contained in:
Jesper 2024-06-12 10:37:26 +02:00
parent d8820edd7d
commit cf76c4837e

View File

@ -8,6 +8,7 @@ import os
import subprocess import subprocess
import threading import threading
import urllib.request, urllib.parse, urllib.error import urllib.request, urllib.parse, urllib.error
from fuzzywuzzy import process
import gi import gi
gi.require_version("Gtk", "3.0") gi.require_version("Gtk", "3.0")
@ -274,9 +275,11 @@ class pluginclass(object):
self.settings.connect("changed::fav-cols", self.changeFavCols) self.settings.connect("changed::fav-cols", self.changeFavCols)
self.settings.connect("changed::remember-filter", self.changeRememberFilter) self.settings.connect("changed::remember-filter", self.changeRememberFilter)
self.settings.connect("changed::enable-internet-search", self.changeEnableInternetSearch) self.settings.connect("changed::enable-internet-search", self.changeEnableInternetSearch)
self.settings.connect("changed::enable-fuzzy-search", self.changeEnableFuzzySearch)
self.settings.connect("changed::category-hover-delay", self.GetGSettingsEntries) self.settings.connect("changed::category-hover-delay", self.GetGSettingsEntries)
self.settings.connect("changed::do-not-filter", self.GetGSettingsEntries) self.settings.connect("changed::do-not-filter", self.GetGSettingsEntries)
self.settings.connect("changed::enable-internet-search", self.GetGSettingsEntries) self.settings.connect("changed::enable-internet-search", self.GetGSettingsEntries)
self.settings.connect("changed::enable-fuzzy-search", self.GetGSettingsEntries)
self.settings.connect("changed::search-command", self.GetGSettingsEntries) self.settings.connect("changed::search-command", self.GetGSettingsEntries)
self.settings.connect("changed::default-tab", self.GetGSettingsEntries) self.settings.connect("changed::default-tab", self.GetGSettingsEntries)
self.settings.connect("changed::favorite-apps-list", self.favoriteAppsChanged) self.settings.connect("changed::favorite-apps-list", self.favoriteAppsChanged)
@ -302,6 +305,7 @@ class pluginclass(object):
self.categoryList = [] self.categoryList = []
self.applicationList = [] self.applicationList = []
self.sortedApplicationList = []
#dirty ugly hack, to get favorites drag origin position #dirty ugly hack, to get favorites drag origin position
self.drag_origin = None self.drag_origin = None
@ -441,6 +445,9 @@ class pluginclass(object):
def changeEnableInternetSearch(self, settings, key): def changeEnableInternetSearch(self, settings, key):
self.enableInternetSearch = settings.get_boolean(key) self.enableInternetSearch = settings.get_boolean(key)
def changeEnableFuzzySearch(self, settings, key):
self.enableFuzzySearch = settings.get_boolean(key)
def changeShowApplicationComments(self, settings, key): def changeShowApplicationComments(self, settings, key):
self.showapplicationcomments = settings.get_boolean(key) self.showapplicationcomments = settings.get_boolean(key)
for child in self.applicationsBox: for child in self.applicationsBox:
@ -516,6 +523,7 @@ class pluginclass(object):
self.useAPT = self.settings.get_boolean("use-apt") self.useAPT = self.settings.get_boolean("use-apt")
self.rememberFilter = self.settings.get_boolean("remember-filter") self.rememberFilter = self.settings.get_boolean("remember-filter")
self.enableInternetSearch = self.settings.get_boolean("enable-internet-search") self.enableInternetSearch = self.settings.get_boolean("enable-internet-search")
self.enableFuzzySearch = self.settings.get_boolean("enable-fuzzy-search")
self.lastActiveTab = self.settings.get_int("last-active-tab") self.lastActiveTab = self.settings.get_int("last-active-tab")
self.defaultTab = self.settings.get_int("default-tab") self.defaultTab = self.settings.get_int("default-tab")
@ -745,6 +753,30 @@ class pluginclass(object):
except Exception as e: except Exception as e:
print(e) print(e)
def fuzzy_application_search(self, search_text):
for item in self.applicationList:
self.applicationsBox.remove(item["button"])
if search_text == "": # Reset application list
for item in self.applicationList:
self.applicationsBox.remove(item["button"])
for item in self.sortedApplicationList:
self.applicationsBox.pack_start(item[1], False, False, 0)
else: # Perform fuzzy search
labels = [app["button"].appName for app in self.applicationList]
results = process.extract(search_text, labels, limit=len(labels))
first_button = True
for match in results:
if match[1] > 60: # Adjust the threshold as needed
for app in self.applicationList:
if app["button"].appName == match[0]:
self.applicationsBox.pack_start(app["button"], False, False, 0)
if first_button is True:
app["button"].grab_focus()
first_button = False
def Filter(self, widget, category = None): def Filter(self, widget, category = None):
self.filterTimer = None self.filterTimer = None
@ -760,29 +792,32 @@ class pluginclass(object):
if self.lastActiveTab != 1: if self.lastActiveTab != 1:
self.changeTab(1, clear = False) self.changeTab(1, clear = False)
text = widget.get_text() text = widget.get_text()
showns = False # Are any app shown? # showns = False # Are any app shown?
shownList = [] # shownList = []
for i in self.applicationsBox.get_children(): # for i in self.applicationsBox.get_children():
shown = i.filterText(text) # shown = i.filterText(text)
if shown: # if shown:
dupe = False # dupe = False
for item in shownList: # for item in shownList:
if i.desktopFile == item.desktopFile: # if i.desktopFile == item.desktopFile:
dupe = True # dupe = True
if dupe: # if dupe:
i.hide() # i.hide()
else: # else:
shownList.append(i) # shownList.append(i)
#if this is the first matching item # #if this is the first matching item
#focus it # #focus it
if(not showns): # if(not showns):
i.grab_focus() # i.grab_focus()
showns = True # showns = True
if not showns: self.fuzzy_application_search(text)
if len(text) >= 3: # TODO Toggle self.enableFuzzySearch
self.add_search_suggestions(text)
if self.useAPT: # if not showns:
GLib.timeout_add(300, self.add_apt_filter_results, text) # if len(text) >= 3:
# self.add_search_suggestions(text)
# if self.useAPT:
# GLib.timeout_add(300, self.add_apt_filter_results, text)
for i in self.categoriesBox.get_children(): for i in self.categoriesBox.get_children():
i.released() i.released()
i.set_relief(Gtk.ReliefStyle.NONE) i.set_relief(Gtk.ReliefStyle.NONE)
@ -809,7 +844,6 @@ class pluginclass(object):
i.released() i.released()
i.set_relief(Gtk.ReliefStyle.NONE) i.set_relief(Gtk.ReliefStyle.NONE)
widget.set_relief(Gtk.ReliefStyle.HALF) widget.set_relief(Gtk.ReliefStyle.HALF)
self.applicationsScrolledWindow.get_vadjustment().set_value(0) self.applicationsScrolledWindow.get_vadjustment().set_value(0)
def FilterAndClear(self, widget, category = None): def FilterAndClear(self, widget, category = None):
@ -1592,10 +1626,10 @@ class pluginclass(object):
self.applicationList[key]["button"].destroy() self.applicationList[key]["button"].destroy()
del self.applicationList[key] del self.applicationList[key]
if addedApplications: if addedApplications:
sortedApplicationList = [] self.sortedApplicationList = []
for item in self.applicationList: for item in self.applicationList:
self.applicationsBox.remove(item["button"]) self.applicationsBox.remove(item["button"])
sortedApplicationList.append((item["button"].appName, item["button"])) self.sortedApplicationList.append((item["button"].appName, item["button"]))
for item in addedApplications: for item in addedApplications:
item["button"] = MenuApplicationLauncher(item["entry"].get_desktop_file_path(), item["button"] = MenuApplicationLauncher(item["entry"].get_desktop_file_path(),
self.iconSize, item["category"], self.showapplicationcomments, self.iconSize, item["category"], self.showapplicationcomments,
@ -1603,21 +1637,21 @@ class pluginclass(object):
if item["button"].appExec: if item["button"].appExec:
self.mintMenuWin.setTooltip(item["button"], item["button"].getTooltip()) self.mintMenuWin.setTooltip(item["button"], item["button"].getTooltip())
item["button"].connect("button-press-event", self.menuPopup) item["button"].connect("button-press-event", self.menuPopup)
item["button"].connect("focus-in-event", self.scrollItemIntoView) # item["button"].connect("focus-in-event", self.scrollItemIntoView)
item["button"].connect("clicked", RecentHelper.applicationButtonClicked) item["button"].connect("clicked", RecentHelper.applicationButtonClicked)
if self.activeFilter[0] == 0: if self.activeFilter[0] == 0:
item["button"].filterText(self.activeFilter[1]) item["button"].filterText(self.activeFilter[1])
else: else:
item["button"].filterCategory(self.activeFilter[1]) item["button"].filterCategory(self.activeFilter[1])
item["button"].desktop_file_path = item["entry"].get_desktop_file_path() item["button"].desktop_file_path = item["entry"].get_desktop_file_path()
sortedApplicationList.append((item["button"].appName.upper(), item["button"])) self.sortedApplicationList.append((item["button"].appName.upper(), item["button"]))
self.applicationList.append(item) self.applicationList.append(item)
else: else:
item["button"].destroy() item["button"].destroy()
sortedApplicationList.sort() self.sortedApplicationList.sort()
launcherNames = [] # Keep track of launcher names so we don't add them twice in the list.. launcherNames = [] # Keep track of launcher names so we don't add them twice in the list..
for item in sortedApplicationList: for item in self.sortedApplicationList:
launcherName = item[0] launcherName = item[0]
button = item[1] button = item[1]
self.applicationsBox.add(button) self.applicationsBox.add(button)