diff options
| author | Arash Esbati | 2022-08-08 15:58:35 +0200 |
|---|---|---|
| committer | Arash Esbati | 2022-08-08 16:02:18 +0200 |
| commit | 7331ee112c107caaece87db9f65751f9cbcc01c3 (patch) | |
| tree | 80483161ebf0f2dfd246f307cf43468e6ad9bd0e | |
| parent | 7f8a3d4e919e495fadb4eb6fae3f73556b987700 (diff) | |
| download | emacs-7331ee112c107caaece87db9f65751f9cbcc01c3.tar.gz emacs-7331ee112c107caaece87db9f65751f9cbcc01c3.zip | |
Improve collecting of citation keys
* lisp/textmodes/reftex-cite.el (reftex-all-used-citation-keys):
Improve regexp for matching various cite commands incl. optional
arguments.
Recognize comments more robustly and don't interpret the control
symbol \% as a comment starter. (bug#56655)
* test/lisp/textmodes/reftex-tests.el
(reftex-all-used-citation-keys): New test.
| -rw-r--r-- | lisp/textmodes/reftex-cite.el | 52 | ||||
| -rw-r--r-- | test/lisp/textmodes/reftex-tests.el | 135 |
2 files changed, 174 insertions, 13 deletions
diff --git a/lisp/textmodes/reftex-cite.el b/lisp/textmodes/reftex-cite.el index 26b14ebc79e..f3f95627af1 100644 --- a/lisp/textmodes/reftex-cite.el +++ b/lisp/textmodes/reftex-cite.el | |||
| @@ -1116,10 +1116,10 @@ recommended for follow mode. It works OK for individual lookups." | |||
| 1116 | (setq bibtype (reftex-bib-or-thebib)) | 1116 | (setq bibtype (reftex-bib-or-thebib)) |
| 1117 | (cond | 1117 | (cond |
| 1118 | ((eq bibtype 'bib) | 1118 | ((eq bibtype 'bib) |
| 1119 | ; ((assq 'bib (symbol-value reftex-docstruct-symbol)) | 1119 | ;; ((assq 'bib (symbol-value reftex-docstruct-symbol)) |
| 1120 | (setq bibfile-list (reftex-get-bibfile-list))) | 1120 | (setq bibfile-list (reftex-get-bibfile-list))) |
| 1121 | ((eq bibtype 'thebib) | 1121 | ((eq bibtype 'thebib) |
| 1122 | ; ((assq 'thebib (symbol-value reftex-docstruct-symbol)) | 1122 | ;; ((assq 'thebib (symbol-value reftex-docstruct-symbol)) |
| 1123 | (setq bibfile-list | 1123 | (setq bibfile-list |
| 1124 | (reftex-uniquify | 1124 | (reftex-uniquify |
| 1125 | (mapcar #'cdr | 1125 | (mapcar #'cdr |
| @@ -1142,8 +1142,35 @@ recommended for follow mode. It works OK for individual lookups." | |||
| 1142 | 1142 | ||
| 1143 | ;;; Global BibTeX file | 1143 | ;;; Global BibTeX file |
| 1144 | (defun reftex-all-used-citation-keys () | 1144 | (defun reftex-all-used-citation-keys () |
| 1145 | "Return a list of all citation keys used in document." | ||
| 1145 | (reftex-access-scan-info) | 1146 | (reftex-access-scan-info) |
| 1146 | (let ((files (reftex-all-document-files)) file keys kk k) | 1147 | ;; FIXME: multicites macros provided by biblatex |
| 1148 | ;; are not covered in this function. | ||
| 1149 | (let ((files (reftex-all-document-files)) | ||
| 1150 | (re (concat "\\\\" | ||
| 1151 | "\\(?:" | ||
| 1152 | ;; biblatex volcite macros take these args: | ||
| 1153 | ;; \volcite[prenote]{volume}[pages]{key} | ||
| 1154 | ;; so cater for the first 3 args: | ||
| 1155 | (regexp-opt '("volcite" "Volcite" | ||
| 1156 | "pvolcite" "Pvolcite" | ||
| 1157 | "fvolcite" "ftvolcite" | ||
| 1158 | "svolcite" "Svolcite" | ||
| 1159 | "tvolcite" "Tvolcite" | ||
| 1160 | "avolcite" "Avolcite")) | ||
| 1161 | "\\(?:\\[[^]]*\\]\\)?" | ||
| 1162 | "{[^}]*}" | ||
| 1163 | "\\(?:\\[[^]]*\\]\\)?" | ||
| 1164 | "\\|" | ||
| 1165 | ;; Other cite macros usually go like: | ||
| 1166 | ;; \cite[prenote][postnote]{key} | ||
| 1167 | ;; so cater for the optional args: | ||
| 1168 | "\\(?:bibentry\\|[a-zA-Z]*[Cc]ite[a-zA-Z*]*\\)" | ||
| 1169 | "\\(?:\\[[^]]*\\]\\)\\{0,2\\}" | ||
| 1170 | "\\)" | ||
| 1171 | ;; Now match the key: | ||
| 1172 | "{\\([^}]+\\)}")) | ||
| 1173 | file keys kk k) | ||
| 1147 | (save-current-buffer | 1174 | (save-current-buffer |
| 1148 | (while (setq file (pop files)) | 1175 | (while (setq file (pop files)) |
| 1149 | (set-buffer (reftex-get-file-buffer-force file 'mark)) | 1176 | (set-buffer (reftex-get-file-buffer-force file 'mark)) |
| @@ -1151,14 +1178,17 @@ recommended for follow mode. It works OK for individual lookups." | |||
| 1151 | (save-restriction | 1178 | (save-restriction |
| 1152 | (widen) | 1179 | (widen) |
| 1153 | (goto-char (point-min)) | 1180 | (goto-char (point-min)) |
| 1154 | (while (re-search-forward "\\(?:^\\|\\=\\)[^%\n\r]*?\\\\\\(bibentry\\|[a-zA-Z]*cite[a-zA-Z]*\\)\\(\\[[^]]*\\]\\)?{\\([^}]+\\)}" nil t) | 1181 | (while (re-search-forward re nil t) |
| 1155 | (setq kk (match-string-no-properties 3)) | 1182 | ;; Make sure we're not inside a comment: |
| 1156 | (while (string-match "%.*\n?" kk) | 1183 | (unless (save-match-data |
| 1157 | (setq kk (replace-match "" t t kk))) | 1184 | (nth 4 (syntax-ppss))) |
| 1158 | (setq kk (split-string kk "[, \t\r\n]+")) | 1185 | (setq kk (match-string-no-properties 1)) |
| 1159 | (while (setq k (pop kk)) | 1186 | (while (string-match "%.*\n?" kk) |
| 1160 | (or (member k keys) | 1187 | (setq kk (replace-match "" t t kk))) |
| 1161 | (setq keys (cons k keys))))))))) | 1188 | (setq kk (split-string kk "[, \t\r\n]+")) |
| 1189 | (while (setq k (pop kk)) | ||
| 1190 | (or (member k keys) | ||
| 1191 | (setq keys (cons k keys)))))))))) | ||
| 1162 | (reftex-kill-temporary-buffers) | 1192 | (reftex-kill-temporary-buffers) |
| 1163 | keys)) | 1193 | keys)) |
| 1164 | 1194 | ||
diff --git a/test/lisp/textmodes/reftex-tests.el b/test/lisp/textmodes/reftex-tests.el index 9ef41088d1e..97ff3908177 100644 --- a/test/lisp/textmodes/reftex-tests.el +++ b/test/lisp/textmodes/reftex-tests.el | |||
| @@ -190,8 +190,8 @@ | |||
| 190 | 190 | ||
| 191 | (ert-deftest reftex-format-citation-test () | 191 | (ert-deftest reftex-format-citation-test () |
| 192 | "Test `reftex-format-citation'." | 192 | "Test `reftex-format-citation'." |
| 193 | (let ((entry (reftex-parse-bibtex-entry | 193 | (let ((entry (reftex-parse-bibtex-entry "\ |
| 194 | "@article{Foo13, | 194 | @article{Foo13, |
| 195 | author = {Jane Roe and John Doe and Jane Q. Taxpayer}, | 195 | author = {Jane Roe and John Doe and Jane Q. Taxpayer}, |
| 196 | title = {Some Article}, | 196 | title = {Some Article}, |
| 197 | journal = {Some Journal}, | 197 | journal = {Some Journal}, |
| @@ -202,6 +202,137 @@ | |||
| 202 | (should (string= (reftex-format-citation entry "%l:%A:%y:%t %j %P %a") | 202 | (should (string= (reftex-format-citation entry "%l:%A:%y:%t %j %P %a") |
| 203 | "Foo13:Jane Roe:2013:Some Article Some Journal 1 Jane Roe, John Doe \\& Jane Taxpayer")))) | 203 | "Foo13:Jane Roe:2013:Some Article Some Journal 1 Jane Roe, John Doe \\& Jane Taxpayer")))) |
| 204 | 204 | ||
| 205 | (ert-deftest reftex-all-used-citation-keys () | ||
| 206 | "Test `reftex-all-used-citation-keys'. | ||
| 207 | Take the cite macros provided by biblatex package as reference." | ||
| 208 | (ert-with-temp-directory temp-dir | ||
| 209 | (let ((tex-file (expand-file-name "keys.tex" temp-dir)) | ||
| 210 | keys) | ||
| 211 | (with-temp-buffer | ||
| 212 | (insert "\ | ||
| 213 | \\documentclass{article} | ||
| 214 | \\usepackage{biblatex} | ||
| 215 | \\begin{document} | ||
| 216 | |||
| 217 | Standard commands: | ||
| 218 | \\cite[pre][pos]{cite:2022} | ||
| 219 | \\Cite[pos]{Cite:2022} | ||
| 220 | \\parencite{parencite:2022} | ||
| 221 | \\Parencite[pre][]{Parencite:2022} | ||
| 222 | \\footcite[][]{footcite:2022} | ||
| 223 | \\footcitetext[pre][pos]{footcitetext:2022} | ||
| 224 | |||
| 225 | Style specific commands: | ||
| 226 | \\textcite{textcite:2022} | ||
| 227 | \\Textcite[pos]{Textcite:2022} | ||
| 228 | \\smartcite[pre][pos]{smartcite:2022} | ||
| 229 | \\Smartcite[pre][]{Smartcite:2022} | ||
| 230 | \\cite*[pre][pos]{cite*:2022} | ||
| 231 | \\parencite*[][]{parencite*:2022} | ||
| 232 | |||
| 233 | Style independent commands: | ||
| 234 | \\autocite[pre][pos]{autocite:2022} | ||
| 235 | \\autocite*[pos]{autocite*:2022} | ||
| 236 | \\Autocite[pre][]{Autocite:2022} | ||
| 237 | \\Autocite*{Autocite*:2022} | ||
| 238 | |||
| 239 | Text commands: | ||
| 240 | \\citeauthor[pre][pos]{citeauthor:2022} | ||
| 241 | \\citeauthor*[pre][]{citeauthor*:2022} | ||
| 242 | \\Citeauthor[pos]{Citeauthor:2022} | ||
| 243 | \\Citeauthor*{Citeauthor*:2022} | ||
| 244 | \\citetitle[][]{citetitle:2022} | ||
| 245 | \\citetitle*[pre][pos]{citetitle*:2022} | ||
| 246 | \\citeyear[pre][pos]{citeyear:2022} | ||
| 247 | \\citeyear*[pre][pos]{citeyear*:2022} | ||
| 248 | \\citedate[pre][pos]{citedate:2022} | ||
| 249 | \\citedate*[pre][pos]{citedate*:2022} | ||
| 250 | \\citeurl[pre][pos]{citeurl:2022} | ||
| 251 | |||
| 252 | Special commands: | ||
| 253 | \\nocite{nocite:2022} | ||
| 254 | \\fullcite[pos]{fullcite:2022} | ||
| 255 | \\footfullcite[][]{fullfootcite:2022} | ||
| 256 | ``volcite'' macros have different number of args. | ||
| 257 | \\volcite{2}{volcite:2022} | ||
| 258 | \\Volcite[pre]{1}{Volcite:2022} | ||
| 259 | \\pvolcite{1}[pg]{pvolcite:2022} | ||
| 260 | \\Pvolcite[pre]{2}[pg]{Pvolcite:2022} | ||
| 261 | \\fvolcite[pre]{3}[pg]{fvolcite:2022} | ||
| 262 | \\ftvolcite[pre]{3}[pg]{ftvolcite:2022} | ||
| 263 | \\svolcite[pre]{2}[pg]{svolcite:2022} | ||
| 264 | \\Svolcite[pre]{4}[pg]{Svolcite:2022} | ||
| 265 | \\tvolcite[pre]{5}[pg]{tvolcite:2022} | ||
| 266 | \\Tvolcite[pre]{2}[pg]{Tvolcite:2022} | ||
| 267 | \\avolcite[pre]{3}[pg]{avolcite:2022} | ||
| 268 | \\Avolcite[pre]{1}[pg]{Avolcite:2022} | ||
| 269 | \\Notecite[pre]{Notecite:2022} | ||
| 270 | \\pnotecite[pre]{pnotecite:2022} | ||
| 271 | \\Pnotecite[pre]{Pnotecite:2022} | ||
| 272 | \\fnotecite[pre]{fnotecite:2022} | ||
| 273 | |||
| 274 | Natbib compatibility commands: | ||
| 275 | \\citet{citet:2022} | ||
| 276 | \\citet*[pre][pos]{citet*:2022} | ||
| 277 | \\citep[pre][pos]{citep:2022} | ||
| 278 | \\citep*[pos]{citep*:2022} | ||
| 279 | \\citealt[pre][]{citealt:2022} | ||
| 280 | \\citealt*[][]{citealt*:2022} | ||
| 281 | \\citealp[pre][pos]{citealp:2022} | ||
| 282 | \\citealp*{citealp*:2022} | ||
| 283 | \\Citet[pre][pos]{Citet:2022} | ||
| 284 | \\Citet*[pre][pos]{Citet*:2022} | ||
| 285 | \\Citep[pre][pos]{Citep:2022} | ||
| 286 | \\Citep*[pre][pos]{Citep*:2022} | ||
| 287 | |||
| 288 | Test for bug#56655: | ||
| 289 | There was a few \\% of increase in budget \\Citep*{bug:56655}. | ||
| 290 | |||
| 291 | And this should be % \\cite{ignored}. | ||
| 292 | \\end{document}") | ||
| 293 | (write-region (point-min) (point-max) tex-file)) | ||
| 294 | (find-file tex-file) | ||
| 295 | (setq keys (reftex-all-used-citation-keys)) | ||
| 296 | (should (equal (sort keys #'string<) | ||
| 297 | (sort '(;; Standard commands: | ||
| 298 | "cite:2022" "Cite:2022" | ||
| 299 | "parencite:2022" "Parencite:2022" | ||
| 300 | "footcite:2022" "footcitetext:2022" | ||
| 301 | ;; Style specific commands: | ||
| 302 | "textcite:2022" "Textcite:2022" | ||
| 303 | "smartcite:2022" "Smartcite:2022" | ||
| 304 | "cite*:2022" "parencite*:2022" | ||
| 305 | ;; Style independent commands: | ||
| 306 | "autocite:2022" "autocite*:2022" | ||
| 307 | "Autocite:2022" "Autocite*:2022" | ||
| 308 | ;; Text commands | ||
| 309 | "citeauthor:2022" "citeauthor*:2022" | ||
| 310 | "Citeauthor:2022" "Citeauthor*:2022" | ||
| 311 | "citetitle:2022" "citetitle*:2022" | ||
| 312 | "citeyear:2022" "citeyear*:2022" | ||
| 313 | "citedate:2022" "citedate*:2022" | ||
| 314 | "citeurl:2022" | ||
| 315 | ;; Special commands: | ||
| 316 | "nocite:2022" "fullcite:2022" | ||
| 317 | "fullfootcite:2022" | ||
| 318 | "volcite:2022" "Volcite:2022" | ||
| 319 | "pvolcite:2022" "Pvolcite:2022" | ||
| 320 | "fvolcite:2022" "ftvolcite:2022" | ||
| 321 | "svolcite:2022" "Svolcite:2022" | ||
| 322 | "tvolcite:2022" "Tvolcite:2022" | ||
| 323 | "avolcite:2022" "Avolcite:2022" | ||
| 324 | "Notecite:2022" "pnotecite:2022" | ||
| 325 | "Pnotecite:2022" "fnotecite:2022" | ||
| 326 | ;; Natbib compatibility commands: | ||
| 327 | "citet:2022" "citet*:2022" | ||
| 328 | "citep:2022" "citep*:2022" | ||
| 329 | "citealt:2022" "citealt*:2022" | ||
| 330 | "citealp:2022" "citealp*:2022" | ||
| 331 | "Citet:2022" "Citet*:2022" | ||
| 332 | "Citep:2022" "Citep*:2022" | ||
| 333 | "bug:56655") | ||
| 334 | #'string<))) | ||
| 335 | (kill-buffer (file-name-nondirectory tex-file))))) | ||
| 205 | 336 | ||
| 206 | ;;; Autoload tests | 337 | ;;; Autoload tests |
| 207 | 338 | ||