Commit 3d954fe441ce

Vincent Demeester <vincent@sbr.pm>
2026-02-10 16:30:09
feat(kitty): added GitHub PR/issue hints
Added kitty hints for GitHub issue and PR references. Detects bare #123 and qualified org/repo#123 patterns. Copy to clipboard with kitty_mod+i, open in browser with kitty_mod+alt+i. Bare references resolve repo from git remote in the active window's working directory.
1 parent 2cf079d
Changed files (1)
home
common
desktop
home/common/desktop/kitty.nix
@@ -114,6 +114,11 @@
       map kitty_mod+j mkh --type regex --regex '\b([A-Z]{2,10}-\d+)\b' --program @
       map kitty_mod+alt+j mkh --customize-processing ~/.config/kitty/jira-hints.py
 
+      # GitHub PR/issue - detect #123 or org/repo#123 patterns
+      # Copy to clipboard or open on github.com (bare #123 uses git remote for context)
+      map kitty_mod+i mkh --type regex --regex '(?:[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+)?#\d+' --program @
+      map kitty_mod+alt+i mkh --customize-processing ~/.config/kitty/github-hints.py
+
       # Word selection hints with multiple actions
       # Copy word to clipboard (default word hint already at kitty_mod+d)
       map kitty_mod+alt+d mkh --customize-processing ~/.config/kitty/word-hints.py define
@@ -173,6 +178,72 @@
               boss.open_url(url)
     '';
 
+    "kitty/github-hints.py".text = ''
+      """
+      Kitty hints for GitHub issue/PR detection and opening in browser.
+      Detects patterns like #123 or org/repo#123.
+      For bare #123, resolves the repo from git remote in the active window's cwd.
+      """
+      import re
+      import subprocess
+
+
+      def mark(text, args, Mark, extra_cli_args, *a):
+          """Find all GitHub issue/PR references in the visible text."""
+          # Match org/repo#123 or bare #123
+          pattern = r'(?:[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+)?#\d+'
+
+          for idx, m in enumerate(re.finditer(pattern, text)):
+              start, end = m.span()
+              ref = text[start:end].replace('\n', ''').replace('\0', ''')
+              yield Mark(idx, start, end, ref, {})
+
+
+      def handle_result(args, data, target_window_id, boss, extra_cli_args, *a):
+          """Open selected GitHub issue/PR in browser."""
+          matches = [m for m in data['match'] if m]
+
+          for ref in matches:
+              if '/' in ref:
+                  # Fully qualified: org/repo#123
+                  repo, number = ref.rsplit('#', 1)
+                  url = f'https://github.com/{repo}/issues/{number}'
+              else:
+                  # Bare #123 - resolve repo from git remote in active window cwd
+                  number = ref.lstrip('#')
+                  repo = _get_github_repo(boss, target_window_id)
+                  if repo:
+                      url = f'https://github.com/{repo}/issues/{number}'
+                  else:
+                      url = None
+
+              if url:
+                  boss.open_url(url)
+
+
+      def _get_github_repo(boss, target_window_id):
+          """Extract GitHub org/repo from git remote in the target window's cwd."""
+          window = boss.window_id_map.get(target_window_id)
+          if not window:
+              return None
+          cwd = window.cwd_of_child
+          if not cwd:
+              return None
+          try:
+              result = subprocess.run(
+                  ['git', 'remote', 'get-url', 'origin'],
+                  capture_output=True, text=True, cwd=cwd, timeout=5,
+              )
+              if result.returncode != 0:
+                  return None
+              url = result.stdout.strip()
+              # Handle git@github.com:org/repo.git and https://github.com/org/repo.git
+              m = re.search(r'github\.com[:/]([^/]+/[^/]+?)(?:\.git)?$', url)
+              return m.group(1) if m else None
+          except Exception:
+              return None
+    '';
+
     "kitty/word-hints.py".text = ''
       """
       Kitty hints for word selection with multiple actions.