Change bracket link escape syntax
* contrib/lisp/org-link-edit.el (org-link-edit--link-data): * lisp/ob-tangle.el (org-babel-tangle-comment-links): Update match-group. (org-babel-detangle): Remove unnecessary `org-link-escape' call. (org-babel-tangle-jump-to-org): Update match group. (org-link-url-hexify): (org-link-escape-chars): Remove variables. * lisp/ol.el (org-link--decode-compound): Renamed from `org-link--unescape-compound'. (org-link--decode-single-byte-sequence): Renamed from `org-link--unescape-single-byte-sequence'. (org-link-make-regexps): Update `org-link-bracket-re' syntax. (org-link-encode): New function, renamed from `org-link-escape'. (org-link-decode): New function, renamed from `org-link-unescape'. (org-link-escape): (org-link-unescape): Use new escape syntax. (org-link-make-string): Apply new escaping rules. (org-link-display-format): (org-insert-link): Update match group. * lisp/org-agenda.el (org-diary): (org-agenda-format-item): (org-agenda-to-appt): Update match group. * lisp/org-clock.el (org-clocktable-write-default): Update match group. * lisp/org-element.el (org-element-link-parser): Update match group. * lisp/org-mobile.el (org-mobile-escape-olp): (org-mobile-locate-entry): Apply function renaming. * lisp/org-protocol.el (org-protocol-split-data): (org-protocol-parse-parameters): Apply function renaming. * lisp/org.el (org-refile): Update match group. * testing/README (Interactive testing from within Emacs): Fix examples. * testing/lisp/test-ol.el (test-ol/encode): Merge old escape tests. (test-ol/decode): Merge old unescape tests. (test-ol/escape): (test-ol/unescape): (test-ol/make-string): New tests. * testing/lisp/test-org-clock.el (test-org-clock/clocktable/link): * testing/lisp/test-org.el (test-org/custom-id): (test-org/fuzzy-links): * testing/lisp/test-ox.el (test-org-export/resolve-fuzzy-link): Update tests.
This commit is contained in:
parent
3318b50a39
commit
2b00d62816
|
@ -95,9 +95,7 @@ The list includes
|
|||
(match-end 0)
|
||||
(save-match-data
|
||||
(org-link-unescape (match-string-no-properties 1)))
|
||||
(or (and (match-end 3)
|
||||
(match-string-no-properties 3))
|
||||
"")))
|
||||
(or (match-string-no-properties 2) "")))
|
||||
((looking-at org-plain-link-re)
|
||||
(list (match-beginning 0)
|
||||
(match-end 0)
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
(require 'cl-lib)
|
||||
(require 'org-src)
|
||||
(require 'org-macs)
|
||||
(require 'ol)
|
||||
|
||||
(declare-function make-directory "files" (dir &optional parents))
|
||||
(declare-function org-at-heading-p "org" (&optional ignored))
|
||||
|
@ -40,14 +41,8 @@
|
|||
(declare-function org-element-type "org-element" (element))
|
||||
(declare-function org-heading-components "org" ())
|
||||
(declare-function org-in-commented-heading-p "org" (&optional no-inheritance))
|
||||
(declare-function org-link-escape "org" (text &optional table merge))
|
||||
(declare-function org-link-open-from-string "ol" (s &optional arg))
|
||||
(declare-function org-link-trim-scheme "ol" (uri))
|
||||
(declare-function org-store-link "org" (arg &optional interactive?))
|
||||
(declare-function outline-previous-heading "outline" ())
|
||||
|
||||
(defvar org-link-types-re)
|
||||
|
||||
(defcustom org-babel-tangle-lang-exts
|
||||
'(("emacs-lisp" . "el")
|
||||
("elisp" . "el"))
|
||||
|
@ -330,8 +325,6 @@ references."
|
|||
(delete-region (save-excursion (beginning-of-line 1) (point))
|
||||
(save-excursion (end-of-line 1) (forward-char 1) (point)))))
|
||||
|
||||
(defvar org-stored-links)
|
||||
(defvar org-link-bracket-re)
|
||||
(defun org-babel-spec-to-string (spec)
|
||||
"Insert SPEC into the current file.
|
||||
|
||||
|
@ -506,10 +499,7 @@ non-nil, return the full association list to be used by
|
|||
`(("start-line" . ,(number-to-string
|
||||
(org-babel-where-is-src-block-head)))
|
||||
("file" . ,(buffer-file-name))
|
||||
("link" . ,(org-link-escape
|
||||
(progn
|
||||
(call-interactively #'org-store-link)
|
||||
(org-no-properties (car (pop org-stored-links))))))
|
||||
("link" . ,(org-no-properties (org-store-link nil)))
|
||||
("source-name" .
|
||||
,(nth 4 (or info (org-babel-get-src-block-info 'light)))))))
|
||||
(list (org-fill-template org-babel-tangle-comment-format-beg link-data)
|
||||
|
@ -527,7 +517,7 @@ which enable the original code blocks to be found."
|
|||
(let ((counter 0) new-body end)
|
||||
(while (re-search-forward org-link-bracket-re nil t)
|
||||
(when (re-search-forward
|
||||
(concat " " (regexp-quote (match-string 3)) " ends here"))
|
||||
(concat " " (regexp-quote (match-string 2)) " ends here"))
|
||||
(setq end (match-end 0))
|
||||
(forward-line -1)
|
||||
(save-excursion
|
||||
|
@ -549,7 +539,7 @@ which enable the original code blocks to be found."
|
|||
(and (setq start (line-beginning-position))
|
||||
(setq body-start (line-beginning-position 2))
|
||||
(setq link (match-string 0))
|
||||
(setq block-name (match-string 3))
|
||||
(setq block-name (match-string 2))
|
||||
(save-excursion
|
||||
(save-match-data
|
||||
(re-search-forward
|
||||
|
|
145
lisp/ol.el
145
lisp/ol.el
|
@ -375,13 +375,6 @@ single keystroke rather than having to type \"yes\"."
|
|||
:tag "Org Store Link"
|
||||
:group 'org-link)
|
||||
|
||||
(defcustom org-link-url-hexify t
|
||||
"When non-nil, hexify URL when creating a link."
|
||||
:type 'boolean
|
||||
:version "24.3"
|
||||
:group 'org-link-store
|
||||
:safe #'booleanp)
|
||||
|
||||
(defcustom org-link-context-for-files t
|
||||
"Non-nil means file links from `org-store-link' contain context.
|
||||
\\<org-mode-map>
|
||||
|
@ -451,12 +444,6 @@ links more efficient."
|
|||
|
||||
;;; Public variables
|
||||
|
||||
(defconst org-link-escape-chars
|
||||
;;%20 %5B %5D %25
|
||||
'(?\s ?\[ ?\] ?%)
|
||||
"List of characters that should be escaped in a link when stored to Org.
|
||||
This is the list that is used for internal purposes.")
|
||||
|
||||
(defconst org-target-regexp (let ((border "[^<>\n\r \t]"))
|
||||
(format "<<\\(%s\\|%s[^<>\n\r]*%s\\)>>"
|
||||
border border border))
|
||||
|
@ -597,7 +584,7 @@ either a link description or nil."
|
|||
(concat (format "%-45s" (substring desc 0 (min (length desc) 40)))
|
||||
"<" (car link) ">")))
|
||||
|
||||
(defun org-link--unescape-compound (hex)
|
||||
(defun org-link--decode-compound (hex)
|
||||
"Unhexify Unicode hex-chars HEX.
|
||||
E.g. \"%C3%B6\" is the German o-Umlaut. Note: this function also
|
||||
decodes single byte encodings like \"%E1\" (a-acute) if not
|
||||
|
@ -628,14 +615,15 @@ followed by another \"%[A-F0-9]{2}\" group."
|
|||
(setq ret (concat ret (char-to-string sum)))
|
||||
(setq sum 0))
|
||||
((not bytes) ; single byte(s)
|
||||
(setq ret (org-link--unescape-single-byte-sequence hex))))))
|
||||
(setq ret (org-link--decode-single-byte-sequence hex))))))
|
||||
ret)))
|
||||
|
||||
(defun org-link--unescape-single-byte-sequence (hex)
|
||||
(defun org-link--decode-single-byte-sequence (hex)
|
||||
"Unhexify hex-encoded single byte character sequence HEX."
|
||||
(mapconcat (lambda (byte)
|
||||
(char-to-string (string-to-number byte 16)))
|
||||
(cdr (split-string hex "%")) ""))
|
||||
(cdr (split-string hex "%"))
|
||||
""))
|
||||
|
||||
(defun org-link--fontify-links-to-this-file ()
|
||||
"Fontify links to the current file in `org-stored-links'."
|
||||
|
@ -750,7 +738,18 @@ This should be called after the variable `org-link-parameters' has changed."
|
|||
"\\([^][ \t\n()<>]+\\(?:([[:word:]0-9_]+)\\|\\([^[:punct:] \t\n]\\|/\\)\\)\\)")
|
||||
;; "\\([^]\t\n\r<>() ]+[^]\t\n\r<>,.;() ]\\)")
|
||||
org-link-bracket-re
|
||||
"\\[\\[\\([^][]+\\)\\]\\(\\[\\([^][]+\\)\\]\\)?\\]"
|
||||
(rx (seq "[["
|
||||
;; URI part: match group 1.
|
||||
(group
|
||||
(*? anything)
|
||||
;; Allow an even number of backslashes right
|
||||
;; before the closing bracket.
|
||||
(not (any "\\"))
|
||||
(zero-or-more "\\\\"))
|
||||
"]"
|
||||
;; Description (optional): match group 2.
|
||||
(opt "[" (group (+? anything)) "]")
|
||||
"]"))
|
||||
org-link-any-re
|
||||
(concat "\\(" org-link-bracket-re "\\)\\|\\("
|
||||
org-link-angle-re "\\)\\|\\("
|
||||
|
@ -841,55 +840,71 @@ and dates."
|
|||
(setq org-store-link-plist
|
||||
(plist-put org-store-link-plist key value)))))
|
||||
|
||||
(defun org-link-escape (text &optional table merge)
|
||||
"Return percent escaped representation of TEXT.
|
||||
TEXT is a string with the text to escape.
|
||||
Optional argument TABLE is a list with characters that should be
|
||||
escaped. When nil, `org-link-escape-chars' is used.
|
||||
If optional argument MERGE is set, merge TABLE into
|
||||
`org-link-escape-chars'."
|
||||
(let ((characters-to-encode
|
||||
(cond ((null table) org-link-escape-chars)
|
||||
(merge (append org-link-escape-chars table))
|
||||
(t table))))
|
||||
(mapconcat
|
||||
(lambda (c)
|
||||
(if (or (memq c characters-to-encode)
|
||||
(and org-link-url-hexify (or (< c 32) (> c 126))))
|
||||
(mapconcat (lambda (e) (format "%%%.2X" e))
|
||||
(or (encode-coding-char c 'utf-8)
|
||||
(error "Unable to percent escape character: %c" c))
|
||||
"")
|
||||
(char-to-string c)))
|
||||
text "")))
|
||||
(defun org-link-encode (text table)
|
||||
"Return percent escaped representation of string TEXT.
|
||||
TEXT is a string with the text to escape. TABLE is a list of
|
||||
characters that should be escaped."
|
||||
(mapconcat
|
||||
(lambda (c)
|
||||
(if (memq c table)
|
||||
(mapconcat (lambda (e) (format "%%%.2X" e))
|
||||
(or (encode-coding-char c 'utf-8)
|
||||
(error "Unable to percent escape character: %c" c))
|
||||
"")
|
||||
(char-to-string c)))
|
||||
text ""))
|
||||
|
||||
(defun org-link-unescape (str)
|
||||
"Unhex hexified Unicode parts in string STR.
|
||||
E.g. \"%C3%B6\" becomes the german o-Umlaut. This is the
|
||||
reciprocal of `org-link-escape', which see."
|
||||
(if (org-string-nw-p str)
|
||||
(replace-regexp-in-string
|
||||
"\\(%[0-9A-Za-z]\\{2\\}\\)+" #'org-link--unescape-compound str t t)
|
||||
str))
|
||||
(defun org-link-decode (s)
|
||||
"Decode percent-encoded parts in string S.
|
||||
E.g. \"%C3%B6\" becomes the german o-Umlaut."
|
||||
(replace-regexp-in-string "\\(%[0-9A-Za-z]\\{2\\}\\)+"
|
||||
#'org-link--decode-compound s t t))
|
||||
|
||||
(defun org-link-escape (link)
|
||||
"Backslash-escape sensitive characters in string LINK."
|
||||
;; Escape closing square brackets followed by another square bracket
|
||||
;; or at the end of the link. Also escape final backslashes so that
|
||||
;; we do not escape inadvertently URI's closing bracket.
|
||||
(with-temp-buffer
|
||||
(insert link)
|
||||
(insert (make-string (- (skip-chars-backward "\\\\"))
|
||||
?\\))
|
||||
(while (search-backward "\]" nil t)
|
||||
(when (looking-at-p "\\]\\(?:[][]\\|\\'\\)")
|
||||
(insert (make-string (1+ (- (skip-chars-backward "\\\\")))
|
||||
?\\))))
|
||||
(buffer-string)))
|
||||
|
||||
(defun org-link-unescape (link)
|
||||
"Remove escaping backslash characters from string LINK."
|
||||
(with-temp-buffer
|
||||
(save-excursion (insert link))
|
||||
(while (re-search-forward "\\(\\\\+\\)\\]\\(?:[][]\\|\\'\\)" nil t)
|
||||
(replace-match (make-string (/ (- (match-end 1) (match-beginning 1)) 2)
|
||||
?\\)
|
||||
nil t nil 1))
|
||||
(goto-char (point-max))
|
||||
(delete-char (/ (- (skip-chars-backward "\\\\")) 2))
|
||||
(buffer-string)))
|
||||
|
||||
(defun org-link-make-string (link &optional description)
|
||||
"Make a bracket link, consisting of LINK and DESCRIPTION."
|
||||
"Make a bracket link, consisting of LINK and DESCRIPTION.
|
||||
LINK is escaped with backslashes for inclusion in buffer."
|
||||
(unless (org-string-nw-p link) (error "Empty link"))
|
||||
(let ((uri (cond ((string-match org-link-types-re link)
|
||||
(concat (match-string 1 link)
|
||||
(org-link-escape (substring link (match-end 1)))))
|
||||
((or (file-name-absolute-p link)
|
||||
(string-match-p "\\`\\.\\.?/" link))
|
||||
(org-link-escape link))
|
||||
;; For readability, do not encode space characters
|
||||
;; in fuzzy links.
|
||||
(t (org-link-escape link (remq ?\s org-link-escape-chars)))))
|
||||
(description
|
||||
(and (org-string-nw-p description)
|
||||
;; Remove brackets from description, as they are fatal.
|
||||
(replace-regexp-in-string
|
||||
"[][]" (lambda (m) (if (equal "[" m) "{" "}"))
|
||||
(org-trim description)))))
|
||||
(let* ((uri (org-link-escape link))
|
||||
(zero-width-space (string ?\x200B))
|
||||
(description
|
||||
(and (org-string-nw-p description)
|
||||
;; Description cannot contain two consecutive square
|
||||
;; brackets, or end with a square bracket. To prevent
|
||||
;; this, insert a zero width space character between
|
||||
;; the brackets, or at the end of the description.
|
||||
(replace-regexp-in-string
|
||||
"\\(]\\)\\(]\\)"
|
||||
(concat "\\1" zero-width-space "\\2")
|
||||
(replace-regexp-in-string "]\\'"
|
||||
(concat "\\&" zero-width-space)
|
||||
(org-trim description))))))
|
||||
(format "[[%s]%s]"
|
||||
uri
|
||||
(if description (format "[%s]" description) ""))))
|
||||
|
@ -1207,7 +1222,7 @@ If there is no description, use the link target."
|
|||
(save-match-data
|
||||
(replace-regexp-in-string
|
||||
org-link-bracket-re
|
||||
(lambda (m) (or (match-string 3 m) (match-string 1 m)))
|
||||
(lambda (m) (or (match-string 2 m) (match-string 1 m)))
|
||||
s nil t)))
|
||||
|
||||
(defun org-link-add-angle-brackets (s)
|
||||
|
@ -1662,7 +1677,7 @@ don't allow to edit the default description."
|
|||
((org-in-regexp org-link-bracket-re 1)
|
||||
;; We do have a link at point, and we are going to edit it.
|
||||
(setq remove (list (match-beginning 0) (match-end 0)))
|
||||
(setq desc (when (match-end 3) (match-string-no-properties 3)))
|
||||
(setq desc (when (match-end 2) (match-string-no-properties 2)))
|
||||
(setq link (read-string "Link: "
|
||||
(org-link-unescape
|
||||
(match-string-no-properties 1)))))
|
||||
|
|
|
@ -5201,7 +5201,7 @@ function from a program - use `org-agenda-get-day-entries' instead."
|
|||
(when results
|
||||
(setq results
|
||||
(mapcar (lambda (i) (replace-regexp-in-string
|
||||
org-link-bracket-re "\\3" i)) results))
|
||||
org-link-bracket-re "\\2" i)) results))
|
||||
(concat (org-agenda-finalize-entries results) "\n"))))
|
||||
|
||||
;;; Agenda entry finders
|
||||
|
@ -6571,9 +6571,7 @@ Any match of REMOVE-RE will be removed from TXT."
|
|||
level (or level ""))
|
||||
(if (string-match org-link-bracket-re category)
|
||||
(progn
|
||||
(setq l (if (match-end 3)
|
||||
(- (match-end 3) (match-beginning 3))
|
||||
(- (match-end 1) (match-beginning 1))))
|
||||
(setq l (string-width (or (match-string 2) (match-string 1))))
|
||||
(when (< l (or org-prefix-category-length 0))
|
||||
(setq category (copy-sequence category))
|
||||
(org-add-props category nil
|
||||
|
@ -10238,7 +10236,7 @@ to override `appt-message-warning-time'."
|
|||
(lambda (x)
|
||||
(let* ((evt (org-trim
|
||||
(replace-regexp-in-string
|
||||
org-link-bracket-re "\\3"
|
||||
org-link-bracket-re "\\2"
|
||||
(or (get-text-property 1 'txt x) ""))))
|
||||
(cat (get-text-property (1- (length x)) 'org-category x))
|
||||
(tod (get-text-property 1 'time-of-day x))
|
||||
|
|
|
@ -2621,10 +2621,10 @@ from the dynamic block definition."
|
|||
(if (and (string-match
|
||||
(format "\\`%s\\'" org-link-bracket-re)
|
||||
headline)
|
||||
(match-end 3))
|
||||
(match-end 2))
|
||||
(format "[[%s][%s]]"
|
||||
(match-string 1 headline)
|
||||
(org-shorten-string (match-string 3 headline)
|
||||
(org-shorten-string (match-string 2 headline)
|
||||
narrow))
|
||||
(org-shorten-string headline narrow))))
|
||||
(cl-flet ((format-field (f) (format (cond ((not emph) "%s |")
|
||||
|
|
|
@ -462,9 +462,6 @@ use of this function is for the stuck project list."
|
|||
(define-obsolete-variable-alias 'org-descriptive-links
|
||||
'org-link-descriptive "Org 9.3")
|
||||
|
||||
(define-obsolete-variable-alias 'org-url-hexify-p
|
||||
'org-link-url-hexify "Org 9.3")
|
||||
|
||||
(define-obsolete-variable-alias 'org-context-in-file-links
|
||||
'org-link-context-for-files "Org 9.3")
|
||||
|
||||
|
|
|
@ -3141,8 +3141,8 @@ Assume point is at the beginning of the link."
|
|||
;; Type 2: Standard link, i.e. [[https://orgmode.org][homepage]]
|
||||
((looking-at org-link-bracket-re)
|
||||
(setq format 'bracket)
|
||||
(setq contents-begin (match-beginning 3))
|
||||
(setq contents-end (match-end 3))
|
||||
(setq contents-begin (match-beginning 2))
|
||||
(setq contents-end (match-end 2))
|
||||
(setq link-end (match-end 0))
|
||||
;; RAW-LINK is the original link. Decode any encoding.
|
||||
;; Expand any abbreviation in it.
|
||||
|
|
|
@ -31,14 +31,10 @@
|
|||
;; iPhone and Android - any external viewer/flagging/editing
|
||||
;; application that uses the same conventions could be used.
|
||||
|
||||
(require 'cl-lib)
|
||||
(require 'org)
|
||||
(require 'org-agenda)
|
||||
(require 'cl-lib)
|
||||
|
||||
(declare-function org-link-escape "ol" (text &optional table merge))
|
||||
(declare-function org-link-unescape "ol" (str))
|
||||
|
||||
(defvar org-agenda-keep-restricted-file-list)
|
||||
(require 'ol)
|
||||
|
||||
;;; Code:
|
||||
|
||||
|
@ -673,8 +669,7 @@ The table of checksums is written to the file mobile-checksums."
|
|||
(org-mobile-escape-olp (nth 4 (org-heading-components))))))
|
||||
|
||||
(defun org-mobile-escape-olp (s)
|
||||
(let ((table '(?: ?/)))
|
||||
(org-link-escape s table)))
|
||||
(org-link-encode s '(?: ?/)))
|
||||
|
||||
(defun org-mobile-create-sumo-agenda ()
|
||||
"Create a file that contains all custom agenda views."
|
||||
|
@ -968,7 +963,7 @@ is currently a noop.")
|
|||
(if (not (string-match "\\`olp:\\(.*?\\)$" link))
|
||||
nil
|
||||
(let ((file (match-string 1 link)))
|
||||
(setq file (org-link-unescape file))
|
||||
(setq file (org-link-decode file))
|
||||
(setq file (expand-file-name file org-directory))
|
||||
(save-excursion
|
||||
(find-file file)
|
||||
|
@ -978,9 +973,9 @@ is currently a noop.")
|
|||
(point-marker))))
|
||||
(let ((file (match-string 1 link))
|
||||
(path (match-string 2 link)))
|
||||
(setq file (org-link-unescape file))
|
||||
(setq file (org-link-decode file))
|
||||
(setq file (expand-file-name file org-directory))
|
||||
(setq path (mapcar 'org-link-unescape
|
||||
(setq path (mapcar #'org-link-decode
|
||||
(org-split-string path "/")))
|
||||
(org-find-olp (cons file path))))))
|
||||
|
||||
|
|
|
@ -301,7 +301,7 @@ results of that splitting are returned as a list."
|
|||
(split-parts (split-string data sep)))
|
||||
(cond ((not unhexify) split-parts)
|
||||
((fboundp unhexify) (mapcar unhexify split-parts))
|
||||
(t (mapcar #'org-link-unescape split-parts)))))
|
||||
(t (mapcar #'org-link-decode split-parts)))))
|
||||
|
||||
(defun org-protocol-flatten-greedy (param-list &optional strip-path replacement)
|
||||
"Transform PARAM-LIST into a flat list for greedy handlers.
|
||||
|
@ -382,7 +382,7 @@ If INFO is already a property list, return it unchanged."
|
|||
(while data
|
||||
(setq result
|
||||
(append result
|
||||
(list (pop data) (org-link-unescape (pop data))))))
|
||||
(list (pop data) (org-link-decode (pop data))))))
|
||||
result)
|
||||
(let ((data (org-protocol-split-data info t org-protocol-data-separator)))
|
||||
(if default-order
|
||||
|
|
|
@ -9389,7 +9389,7 @@ prefix argument (`C-u C-u C-u C-c C-w')."
|
|||
(setq heading-text
|
||||
(replace-regexp-in-string
|
||||
org-link-bracket-re
|
||||
"\\3"
|
||||
"\\2"
|
||||
(or (nth 4 (org-heading-components))
|
||||
""))))
|
||||
(org-refile-get-location
|
||||
|
|
|
@ -120,15 +120,15 @@ load and run the test suite with the following commands.
|
|||
|
||||
To run one test: Use this as a demo example of a failing test
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(ert-deftest test-org/org-link-escape-ascii-character-demo-of-fail ()
|
||||
(ert-deftest test-org/org-link-encode-ascii-character-demo-of-fail ()
|
||||
(should (string= "%5B" ; Expecting %5B is correct.
|
||||
(org-link-escape "[")))
|
||||
(org-link-encode "[")))
|
||||
(should (string= "%5C" ; Expecting %5C is wrong, %5D correct.
|
||||
(org-link-escape "]"))))
|
||||
(org-link-encode "]"))))
|
||||
#+END_SRC
|
||||
or evaluate the ~ert-deftest form~ of the test you want to run.
|
||||
Then ~M-x ert RET
|
||||
test-org/org-link-escape-ascii-character-demo-of-fail RET~. When
|
||||
test-org/org-link-encode-ascii-character-demo-of-fail RET~. When
|
||||
not visible yet switch to the ERT results buffer named ~*ert*~.
|
||||
When a test failed the ERT results buffer shows the details of the
|
||||
first ~should~ that failed. See ~(info "(ert)Running Tests
|
||||
|
|
|
@ -20,80 +20,106 @@
|
|||
;;; Code:
|
||||
|
||||
|
||||
;;; (Un)Escape links
|
||||
;;; Decode and Encode Links
|
||||
|
||||
(ert-deftest test-ol/escape-ascii-character ()
|
||||
"Escape an ascii character."
|
||||
(should
|
||||
(string=
|
||||
"%5B"
|
||||
(org-link-escape "["))))
|
||||
(ert-deftest test-ol/encode ()
|
||||
"Test `org-link-encode' specifications."
|
||||
;; Regural test.
|
||||
(should (string= "Foo%3A%42ar" (org-link-encode "Foo:Bar" '(?\: ?\B))))
|
||||
;; Encode an ASCII character.
|
||||
(should (string= "%5B" (org-link-encode "[" '(?\[))))
|
||||
;; Encode an ASCII control character.
|
||||
(should (string= "%09" (org-link-encode "\t" '(9))))
|
||||
;; Encode a Unicode multibyte character.
|
||||
(should (string= "%E2%82%AC" (org-link-encode "€" '(?\€)))))
|
||||
|
||||
(ert-deftest test-ol/escape-ascii-ctrl-character ()
|
||||
"Escape an ascii control character."
|
||||
(should
|
||||
(string=
|
||||
"%09"
|
||||
(org-link-escape "\t"))))
|
||||
(ert-deftest test-ol/decode ()
|
||||
"Test `org-link-decode' specifications."
|
||||
;; Decode an ASCII character.
|
||||
(should (string= "[" (org-link-decode "%5B")))
|
||||
;; Decode an ASCII control character.
|
||||
(should (string= "\n" (org-link-decode "%0A")))
|
||||
;; Decode a Unicode multibyte character.
|
||||
(should (string= "€" (org-link-decode "%E2%82%AC"))))
|
||||
|
||||
(ert-deftest test-ol/escape-multibyte-character ()
|
||||
"Escape an unicode multibyte character."
|
||||
(ert-deftest test-ol/encode-url-with-escaped-char ()
|
||||
"Encode and decode a URL that includes an encoded char."
|
||||
(should
|
||||
(string=
|
||||
"%E2%82%AC"
|
||||
(org-link-escape "€"))))
|
||||
(string= "http://some.host.com/form?&id=blah%2Bblah25"
|
||||
(org-link-decode
|
||||
(org-link-encode "http://some.host.com/form?&id=blah%2Bblah25"
|
||||
'(?\s ?\[ ?\] ?%))))))
|
||||
|
||||
(ert-deftest test-ol/escape-custom-table ()
|
||||
"Escape string with custom character table."
|
||||
(should
|
||||
(string=
|
||||
"Foo%3A%42ar%0A"
|
||||
(org-link-escape "Foo:Bar\n" '(?\: ?\B)))))
|
||||
|
||||
;;; Escape and Unescape Links
|
||||
|
||||
(ert-deftest test-ol/escape-custom-table-merge ()
|
||||
"Escape string with custom table merged with default table."
|
||||
(should
|
||||
(string=
|
||||
"%5BF%6F%6F%3A%42ar%0A%5D"
|
||||
(org-link-escape "[Foo:Bar\n]" '(?\: ?\B ?\o) t))))
|
||||
(ert-deftest test-ol/escape ()
|
||||
"Test `org-link-escape' specifications."
|
||||
;; No-op when there is no backslash or closing square bracket.
|
||||
(should (string= "foo[" (org-link-escape "foo[")))
|
||||
;; Escape closing square bracket at the end of the link.
|
||||
(should (string= "[foo\\]" (org-link-escape "[foo]")))
|
||||
;; Escape closing square brackets followed by another square
|
||||
;; bracket.
|
||||
(should (string= "foo\\][bar" (org-link-escape "foo][bar")))
|
||||
(should (string= "foo\\]]bar" (org-link-escape "foo]]bar")))
|
||||
;; However, escaping closing square bracket at the end of the link
|
||||
;; has precedence over the previous rule.
|
||||
(should (string= "foo]\\]" (org-link-escape "foo]]")))
|
||||
;; Escape backslashes at the end of the link.
|
||||
(should (string= "foo\\\\" (org-link-escape "foo\\")))
|
||||
;; Escape backslashes that could be confused with escaping
|
||||
;; characters.
|
||||
(should (string= "foo\\\\\\]" (org-link-escape "foo\\]")))
|
||||
(should (string= "foo\\\\\\][" (org-link-escape "foo\\][")))
|
||||
(should (string= "foo\\\\\\]]bar" (org-link-escape "foo\\]]bar")))
|
||||
;; Do not escape backslash characters when unnecessary.
|
||||
(should (string= "foo\\bar" (org-link-escape "foo\\bar")))
|
||||
(should (string= "foo\\]bar" (org-link-escape "foo\\]bar")))
|
||||
;; Pathological cases: consecutive closing square brackets.
|
||||
(should (string= "[[[foo\\]]\\]" (org-link-escape "[[[foo]]]")))
|
||||
(should (string= "[[[foo]\\]] bar" (org-link-escape "[[[foo]]] bar"))))
|
||||
|
||||
(ert-deftest test-ol/unescape-ascii-character ()
|
||||
"Unescape an ascii character."
|
||||
(should
|
||||
(string=
|
||||
"["
|
||||
(org-link-unescape "%5B"))))
|
||||
(ert-deftest test-ol/unescape ()
|
||||
"Test `org-link-unescape' specifications."
|
||||
;; No-op if there is no backslash.
|
||||
(should (string= "foo[" (org-link-unescape "foo[")))
|
||||
;; No-op if backslashes are not escaping backslashes.
|
||||
(should (string= "foo\\bar" (org-link-unescape "foo\\bar")))
|
||||
(should (string= "foo\\]bar" (org-link-unescape "foo\\]bar")))
|
||||
;;
|
||||
(should (string= "foo\\]" (org-link-unescape "foo\\\\\\]")))
|
||||
(should (string= "foo\\][" (org-link-unescape "foo\\\\\\][")))
|
||||
(should (string= "foo\\]]bar" (org-link-unescape "foo\\\\\\]]bar")))
|
||||
;; Unescape backslashes at the end of the link.
|
||||
(should (string= "foo\\" (org-link-unescape "foo\\\\")))
|
||||
;; Unescape closing square bracket at the end of the link.
|
||||
(should (string= "[foo]" (org-link-unescape "[foo\\]")))
|
||||
;; Pathological cases: consecutive closing square brackets.
|
||||
(should (string= "[[[foo]]]" (org-link-unescape "[[[foo\\]]\\]")))
|
||||
(should (string= "[[[foo]]] bar" (org-link-unescape "[[[foo]\\]] bar"))))
|
||||
|
||||
(ert-deftest test-ol/unescape-ascii-ctrl-character ()
|
||||
"Unescpae an ascii control character."
|
||||
(ert-deftest test-ol/make-string ()
|
||||
"Test `org-link-make-string' specifications."
|
||||
;; Throw an error on empty URI.
|
||||
(should-error (org-link-make-string ""))
|
||||
;; Empty description returns a [[URI]] construct.
|
||||
(should (string= "[[uri]]"(org-link-make-string "uri")))
|
||||
;; Non-empty description returns a [[URI][DESCRIPTION]] construct.
|
||||
(should
|
||||
(string=
|
||||
"\n"
|
||||
(org-link-unescape "%0A"))))
|
||||
|
||||
(ert-deftest test-ol/unescape-multibyte-character ()
|
||||
"Unescape unicode multibyte character."
|
||||
(string= "[[uri][description]]"
|
||||
(org-link-make-string "uri" "description")))
|
||||
;; Escape "]]" strings in the description with zero-width spaces.
|
||||
(should
|
||||
(string=
|
||||
"€"
|
||||
(org-link-unescape "%E2%82%AC"))))
|
||||
|
||||
(ert-deftest test-ol/unescape-ascii-extended-char ()
|
||||
"Unescape old style percent escaped character."
|
||||
(let ((zws (string ?\x200B)))
|
||||
(string= (format "[[uri][foo]%s]bar]]" zws)
|
||||
(org-link-make-string "uri" "foo]]bar"))))
|
||||
;; Prevent description from ending with a closing square bracket
|
||||
;; with a zero-width space.
|
||||
(should
|
||||
(string=
|
||||
"àâçèéêîôùû"
|
||||
(decode-coding-string
|
||||
(org-link-unescape "%E0%E2%E7%E8%E9%EA%EE%F4%F9%FB") 'latin-1))))
|
||||
|
||||
(ert-deftest test-ol/escape-url-with-escaped-char ()
|
||||
"Escape and unescape a URL that includes an escaped char.
|
||||
http://article.gmane.org/gmane.emacs.orgmode/21459/"
|
||||
(should
|
||||
(string=
|
||||
"http://some.host.com/form?&id=blah%2Bblah25"
|
||||
(org-link-unescape
|
||||
(org-link-escape "http://some.host.com/form?&id=blah%2Bblah25")))))
|
||||
(let ((zws (string ?\x200B)))
|
||||
(string= (format "[[uri][foo]%s]]" zws)
|
||||
(org-link-make-string "uri" "foo]")))))
|
||||
|
||||
|
||||
;;; Store links
|
||||
|
|
|
@ -590,18 +590,18 @@ CLOCK: [2016-12-27 Wed 13:09]--[2016-12-28 Wed 15:09] => 26:00"
|
|||
;; Otherwise, link to the headline in the current file.
|
||||
(should
|
||||
(equal
|
||||
"| Headline | Time |
|
||||
|--------------+---------|
|
||||
| *Total time* | *26:00* |
|
||||
|--------------+---------|
|
||||
| [[file:filename::Foo][Foo]] | 26:00 |"
|
||||
"| Headline | Time |
|
||||
|-------------------------------+---------|
|
||||
| *Total time* | *26:00* |
|
||||
|-------------------------------+---------|
|
||||
| [[file:filename::Foo][Foo]] | 26:00 |"
|
||||
(org-test-with-temp-text-in-file
|
||||
"* Foo
|
||||
CLOCK: [2016-12-27 Wed 13:09]--[2016-12-28 Wed 15:09] => 26:00"
|
||||
(let ((file (buffer-file-name)))
|
||||
(replace-regexp-in-string
|
||||
(regexp-quote file) "filename"
|
||||
(test-org-clock-clocktable-contents ":link t"))))))
|
||||
(test-org-clock-clocktable-contents ":link t :lang en"))))))
|
||||
;; Ignore TODO keyword, priority cookie, COMMENT and tags in
|
||||
;; headline.
|
||||
(should
|
||||
|
@ -675,26 +675,26 @@ CLOCK: [2016-12-27 Wed 13:09]--[2016-12-28 Wed 15:09] => 26:00"
|
|||
;; links if there is no description.
|
||||
(should
|
||||
(equal
|
||||
"| Headline | Time |
|
||||
|--------------+---------|
|
||||
| *Total time* | *26:00* |
|
||||
|--------------+---------|
|
||||
| [[Foo %5B%5Bhttps://orgmode.org%5D%5BOrg mode%5D%5D][Foo Org mode]] | 26:00 |"
|
||||
"| Headline | Time |
|
||||
|-----------------------------------------+---------|
|
||||
| *Total time* | *26:00* |
|
||||
|-----------------------------------------+---------|
|
||||
| [[Foo [[https://orgmode.org\\][Org mode]\\]][Foo Org mode]] | 26:00 |"
|
||||
(org-test-with-temp-text
|
||||
"* Foo [[https://orgmode.org][Org mode]]
|
||||
CLOCK: [2016-12-27 Wed 13:09]--[2016-12-28 Wed 15:09] => 26:00"
|
||||
(test-org-clock-clocktable-contents ":link t"))))
|
||||
(test-org-clock-clocktable-contents ":link t :lang en"))))
|
||||
(should
|
||||
(equal
|
||||
"| Headline | Time |
|
||||
|-------------------------+---------|
|
||||
| *Total time* | *26:00* |
|
||||
|-------------------------+---------|
|
||||
| [[Foo %5B%5Bhttps://orgmode.org%5D%5D][Foo https://orgmode.org]] | 26:00 |"
|
||||
"| Headline | Time |
|
||||
|------------------------------+---------|
|
||||
| *Total time* | *26:00* |
|
||||
|------------------------------+---------|
|
||||
| [[Foo [[https://orgmode.org]\\]][Foo https://orgmode.org]] | 26:00 |"
|
||||
(org-test-with-temp-text
|
||||
"* Foo [[https://orgmode.org]]
|
||||
CLOCK: [2016-12-27 Wed 13:09]--[2016-12-28 Wed 15:09] => 26:00"
|
||||
(test-org-clock-clocktable-contents ":link t")))))
|
||||
(test-org-clock-clocktable-contents ":link t :lang en")))))
|
||||
|
||||
(ert-deftest test-org-clock/clocktable/compact ()
|
||||
"Test \":compact\" parameter in Clock table."
|
||||
|
|
|
@ -2331,7 +2331,7 @@ SCHEDULED: <2014-03-04 tue.>"
|
|||
;; Handle escape characters.
|
||||
(should
|
||||
(org-test-with-temp-text
|
||||
"* H1\n:PROPERTIES:\n:CUSTOM_ID: [%]\n:END:\n* H2\n[[#%5B%25%5D<point>]]"
|
||||
"* H1\n:PROPERTIES:\n:CUSTOM_ID: [%]\n:END:\n* H2\n[[#[%\\]<point>]]"
|
||||
(org-open-at-point)
|
||||
(looking-at-p "\\* H1")))
|
||||
;; Throw an error on false positives.
|
||||
|
@ -2425,13 +2425,9 @@ Foo Bar
|
|||
(org-test-with-temp-text "[[*Test]]\n* TODO COMMENT Test"
|
||||
(org-open-at-point)
|
||||
(looking-at "\\* TODO COMMENT Test")))
|
||||
;; Correctly un-hexify fuzzy links.
|
||||
;; Correctly un-escape fuzzy links.
|
||||
(should
|
||||
(org-test-with-temp-text "* With space\n[[*With%20space][With space<point>]]"
|
||||
(org-open-at-point)
|
||||
(bobp)))
|
||||
(should
|
||||
(org-test-with-temp-text "* [1]\n[[*%5B1%5D<point>]]"
|
||||
(org-test-with-temp-text "* [foo]\n[[*[foo\\]][With escaped characters]]"
|
||||
(org-open-at-point)
|
||||
(bobp)))
|
||||
;; Match search strings containing newline characters, including
|
||||
|
|
|
@ -3510,9 +3510,9 @@ Another text. (ref:text)
|
|||
(org-element-type
|
||||
(org-export-resolve-fuzzy-link
|
||||
(org-element-map tree 'link 'identity info t) info)))))
|
||||
;; Handle url-encoded fuzzy links.
|
||||
;; Handle escaped fuzzy links.
|
||||
(should
|
||||
(org-test-with-parsed-data "* A B\n[[A%20B]]"
|
||||
(org-test-with-parsed-data "* [foo]\n[[[foo\\]]]"
|
||||
(org-export-resolve-fuzzy-link
|
||||
(org-element-map tree 'link #'identity info t) info))))
|
||||
|
||||
|
|
Loading…
Reference in New Issue