113 lines
3.5 KiB
EmacsLisp
113 lines
3.5 KiB
EmacsLisp
;;; +org-wc.el --- org-wc in the modeline -*- lexical-binding: t; -*-
|
|
|
|
;;; Commentary:
|
|
|
|
;;; Code:
|
|
|
|
(require 'org-wc)
|
|
(require '+modeline)
|
|
(require 'cl-lib)
|
|
|
|
(defgroup +org-wc nil
|
|
"Extra fast word-counting in `org-mode'"
|
|
:group 'org-wc
|
|
:group 'org)
|
|
|
|
(defvar-local +org-wc-word-count nil
|
|
"Running total of words in this buffer.")
|
|
|
|
(defcustom +org-wc-update-after-funcs '(org-narrow-to-subtree
|
|
org-narrow-to-block
|
|
org-narrow-to-element
|
|
org-capture-narrow)
|
|
"Functions after which to update the word count."
|
|
:type '(repeat function))
|
|
|
|
(defcustom +org-wc-deletion-idle-timer 0.25
|
|
"Length of time, in seconds, to wait before updating word-count."
|
|
:type 'number)
|
|
|
|
(defcustom +org-wc-huge-change 5000
|
|
"Number of characters that constitute a \"huge\" insertion."
|
|
:type 'number)
|
|
|
|
(defcustom +org-wc-huge-buffer 10000
|
|
"Number of words past which we're not going to try to count."
|
|
:type 'number)
|
|
|
|
(defvar +org-wc-correction -5
|
|
"Number to add to `+org-wc-word-count', for some reason?
|
|
`+org-wc-word-count' seems to consistently be off by 5. Thus
|
|
this correction. (At some point I should correct the underlying
|
|
code... probably).")
|
|
|
|
(defvar-local +org-wc-update-timer nil)
|
|
|
|
(defun +org-wc-delayed-update (&rest _)
|
|
(if +org-wc-update-timer
|
|
(setq +org-wc-update-timer nil)
|
|
(setq +org-wc-update-timer
|
|
(run-with-idle-timer +org-wc-deletion-idle-timer nil #'+org-wc-update))))
|
|
|
|
(defun +org-wc-force-update ()
|
|
(interactive)
|
|
(message "Counting words...")
|
|
(when (timerp +org-wc-update-timer)
|
|
(cancel-timer +org-wc-update-timer))
|
|
(+org-wc-update)
|
|
(message "Counting words...done"))
|
|
|
|
(defun +org-wc-update (&rest _) ; Needs variadic parameters, since it's advice
|
|
(dlet ((+org-wc-counting t))
|
|
(+org-wc-buffer)
|
|
(force-mode-line-update)
|
|
(setq +org-wc-update-timer nil)))
|
|
|
|
(defun +org-wc-changed (start end length)
|
|
(+org-wc-delayed-update))
|
|
|
|
(defun +org-wc-buffer ()
|
|
"Count the words in the buffer."
|
|
(when (and (derived-mode-p 'org-mode)
|
|
(not (eq +org-wc-word-count 'huge)))
|
|
(setq +org-wc-word-count
|
|
(cond
|
|
((> (count-words (point-min) (point-max))
|
|
+org-wc-huge-buffer)
|
|
'huge)
|
|
(t (org-word-count-aux (point-min) (point-max)))))))
|
|
|
|
(defvar +org-wc-counting nil
|
|
"Are we currently counting?")
|
|
|
|
(defun +org-wc-recount-widen (&rest _)
|
|
(when (and (not +org-wc-counting))
|
|
(+org-wc-update)))
|
|
|
|
(defun +org-wc-modeline ()
|
|
(cond
|
|
((eq +org-wc-word-count 'huge) "huge")
|
|
(+org-wc-word-count (format "%sw" (max 0 (+ +org-wc-word-count +org-wc-correction))))))
|
|
|
|
(define-minor-mode +org-wc-mode
|
|
"Count words in `org-mode' buffers in the mode-line."
|
|
:lighter ""
|
|
:keymap (let ((map (make-sparse-keymap)))
|
|
(define-key map (kbd "C-c C-.") #'+org-wc-force-update)
|
|
map)
|
|
(if +org-wc-mode
|
|
(progn ; turn on
|
|
(+org-wc-buffer)
|
|
(add-hook 'after-change-functions #'+org-wc-delayed-update nil t)
|
|
(setq-local +modeline-position-function #'+org-wc-modeline)
|
|
(dolist (fn +org-wc-update-after-funcs)
|
|
(advice-add fn :after #'+org-wc-update)))
|
|
(progn ; turn off
|
|
(remove-hook 'after-change-functions #'+org-wc-delayed-update t)
|
|
(kill-local-variable '+modeline-position-function)
|
|
(dolist (fn +org-wc-update-after-funcs)
|
|
(advice-remove fn #'+org-wc-update)))))
|
|
|
|
(provide '+org-wc)
|
|
;;; +org-wc.el ends here
|