summaryrefslogtreecommitdiff
path: root/.config/eww/listapps.py
diff options
context:
space:
mode:
Diffstat (limited to '.config/eww/listapps.py')
-rwxr-xr-x.config/eww/listapps.py120
1 files changed, 120 insertions, 0 deletions
diff --git a/.config/eww/listapps.py b/.config/eww/listapps.py
new file mode 100755
index 0000000..2dae1dc
--- /dev/null
+++ b/.config/eww/listapps.py
@@ -0,0 +1,120 @@
+#!/usr/bin/env python3
+
+import glob
+import json
+import os
+import os.path
+import shlex
+import sqlite3
+import sys
+from dataclasses import dataclass
+
+
+@dataclass
+class App:
+ name: str
+ icon: str | None
+ command: str
+
+
+def parse_desktop_file(path: str) -> App:
+ section = ''
+ app = App('', None, '')
+ with open(path, 'r') as file:
+ for line in file:
+ line = line.split('#')[0]
+ if line == '':
+ continue
+ if line.startswith('['):
+ section = line.rstrip().removeprefix('[').removesuffix(']')
+ continue
+ entry = line.split('=')
+ if len(entry) < 2:
+ continue
+ k, v = entry[0], entry[1].rstrip()
+ if k == 'Name':
+ app.name = v
+ elif k == 'Icon':
+ app.icon = v
+ elif k == 'Exec':
+ app.command = v.replace('%u', '').replace('%U', '').replace('%F', '').rstrip()
+ return app
+
+
+def get_apps() -> dict[str, App]:
+ apps = {}
+ for dir in os.environ['PATH'].split(':'):
+ if os.path.exists(dir):
+ for ent in os.listdir(dir):
+ if os.access(os.path.join(dir, ent), os.X_OK):
+ apps[ent] = App(ent, None, ent)
+ for path in glob.glob('/usr/share/applications/*.desktop'):
+ app = parse_desktop_file(path)
+ apps[app.name] = app
+ for path in glob.glob(os.path.expanduser('~/.local/share/applications/*.desktop')):
+ app = parse_desktop_file(path)
+ apps[app.name] = app
+ return apps
+
+
+def printusage(argv0):
+ print(f'{argv0} query [QUERY] | run NAME', file=sys.stderr)
+
+
+def main(argv: list[str]) -> int:
+ conn = sqlite3.connect(os.path.expanduser('~/.local/share/eww/apps.sqlite'))
+ conn.execute('''
+ create table if not exists app(
+ id integer primary key,
+ name text unique not null,
+ count integer default 0 not null
+ );
+ ''')
+
+ apps = get_apps()
+ with conn:
+ for app in apps.values():
+ conn.execute('insert or ignore into app (name) values (?)', (app.name, ))
+
+ if len(argv) < 2:
+ printusage(argv[0])
+ return 1
+
+ if argv[1] == 'query':
+ out = []
+ query = '' if len(argv) < 3 else argv[2]
+ for name, in conn.execute('''
+ select name
+ from app
+ where name like '%'||?||'%'
+ order by count desc, name
+ ''', (query, )).fetchall():
+ app = apps[name]
+ d = {'name': app.name}
+ if app.icon is not None:
+ d['icon'] = app.icon
+ out.append(d)
+ data = json.dumps(out, separators=(',', ':'))
+ argv = ['eww', 'update', 'applist=' + data]
+ os.execvp(argv[0], argv)
+ elif argv[1] == 'run':
+ if app := apps.get(argv[2]):
+ with conn:
+ conn.execute('insert or ignore into app (name) values (?)', (app.name, ))
+ conn.execute('update app set count = count + 1 where name = ?', (app.name, ))
+ argv = shlex.split(app.command)
+ os.execvp(argv[0], argv)
+ else:
+ print(f'app {argv[2]} not found', file=sys.stderr)
+ else:
+ printusage(argv[0])
+ return 1
+
+ return 0
+
+
+if __name__ == '__main__':
+ try:
+ sys.exit(main(sys.argv))
+ except BrokenPipeError:
+ pass