Skip to content

Commit

Permalink
feat: support custom (and provide default) search settings
Browse files Browse the repository at this point in the history
  • Loading branch information
m-k-l-s committed Jan 5, 2023
1 parent 5d52196 commit fd0e50c
Show file tree
Hide file tree
Showing 13 changed files with 410 additions and 55 deletions.
133 changes: 131 additions & 2 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ readme = "README.md"
repository = "https://github.com/MikulasZelinka/searchlauncher"

[tool.poetry.scripts]
searchlauncher = 'searchlauncher.cli:main'
searchlauncher = 'searchlauncher.cli:cli'

[tool.poetry.dependencies]
python = "^3.11"
keyboard = "^0.13.5"
typer = "^0.7.0"
typer = {extras = ["all"], version = "^0.7.0"}
loguru = "^0.6.0"
pydantic = "^1.10.4"
tomlkit = "^0.11.6"

[tool.poetry.group.dev.dependencies]
black = "^22.10.0"
Expand All @@ -38,6 +40,7 @@ profile = "black"

[tool.mypy]
disallow_untyped_defs = true
strict = true

[[tool.mypy.overrides]]
module = "tests.*"
Expand Down
2 changes: 2 additions & 0 deletions src/searchlauncher/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from .gui import start_gui
from .search import open_in_browser
from .settings import load_settings

__all__ = [
"start_gui",
"open_in_browser",
"load_settings",
]
71 changes: 56 additions & 15 deletions src/searchlauncher/cli.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,72 @@
from typing import Optional
from enum import StrEnum
from typing import Generator

import typer
from loguru import logger

from searchlauncher import open_in_browser, start_gui
from searchlauncher.settings import DEFAULT_SETTINGS_PATH, load_settings

cli = typer.Typer()

def cli(query: Optional[str] = typer.Argument(None)) -> None:
settings = load_settings()
Group = StrEnum("Group", list(settings.groups.keys())) # type: ignore


def complete_groups(incomplete: str) -> Generator[tuple[str, str], None, None]:
for group_name, group in settings.groups.items():
if group_name.startswith(incomplete):
yield group_name, ", ".join(group.sites)


@cli.command()
def search(
query: str,
group: Group = typer.Option( # type: ignore
None,
"--group",
"-g",
autocompletion=complete_groups,
case_sensitive=False,
),
) -> None:
"""
Starts a daemon listening for a keyboard shortcut,
unless query is specified – in which case, it opens search for the query.
Directly open search for the given query using all sites or the specified group.
Args:
query:
Searches all sites unless a group is specified with "-g" or "--group" (see "searchlauncher config").
"""
open_in_browser(query, group_name=group)

Returns:

@cli.command()
def config() -> None:
"""
if query:
open_in_browser(query)
else:
start_gui()
Open the config directory.
You can modify the "toml" file to modify keyboard shortcuts, sites and groups.
"""
settings_dir = str(DEFAULT_SETTINGS_PATH)
logger.info(f"Opening settings directory: {settings_dir}")
typer.launch(settings_dir, locate=True)


@cli.callback(invoke_without_command=True)
def run(
ctx: typer.Context,
) -> None:
"""
Run search launcher in background, waiting for shortcuts.
See the "Commands" section below for more.
"""

def main() -> None:
# we wrap cli() inside main() so that typer runs even when main() is invoked directly
typer.run(cli)
# This makes running just "searchlauncher" without any further commands run the main loop
# https://github.com/tiangolo/typer/issues/18
if ctx.invoked_subcommand is not None:
# If there's any command, we don't run the main loop
return
start_gui()


if __name__ == "__main__":
main()
cli()
31 changes: 22 additions & 9 deletions src/searchlauncher/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,36 @@
import keyboard
from loguru import logger

from searchlauncher.settings import load_settings

from .search import open_in_browser

SHORTCUT = "ctrl+shift+f"
QUERY_WIDTH = 25
FONT = "Arial 30"

# Our popup window will get focused after this many milliseconds
FOCUS_DELAY = 42
# FOCUS_DELAY = 42
FOCUS_DELAY = 69
# FOCUS_DELAY = 420


def start_search(query: StringVar, root: Tk) -> None:
def start_search(query: StringVar, group_name: str | None, root: Tk) -> None:
query_str: str = query.get()

# To handle invalid queries:
# if not(query.startswith('http://') or query.startswith('https://')):
# messagebox.showerror("Invalid query", "Must start with http:// or https://")
# return

open_in_browser(query_str)
open_in_browser(query_str, group_name)

root.destroy()


def show_popup() -> None:
def show_launcher(group_name: str) -> None:
root = Tk()
root.title("Search launcher")
root.title(f"Search launcher{group_name}")

# center on screen
root.eval("tk::PlaceWindow . center")
Expand All @@ -40,7 +44,7 @@ def show_popup() -> None:
entry.pack()

# submit on enter, quit on escape
root.bind("<Return>", lambda _: start_search(query, root))
root.bind("<Return>", lambda _: start_search(query, group_name, root))
root.bind("<Escape>", lambda _: root.destroy())

# move into foreground
Expand All @@ -54,13 +58,22 @@ def show_popup() -> None:
def start_gui() -> None:
if platform.system() == "Windows":
logger.debug("Fixing resolution scaling on Windows")
from ctypes import windll # type: ignore
from ctypes import windll

# Fix blurry font with resolution scaling on Windows:
windll.shcore.SetProcessDpiAwareness(1)

logger.info(f"Starting in background, activate the search by using '{SHORTCUT}'")
keyboard.add_hotkey(SHORTCUT, show_popup)
settings = load_settings()

for group_name, group in settings.groups.items():

# a group does not need to have a shortcut, it could just be used by a different group
if not group.shortcut:
continue

logger.info(f"Search {group_name} with '{group.shortcut}'")
keyboard.add_hotkey(group.shortcut, show_launcher, args=(group_name,))

# wait() loops automatically:
keyboard.wait()

Expand Down
Loading

0 comments on commit fd0e50c

Please sign in to comment.