From c28605bb38be26ddc3f84d381e681e92036f7da8 Mon Sep 17 00:00:00 2001 From: Fabio Scotto di Santolo Date: Sat, 11 Apr 2026 22:14:32 +0200 Subject: [PATCH] Add OpenCode session picker for Emacs --- .../desktop/.emacs.d/lisp/core/keybindings.el | 1 + .../.emacs.d/lisp/misc/custom-functions.el | 61 +++++++++++++++++-- .../desktop/.emacs.d/lisp/misc/which-key.el | 1 + 3 files changed, 59 insertions(+), 4 deletions(-) diff --git a/dotfiles/desktop/.emacs.d/lisp/core/keybindings.el b/dotfiles/desktop/.emacs.d/lisp/core/keybindings.el index 55843e0..4419ca3 100644 --- a/dotfiles/desktop/.emacs.d/lisp/core/keybindings.el +++ b/dotfiles/desktop/.emacs.d/lisp/core/keybindings.el @@ -86,6 +86,7 @@ (define-key projectile-command-map (kbd "V") #'fscotto/project-multi-vterm) (define-key projectile-command-map (kbd "x") #'fscotto/project-external-terminal) (define-key projectile-command-map (kbd "a") #'fscotto/project-opencode) + (define-key projectile-command-map (kbd "A") #'fscotto/project-opencode-session) (define-key projectile-command-map (kbd "g") #'fscotto/project-magit-status)) ;;;; LSP diff --git a/dotfiles/desktop/.emacs.d/lisp/misc/custom-functions.el b/dotfiles/desktop/.emacs.d/lisp/misc/custom-functions.el index becdc80..82c0623 100644 --- a/dotfiles/desktop/.emacs.d/lisp/misc/custom-functions.el +++ b/dotfiles/desktop/.emacs.d/lisp/misc/custom-functions.el @@ -38,13 +38,17 @@ (interactive) (fscotto/open-multi-vterm-in (fscotto/project-root))) -(defun fscotto/launch-external-terminal (&optional command) - "Launch external terminal in project root, optionally running COMMAND." - (let* ((default-directory (file-name-as-directory (fscotto/project-root))) +(defconst fscotto/opencode-db-path + (expand-file-name "~/.local/share/opencode/opencode.db") + "Path to the OpenCode SQLite database.") + +(defun fscotto/launch-external-terminal (&optional command directory) + "Launch external terminal in DIRECTORY, optionally running COMMAND." + (let* ((default-directory (file-name-as-directory (or directory (fscotto/project-root)))) (terminal-program (or (executable-find fscotto/external-terminal-program) fscotto/external-terminal-program)) (args (append - (list fscotto/external-terminal-working-directory-option + (list fscotto/external-terminal-working-directory-option default-directory) (when command (append @@ -58,6 +62,55 @@ terminal-program args))) +(defun fscotto/opencode-session-candidates (directory) + "Return OpenCode session candidates for DIRECTORY. + +Each entry is a cons cell of display string and session id." + (let ((sqlite3-program (executable-find "sqlite3")) + (session-directory (directory-file-name (expand-file-name directory)))) + (unless sqlite3-program + (user-error "sqlite3 not found")) + (unless (file-exists-p fscotto/opencode-db-path) + (user-error "OpenCode database not found: %s" fscotto/opencode-db-path)) + (mapcar + (lambda (line) + (pcase-let* ((fields (split-string line "\t")) + (`(,session-id ,title ,updated-at) fields) + (title (if (and title (not (string= title ""))) + title + "Untitled session")) + (updated-seconds (/ (string-to-number updated-at) 1000)) + (updated-label (format-time-string "%Y-%m-%d %H:%M" + (seconds-to-time updated-seconds))) + (short-id (if (> (length session-id) 12) + (substring session-id 0 12) + session-id))) + (cons (format "%s | %s | %s" title updated-label short-id) + session-id))) + (process-lines + sqlite3-program + "-tabs" + "-noheader" + fscotto/opencode-db-path + (format (concat + "select id, title, time_updated " + "from session " + "where directory = '%s' and time_archived is null " + "order by time_updated desc;") + (replace-regexp-in-string "'" "''" session-directory)))))) + +(defun fscotto/project-opencode-session () + "Resume a saved OpenCode session for the current project." + (interactive) + (let* ((project-directory (fscotto/project-root)) + (candidates (fscotto/opencode-session-candidates project-directory))) + (unless candidates + (user-error "No OpenCode sessions found for %s" project-directory)) + (let* ((selection (completing-read "OpenCode session: " candidates nil t)) + (session-id (cdr (assoc selection candidates)))) + (fscotto/launch-external-terminal (list "opencode" "--session" session-id) + project-directory)))) + (defun fscotto/project-external-terminal () "Open the external terminal in project root." (interactive) diff --git a/dotfiles/desktop/.emacs.d/lisp/misc/which-key.el b/dotfiles/desktop/.emacs.d/lisp/misc/which-key.el index 9352e7b..69abdc0 100644 --- a/dotfiles/desktop/.emacs.d/lisp/misc/which-key.el +++ b/dotfiles/desktop/.emacs.d/lisp/misc/which-key.el @@ -145,6 +145,7 @@ "C-c p V" "Open multi-vterm in project" "C-c p x" "Open external term" "C-c p a" "Open opencode" + "C-c p A" "Resume opencode session" "C-c p e" "Edit project config" "C-c p g" "Project Git status" "C-c p 4" "Other Window"