2023-05-14 17:57:22 +01:00
|
|
|
import difflib
|
2022-03-25 12:04:29 +00:00
|
|
|
import json
|
|
|
|
import os
|
|
|
|
import sqlite3
|
2023-05-14 18:00:35 +01:00
|
|
|
import sys
|
|
|
|
from operator import attrgetter
|
2022-04-09 16:42:40 +01:00
|
|
|
from pathlib import Path
|
2022-03-25 12:04:29 +00:00
|
|
|
from typing import NamedTuple
|
|
|
|
|
|
|
|
import dbus.service
|
|
|
|
from dbus.mainloop.glib import DBusGMainLoop
|
|
|
|
from gi.repository import GLib
|
|
|
|
|
|
|
|
DBusGMainLoop(set_as_default=True)
|
|
|
|
|
|
|
|
objpath = "/vscode"
|
|
|
|
|
|
|
|
iface = "org.kde.krunner1"
|
|
|
|
|
|
|
|
|
2023-04-29 12:24:19 +01:00
|
|
|
VSCODE_DIRS = [
|
|
|
|
"Code",
|
|
|
|
"Code - OSS",
|
|
|
|
"VSCodium"
|
|
|
|
]
|
|
|
|
|
|
|
|
|
2022-03-25 12:04:29 +00:00
|
|
|
class Match(NamedTuple):
|
|
|
|
data: str
|
|
|
|
display_text: str
|
|
|
|
icon: str
|
|
|
|
type: int
|
|
|
|
relevance: float
|
|
|
|
properties: dict
|
|
|
|
|
|
|
|
|
2023-05-14 17:57:22 +01:00
|
|
|
def get_matches(paths, query):
|
|
|
|
"""
|
|
|
|
Equivalent to `difflib.get_close_matches`, but returning the ratio too
|
|
|
|
"""
|
|
|
|
matches = []
|
|
|
|
s = difflib.SequenceMatcher()
|
|
|
|
s.set_seq2(query)
|
|
|
|
|
|
|
|
for path in paths:
|
|
|
|
s.set_seq1(path)
|
|
|
|
matches.append((s.ratio(), path))
|
|
|
|
|
|
|
|
return matches
|
|
|
|
|
|
|
|
|
2022-03-25 12:04:29 +00:00
|
|
|
# Read path_list from database
|
2022-03-28 09:36:38 +01:00
|
|
|
def get_path_list():
|
2023-05-07 17:38:10 +01:00
|
|
|
paths = set()
|
2023-04-29 12:24:19 +01:00
|
|
|
|
|
|
|
for vscode_dir in VSCODE_DIRS:
|
|
|
|
state_file = os.path.join(
|
|
|
|
os.environ["HOME"], ".config", vscode_dir, "User/globalStorage/state.vscdb"
|
|
|
|
)
|
|
|
|
|
|
|
|
if not os.path.exists(state_file):
|
|
|
|
continue
|
|
|
|
|
|
|
|
con = sqlite3.connect(state_file)
|
|
|
|
cur = con.cursor()
|
|
|
|
rows = cur.execute(
|
|
|
|
"SELECT value FROM ItemTable WHERE key = 'history.recentlyOpenedPathsList'"
|
|
|
|
)
|
|
|
|
data = json.loads(rows.fetchone()[0])
|
|
|
|
con.close()
|
|
|
|
paths.update(
|
|
|
|
{
|
|
|
|
"~" + path[len(os.environ["HOME"]) :] if os.environ["HOME"] in path else path
|
|
|
|
for path in [i["folderUri"][7:] for i in data["entries"] if "folderUri" in i]
|
|
|
|
}
|
2022-03-28 09:36:38 +01:00
|
|
|
)
|
2023-05-07 17:38:10 +01:00
|
|
|
return paths
|
2022-03-25 12:04:29 +00:00
|
|
|
|
|
|
|
|
|
|
|
class Runner(dbus.service.Object):
|
|
|
|
def __init__(self):
|
|
|
|
dbus.service.Object.__init__(
|
|
|
|
self,
|
|
|
|
dbus.service.BusName(
|
|
|
|
"com.github.j1g5awi.vscode", dbus.SessionBus() # type:ignore
|
|
|
|
),
|
|
|
|
objpath,
|
|
|
|
)
|
|
|
|
|
|
|
|
@dbus.service.method(iface, in_signature="s", out_signature="a(sssida{sv})")
|
|
|
|
def Match(self, query: str):
|
|
|
|
# data, display text, icon, type (Plasma::QueryType), relevance (0-1), properties (subtext, category and urls)
|
2023-05-14 17:57:22 +01:00
|
|
|
matches = get_matches(get_path_list(), query)
|
|
|
|
|
2022-03-25 12:04:29 +00:00
|
|
|
return [
|
|
|
|
Match(
|
|
|
|
path,
|
2022-04-09 16:42:40 +01:00
|
|
|
Path(path).name,
|
2022-03-25 12:04:29 +00:00
|
|
|
"com.visualstudio.code.oss",
|
|
|
|
100,
|
2023-05-14 17:57:22 +01:00
|
|
|
ratio,
|
2022-03-25 12:04:29 +00:00
|
|
|
{"subtext": path},
|
|
|
|
)
|
2023-05-14 17:57:22 +01:00
|
|
|
for ratio, path in matches
|
2022-03-25 12:04:29 +00:00
|
|
|
]
|
|
|
|
|
|
|
|
@dbus.service.method(iface, out_signature="a(sss)")
|
|
|
|
def Actions(self):
|
|
|
|
# id, text, icon
|
|
|
|
return [("id", "Open Folder", "document-open-folder")]
|
|
|
|
|
|
|
|
@dbus.service.method(iface, in_signature="ss")
|
|
|
|
def Run(self, data: str, action_id: str):
|
|
|
|
if not action_id:
|
|
|
|
os.system("code " + data)
|
|
|
|
else:
|
|
|
|
os.system("xdg-open " + data)
|
|
|
|
|
|
|
|
|
2023-05-14 18:00:35 +01:00
|
|
|
def main():
|
|
|
|
runner = Runner()
|
|
|
|
if sys.argv[1:]:
|
|
|
|
# Manual search - useful for local testing
|
|
|
|
for match in sorted(runner.Match(sys.argv[1]), key=attrgetter("relevance")):
|
|
|
|
print(match.data, match.relevance)
|
|
|
|
else:
|
|
|
|
loop = GLib.MainLoop()
|
|
|
|
loop.run()
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
main()
|