From 730f572806c836b84beb2569b0749b1f25d2afbb Mon Sep 17 00:00:00 2001 From: Richard Date: Mon, 13 Apr 2026 13:40:19 +0200 Subject: [PATCH] feat: click task numbers to open detail view Click on any #NNNN task number in the briefing to load its full detail view. Uses SGR mouse protocol for accurate click position, strips ANSI to find task IDs in visible text. Tolerates clicks within 5 chars of the # symbol. Co-Authored-By: Claude Opus 4.6 (1M context) --- briefing | 87 +++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 76 insertions(+), 11 deletions(-) diff --git a/briefing b/briefing index e9d0391..cdc1c00 100755 --- a/briefing +++ b/briefing @@ -528,25 +528,57 @@ def get_terminal_size(): def read_key(fd): - """Read a keypress from raw terminal. Returns key string.""" + """Read a keypress from raw terminal. Returns key string or ('CLICK', row, col) tuple.""" ch = os.read(fd, 1) if not ch: return '' if ch == b'\x1b': - # Escape sequence - seq = os.read(fd, 2) - if seq == b'[A': return 'UP' - if seq == b'[B': return 'DOWN' - if seq == b'[5': os.read(fd, 1); return 'PGUP' - if seq == b'[6': os.read(fd, 1); return 'PGDN' - if seq == b'[H': return 'HOME' - if seq == b'[F': return 'END' - if seq == b'[M': - # Mouse event: read 3 more bytes + # Read next bytes + b2 = os.read(fd, 1) + if b2 != b'[': + return 'ESC' + b3 = os.read(fd, 1) + + # SGR mouse: \033[= len(lines): + return None + # Strip ANSI to get visible text and map positions + raw = lines[line_idx] + clean = ANSI_ESC.sub('', raw) + # Find all #NNNN in the visible text + best = None + best_dist = 999 + for m in TASK_ID_RE.finditer(clean): + start, end = m.start(), m.end() + # Distance from click to the match + if start <= col <= end: + return int(m.group(1)) + dist = min(abs(col - start), abs(col - end)) + if dist < best_dist and dist <= 5: + best_dist = dist + best = int(m.group(1)) + return best + def split_lines(content): return content.split('\n') @@ -686,6 +742,15 @@ def tui_viewer(range_days, client): input_buf += key continue + # Mouse click — find task number + if isinstance(key, tuple) and key[0] == 'CLICK': + _, click_row, click_col = key + task_id = find_task_at_click(click_row, click_col) + if task_id: + viewing_task = True + load_task(task_id) + continue + if key == 'q': break elif key == 'r':