branch: externals/forgejo
commit 7d5903668a7ee13184e8172062d8dd015823d12e
Author: Thanos Apollo <[email protected]>
Commit: Thanos Apollo <[email protected]>
vc: Add per-repo remote selection for multi-remote setups
---
lisp/forgejo-vc.el | 64 +++++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 56 insertions(+), 8 deletions(-)
diff --git a/lisp/forgejo-vc.el b/lisp/forgejo-vc.el
index dca4f90bd6..0838508195 100644
--- a/lisp/forgejo-vc.el
+++ b/lisp/forgejo-vc.el
@@ -160,15 +160,37 @@ Also syncs repo metadata if not yet cached."
(match-string 2 remote-url)
(match-string 3 remote-url)))))
+(defun forgejo-vc--all-forge-remotes ()
+ "Return all git remotes that parse as forge URLs.
+Each element is (HOST OWNER REPO REMOTE-NAME)."
+ (cl-loop for remote in (forgejo-vc--remotes)
+ for url = (forgejo-vc--remote-url remote)
+ for parsed = (and url (forgejo-vc--parse-remote-url url))
+ when parsed collect (append parsed (list remote))))
+
+(defvar forgejo-vc--selected-remotes (make-hash-table :test 'equal)
+ "Selected remote name per repo root directory.")
+
+(defun forgejo-vc--repo-root ()
+ "Return git toplevel for `default-directory', or nil."
+ (vc-git-root default-directory))
+
+(defun forgejo-vc--selected-remote ()
+ "Return the user-selected remote for the current repo, or nil."
+ (when-let* ((root (forgejo-vc--repo-root)))
+ (gethash root forgejo-vc--selected-remotes)))
+
(defun forgejo-vc--repo-from-remote ()
- "Detect host, owner, repo, and remote name from any git remote.
-Tries all remotes and returns the first that parses as a forge URL.
+ "Detect host, owner, repo, and remote name from a git remote.
+When a remote has been selected via `forgejo-vc-select-remote',
+prefer that remote. Otherwise return the first forge remote.
Returns (HOST OWNER REPO REMOTE-NAME) or nil."
- (cl-some (lambda (remote)
- (when-let* ((url (forgejo-vc--remote-url remote))
- (parsed (forgejo-vc--parse-remote-url url)))
- (append parsed (list remote))))
- (forgejo-vc--remotes)))
+ (let ((all (forgejo-vc--all-forge-remotes))
+ (selected (forgejo-vc--selected-remote)))
+ (or (and selected
+ (cl-find selected all
+ :key (lambda (r) (nth 3 r)) :test #'string=))
+ (car all))))
(defun forgejo-vc--upstream-branch (branch)
"Return the upstream remote/branch for BRANCH, or nil."
@@ -552,6 +574,25 @@ and mark it as manually merged after a successful push."
(cl-destructuring-bind (host owner repo) (forgejo-vc--require-repo)
(forgejo-utils-browse-repo host owner repo)))
+;;; Remote selection
+
+(defun forgejo-vc--multiple-remotes-p ()
+ "Return non-nil when more than one forge remote exists."
+ (> (length (forgejo-vc--all-forge-remotes)) 1))
+
+(defun forgejo-vc-select-remote ()
+ "Select which forge remote to use for this repository."
+ (interactive)
+ (let* ((all (forgejo-vc--all-forge-remotes))
+ (candidates (mapcar (lambda (r)
+ (format "%s (%s/%s)" (nth 3 r) (nth 1 r) (nth 2
r)))
+ all))
+ (choice (completing-read "Remote: " candidates nil t))
+ (idx (cl-position choice candidates :test #'string=))
+ (root (forgejo-vc--repo-root)))
+ (puthash root (nth 3 (nth idx all)) forgejo-vc--selected-remotes)
+ (setq forgejo-vc--repo-key nil)))
+
;;; Popup keymap
(defun forgejo-vc--no-remote-p ()
@@ -592,7 +633,14 @@ and mark it as manually merged after a successful push."
:inapt-if (lambda () (forgejo-vc--no-remote-p)))
:group "Actions"
"S" ("Settings" forgejo-settings)
- "b" ("Browse repo" forgejo-vc-browse))
+ "b" ("Browse repo" forgejo-vc-browse)
+ "r" ((lambda ()
+ (format "Remote %s" (propertize
+ (or (forgejo-vc--selected-remote)
+ (nth 3 (car
(forgejo-vc--all-forge-remotes))))
+ 'face 'keymap-popup-value)))
+ forgejo-vc-select-remote
+ :if (lambda () (forgejo-vc--multiple-remotes-p))))
;;;###autoload
(defun forgejo-vc ()