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:
Nicolas Goaziou 2019-03-09 10:58:41 +01:00
parent 3318b50a39
commit 2b00d62816
15 changed files with 217 additions and 202 deletions

View File

@ -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)

View File

@ -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

View File

@ -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)))))

View File

@ -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))

View File

@ -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 |")

View File

@ -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")

View File

@ -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.

View File

@ -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))))))

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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."

View File

@ -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

View File

@ -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))))