Better Sentence Movement Commands and Evil Text Objects
Emacs Lisp Makefile
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.


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)

Example Configuration

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.


Note that ) and ( 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)

No Evil

(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.


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
        "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"))

Jump Locations

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 sentence-nav-jump-to-syntax to nil.

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 _ 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.

Impossible Cases

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)