diff options
Diffstat (limited to 'lisp/acdw-org.el')
-rw-r--r-- | lisp/acdw-org.el | 142 |
1 files changed, 57 insertions, 85 deletions
diff --git a/lisp/acdw-org.el b/lisp/acdw-org.el index 3f0c4ea..7e68712 100644 --- a/lisp/acdw-org.el +++ b/lisp/acdw-org.el | |||
@@ -243,91 +243,63 @@ the deletion might narrow the column." | |||
243 | (org-table-copy-down n) | 243 | (org-table-copy-down n) |
244 | (acdw-org/return-dwim n))) | 244 | (acdw-org/return-dwim n))) |
245 | 245 | ||
246 | (defun acdw-org/word-count (beg end | 246 | (defun acdw-org/count-words (start end) |
247 | &optional count-latex-macro-args? | 247 | "Count words between START and END, respecting `org-mode' conventions." |
248 | count-footnotes?) | 248 | (interactive (list nil nil)) |
249 | "Report the number of words in the Org mode buffer or selected region. | 249 | (cond ((not (called-interactively-p 'any)) |
250 | Ignores: | 250 | (let ((words 0)) |
251 | - comments | 251 | (save-excursion |
252 | - tables | 252 | (save-restriction |
253 | - source code blocks (#+BEGIN_SRC ... #+END_SRC, and inline blocks) | 253 | (narrow-to-region start end) |
254 | - hyperlinks (but does count words in hyperlink descriptions) | 254 | (goto-char (point-min)) |
255 | - tags, priorities, and TODO keywords in headers | 255 | (while (< (point) (point-max)) |
256 | - sections tagged as 'not for export'. | 256 | (cond |
257 | ;; Ignore comments | ||
258 | ((or (org-at-comment-p) | ||
259 | (org-in-commented-heading-p)) nil) | ||
260 | ;; Ignore tables | ||
261 | ((org-at-table-p) nil) | ||
262 | ;; Ignore hyperlinks, but count the descriptions | ||
263 | ((looking-at org-bracket-link-analytic-regexp) | ||
264 | (when-let ((desc (match-string-no-properties 5))) | ||
265 | (save-match-data | ||
266 | (setq words (+ words | ||
267 | (length (remove "" | ||
268 | (org-split-string | ||
269 | desc "\\W"))))))) | ||
270 | (goto-char (match-end 0))) | ||
271 | ;; Ignore source code blocks | ||
272 | ((org-in-src-block-p) nil) | ||
273 | ;; Ignore footnotes | ||
274 | ((or (org-footnote-at-definition-p) | ||
275 | (org-footnote-at-reference-p)) | ||
276 | nil) | ||
277 | ;; else... check the context | ||
278 | (t (let ((contexts (org-context))) | ||
279 | (cond | ||
280 | ;; Ignore tags, TODO keywords, etc. | ||
281 | ((or (assoc :todo-keyword contexts) | ||
282 | (assoc :priority contexts) | ||
283 | (assoc :keyword contexts) | ||
284 | (assoc :checkbox contexts)) | ||
285 | nil) | ||
286 | ;; Ignore sections tagged :no-export | ||
287 | ((assoc :tags contexts) | ||
288 | (if (intersection (org-get-tags-at) | ||
289 | org-export-exclude-tags | ||
290 | :test 'equal) | ||
291 | (org-forward-same-level 1) | ||
292 | nil)) | ||
293 | ;; else... count the word | ||
294 | (t (setq words (1+ words))))))) | ||
295 | (re-search-forward "\\w+\\W*"))) | ||
296 | words))) | ||
297 | ((use-region-p) | ||
298 | (message "%d words in region" | ||
299 | (acdw-org/count-words (region-beginning) (region-end)))) | ||
300 | (t | ||
301 | (message "%d words in buffer" | ||
302 | (acdw-org/count-words (point-min) (point-max)))))) | ||
257 | 303 | ||
258 | The text of footnote definitions is ignored, unless the optional argument | ||
259 | COUNT-FOOTNOTES? is non-nil. | ||
260 | |||
261 | If the optional argument COUNT-LATEX-MACRO-ARGS? is non-nil, the word count | ||
262 | includes LaTeX macro arguments (the material between {curly braces}). | ||
263 | Otherwise, and by default, every LaTeX macro counts as 1 word regardless | ||
264 | of its arguments." | ||
265 | (interactive "r") | ||
266 | (unless mark-active | ||
267 | (setf beg (point-min) | ||
268 | end (point-max))) | ||
269 | (let ((wc 0) | ||
270 | (latex-macro-regexp "\\\\[A-Za-z]+\\(\\[[^]]*\\]\\|\\){\\([^}]*\\)}")) | ||
271 | (save-excursion | ||
272 | (goto-char beg) | ||
273 | (while (< (point) end) | ||
274 | (cond | ||
275 | ;; Ignore comments. | ||
276 | ((or (org-in-commented-line) (org-at-table-p)) | ||
277 | nil) | ||
278 | ;; Ignore hyperlinks. But if link has a description, count | ||
279 | ;; the words within the description. | ||
280 | ((looking-at org-bracket-link-analytic-regexp) | ||
281 | (when (match-string-no-properties 5) | ||
282 | (let ((desc (match-string-no-properties 5))) | ||
283 | (save-match-data | ||
284 | (incf wc (length (remove "" (org-split-string | ||
285 | desc "\\W"))))))) | ||
286 | (goto-char (match-end 0))) | ||
287 | ((looking-at org-any-link-re) | ||
288 | (goto-char (match-end 0))) | ||
289 | ;; Ignore source code blocks. | ||
290 | ((org-in-regexps-block-p "^#\\+BEGIN_SRC\\W" "^#\\+END_SRC\\W") | ||
291 | nil) | ||
292 | ;; Ignore inline source blocks, counting them as 1 word. | ||
293 | ((save-excursion | ||
294 | (backward-char) | ||
295 | (looking-at org-babel-inline-src-block-regexp)) | ||
296 | (goto-char (match-end 0)) | ||
297 | (setf wc (+ 2 wc))) | ||
298 | ;; Count latex macros as 1 word, ignoring their arguments. | ||
299 | ((save-excursion | ||
300 | (backward-char) | ||
301 | (looking-at latex-macro-regexp)) | ||
302 | (goto-char (if count-latex-macro-args? | ||
303 | (match-beginning 2) | ||
304 | (match-end 0))) | ||
305 | (setf wc (+ 2 wc))) | ||
306 | ;; Ignore footnotes. | ||
307 | ((and (not count-footnotes?) | ||
308 | (or (org-footnote-at-definition-p) | ||
309 | (org-footnote-at-reference-p))) | ||
310 | nil) | ||
311 | (t | ||
312 | (let ((contexts (org-context))) | ||
313 | (cond | ||
314 | ;; Ignore tags and TODO keywords, etc. | ||
315 | ((or (assoc :todo-keyword contexts) | ||
316 | (assoc :priority contexts) | ||
317 | (assoc :keyword contexts) | ||
318 | (assoc :checkbox contexts)) | ||
319 | nil) | ||
320 | ;; Ignore sections marked with tags that are | ||
321 | ;; excluded from export. | ||
322 | ((assoc :tags contexts) | ||
323 | (if (intersection (org-get-tags-at) org-export-exclude-tags | ||
324 | :test 'equal) | ||
325 | (org-forward-same-level 1) | ||
326 | nil)) | ||
327 | (t | ||
328 | (incf wc)))))) | ||
329 | (re-search-forward "\\w+\\W*"))) | ||
330 | (message (format "%d words in %s." wc | ||
331 | (if mark-active "region" "buffer"))))) | ||
332 | 304 | ||
333 | (provide 'acdw-org) | 305 | (provide 'acdw-org) |