org-export: Do not treat unpaired ' and " as smart quotes
* lisp/ox.el (org-export--smart-quote-status): When quotes are not balanced, treat " literally and ' as apostrophes. * testing/lisp/test-ox.el (test-org-export/activate-smart-quotes): Fix test with unbalanced " and add new tests for unbalanced quotes. Reported-by: Juan Manuel Macías <maciaschain@posteo.net> Link: https://list.orgmode.org/orgmode/875xxfqdpt.fsf@posteo.net/
This commit is contained in:
parent
8507efa848
commit
33503445e6
50
lisp/ox.el
50
lisp/ox.el
|
@ -5942,6 +5942,56 @@ INFO is the current export state, as a plist."
|
|||
(when current-status
|
||||
(push (cons text (nreverse current-status)) full-status))))
|
||||
info nil org-element-recursive-objects)
|
||||
;; When quotes are not balanced, treat them as apostrophes.
|
||||
(setq full-status (nreverse full-status))
|
||||
(let (primary-openings secondary-openings)
|
||||
(dolist (substatus full-status)
|
||||
(let ((status (cdr substatus)))
|
||||
(while status
|
||||
(pcase (car status)
|
||||
(`apostrophe nil)
|
||||
(`primary-opening
|
||||
(push status primary-openings))
|
||||
(`secondary-opening
|
||||
(push status secondary-openings))
|
||||
(`secondary-closing
|
||||
(if secondary-openings
|
||||
;; Remove matched opening.
|
||||
(pop secondary-openings)
|
||||
;; No matching openings for a given closing. Replace
|
||||
;; it with apostrophe.
|
||||
(setcar status 'apostrophe)))
|
||||
(`primary-closing
|
||||
(when secondary-openings
|
||||
;; Some secondary opening quotes are not closed
|
||||
;; within "...". Replace them all with apostrophes.
|
||||
(dolist (opening secondary-openings)
|
||||
(setcar opening 'apostrophe))
|
||||
(setq secondary-openings nil))
|
||||
(if primary-openings
|
||||
;; Remove matched opening.
|
||||
(pop primary-openings)
|
||||
;; No matching openings for a given closing.
|
||||
(error "This should no happen"))))
|
||||
(setq status (cdr status)))))
|
||||
(when primary-openings
|
||||
;; Trailing unclosed "
|
||||
(unless (= 1 (length primary-openings))
|
||||
(error "This should not happen"))
|
||||
;; Mark for not replacing.
|
||||
(setcar (car primary-openings) nil)
|
||||
;; Mark all the secondary openings and closings after
|
||||
;; trailing unclosed " as apostrophes.
|
||||
(let ((after-unbalanced-primary nil))
|
||||
(dolist (substatus full-status)
|
||||
(let ((status (cdr substatus)))
|
||||
(while status
|
||||
(when (eq status (car primary-openings))
|
||||
(setq after-unbalanced-primary t))
|
||||
(when after-unbalanced-primary
|
||||
(when (memq (car status) '(secondary-opening secondary-closing))
|
||||
(setcar status 'apostrophe)))
|
||||
(setq status (cdr status))))))))
|
||||
(puthash (cons parent (org-element-secondary-p s)) full-status cache)
|
||||
(cdr (assq s full-status))))))
|
||||
|
||||
|
|
|
@ -4134,9 +4134,9 @@ This test does not cover listings and custom environments."
|
|||
;; Opening quotes: at the beginning of a paragraph.
|
||||
(should
|
||||
(equal
|
||||
'("“begin")
|
||||
'("“begin”")
|
||||
(let ((org-export-default-language "en"))
|
||||
(org-test-with-parsed-data "\"begin"
|
||||
(org-test-with-parsed-data "\"begin\""
|
||||
(org-element-map tree 'plain-text
|
||||
(lambda (s) (org-export-activate-smart-quotes s :html info))
|
||||
info)))))
|
||||
|
@ -4267,6 +4267,39 @@ This test does not cover listings and custom environments."
|
|||
(org-test-with-parsed-data "*\"foo\"*"
|
||||
(org-element-map tree 'plain-text
|
||||
(lambda (s) (org-export-activate-smart-quotes s :html info))
|
||||
info nil nil t)))))
|
||||
;; Unmatched quotes.
|
||||
(should
|
||||
(equal '("\\guillemotleft{}my friends' party and the students' papers\\guillemotright{} \\guillemotleft{}``mothers''\\guillemotright{}")
|
||||
(let ((org-export-default-language "es"))
|
||||
(org-test-with-parsed-data
|
||||
"\"my friends' party and the students' papers\" \"'mothers'\""
|
||||
(org-element-map tree 'plain-text
|
||||
(lambda (s) (org-export-activate-smart-quotes s :latex info))
|
||||
info nil nil t)))))
|
||||
(should
|
||||
(equal '("\"'mothers'")
|
||||
(let ((org-export-default-language "es"))
|
||||
(org-test-with-parsed-data
|
||||
"\"'mothers'"
|
||||
(org-element-map tree 'plain-text
|
||||
(lambda (s) (org-export-activate-smart-quotes s :latex info))
|
||||
info nil nil t)))))
|
||||
(should
|
||||
(equal '("\"'mothers " "end'")
|
||||
(let ((org-export-default-language "es"))
|
||||
(org-test-with-parsed-data
|
||||
"\"'mothers =verbatim= end'"
|
||||
(org-element-map tree 'plain-text
|
||||
(lambda (s) (org-export-activate-smart-quotes s :latex info))
|
||||
info nil nil t)))))
|
||||
(should
|
||||
(equal '("\\guillemotleft{}να 'ρθώ το βράδυ\\guillemotright{}")
|
||||
(let ((org-export-default-language "el"))
|
||||
(org-test-with-parsed-data
|
||||
"\"να 'ρθώ το βράδυ\""
|
||||
(org-element-map tree 'plain-text
|
||||
(lambda (s) (org-export-activate-smart-quotes s :latex info))
|
||||
info nil nil t))))))
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue