Update project files

This commit is contained in:
Thales Maciel 2026-02-10 11:01:36 -03:00
parent ad66a0d3cb
commit a17c234360
14 changed files with 952 additions and 529 deletions

View file

@ -1,8 +1,9 @@
from __future__ import annotations
import re
from dataclasses import dataclass
import i3ipc
@dataclass
class Context:
@ -13,88 +14,30 @@ class Context:
title: str
@dataclass
class ContextRule:
match: dict
ai_prompt_file: str | None = None
ai_enabled: bool | None = None
injection_backend: str | None = None
tag: str | None = None
class ContextProvider:
def capture(self) -> Context:
raise NotImplementedError
def is_same_focus(self, ctx: Context) -> bool:
raise NotImplementedError
class I3Provider(ContextProvider):
class I3Provider:
def __init__(self):
import i3ipc
self.i3 = i3ipc.Connection()
self._conn = i3ipc.Connection()
def _focused(self):
node = self.i3.get_tree().find_focused()
if node is None:
raise RuntimeError("no focused window")
return node
return self._conn.get_tree().find_focused()
def capture(self) -> Context:
node = self._focused()
props = getattr(node, "window_properties", None) or {}
return Context(
window_id=node.id,
app_id=getattr(node, "app_id", None) or "",
klass=props.get("class") or "",
instance=props.get("instance") or "",
title=getattr(node, "name", None) or "",
app_id=node.app_id or "",
klass=node.window_class or "",
instance=node.window_instance or "",
title=node.name or "",
)
def is_same_focus(self, ctx: Context) -> bool:
node = self._focused()
return node.id == ctx.window_id
return bool(node and node.id == ctx.window_id)
def focus_window(self, window_id: int) -> bool:
node = self.i3.get_tree().find_by_id(window_id)
if node is None:
try:
self._conn.command(f"[con_id={window_id}] focus")
return True
except Exception:
return False
node.command("focus")
return True
def _match_text(val: str, needle: str | None) -> bool:
if not needle:
return True
return val == needle
def _match_title_contains(title: str, needle: str | None) -> bool:
if not needle:
return True
return needle.lower() in title.lower()
def _match_title_regex(title: str, pattern: str | None) -> bool:
if not pattern:
return True
return re.search(pattern, title) is not None
def match_rule(ctx: Context, rules: list[ContextRule]) -> ContextRule | None:
for rule in rules:
match = rule.match or {}
if not _match_text(ctx.app_id, match.get("app_id")):
continue
if not _match_text(ctx.klass, match.get("class")):
continue
if not _match_text(ctx.instance, match.get("instance")):
continue
if not _match_title_contains(ctx.title, match.get("title_contains")):
continue
if not _match_title_regex(ctx.title, match.get("title_regex")):
continue
return rule
return None