Skip to content
This repository has been archived by the owner on May 18, 2020. It is now read-only.

Commit

Permalink
Merge branch 'km/transport'
Browse files Browse the repository at this point in the history
  • Loading branch information
kyleam committed Mar 3, 2017
2 parents 48ebfc7 + 2cda5ae commit 0ccc32b
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 15 deletions.
9 changes: 9 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Org Link Edit NEWS -- history of user-visible changes -*- mode: org; -*-

* master (unreleased)

** New features

- New command ~org-link-edit-transport-next-link~ searches for the
next (or previous) link and moves it to point, using the word at
point or the selected region as the link's description.
88 changes: 76 additions & 12 deletions org-link-edit.el
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
;; Org Link Edit provides Paredit-inspired slurping and barfing
;; commands for Org link descriptions.
;;
;; There are four commands, all which operate when point is on an Org
;; link.
;; There are four slurp and barf commands, all which operate when
;; point is on an Org link.
;;
;; - org-link-edit-forward-slurp
;; - org-link-edit-backward-slurp
Expand All @@ -53,6 +53,11 @@
;; ("i" org-link-edit-backward-barf "backward barf")
;; ("q" nil "cancel")))
;;
;; In addition to the slurp and barf commands, the command
;; `org-link-edit-transport-next-link' searches for the next (or
;; previous) link and moves it to point, using the word at point or
;; the selected region as the link's description.
;;
;; [1] https://github.com/abo-abo/hydra

;;; Code:
Expand All @@ -61,19 +66,23 @@
(require 'org-element)
(require 'cl-lib)

(defun org-link-edit--get-link-data ()
(defun org-link-edit--on-link-p (&optional element)
(let ((el (or element (org-element-context))))
;; Don't use `org-element-lineage' because it isn't available
;; until Org version 8.3.
(while (and el (not (memq (car el) '(link))))
(setq el (org-element-property :parent el)))
(eq (car el) 'link)))

(defun org-link-edit--link-data ()
"Return list with information about the link at point.
The list includes
- the position at the start of the link
- the position at the end of the link
- the link text
- the link description (nil when on a plain link)"
(let ((el (org-element-context)))
;; Don't use `org-element-lineage' because it isn't available
;; until Org version 8.3.
(while (and el (not (memq (car el) '(link))))
(setq el (org-element-property :parent el)))
(unless (eq (car el) 'link)
(unless (org-link-edit--on-link-p el)
(user-error "Point is not on a link"))
(save-excursion
(goto-char (org-element-property :begin el))
Expand Down Expand Up @@ -149,7 +158,7 @@ If N is negative, slurp leading blobs instead of trailing blobs."
((< n 0)
(org-link-edit-backward-slurp (- n)))
(t
(cl-multiple-value-bind (beg end link desc) (org-link-edit--get-link-data)
(cl-multiple-value-bind (beg end link desc) (org-link-edit--link-data)
(goto-char (save-excursion
(goto-char end)
(or (org-link-edit--forward-blob n 'no-punctuation)
Expand Down Expand Up @@ -191,7 +200,7 @@ If N is negative, slurp trailing blobs instead of leading blobs."
((< n 0)
(org-link-edit-forward-slurp (- n)))
(t
(cl-multiple-value-bind (beg end link desc) (org-link-edit--get-link-data)
(cl-multiple-value-bind (beg end link desc) (org-link-edit--link-data)
(goto-char (save-excursion
(goto-char beg)
(or (org-link-edit--forward-blob (- n))
Expand Down Expand Up @@ -267,7 +276,7 @@ If N is negative, barf leading blobs instead of trailing blobs."
((< n 0)
(org-link-edit-backward-barf (- n)))
(t
(cl-multiple-value-bind (beg end link desc) (org-link-edit--get-link-data)
(cl-multiple-value-bind (beg end link desc) (org-link-edit--link-data)
(when (= (length desc) 0)
(user-error "Link has no description"))
(pcase-let ((`(,new-desc . ,barfed) (org-link-edit--split-last-blobs
Expand Down Expand Up @@ -306,7 +315,7 @@ If N is negative, barf trailing blobs instead of leading blobs."
((< n 0)
(org-link-edit-forward-barf (- n)))
(t
(cl-multiple-value-bind (beg end link desc) (org-link-edit--get-link-data)
(cl-multiple-value-bind (beg end link desc) (org-link-edit--link-data)
(when (= (length desc) 0)
(user-error "Link has no description"))
(pcase-let ((`(,barfed . ,new-desc) (org-link-edit--split-first-blobs
Expand All @@ -321,5 +330,60 @@ If N is negative, barf trailing blobs instead of leading blobs."
(insert barfed)
barfed)))))

(defun org-link-edit--next-link-data (&optional previous)
(save-excursion
(if (funcall (if previous #'re-search-backward #'re-search-forward)
org-any-link-re nil t)
(org-link-edit--link-data)
(user-error "No %s link found" (if previous "previous" "next")))))

;;;###autoload
(defun org-link-edit-transport-next-link (&optional previous beg end)
"Move the next link to point.
If the region is active, use the selected text as the link's
description. Otherwise, use the word at point.
With prefix argument PREVIOUS, move the previous link instead of
the next link.
Non-interactively, use the text between BEG and END as the
description, moving the next (or previous) link relative BEG and
END."
(interactive (cons current-prefix-arg
(and (use-region-p)
(list (region-beginning) (region-end)))))
(let ((pt (point))
(desc-bounds (cond
((and beg end)
(cons (progn (goto-char beg)
(point-marker))
(progn (goto-char end)
(point-marker))))
((not (looking-at-p "\\s-"))
(progn (skip-syntax-backward "w")
(let ((beg (point-marker)))
(skip-syntax-forward "w")
(cons beg (point-marker))))))))
(when (or (and desc-bounds
(or (progn (goto-char (car desc-bounds))
(org-link-edit--on-link-p))
(progn (goto-char (cdr desc-bounds))
(org-link-edit--on-link-p))))
(progn (goto-char pt)
(org-link-edit--on-link-p)))
(user-error "Cannot transport next link with point on a link"))
(goto-char (car desc-bounds))
(cl-multiple-value-bind (link-beg link-end link desc)
(org-link-edit--next-link-data previous)
(unless (or (not desc-bounds) (= (length desc) 0))
(user-error "Link already has a description"))
(delete-region link-beg link-end)
(insert (org-make-link-string
link
(and desc-bounds
(delete-and-extract-region (car desc-bounds)
(cdr desc-bounds))))))))

(provide 'org-link-edit)
;;; org-link-edit.el ends here
72 changes: 69 additions & 3 deletions test-org-link-edit.el
Original file line number Diff line number Diff line change
Expand Up @@ -510,21 +510,87 @@ website"
(org-link-edit-forward-barf 1)
(buffer-string)))))


;;; Transport

(ert-deftest test-org-link-edit/transport-next-link ()
"Test `org-link-edit-transport-next-link'."
(should
(string= "Here is \[\[http://orgmode.org/\]\[Org's\]\] website "
(org-test-with-temp-text
"Here is <point>Org's website http://orgmode.org/"
(org-link-edit-transport-next-link)
(buffer-string))))
(should
(string= " Here is \[\[http://orgmode.org/\]\[Org's\]\] website"
(org-test-with-temp-text
"http://orgmode.org/ Here is <point>Org's website"
(org-link-edit-transport-next-link 'previous)
(buffer-string))))
(should
(string= "\[\[http://orgmode.org/\]\[Here is Org's\]\] website "
(org-test-with-temp-text
"Here is Org's<point> website http://orgmode.org/"
(org-link-edit-transport-next-link
nil (point-min) (point))
(buffer-string))))
(should
(string= " Here is \[\[http://orgmode.org/\]\[Org's website\]\]"
(org-test-with-temp-text
"http://orgmode.org/ Here is <point>Org's website"
(org-link-edit-transport-next-link
'previous (point) (point-max))
(buffer-string))))
(should-error
(org-test-with-temp-text
"Here is Org's website http://orgmode.org/<point>"
(org-link-edit-transport-next-link)
(buffer-string)))
(should-error
(org-test-with-temp-text
"Here is Org's website <point>http://orgmode.org/"
(org-link-edit-transport-next-link
nil (point-min) (point))
(buffer-string)))
)


;;; Other

(ert-deftest test-org-link-edit/on-link-p ()
"Test `org-link-edit--on-link-p'."
;; On plain link
(should
(org-test-with-temp-text "http://orgmode.org/"
(org-link-edit--on-link-p)))
;; On bracket link
(should
(org-test-with-temp-text "\[\[http://orgmode.org/\]\[org\]\]"
(org-link-edit--on-link-p)))
;; Point beyond link, but technically still within link element.
(should
(org-test-with-temp-text "\[\[http://orgmode.org/\]\[org\]\] <point>"
(org-link-edit--on-link-p)))
;; Not on a link
(should-not
(org-test-with-temp-text " \[\[http://orgmode.org/\]\[org\]\]"
(org-link-edit--on-link-p)))
(should-not
(org-test-with-temp-text "not a link"
(org-link-edit--on-link-p))))

(ert-deftest test-org-link-edit/get-link-data ()
"Test `org-link-edit--get-link-data'."
"Test `org-link-edit--link-data'."
;; Plain link
(cl-multiple-value-bind (beg end link desc)
(org-test-with-temp-text "http://orgmode.org/"
(org-link-edit--get-link-data))
(org-link-edit--link-data))
(should (string= link "http://orgmode.org/"))
(should-not desc))
;; Bracket link
(cl-multiple-value-bind (beg end link desc)
(org-test-with-temp-text "\[\[http://orgmode.org/\]\[org\]\]"
(org-link-edit--get-link-data))
(org-link-edit--link-data))
(should (string= link "http://orgmode.org/"))
(should (string= desc "org"))))

Expand Down

0 comments on commit 0ccc32b

Please sign in to comment.