Commit 7b8a030badb9

Vincent Demeester <vincent@sbr.pm>
2026-07-10 14:32:55
feat(emacs): add clickable markdown links in pi chat
Made markdown inline links clickable in pi-coding-agent chat buffers via jit-lock buttonization. Also fixed indentation in the extension-loaded state refresh callback.
1 parent 8f72990
Changed files (1)
dots
config
emacs
dots/config/emacs/init.el
@@ -3408,16 +3408,58 @@ With \\[universal-argument] \\[universal-argument]: always prompt with completio
           (when (and proc (process-live-p proc) (buffer-live-p chat-buf))
             ;; Delay: let the extension handler finish its async work
             (run-at-time 2.0 nil
-              (lambda ()
-                (when (and (process-live-p proc) (buffer-live-p chat-buf))
-                  (pi-coding-agent--rpc-async proc '(:type "get_state")
-                    (lambda (r)
-                      (when (and (plist-get r :success) (buffer-live-p chat-buf))
-                        (with-current-buffer chat-buf
-                          (pi-coding-agent--update-state-from-response r)
-                          (pi-coding-agent--refresh-header))))))))))
+			 (lambda ()
+			   (when (and (process-live-p proc) (buffer-live-p chat-buf))
+			     (pi-coding-agent--rpc-async proc '(:type "get_state")
+							 (lambda (r)
+							   (when (and (plist-get r :success) (buffer-live-p chat-buf))
+							     (with-current-buffer chat-buf
+							       (pi-coding-agent--update-state-from-response r)
+							       (pi-coding-agent--refresh-header))))))))))
       (apply orig text args))))
 
+;; Make markdown links [text](url) clickable in pi chat buffers.
+;; Tree-sitter markdown hides the URL portion; this jit-lock function
+;; finds inline links and adds button properties so RET/click opens them.
+(with-eval-after-load 'pi-coding-agent
+  (defvar vde/pi-link-keymap
+    (let ((map (make-sparse-keymap)))
+      (define-key map [mouse-1]
+		  (lambda (e)
+		    (interactive "e")
+		    (when-let ((url (get-text-property
+				     (posn-point (event-start e))
+				     'pi-link-url)))
+		      (browse-url url))))
+      (define-key map (kbd "RET")
+		  (lambda ()
+		    (interactive)
+		    (when-let ((url (get-text-property (point) 'pi-link-url)))
+		      (browse-url url))))
+      map)
+    "Keymap for clickable markdown links in pi chat buffers.")
+
+  (defun vde/pi-buttonize-markdown-links (beg end)
+    "Buttonize markdown inline links in BEG..END for pi chat buffers."
+    (save-excursion
+      (goto-char beg)
+      (while (re-search-forward "\\[\\([^]]+\\)\\](\\([^)]+\\))" end t)
+	(let ((text-beg (match-beginning 1))
+	      (text-end (match-end 1))
+	      (url (match-string-no-properties 2)))
+	  (unless (get-text-property text-beg 'pi-link-url)
+	    (let ((inhibit-read-only t))
+	      (put-text-property text-beg text-end 'pi-link-url url)
+	      (put-text-property text-beg text-end 'help-echo url)
+	      (put-text-property text-beg text-end 'mouse-face 'highlight)
+	      (put-text-property text-beg text-end 'keymap vde/pi-link-keymap)
+	      (add-face-text-property text-beg text-end
+					'(:underline t) 'append)))))))
+
+  (add-hook 'pi-coding-agent-chat-mode-hook
+	    (lambda ()
+	      (jit-lock-register #'vde/pi-buttonize-markdown-links))))
+
 (use-package devdocs
   :commands (devdocs-lookup devdocs-install vde/install-devdocs)
   :bind (("C-h D" . devdocs-lookup))