sentence-navigation.el
is inspired by vim-textobj-sentence and uses a mostly the same default abbreviation list. It provides alternatives to forward-sentence
, backward-sentence
, and sentence text objects that work with sentences separated by one (or two) space(s) and is aware of abbreviations.
If you use MELPA, sentence-navigation.el
can be installed with package-install
. Here’s an example use-package configuration:
(use-package sentence-navigation
:ensure t
;; autoloads will be created for all commands and text objects
;; when installed with package.el
:defer t)
There are no default key bindings. Unlike with the normal forward and backward sentence commands, these commands will move to the beginning or end of the sentence, not to the space in between.
The list of abbreviations to ignore can be customized. The defaults are mostly the same as vim-textobj-sentence’s.
(setq sentence-nav-abbreviation-list
'("[ABCDIMPSUabcdegimpsv]"
"l[ab]" "[eRr]d" "Ph" "[Ccp]l" "[Ll]n" "[c]o"
"[Oe]p" "[DJMSh]r" "[MVv]s" "[CFMPScfpw]t"
"alt" "[Ee]tc" "div" "es[pt]" "[Ll]td" "min"
"[MD]rs" "[Aa]pt" "[Aa]ve?" "[Ss]tr?" "e\\.g"
"[Aa]ssn" "[Bb]lvd" "[Dd]ept" "incl" "Inst" "Prof" "Univ"))
If you change the abbreviation list after loading the package, you will need to run the following as well:
(sentence-nav-reload-abbreviations)
(define-key evil-normal-state-map ")" 'sentence-nav-evil-forward)
(define-key evil-normal-state-map "(" 'sentence-nav-evil-backward)
(define-key evil-operator-state-map ")" 'sentence-nav-evil-forward)
(define-key evil-operator-state-map "(" 'sentence-nav-evil-backward)
(define-key evil-normal-state-map "g)" 'sentence-nav-evil-forward-end)
(define-key evil-normal-state-map "g(" 'sentence-nav-evil-backward-end)
(define-key evil-outer-text-objects-map "s" 'sentence-nav-evil-outer-sentence)
(define-key evil-inner-text-objects-map "s" 'sentence-nav-evil-inner-sentence)
(global-set-key (kbd "M-e") 'sentence-nav-forward)
(global-set-key (kbd "M-a") 'sentence-nav-backward)
Both sentence-nav-forward-end
and sentence-nav-backward-end
can also be bound.
Sentences start with a capital letter (possibly preceded some type of a left quotation mark). They end with a period (or other characters like “!”, “?”, or an ellipsis) possibly followed by some right quotation mark(s). In addition to quotes, org and markdown markup characters (such as _
and *
) can be around sentences. Like with quotes, the point will be moved to just before or after the last surrounding markup character. Abbreviations are irrelevant for two-spaced sentences, and this plugin will work fine for them.
For the most part, this plugin can distinguish accurately between one-spaced sentences and abbreviations. In the rare case that a sentence actually does end in an abbreviation (not followed by “?”, “!”, etc.), this plugin will skip over that sentence. Because of this, I have removed the abbreviations “in” and “no” from vim-textobj-sentence
’s list since I think a sentence is more likely to end in either “in” or “no” than for either to be used as an abbreviation.
Also, if hard line wrapping is being used, there is no way to distinguish between a sentence that starts at the beginning of the line and a capitalized word at the beginning of the line. It is possible to fix this for single-spaced hard-wrapped sentences by checking if the previous line ends in a period and not an abbreviation, but I haven’t bothered implementing this extra check for now at least.
Emacs doesn’t have support for negative look behind, so this uses looking-back
. Emacs says this should be avoided because it is slow, but it works fine for this.