diff --git a/devices/wim/config/ags/js/applauncher/app-item.js b/devices/wim/config/ags/js/applauncher/app-item.js index e1739227..9fc05e55 100644 --- a/devices/wim/config/ags/js/applauncher/app-item.js +++ b/devices/wim/config/ags/js/applauncher/app-item.js @@ -44,13 +44,14 @@ export default (app) => { return Button({ + hexpand: true, class_name: 'app', setup: (self) => { self.app = app; }, - on_clicked: () => { + onPrimaryClickRelease: () => { App.closeWindow('applauncher'); Hyprland.sendMessage(`dispatch exec sh -c ${app.executable}`); ++app.frequency; diff --git a/devices/wim/config/ags/js/applauncher/main.js b/devices/wim/config/ags/js/applauncher/main.js index 2f1729ec..52704aaf 100644 --- a/devices/wim/config/ags/js/applauncher/main.js +++ b/devices/wim/config/ags/js/applauncher/main.js @@ -1,8 +1,10 @@ import App from 'resource:///com/github/Aylur/ags/app.js'; import Applications from 'resource:///com/github/Aylur/ags/service/applications.js'; import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js'; +// TODO: find cleaner way to import this +import { Fzf } from '../../node_modules/fzf/dist/fzf.es.js'; -import { Box, Entry, Icon, Label, Scrollable } from 'resource:///com/github/Aylur/ags/widget.js'; +import { Box, Entry, Icon, Label, ListBox, Scrollable } from 'resource:///com/github/Aylur/ags/widget.js'; import PopupWindow from '../misc/popup.js'; import Separator from '../misc/separator.js'; @@ -12,24 +14,53 @@ import AppItem from './app-item.js'; const Applauncher = ({ window_name = 'applauncher' } = {}) => { const ICON_SEPARATION = 4; - const children = () => [ - ...Applications.query('').flatMap((app) => { + let fzfResults; + const list = ListBox(); + const setSort = (text) => { + const fzf = new Fzf(Applications.list, { + selector: (app) => app.name, + tiebreakers: [(a, b) => b._frequency - + a._frequency], + }); + + fzfResults = fzf.find(text); + list.set_sort_func((a, b) => { + const row1 = a.get_children()[0].children[1]?.app.name; + const row2 = b.get_children()[0].children[1]?.app.name; + + if (!row1 || !row2) { + return 0; + } + + return fzfResults.indexOf(row1) - + fzfResults.indexOf(row1) || 0; + }); + }; + + const makeNewChildren = () => { + list.get_children().forEach((ch) => { + ch.destroy(); + }); + + [...Applications.query('').flatMap((app) => { const item = AppItem(app); - return [ - Separator(ICON_SEPARATION, { - binds: [['visible', item, 'visible']], - }), - item, - ]; + return Box({ + children: [ + Separator(ICON_SEPARATION, { + binds: [['visible', item, 'visible']], + }), + item, + ], + }); }), - Separator(ICON_SEPARATION), - ]; + Separator(ICON_SEPARATION)] + .forEach(((ch) => { + list.add(ch); + })); + }; - const list = Box({ - vertical: true, - children: children(), - }); + makeNewChildren(); const placeholder = Label({ label: " Couldn't find a match", @@ -45,7 +76,7 @@ const Applauncher = ({ window_name = 'applauncher' } = {}) => { const appList = Applications.query(text || ''); if (appList[0]) { - App.toggleWindow(window_name); + App.closeWindow(window_name); Hyprland.sendMessage(`dispatch exec sh -c ${appList[0].executable}`); ++appList[0].frequency; @@ -53,13 +84,22 @@ const Applauncher = ({ window_name = 'applauncher' } = {}) => { }, on_change: ({ text }) => { + setSort(text); let visibleApps = 0; - list.children.forEach((item) => { - if (item.app) { - item.visible = item.app.match(text); + list.get_children().forEach((row) => { + row.changed(); - if (item.app.match(text)) { + const item = row.get_children()[0].children[1]; + + if (item?.app) { + const isMatching = fzfResults.find((r) => { + return r.item.name === item.app.name; + }); + + row.visible = isMatching; + + if (isMatching) { ++visibleApps; } } @@ -101,7 +141,7 @@ const Applauncher = ({ window_name = 'applauncher' } = {}) => { entry.grab_focus(); } else { - list.children = children(); + makeNewChildren(); } }]], }); diff --git a/devices/wim/config/ags/package.json b/devices/wim/config/ags/package.json index e9a841a4..996d98ac 100644 --- a/devices/wim/config/ags/package.json +++ b/devices/wim/config/ags/package.json @@ -8,6 +8,7 @@ "@typescript-eslint/eslint-plugin": "^6.9.1", "@typescript-eslint/parser": "^6.9.1", "eslint": "^8.52.0", + "fzf": "^0.5.2", "stylelint-config-standard-scss": "^11.0.0" }, "devDependencies": { diff --git a/devices/wim/config/ags/scss/widgets/applauncher.scss b/devices/wim/config/ags/scss/widgets/applauncher.scss index 497bc8e6..77540e28 100644 --- a/devices/wim/config/ags/scss/widgets/applauncher.scss +++ b/devices/wim/config/ags/scss/widgets/applauncher.scss @@ -10,6 +10,10 @@ font-size: 16px; } + list, row { + all: unset; + } + .header { margin: 16.2px; margin-bottom: 0; diff --git a/modules/ags/default.nix b/modules/ags/default.nix index 34ea7b7c..15e03807 100644 --- a/modules/ags/default.nix +++ b/modules/ags/default.nix @@ -38,7 +38,6 @@ in { pavucontrol # TODO: replace with ags widget ]) ++ (optionals isTouchscreen (with pkgs; [ - # touchscreen lisgd squeekboard ydotool