bnbeckwith / writegood-mode

Minor mode for Emacs to improve English writing
http://bnbeckwith.com/code/writegood-mode.html
459 stars 32 forks source link

Calculate score on the fly #25

Open ag91 opened 5 years ago

ag91 commented 5 years ago

Hi,

Thanks for this mode: it very useful for my writing activities! I liked the ease score functionality so much that I wanted it on the fly. Now every time I add a dot to close a sentence, every time I fill the paragraph, and every time I save the buffer the easy score is calculated for a sentence, paragraph, whole buffer respectively. If you think that it would be useful for others I can try to generalise this and open a pull request.

I leave my code as reference at the bottom.

Thanks again for this mode!

(defun writegood-fk-parameters (&optional rstart rend)
  "Flesch-Kincaid reading parameters"
  (let* ((start (cond (rstart rstart)
                      ((and transient-mark-mode mark-active) (region-beginning))
                      ('t (point-min))))
         (end   (cond (rend rend)
                      ((and transient-mark-mode mark-active) (region-end))
                      ('t (point-max))))
         (words     (float (writegood-count-words start end)))
         (syllables (float (writegood-count-syllables start end)))
         (sentences (float (writegood-count-sentences start end))))
    (list sentences words syllables)))

(defun writegood-reading-ease-score->comment (score)
  "Rough interpreation of the Flesch-Kincaid Reading ease SCORE.

From Wikipedia URL `https://en.wikipedia.org/wiki/Flesch–Kincaid_readability_tests'."
   (cond
    ((< score 0) "Ouch! (Proust literature)")
    ((and (<= 0 score) (< score 30.0)) "Very difficult (college graduate)")
    ((and (<= 30.0 score) (< score 50.0)) "Difficult (almost college)")
    ((and (<= 50.0 score) (< score 60.0)) "Fairly difficult (10-12th grade)")
    ((and (<= 60.0 score) (< score 70.0)) "Plain English (8-9th grade)")
    ((and (<= 70.0 score) (< score 80.0)) "Fairly easy (7th grade)")
    ((and (<= 80.0 score) (< score 90.0)) "Easy (6th grade)")
    ((<= 90.0 score) "Very easy (5th grade)")))

(defun writegood-calculate-reading-ease (&optional start end)
  "Calculate score of Flesch-Kincaid reading ease test in the region bounded by START and END.

Scores roughly between 0 and 100."
   (let* ((params (writegood-fk-parameters start end))
          (sentences (nth 0 params))
          (words     (nth 1 params))
          (syllables (nth 2 params))
          (score  (- 206.835 (* 1.015 (/ words sentences)) (* 84.6 (/ syllables words)))))
     score))

(defun writegood-reading-ease (&optional start end)
  "Flesch-Kincaid reading ease test in the region bounded by START and END.

Scores roughly between 0 and 100."
   (interactive)
   (let ((score (writegood-calculate-reading-ease start end)))
     (message "Flesch-Kincaid reading ease score: %.2f %s" score
            (writegood-reading-ease-score->comment score))))

(defun writegoodmode-reading-ease-thing-at-point (thing)
  (let* ((bounds (bounds-of-thing-at-point thing))
         (b (car bounds))
         (e (cdr bounds)))
    (if (and
         (not (null b))
         (not (null e))
         ;; this is a guess: when the interval between boundaries is
         ;; huge, the paragraph is too big to be validated.
         (< (- e b) 100000))
        (let ((score (writegood-calculate-reading-ease b e)))
          (message "%s reading ease score: %.2f %s" (symbol-name thing) score
            (writegood-reading-ease-score->comment score))))))

(defun writegoodmode-reading-ease-sentence ()
  (interactive)
  (writegoodmode-reading-ease-thing-at-point 'sentence))

(defun writegoodmode-reading-ease-paragraph ()
  (interactive)
  (writegoodmode-reading-ease-thing-at-point 'paragraph))

(defun writegoodmode-reading-ease-page ()
  (interactive)
  (writegoodmode-reading-ease-thing-at-point 'page))

(defun writegood-after-sentence ()
  "Calculate reading ease after a sentence is completed. Here we
consider the sentence completion the addition of a dot."
  (if (and (string-match-p (regexp-quote "self-insert-command") (symbol-name last-command)) (eq (char-before) 46)) (writegoodmode-reading-ease-sentence)))

(defun writegood-after-paragraph ()
  "Calculate reading ease after a paragraph is completed. Here we
consider the paragraph completion to be the call of a
,*-fill-paragraph command."
  (if (string-match-p (regexp-quote "fill-paragraph") (symbol-name last-command)) (writegoodmode-reading-ease-paragraph)))

(setq text-modes '("text-mode" "org-mode" "latex-mode" "rst-mode" "markdown-mode" "mu4e-compose-mode"))

(defun apply-only-in-text-major-modes (fn)
  (if (and
       ;; only for text modes
       (member (symbol-name major-mode) text-modes)
       ;; not in a org source block
       (null (org-babel-get-src-block-info 'light)))
      (funcall fn)))

(defun writegood-after-sentence-hook () (apply-only-in-text-major-modes 'writegood-after-sentence))
(defun writegood-after-paragraph-hook () (apply-only-in-text-major-modes 'writegood-after-paragraph))
(defun writegood-after-page-hook () (apply-only-in-text-major-modes 'writegoodmode-reading-ease-page))
(add-hook 'post-command-hook 'writegood-after-sentence-hook)
(add-hook 'post-command-hook 'writegood-after-paragraph-hook)
(add-hook 'after-save-hook 'writegood-after-page-hook)
robstewart57 commented 5 years ago

This is great!

I am using this code, to good effect. A pull request would be useful for others. Thoughts @bnbeckwith ?

bnbeckwith commented 5 years ago

@ag91 @robstewart57 Feel free to make a pull request. We can review and add in the on-the-fly functionality.

ag91 commented 5 years ago

Great to hear you like this feature :) I can open a pull request as is and then refine it with your feedback.

On Tue 04 Dec 2018 at 15:31, Benjamin Beckwith notifications@github.com wrote:

@ag91 @robstewart57 Feel free to make a pull request. We can review and add in the on-the-fly functionality.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.