diff options
-rw-r--r-- | lisp/acdw-org.el | 97 |
1 files changed, 29 insertions, 68 deletions
diff --git a/lisp/acdw-org.el b/lisp/acdw-org.el index 189ac67..f8f23c6 100644 --- a/lisp/acdw-org.el +++ b/lisp/acdw-org.el | |||
@@ -243,74 +243,13 @@ 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/count-words (start end) | ||
247 | "Count words between START and END, respecting `org-mode' conventions." | ||
248 | (interactive (list nil nil)) | ||
249 | (require 'cl-lib) | ||
250 | (require 'ox) | ||
251 | (message "Counting words...") | ||
252 | (cond ((not (called-interactively-p 'any)) | ||
253 | (let ((words 0)) | ||
254 | (save-excursion | ||
255 | (save-restriction | ||
256 | (narrow-to-region start end) | ||
257 | (goto-char (point-min)) | ||
258 | (while (< (point) (point-max)) | ||
259 | (cond | ||
260 | ;; Ignore comments | ||
261 | ((or (org-at-comment-p) | ||
262 | (org-in-commented-heading-p)) nil) | ||
263 | ;; Ignore tables | ||
264 | ((org-at-table-p) nil) | ||
265 | ;; Ignore hyperlinks, but count the descriptions | ||
266 | ((looking-at org-bracket-link-analytic-regexp) | ||
267 | (when-let ((desc (match-string-no-properties 5))) | ||
268 | (save-match-data | ||
269 | (setq words (+ words | ||
270 | (length (remove "" | ||
271 | (org-split-string | ||
272 | desc "\\W"))))))) | ||
273 | (goto-char (match-end 0))) | ||
274 | ;; Ignore source code blocks | ||
275 | ((org-in-src-block-p) nil) | ||
276 | ;; Ignore footnotes | ||
277 | ((or (org-footnote-at-definition-p) | ||
278 | (org-footnote-at-reference-p)) | ||
279 | nil) | ||
280 | ;; else... check the context | ||
281 | (t (let ((contexts (org-context))) | ||
282 | (cond | ||
283 | ;; Ignore tags, TODO keywords, etc. | ||
284 | ((or (assoc :todo-keyword contexts) | ||
285 | (assoc :priority contexts) | ||
286 | (assoc :keyword contexts) | ||
287 | (assoc :checkbox contexts)) | ||
288 | nil) | ||
289 | ;; Ignore sections tagged :no-export | ||
290 | ((assoc :tags contexts) | ||
291 | (if (cl-intersection (org-get-tags-at) | ||
292 | org-export-exclude-tags | ||
293 | :test 'equal) | ||
294 | (org-forward-same-level 1) | ||
295 | nil)) | ||
296 | ;; else... count the word | ||
297 | (t (setq words (1+ words))))))) | ||
298 | (re-search-forward "\\w+\\W*"))) | ||
299 | words))) | ||
300 | ((use-region-p) | ||
301 | (message "%d words in region" | ||
302 | (acdw-org/count-words (region-beginning) (region-end)))) | ||
303 | (t | ||
304 | (message "%d words in buffer" | ||
305 | (acdw-org/count-words (point-min) (point-max)))))) | ||
306 | |||
307 | ;; This isn't the best code, but it'll do. | 246 | ;; This isn't the best code, but it'll do. |
308 | (defun acdw-org/count-words-stupidly (start end &optional limit) | 247 | (defun acdw-org/count-words-stupidly (start end &optional limit) |
309 | "Count words between START and END, ignoring a lot. | 248 | "Count words between START and END, ignoring a lot. |
310 | 249 | ||
311 | Since this function is, for some reason, pricy, the optional | 250 | Since this function is, for some reason, pricy, the optional |
312 | parameter LIMIT sets a word limit at which to stop counting. | 251 | parameter LIMIT sets a word limit at which to stop counting. |
313 | Once the function hits that number, it'll return \"-LIMIT\" | 252 | Once the function hits that number, it'll return -LIMIT |
314 | instead of the true count." | 253 | instead of the true count." |
315 | (interactive (list nil nil)) | 254 | (interactive (list nil nil)) |
316 | (cond ((not (called-interactively-p 'any)) | 255 | (cond ((not (called-interactively-p 'any)) |
@@ -334,13 +273,35 @@ instead of the true count." | |||
334 | ((or (looking-at org-drawer-regexp) | 273 | ((or (looking-at org-drawer-regexp) |
335 | (looking-at org-clock-drawer-re)) | 274 | (looking-at org-clock-drawer-re)) |
336 | (search-forward ":END:" nil :noerror)) | 275 | (search-forward ":END:" nil :noerror)) |
276 | ;; Ignore tables | ||
277 | ((org-at-table-p) (forward-line)) | ||
278 | ;; Ignore hyperlinks, but count the descriptions | ||
279 | ((looking-at org-bracket-link-analytic-regexp) | ||
280 | (when-let ((desc (match-string-no-properties 5))) | ||
281 | (save-match-data | ||
282 | (setq words (+ words | ||
283 | (length (remove "" | ||
284 | (org-split-string | ||
285 | desc "\\W"))))))) | ||
286 | (goto-char (match-end 0))) | ||
287 | ;; Ignore source blocks | ||
288 | ((org-in-src-block-p) (foreward-line)) | ||
337 | ;; Count everything else | 289 | ;; Count everything else |
338 | (t (setq words (1+ words)) | 290 | (t |
339 | (if (and limit | 291 | ;; ... unless it's in a few weird contexts |
340 | (> words limit)) | 292 | (let ((contexts (org-context))) |
341 | (setq words limit | 293 | (cond ((or (assoc :todo-keyword contexts) |
342 | continue nil)) | 294 | (assoc :priority contexts) |
343 | (forward-word-strictly)))))) | 295 | (assoc :keyword contexts) |
296 | (assoc :checkbox contexts)) | ||
297 | (forward-word-strictly)) | ||
298 | |||
299 | (t (setq words (1+ words)) | ||
300 | (if (and limit | ||
301 | (> words limit)) | ||
302 | (setq words (- limit) | ||
303 | continue nil)) | ||
304 | (forward-word-strictly))))))))) | ||
344 | words)) | 305 | words)) |
345 | ((use-region-p) | 306 | ((use-region-p) |
346 | (message "%d words in region" | 307 | (message "%d words in region" |