emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/captain 3ada93d 01/11: Added captain package


From: Stefan Monnier
Subject: [elpa] externals/captain 3ada93d 01/11: Added captain package
Date: Tue, 1 Dec 2020 15:22:46 -0500 (EST)

branch: externals/captain
commit 3ada93dc1fb5a66afa054833d346023c0fef3f50
Author: Ian Dunn <dunni@gnu.org>
Commit: Ian Dunn <dunni@gnu.org>

    Added captain package
    
    Single-file package to handle automatic capitalization
    
    * packages/captain/captain.el: Added.
---
 captain.el | 194 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 194 insertions(+)

diff --git a/captain.el b/captain.el
new file mode 100644
index 0000000..8c019e0
--- /dev/null
+++ b/captain.el
@@ -0,0 +1,194 @@
+;;; captain.el --- CAPiTalization is Automatic IN emacs -*- lexical-binding: 
t; -*-
+
+;; Copyright (C) 2017 Free Software Foundation, Inc.
+
+;; Author: Ian Dunn <dunni@gnu.org>
+;; Maintainer: Ian Dunn <dunni@gnu.org>
+;; Keywords: editing
+;; Version: 1.0
+
+;; This file is part of GNU Emacs.
+
+;; This program is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; The captain handles capitalizing text as you type, freeing you to do other
+;; things.
+
+;; Invoke the captain across the globe with `global-captain-mode', or just on
+;; one ship (buffer) at a time with `captain-mode'.
+
+;; For normal people:
+
+;; Automatically capitalizes the first word of a sentence as you type.  The
+;; bounds of a sentence are determined by local variable
+;; `captain-sentence-start-function'.  For example, you can set it to find the
+;; start of a list or heading in `org-mode'.
+
+;; Further control can be obtained by modifying the local variable
+;; `captain-predicate', which tells the captain when to work and when to relax.
+
+;; It's also possible to automatically capitalize individual words using the
+;; command `captain-capitalize-word'.  This will capitalize the word at point
+;; and tell the captain about it, so he knows that you want it capitalized from
+;; then on.
+
+;; This solves a similar problem to that of Kevin Rodgers's auto-capitalize
+;; package, but using more modern Emacs features.
+
+;;; Code:
+
+(eval-when-compile (require 'subr-x))
+(require 'thingatpt)
+
+(defvar-local captain-predicate nil
+  "Predicate to check for whether auto-capitalization should be handled.
+
+Should be a function of no arguments, and return non-nil if
+auto-capitalization should be performed at the current point.
+
+For example, this could be a function to check if point is in a
+comment.")
+
+(defun captain-should-capitalize-p ()
+  "Return non-nil if the captain should auto-capitalize your work."
+  (when captain-predicate
+    (funcall captain-predicate)))
+
+(defun captain--default-sentence-start ()
+  "Default value of `captain-sentence-start-function'.
+
+Just runs `bounds-of-thing-at-point' for a sentence."
+  (car (bounds-of-thing-at-point 'sentence)))
+
+(defvar-local captain-sentence-start-function
+  #'captain--default-sentence-start
+  "Function to determine the start of the current sentence.
+
+This should be a function of no arguments that returns the point
+at which the current function begins.")
+
+(defun captain--run ()
+  "Automatically capitalize the word preceding point if it is the start of a 
sentence."
+  ;; Only do this if the last inserted character isn't part of a word,
+  ;; (preceding-char) is the previously inserted character;
+  ;; We also need the character before that (It must be a word constituent, so
+  ;; enter or space don't keep trying to capitalize the sentence).
+  (when (and (captain-should-capitalize-p)
+             (not (or (bobp) (eq (char-syntax (preceding-char)) ?w)))
+             (eq (char-syntax (save-excursion (forward-char -1)
+                                              (preceding-char)))
+                 ?w))
+    (save-excursion
+      ;; Move back to the word that was just finished, and determine if it
+      ;; starts a sentence.
+      (backward-word-strictly)
+      ;; Ensure we're still expected to capitalize.  Case: New character put us
+      ;; inside a string, but backward-word-strictly brought us outside the
+      ;; string.
+      (when (captain-should-capitalize-p)
+        (when-let ((word-bounds (bounds-of-thing-at-point 'word))
+                   (sentence-start (funcall captain-sentence-start-function)))
+          (cond
+           ((let ((case-fold-search nil))
+              (string-match-p "[[:upper:]]" (word-at-point)))
+            nil)
+           ;; This word does start a sentence, so capitalize it
+           ((eq (car word-bounds) sentence-start) (capitalize-word 1))
+           ;; Word bound will only ever be one greater than the sentence bound 
if
+           ;; the sentence begins with some sort of punctuation.  Remember, 
spaces
+           ;; don’t count, so if we have a sentence starting with "A ball...",
+           ;; ’ball’ wont trigger this, only ’A’.
+           ((eq (car word-bounds) (1+ sentence-start))
+            (capitalize-word 1))))))))
+
+(defun captain-capitalize-sentence ()
+  "Tell the captain to capitalize the start of the current sentence."
+  (interactive)
+  (save-excursion
+    (goto-char (funcall captain-sentence-start-function))
+    (capitalize-word 1)))
+
+;;;###autoload
+(define-minor-mode captain-mode
+  "Call the captain to automatically capitalize the start of every sentence.
+
+The captain will also automatically capitalize words you've told
+him you want capitalized with `captain-capitalize-word'.
+
+\\{captain-mode-map}"
+  :init-value nil
+  :lighter " Captain"
+  :global nil
+  (if captain-mode
+      (progn
+        (add-hook 'post-self-insert-hook 'captain--run nil t))
+    (remove-hook 'post-self-insert-hook 'captain--run t)))
+
+;;;###autoload
+(define-globalized-minor-mode global-captain-mode
+  captain-mode captain-mode)
+
+;; Support for capitalizing individual words automatically
+
+(define-abbrev-table 'captain-mode-abbrev-table nil
+  "Abbrev table where words that should be automatically capitalized are 
stored."
+  :enable-function #'captain-should-capitalize-p)
+
+;; Only enable the abbrev table when captain-mode is active
+(add-to-list 'abbrev-minor-mode-table-alist
+             `(captain-mode ,captain-mode-abbrev-table)
+             'append
+             #'equal)
+
+(defun captain--start-of-word-p ()
+  "Return non-nil if at the start of a word."
+  (and
+   ;; looking at a word constituent...
+   (eq (char-syntax (following-char)) ?w)
+   ;; ...but before us isn't a word constituent
+   (not (eq (char-syntax (preceding-char)) ?w))))
+
+(defun captain-capitalize-word ()
+  "Tell the captain to capitalize the word at point.
+
+After that, the captain will remember your choice, and
+automatically capitalize the word from then on.
+
+If not looking at a word, move forward to find the next word."
+  (interactive)
+  (save-excursion
+    ;; Cases for where we are:
+    (cond
+     ;; Looking at the start of a word, so don't move
+     ((captain--start-of-word-p))
+     ((word-at-point)
+      ;; If we're in the middle of a word, then move back to the start.
+      (backward-word-strictly))
+     (t
+      ;; Otherwise, we're not on a word, so move forward to find the next one.
+      ;; This is to remain consistent with the behavior of `capitalize-word'.
+      (forward-to-word 1)))
+    (when-let ((old-word (substring-no-properties (word-at-point)))
+               (new-word (capitalize old-word)))
+      ;; Store the abbrev so this word is automatically capitalized later.
+      (define-abbrev captain-mode-abbrev-table
+        old-word new-word nil :count 1))
+    ;; Finally, capitalize the word at point.
+    (capitalize-word 1)))
+
+(provide 'captain)
+
+;;; captain.el ends here



reply via email to

[Prev in Thread] Current Thread [Next in Thread]