ox-latex-subfigure.el 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. ;;; ox-latex-subfigure.el --- Subfigure for latex export
  2. ;; Copyright (C) 2014-2019 Quang Linh LE
  3. ;; Copyright (C) 2019-2021 eDgar
  4. ;; Author: Quang Linh LE <linktohack@gmail.com>
  5. ;; URL: http://www.notabug.com/broncodev/ox-latex-subfigure
  6. ;; Version: 0.0.2
  7. ;; Keywords: convenience ox latex subfigure org org-mode
  8. ;; Package-Requires: ((emacs "24"))
  9. ;; This file is not part of GNU Emacs.
  10. ;;; License:
  11. ;; This file is part of ox-latex-subfigure
  12. ;;
  13. ;; ox-latex-subfigure is free software: you can redistribute it and/or
  14. ;; modify it under the terms of the GNU General Public License as
  15. ;; published by the Free Software Foundation, either version 3 of the
  16. ;; License.
  17. ;;
  18. ;; ox-latex-subfigure is distributed in the hope that it will be
  19. ;; useful, but WITHOUT ANY WARRANTY; without even the implied warranty
  20. ;; of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. ;; GNU General Public License for more details.
  22. ;;
  23. ;; You should have received a copy of the GNU General Public License
  24. ;; along with this program. If not, see
  25. ;; <http://www.gnu.org/licenses/>.
  26. ;;; Commentary:
  27. ;; ox-latex-subfigure.el permits to export subfigure to latex
  28. ;;; Code:
  29. (require 'ox-latex)
  30. (require 'org-loaddefs)
  31. (defun ox-latex-subfigure-org-export-table-to-subfigure (text backend info)
  32. "Convert table to subfigure in LaTeX export.
  33. TEXT is raw text, BACKEND is backend, INFO is info."
  34. (when (org-export-derived-backend-p backend 'latex)
  35. (if (not (next-property-change 0 text))
  36. text
  37. (let
  38. ((pt 0)
  39. cell
  40. table)
  41. (while
  42. (or
  43. (not table)
  44. (not pt))
  45. (setq
  46. pt (next-property-change pt text)
  47. cell (plist-get (text-properties-at pt text) :parent)
  48. table (org-export-get-parent-table cell)))
  49. (let*
  50. ((attr (org-export-read-attribute :attr_latex table))
  51. (env (plist-get attr :environment))
  52. (limit (string-to-number (or (plist-get attr :limit) "0"))))
  53. (if (not (string= "subfigure" env))
  54. text
  55. (with-temp-buffer
  56. (insert text)
  57. (goto-char 1)
  58. (ox-latex-subfigure-latex-table-to-subfigure limit)
  59. (buffer-string))))))))
  60. (defun ox-latex-subfigure-latex-table-to-subfigure (limit)
  61. "Convert well-formed table to subfigure.
  62. LIMIT is limit."
  63. (interactive "p")
  64. (let ((width ".9\\textwidth")
  65. (align "")
  66. (option "")
  67. (centering "")
  68. (caption "")
  69. fig
  70. cap
  71. opn
  72. wdt
  73. aln)
  74. (beginning-of-line)
  75. (while (not (looking-at "^\\\\end{table}"))
  76. (let ((row (thing-at-point 'line t)))
  77. (kill-whole-line)
  78. (cond
  79. ;; \begin{table}[option], \end{table}
  80. ((string-match
  81. "^\\\\begin{table}\\(\\[.*\\]\\)?" row)
  82. (setq
  83. option (or (match-string 1 row) "")))
  84. ;; \centering
  85. ((string-match "^\\\\centering" row)
  86. (setq centering "\\centering\n"))
  87. ;; \begin{subfigure}{width}{align}, \begin{subfigure}{align}
  88. ;; \end{subfigure}
  89. ((string-match
  90. "^\\\\begin{subfigure}\\({\\(.*?\\)}\\)?\\({\\(.*?\\)}\\)?" row)
  91. ;; This will happen when \begin{subfigure} is found
  92. (let (maybe-width
  93. maybe-align
  94. start-of-table
  95. row-start
  96. row-end
  97. rules)
  98. (setq maybe-width (match-string 2 row))
  99. (setq maybe-align (match-string 4 row))
  100. (unless maybe-align
  101. (setq maybe-align maybe-width)
  102. (setq maybe-width nil))
  103. (setq width (or maybe-width width))
  104. (setq align (or maybe-align align))
  105. (setq start-of-table (point))
  106. ;; Remove all possible rules or hlines
  107. (setq rules
  108. (mapconcat
  109. 'identity
  110. '("hline"
  111. "vline"
  112. "toprule"
  113. "midrule"
  114. "bottomrule")
  115. "\\|"))
  116. (while (re-search-forward (concat "\\\\\\(" rules "\\)\n?") nil t)
  117. (replace-match ""))
  118. (goto-char start-of-table)
  119. ;; Transform all multi line rows to single line
  120. ;; rows by replacing newlines with spaces
  121. (while (not (looking-at "\\\\end{subfigure}"))
  122. (setq row-start (point))
  123. ;; Search for a new row delimiter
  124. (when (re-search-forward "\\\\\\\\\n?" nil t)
  125. (goto-char row-start)
  126. (setq row-end (match-beginning 0))
  127. ;; Replace all newlines in the row with spaces
  128. (save-match-data
  129. (while (re-search-forward "\n" row-end t)
  130. (replace-match " ")))
  131. (setq row-start (match-end 0))
  132. (goto-char row-start)))
  133. ;; Go back the start of the table and continue with normal
  134. ;; row formatting
  135. (goto-char start-of-table)))
  136. ;; \caption{\label{tab:orgtable1}
  137. ;; xxx}
  138. ((string-match "^\\\\caption[\\\\[{]" row)
  139. (setq
  140. caption (concat
  141. row (thing-at-point 'line t)))
  142. (kill-whole-line))
  143. ;; table row
  144. ((string-match ".*\\\\\\\\$" row)
  145. (let ((striped-row (replace-regexp-in-string
  146. "\\\\\\\\\n$" "" row)))
  147. (setq
  148. fig (append
  149. fig (split-string striped-row " & ")))
  150. (setq
  151. row (thing-at-point
  152. 'line t))
  153. (kill-whole-line)
  154. (setq
  155. striped-row (replace-regexp-in-string
  156. "\\\\\\\\\n$" "" row))
  157. (setq
  158. cap (append
  159. cap (split-string
  160. striped-row " & ")))
  161. ;;
  162. (setq
  163. row (thing-at-point
  164. 'line t))
  165. (kill-whole-line)
  166. (setq
  167. striped-row (replace-regexp-in-string
  168. "\\\\\\\\\n$" "" row))
  169. (setq
  170. opn (append
  171. opn (split-string striped-row " & "))))))))
  172. (kill-whole-line)
  173. (insert (format "\\begin{figure}%s\n%s%s" option
  174. (if (member 'subfigure org-latex-caption-above) caption "")
  175. centering))
  176. (dotimes (i (length fig))
  177. (let ((f (nth i fig))
  178. (c (nth i cap))
  179. (o (if (and (nth i opn)
  180. (string-match "\\\\end{subfigure}" (nth i opn)))
  181. nil
  182. (nth i opn)))
  183. (std "includegraphics")
  184. (svg "includesvg"))
  185. (when (or (string-match std c)
  186. (string-match svg c))
  187. (setq f (prog1 c (setq c f))))
  188. (when
  189. (or
  190. (string-match (concat
  191. "\\(\\\\"
  192. std
  193. "\\(:?\\[.*?\\]\\)?{.*?}\\)")
  194. f)
  195. (string-match (concat
  196. "\\(\\\\"
  197. svg
  198. "\\(:?\\[.*?\\]\\)?{.*?}\\)")
  199. f))
  200. (setq
  201. f (replace-regexp-in-string
  202. "\\[.*?\\]"
  203. (concat
  204. "[" o "]")
  205. (match-string 1 f)
  206. t t))
  207. ;; Split width by commas for each column
  208. (if
  209. ;; If only one width is given, and there are
  210. ;; many columns, the conditional forces wdt to
  211. ;; remain with the previous value of width,
  212. ;; because width was previously vacated
  213. (> (length width) 0)
  214. (setq
  215. ;; Get the the width for the current column
  216. wdt (car (split-string width ","))
  217. ;; Remove current instance of width and update
  218. ;; https://stackoverflow.com/a/32580403
  219. ;; https://www.emacswiki.org/emacs/ReplaceInString
  220. width (mapconcat
  221. 'identity
  222. (cdr
  223. (split-string
  224. width
  225. ","))
  226. ",")))
  227. ;; Split align if is not given (ox-latex sets a
  228. ;; default) or has several characters
  229. (if
  230. ;; If only one align char is given, and there
  231. ;; are many columns, the conditional forces
  232. ;; aln to remain with the previous value of
  233. ;; align, because align was previously vacated
  234. (> (length align) 0)
  235. (setq
  236. ;; Get the the alignment for the current
  237. ;; column (a single character)
  238. aln (substring align 0 1)
  239. ;; Remove current instance of align and update
  240. ;; https://stackoverflow.com/a/32580403
  241. ;; https://www.emacswiki.org/emacs/ReplaceInString
  242. align (mapconcat
  243. 'identity
  244. (cdr
  245. ;; Breaking strings into characters
  246. ;; https://www.emacswiki.org/emacs/SplitString#toc3
  247. (mapcar
  248. 'char-to-string
  249. align))
  250. "")))
  251. (insert (format "\\begin{subfigure}[%s]{%s}\\centering
  252. %s
  253. \\caption{%s}
  254. \\end{subfigure}\n" aln wdt f c))
  255. (when (and (> limit 0)
  256. (< i (1- (length fig)))
  257. (= (mod (1+ i) limit) 0))
  258. (insert (format "\\end{figure}\n
  259. \\begin{figure}%s
  260. %s\\ContinuedFloat\n" option centering))))))
  261. (insert (format "%s\\end{figure}\n"
  262. (if (member 'subfigure org-latex-caption-above) "" caption)))))
  263. (add-hook 'org-export-filter-table-functions
  264. 'ox-latex-subfigure-org-export-table-to-subfigure)
  265. (provide 'ox-latex-subfigure)
  266. ;;; ox-latex-subfigure.el ends here