From f29a26c353441b750a7f2c4f14834f68b6f15ecd Mon Sep 17 00:00:00 2001 From: Kyle Meyer Date: Thu, 12 Feb 2015 20:39:01 -0500 Subject: Slurp --- .gitignore | 2 + Makefile | 35 +++++ README.md | 6 + org-link-edit.el | 287 ++++++++++++++++++++++++++++++++++++++ test-org-link-edit.el | 372 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 702 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 README.md create mode 100644 org-link-edit.el create mode 100644 test-org-link-edit.el diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2408d62 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*-autoloads.el +*.elc diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1a2f3f7 --- /dev/null +++ b/Makefile @@ -0,0 +1,35 @@ +EMACS = emacs -Q --batch +name = org-link-edit +main_el := $(name).el +main_elc = $(main_el)c +AUTOLOADS_FILE := $(name)-autoloads.el + +all: $(main_elc) + +.PHONY: autoloads +autoloads: $(AUTOLOADS_FILE) + +$(AUTOLOADS_FILE): $(main_el) + @$(EMACS) --eval \ + "(update-file-autoloads \"$(CURDIR)/$<\" nil \"$(CURDIR)/$@\")" + +.PHONY: clean +clean: + $(RM) $(main_elc) $(AUTOLOADS_FILE) + +.PHONY: help +help: + @printf "\nTargets:\n\n" + @printf " all Byte compile $(main_el).\n" + @printf " autoloads Generate $(AUTOLOADS_FILE).\n" + @printf " clean Remove generated files.\n" + @printf " help Print this message.\n" + @printf " test Run tests.\n" + +.PHONY: test +test: + @$(EMACS) -L . -l test-org-link-edit \ + --eval "(ert-run-tests-batch-and-exit '(not (tag interactive)))" + +%.elc: %.el + @$(EMACS) -f batch-byte-compile $< diff --git a/README.md b/README.md new file mode 100644 index 0000000..dc1c91f --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +Org Link Edit provides Paredit-inspired slurping and barfing commands +for Org link descriptions. + +The commentary in [org-link-edit.el][el] contains more details. + +[el]: https://github.com/kyleam/org-link-edit/blob/master/org-link-edit.el diff --git a/org-link-edit.el b/org-link-edit.el new file mode 100644 index 0000000..5de3031 --- /dev/null +++ b/org-link-edit.el @@ -0,0 +1,287 @@ +;;; org-link-edit.el --- Slurp and barf with Org links + +;; Copyright (C) 2015 Kyle Meyer + +;; Author: Kyle Meyer +;; URL: https://github.com/kyleam/org-link-edit +;; Keywords: convenience +;; Version: 0.1.0 +;; Package-Requires: ((cl-lib "0.5") (org "8.2")) + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; 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. +;; +;; - org-link-edit-forward-slurp-word +;; - org-link-edit-backward-slurp-word +;; - org-link-edit-forward-barf-word +;; - org-link-edit-backward-barf-word +;; +;; Org Link Edit doesn't bind these commands to any keys. Finding +;; good keys for these commands is difficult because, while it's +;; convenient to be able to quickly repeat these commands, they won't +;; be used frequently enough to be worthy of a short, repeat-friendly +;; binding. Using Hydra [1] provides a nice solution to this. After +;; an initial key sequence, any of the commands will be repeatable +;; with a single key. (Plus, you get a nice interface that reminds +;; you of the keys). Below is one example of how you could configure +;; this. +;; +;; (define-key org-mode-map YOUR-KEY +;; (defhydra hydra-org-link-edit () +;; "Org Link Edit" +;; ("j" org-link-edit-forward-slurp-word "forward slurp") +;; ("k" org-link-edit-forward-barf-word "forward barf") +;; ("u" org-link-edit-backward-slurp-word "backward slurp") +;; ("i" org-link-edit-backward-barf-word "backward barf") +;; ("q" nil "cancel"))) +;; +;; [1] https://github.com/abo-abo/hydra + +;;; Code: + +(require 'org) +(require 'org-element) +(require 'cl-lib) + +(defun org-link-edit--get-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) + (user-error "Point is not on a link")) + (save-excursion + (goto-char (org-element-property :begin el)) + (cond + ;; Use match-{beginning,end} because match-end is consistently + ;; positioned after ]], while the :end property is positioned + ;; at the next word on the line, if one is present. + ((looking-at org-bracket-link-regexp) + (list (match-beginning 0) + (match-end 0) + (match-string-no-properties 1) + (or (and (match-end 3) + (match-string-no-properties 3)) + ""))) + ((looking-at org-plain-link-re) + (list (match-beginning 0) + (match-end 0) + (match-string-no-properties 0) + nil)) + (t + (error "What am I looking at?")))))) + +;;;###autoload +(defun org-link-edit-forward-slurp-word (&optional n) + "Slurp N trailing words into link's description. + + The \[\[http://orgmode.org/\]\[Org mode\]\] site + + | + v + + The \[\[http://orgmode.org/\]\[Org mode site\]\] + +After slurping, return the slurped text and move point to the +beginning of the link. + +If N is negative, slurp leading words instead of trailing words." + (interactive "p") + (setq n (or n 1)) + (cond + ((= n 0)) + ((< n 0) + (org-link-edit-backward-slurp-word (- n))) + (t + (cl-multiple-value-bind (beg end link desc) (org-link-edit--get-link-data) + (goto-char (save-excursion + (goto-char end) + (or (forward-word n) + (user-error "Not enough words after the link")) + (point))) + (let ((slurped (buffer-substring-no-properties end (point)))) + (setq slurped (replace-regexp-in-string "\n" " " slurped)) + (when (and (= (length desc) 0) + (string-match "^\\W*\\(\\w.*\\)" slurped)) + (setq slurped (match-string 1 slurped))) + (setq desc (concat desc slurped) + end (+ end (length slurped))) + (delete-region beg (point)) + (insert (org-make-link-string link desc)) + (goto-char beg) + slurped))))) + +;;;###autoload +(defun org-link-edit-backward-slurp-word (&optional n) + "Slurp N leading words into link's description. + + The \[\[http://orgmode.org/\]\[Org mode\]\] site + + | + v + + \[\[http://orgmode.org/\]\[The Org mode\]\] site + +After slurping, return the slurped text and move point to the +beginning of the link. + +If N is negative, slurp trailing words instead of leading +words." + (interactive "p") + (setq n (or n 1)) + (cond + ((= n 0)) + ((< n 0) + (org-link-edit-forward-slurp-word (- n))) + (t + (cl-multiple-value-bind (beg end link desc) (org-link-edit--get-link-data) + (goto-char (save-excursion + (goto-char beg) + (or (forward-word (- n)) + (user-error "Not enough words before the link")) + (point))) + (let ((slurped (buffer-substring-no-properties (point) beg))) + (when (= (length desc) 0) + (setq slurped (progn (string-match "\\(.*\\w\\)\\W*$" slurped) + (match-string 1 slurped)))) + (setq slurped (replace-regexp-in-string "\n" " " slurped)) + (setq desc (concat slurped desc) + beg (- beg (length slurped))) + (delete-region (point) end) + (insert (org-make-link-string link desc)) + (goto-char beg) + slurped))))) + +(defun org-link-edit--split-first-words (string n) + "Split STRING into (N first words . other) cons cell. +The N first word contains all text up to the next word. If there +number of words in STRING is fewer than N, 'other' is nil." + (when (< n 0) (user-error "N cannot be negative")) + (with-temp-buffer + (insert string) + (goto-char (point-min)) + (let ((within-bound (forward-word n))) + (skip-syntax-forward "^\w") + (cons (buffer-substring 1 (point)) + (and within-bound + (buffer-substring (point) (point-max))))))) + +(defun org-link-edit--split-last-words (string n) + "Split STRING into (other . N last words) cons cell. +The N last words contains all leading text up to the previous +word. If there number of words in STRING is fewer than N, +'other' is nil." + (when (< n 0) (user-error "N cannot be negative")) + (with-temp-buffer + (insert string) + (goto-char (point-max)) + (let ((within-bound (forward-word (- n)))) + (skip-syntax-backward "^\w") + (cons (and within-bound + (buffer-substring 1 (point))) + (buffer-substring (point) (point-max)))))) + +;;;###autoload +(defun org-link-edit-forward-barf-word (&optional n) + "Barf N trailing words from link's description. + + The \[\[http://orgmode.org/\]\[Org mode\]\] site + + | + v + + The \[\[http://orgmode.org/\]\[Org\]\] mode site + +After barfing, return the barfed text and move point to the +beginning of the link. + +If N is negative, barf leading words instead of trailing words." + (interactive "p") + (setq n (or n 1)) + (cond + ((= n 0)) + ((< n 0) + (org-link-edit-backward-barf-word (- n))) + (t + (cl-multiple-value-bind (beg end link desc) (org-link-edit--get-link-data) + (when (= (length desc) 0) + (user-error "Link has no description")) + (pcase-let ((`(,new-desc . ,barfed) (org-link-edit--split-last-words + desc n))) + (unless new-desc (user-error "Not enough words in description")) + (delete-region beg end) + (insert (org-make-link-string link new-desc)) + (if (string= new-desc "") + ;; Two brackets are dropped when pass nil description is + ;; passed to `org-make-link-string'. + (progn (goto-char (- end (+ 2 (length desc)))) + (setq barfed (concat " " barfed))) + (goto-char (- end (- (length desc) (length new-desc))))) + (insert barfed) + (goto-char beg) + barfed))))) + +;;;###autoload +(defun org-link-edit-backward-barf-word (&optional n) + "Barf N leading words from link's description. + + The \[\[http://orgmode.org/\]\[Org mode\]\] site + + | + v + + The Org \[\[http://orgmode.org/\]\[mode\]\] site + +After barfing, return the barfed text and move point to the +beginning of the link. + +If N is negative, barf trailing words instead of leading words." + (interactive "p") + (setq n (or n 1)) + (cond + ((= n 0)) + ((< n 0) + (org-link-edit-forward-barf-word (- n))) + (t + (cl-multiple-value-bind (beg end link desc) (org-link-edit--get-link-data) + (when (= (length desc) 0) + (user-error "Link has no description")) + (pcase-let ((`(,barfed . ,new-desc) (org-link-edit--split-first-words + desc n))) + (unless new-desc (user-error "Not enough words in description")) + (delete-region beg end) + (insert (org-make-link-string link new-desc)) + (when (string= new-desc "") + (setq barfed (concat barfed " "))) + (goto-char beg) + (insert barfed) + (goto-char (+ beg (length barfed))) + barfed))))) + +(provide 'org-link-edit) +;;; org-link-edit.el ends here diff --git a/test-org-link-edit.el b/test-org-link-edit.el new file mode 100644 index 0000000..7c2a914 --- /dev/null +++ b/test-org-link-edit.el @@ -0,0 +1,372 @@ +;;; test-org-link-edit.el --- Tests for org-link-edit.el + +;; Copyright (C) 2015 Kyle Meyer + +;; Author: Kyle Meyer + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Code: + +(require 'org-link-edit) +(require 'ert) + +;; This is taken from `org-tests.el' (55c0708). +(defmacro org-test-with-temp-text (text &rest body) + "Run body in a temporary buffer with Org-mode as the active +mode holding TEXT. If the string \"\" appears in TEXT +then remove it and place the point there before running BODY, +otherwise place the point at the beginning of the inserted text." + (declare (indent 1)) + `(let ((inside-text (if (stringp ,text) ,text (eval ,text))) + (org-mode-hook nil)) + (with-temp-buffer + (org-mode) + (let ((point (string-match "" inside-text))) + (if point + (progn + (insert (replace-match "" nil nil inside-text)) + (goto-char (1+ (match-beginning 0)))) + (insert inside-text) + (goto-char (point-min)))) + ,@body))) +(def-edebug-spec org-test-with-temp-text (form body)) + + +;;; Slurping + +(ert-deftest test-org-link-edit/forward-slurp-word () + "Test `org-link-edit-forward-slurp-word'." + ;; Slurp one word into plain link. + (should + (string= + "\[\[http://orgmode.org/\]\[Org's\]\] website is" + (org-test-with-temp-text + "http://orgmode.org/ Org's website is" + (org-link-edit-forward-slurp-word) + (buffer-string)))) + ;; Slurp one word into empty bracket link. + (should + (string= + "\[\[http://orgmode.org/\]\[Org's\]\] website is" + (org-test-with-temp-text + "\[\[http://orgmode.org/\]\] Org's website is" + (org-link-edit-forward-slurp-word) + (buffer-string)))) + ;; Slurp one word into bracket link. + (should + (string= + "\[\[http://orgmode.org/\]\[Org's website\]\] is" + (org-test-with-temp-text + "\[\[http://orgmode.org/\]\[Org's\]\] website is" + (org-link-edit-forward-slurp-word) + (buffer-string)))) + ;; Slurp two words into plain link. + (should + (string= + "\[\[http://orgmode.org/\]\[Org's website\]\] is" + (org-test-with-temp-text + "http://orgmode.org/ Org's website is" + (org-link-edit-forward-slurp-word 2) + (buffer-string)))) + ;; Slurp two words into bracket link. + (should + (string= + "\[\[http://orgmode.org/\]\[Org's website is\]\]" + (org-test-with-temp-text + "\[\[http://orgmode.org/\]\[Org's\]\] website is" + (org-link-edit-forward-slurp-word 2) + (buffer-string)))) + ;; Slurp new line as space. + (should + (string= + "\[\[http://orgmode.org/\]\[Org's website\]\] is" + (org-test-with-temp-text + "\[\[http://orgmode.org/\]\[Org's\]\] +website is" + (org-link-edit-forward-slurp-word 1) + (buffer-string)))) + ;; Slurp beyond the number of present words. + (should-error + (org-test-with-temp-text + "\[\[http://orgmode.org/\]\[Org's\]\] website is" + (org-link-edit-forward-slurp-word 3) + (buffer-string)) + :type (list 'user-error))) + +(ert-deftest test-org-link-edit/backward-slurp-word () + "Test `org-link-edit-backward-slurp-word'." + ;; Slurp one word into plain link. + (should + (string= + "Here \[\[http://orgmode.org/\]\[is\]\] Org's website" + (org-test-with-temp-text + "Here is http://orgmode.org/ Org's website" + (org-link-edit-backward-slurp-word) + (buffer-string)))) + ;; Slurp one word into empty bracket link. + (should + (string= + "Here \[\[http://orgmode.org/\]\[is\]\] Org's website" + (org-test-with-temp-text + "Here is \[\[http://orgmode.org/\]\] Org's website" + (org-link-edit-backward-slurp-word) + (buffer-string)))) + ;; Slurp one word into bracket link. + (should + (string= + "Here \[\[http://orgmode.org/\]\[is Org's\]\] website" + (org-test-with-temp-text + "Here is \[\[http://orgmode.org/\]\[Org's\]\] website" + (org-link-edit-backward-slurp-word) + (buffer-string)))) + ;; Slurp two words into plain link. + (should + (string= + "\[\[http://orgmode.org/\]\[Here is\]\] Org's website" + (org-test-with-temp-text + "Here is http://orgmode.org/ Org's website" + (org-link-edit-backward-slurp-word 2) + (buffer-string)))) + ;; Slurp two words into bracket link. + (should + (string= + "\[\[http://orgmode.org/\]\[Here is Org's\]\] website" + (org-test-with-temp-text + "Here is \[\[http://orgmode.org/\]\[Org's\]\] website" + (org-link-edit-backward-slurp-word 2) + (buffer-string)))) + ;; Slurp new line as space. + (should + (string= + "Here \[\[http://orgmode.org/\]\[is Org's website\]\]" + (org-test-with-temp-text + "Here is +\[\[http://orgmode.org/\]\[Org's website\]\]" + (org-link-edit-backward-slurp-word 1) + (buffer-string)))) + ;; Slurp beyond the number of present words. + (should-error + (org-test-with-temp-text + "Here is \[\[http://orgmode.org/\]\[Org's\]\] website" + (org-link-edit-backward-slurp-word 3) + (buffer-string)) + :type (list 'user-error))) + +(ert-deftest test-org-link-edit/slurp-negative-argument () + "Test `org-link-edit-forward-slurp-word' and +`org-link-edit-backward-slurp-word' with negative arguments." + (should + (string= + (org-test-with-temp-text + "Here is \[\[http://orgmode.org/\]\[Org's\]\] website" + (org-link-edit-forward-slurp-word 1) + (buffer-string)) + (org-test-with-temp-text + "Here is \[\[http://orgmode.org/\]\[Org's\]\] website" + (org-link-edit-backward-slurp-word -1) + (buffer-string)))) + (should + (string= + (org-test-with-temp-text + "Here is \[\[http://orgmode.org/\]\[Org's\]\] website" + (org-link-edit-forward-slurp-word -1) + (buffer-string)) + (org-test-with-temp-text + "Here is \[\[http://orgmode.org/\]\[Org's\]\] website" + (org-link-edit-backward-slurp-word) + (buffer-string))))) + + +;;; Barfing + +(ert-deftest test-org-link-edit/forward-barf-word () + "Test `org-link-edit-forward-barf-word'." + ;; Barf last word. + (should + (string= + "Org's \[\[http://orgmode.org/\]\] website is" + (org-test-with-temp-text + "Org's \[\[http://orgmode.org/\]\[website\]\] is" + (org-link-edit-forward-barf-word) + (buffer-string)))) + ;; Barf two last words. + (should + (string= + "Org's \[\[http://orgmode.org/\]\] website is" + (org-test-with-temp-text + "Org's \[\[http://orgmode.org/\]\[website is\]\]" + (org-link-edit-forward-barf-word 2) + (buffer-string)))) + ;; Barf one word, not last. + (should + (string= + "Org's \[\[http://orgmode.org/\]\[website\]\] is" + (org-test-with-temp-text + "Org's \[\[http://orgmode.org/\]\[website is\]\]" + (org-link-edit-forward-barf-word 1) + (buffer-string)))) + ;; Barf beyond the number of present words. + (should-error + (org-test-with-temp-text + "Org's \[\[http://orgmode.org/\]\[website is\]\]" + (org-link-edit-forward-barf-word 3) + (buffer-string)) + :type (list 'user-error))) + +(ert-deftest test-org-link-edit/backward-barf-word () + "Test `org-link-edit-backward-barf-word'." + ;; Barf last word. + (should + (string= + "Org's website \[\[http://orgmode.org/\]\] is" + (org-test-with-temp-text + "Org's \[\[http://orgmode.org/\]\[website\]\] is" + (org-link-edit-backward-barf-word) + (buffer-string)))) + ;; Barf two last words. + (should + (string= + "Org's website is \[\[http://orgmode.org/\]\]" + (org-test-with-temp-text + "Org's \[\[http://orgmode.org/\]\[website is\]\]" + (org-link-edit-backward-barf-word 2) + (buffer-string)))) + ;; Barf one word, not last. + (should + (string= + "Org's website \[\[http://orgmode.org/\]\[is\]\]" + (org-test-with-temp-text + "Org's \[\[http://orgmode.org/\]\[website is\]\]" + (org-link-edit-backward-barf-word 1) + (buffer-string)))) + ;; Barf beyond the number of present words. + (should-error + (org-test-with-temp-text + "Org's \[\[http://orgmode.org/\]\[website is\]\]" + (org-link-edit-backward-barf-word 3) + (buffer-string)) + :type (list 'user-error))) + +(ert-deftest test-org-link-edit/barf-negative-argument () + "Test `org-link-edit-forward-barf-word' and +`org-link-edit-backward-barf-word' with negative arguments." + (should + (string= + (org-test-with-temp-text + "Here is \[\[http://orgmode.org/\]\[Org's\]\] website" + (org-link-edit-forward-barf-word 1) + (buffer-string)) + (org-test-with-temp-text + "Here is \[\[http://orgmode.org/\]\[Org's\]\] website" + (org-link-edit-backward-barf-word -1) + (buffer-string)))) + (should + (string= + (org-test-with-temp-text + "Here is \[\[http://orgmode.org/\]\[Org's\]\] website" + (org-link-edit-forward-barf-word -1) + (buffer-string)) + (org-test-with-temp-text + "Here is \[\[http://orgmode.org/\]\[Org's\]\] website" + (org-link-edit-backward-barf-word) + (buffer-string))))) + + +;;; Slurp and Barf round trip +;; +;; Slurping and barfing should round trip unless there are new lines +;; in the slurped string, which slurping replaces with spaces. + +(ert-deftest test-org-link-edit/slurp-barf-round-trip () + "Test `org-link-edit-forward-barf-word' and +`org-link-edit-backward-barf-word' reversibility." + (should + (string= "Here is \[\[http://orgmode.org/\]\[Org's\]\] website" + (org-test-with-temp-text + "Here is \[\[http://orgmode.org/\]\[Org's\]\] website" + (org-link-edit-forward-barf-word 1) + (org-link-edit-forward-slurp-word 1) + (buffer-string)))) + (string= "Here is \[\[http://orgmode.org/\]\[Org's\]\] website" + (org-test-with-temp-text + "Here is \[\[http://orgmode.org/\]\[Org's\]\] website" + (org-link-edit-forward-slurp-word 1) + (org-link-edit-forward-barf-word 1) + (buffer-string))) + (should + (string= "Here is \[\[http://orgmode.org/\]\[Org's\]\] website" + (org-test-with-temp-text + "Here is \[\[http://orgmode.org/\]\[Org's\]\] website" + (org-link-edit-backward-barf-word 1) + (org-link-edit-backward-slurp-word 1) + (buffer-string)))) + (should + (string= "Here is \[\[http://orgmode.org/\]\[Org's\]\] website" + (org-test-with-temp-text + "Here is \[\[http://orgmode.org/\]\[Org's\]\] website" + (org-link-edit-backward-slurp-word 1) + (org-link-edit-backward-barf-word 1) + (buffer-string))))) + + +;;; Other + +(ert-deftest test-org-link-edit/get-link-data () + "Test `org-link-edit--get-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)) + (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)) + (should (string= link "http://orgmode.org/")) + (should (string= desc "org")))) + +(ert-deftest test-org-link-edit/split-first-words () + "Test `org-link-edit--split-first-words'." + ;; Single word, n = 1 + (should (equal '("one" . "") + (org-link-edit--split-first-words "one" 1))) + ;; Single word, out-of-bounds + (should (equal '("one" . nil) + (org-link-edit--split-first-words "one" 2))) + ;; Multiple words, n = 1 + (should (equal '("one " . "two three") + (org-link-edit--split-first-words "one two three" 1))) + ;; Multiple words, n > 1 + (should (equal '("one two " . "three") + (org-link-edit--split-first-words "one two three" 2)))) + +(ert-deftest test-org-link-edit/split-last-words () + "Test `org-link-edit--split-last-words'." + ;; Single word, n = 1 + (should (equal '("" . "one") + (org-link-edit--split-last-words "one" 1))) + ;; Single word, out-of-bounds + (should (equal '(nil . "one") + (org-link-edit--split-last-words "one" 2))) + ;; Multiple words, n = 1 + (should (equal '("one two" . " three") + (org-link-edit--split-last-words "one two three" 1))) + ;; Multiple words, n > 1 + (should (equal '("one" . " two three") + (org-link-edit--split-last-words "one two three" 2)))) + +(provide 'test-org-link-edit) +;;; test-org-link-edit.el ends here -- cgit v1.2.3