branch: master
commit 01e305ce5bbaf9b2756d1ee3cd16d3d75a9177ba
Author: Brendan Cully <[email protected]>
Commit: Oleh Krehel <[email protected]>

    Add counsel-url-expand helper for ivy-ffap-url-functions
    
    counsel-url-expand makes it easy to add keyword to URL expansions for
    ivy-ffap, simply by adding a (REGEXP . FORMAT) pair to
    counsel-url-expansions.
    
    Fixes #1164
---
 counsel.el  | 44 ++++++++++++++++++++++++++++++++++++++++++++
 ivy-test.el | 29 +++++++++++++++++++++++++++++
 2 files changed, 73 insertions(+)

diff --git a/counsel.el b/counsel.el
index e07fc97..e7a6984 100644
--- a/counsel.el
+++ b/counsel.el
@@ -1537,6 +1537,7 @@ Does not list the currently checked out one."
 
 (add-to-list 'ivy-ffap-url-functions 'counsel-github-url-p)
 (add-to-list 'ivy-ffap-url-functions 'counsel-emacs-url-p)
+(add-to-list 'ivy-ffap-url-functions 'counsel-url-expand)
 (defun counsel-find-file-cd-bookmark-action (_)
   "Reset `counsel-find-file' from selected directory."
   (ivy-read "cd: "
@@ -1699,6 +1700,49 @@ When INITIAL-INPUT is non-nil, use it in the minibuffer 
during completion."
           (format "http://debbugs.gnu.org/cgi/bugreport.cgi?bug=%s";
                   (substring url 1)))))))
 
+(defvar counsel-url-expansions nil
+  "Map of regular expressions to expansions.
+
+This variable should take the form of a list of (REGEXP . FORMAT)
+pairs.
+
+`counsel-url-expand' will expand the word at point according to
+FORMAT for the first matching REGEXP.  FORMAT can be either a
+string or a function.  If it is a string, it will be used as the
+format string for the `format' function, with the word at point
+as the next argument.  If it is a function, it will be called
+with the word at point as the sole argument.
+
+For example, a pair of the form:
+  '(\"\\`BSERV-[[:digit:]]+\\'\" . \"https://jira.atlassian.com/browse/%s\";)
+will expand to URL `https://jira.atlassian.com/browse/BSERV-100'
+when the word at point is BSERV-100.
+
+If the format element is a function, more powerful
+transformations are possible.  As an example,
+  '(\"\\`issue\\([[:digit:]]+\\)\\'\" .
+    (lambda (word)
+      (concat \"http://debbugs.gnu.org/cgi/bugreport.cgi?bug=\";
+              (match-string 1 word))))
+trims the \"issue\" prefix from the word at point before creating the URL.")
+
+(defun counsel-url-expand ()
+  "Expand word at point using `counsel-url-expansions'.
+The first pair in the list whose regexp matches the word at point
+will be expanded according to its format.  This function is
+intended to be used in `ivy-ffap-url-functions' to browse the
+result as a URL."
+  (let ((word-at-point (current-word)))
+    (cl-some
+     (lambda (pair)
+       (let ((regexp (car pair))
+             (formatter (cdr pair)))
+         (when (string-match regexp word-at-point)
+           (if (functionp formatter)
+               (funcall formatter word-at-point)
+             (format formatter word-at-point)))))
+     counsel-url-expansions)))
+
 ;;** `counsel-recentf'
 (defvar recentf-list)
 (declare-function recentf-mode "recentf")
diff --git a/ivy-test.el b/ivy-test.el
index ea30f13..7ac9326 100644
--- a/ivy-test.el
+++ b/ivy-test.el
@@ -249,6 +249,35 @@ will bring the behavior in line with the newer Emacsen."
                   (ivy--regex "(foo bar"))
                  "(\\(foo).*?(bar)")))
 
+(defmacro ivy--string-buffer (text &rest body)
+  "Test helper that wraps TEXT in a temp buffer while running BODY."
+  `(with-temp-buffer
+    (insert ,text)
+    ,@body))
+
+(ert-deftest counsel-url-expand ()
+  "Test ffap expansion using counsel-url-expansions."
+  ;; no expansions defined
+  (let (counsel-url-expansions)
+    (should (eq (counsel-url-expand) nil)))
+  (let ((counsel-url-expansions
+         `(("^foo$" . "https://foo.com/%s";)
+           ("^issue\\([0-9]+\\)" . ,(lambda (word)
+                                      (concat "https://foo.com/issues/";
+                                              (match-string 1 word)))))))
+    ;; no match
+    (ivy--string-buffer
+     "foobar"
+     (should (equal (counsel-url-expand) nil)))
+    ;; string expansion
+    (ivy--string-buffer
+     "foo"
+     (should (equal (counsel-url-expand) "https://foo.com/foo";)))
+    ;; function expansion
+    (ivy--string-buffer
+     "issue123"
+     (should (equal (counsel-url-expand) "https://foo.com/issues/123";)))))
+
 (ert-deftest colir-color-parse ()
   (should (equal (colir-color-parse "#ab1234")
                  ;; (color-name-to-rgb "#ab1234")

Reply via email to