sentence-navigation.el is inspired by vim-textobj-sentence and uses a mostly the same default abbreviation list. It provides alternatives to
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 emacs’ normal forward and backward sentence commands, this package provides four commands that will move either to the start or end of a sentence instead of to the space in between sentences.
( are bound in motion state by default. Keys bound in motion state are inherited by the normal, visual, and operator states if they are not explicitly bound in those states.
(define-key evil-motion-state-map ")" 'sentence-nav-evil-forward) (define-key evil-motion-state-map "(" 'sentence-nav-evil-backward) (define-key evil-motion-state-map "g)" 'sentence-nav-evil-forward-end) (define-key evil-motion-state-map "g(" 'sentence-nav-evil-backward-end) (define-key evil-outer-text-objects-map "s" 'sentence-nav-evil-a-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)
sentence-nav-backward-end can also be bound.
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"))
By default, any delimiters that can surround a sentence such as quotation marks will be considered as part of the start or end of a sentence. This means that the jump commands will jump to quotation marks. If you would prefer to have the commands always jump to the capital letter at the start of the sentence or the period at the end, you can set
For evil users,
sentence-nav-syntax-text-objects can be set to a non-nil value to change the distinction between the inner and outer text objects. When this variable is non-nil, the outer text object will include any delimiters such as quotation marks while the inner text object will not.
Accurate Jumps for Hard-Wrapped Sentences
By default, this package assumes that a capital letter at the beginning of the line starts a sentence. While this works fine for soft-wrapped sentences, it can result in incorrect jumps when using hard-wrapped sentences (e.g. when a line begins with a name that is in the middle of a sentence). To fix this, users must set
sentence-nav-hard-wrapping to a non-nil value and ensure that
sentence-nav-non-sentence-line-alist is properly set for the
major-mode being used. This is necessary to ensure that sentences that start the line after some markup (e.g. a markdown or org heading) are handled correctly.
Definition of a Sentence
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
*) 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.
Why doesn’t it work with commented sentences?
This packages uses regular expressions to check for comment starting characters, and not all major modes with comments add syntax table entries for their comment characters (e.g. org mode). It is recommended that you file an issue with the relevant package if you believe that it should make a syntax table entry. As a workaround, you can modify the syntax table yourself in your init file:
(with-eval-after-load 'org (modify-syntax-entry ?# "<" org-mode-syntax-table)) ;; alternatively after starting emacs in the relevant buffer (modify-syntax-entry ?# "<")
Another example for text mode:
(modify-syntax-entry ?# "<" text-mode-syntax-table)