Vim-pencil aims to redefine Vim as an effective tool for writers. This plugin concentrates on specific adjustments to streamline the process of writing prose.
Features
The pencil plugin is designed to make Vim as robust for writers as it is for programmers by concentrating on the necessary adjustments to facilitate prose writing.
- Supports prose-oriented file types such as text, markdown, mail, rst, tex, textile, and asciidoc.
- Offers flexibility between soft line wrap and hard line breaks.
- Automatically detects wrap mode through modeline and content sampling.
- Adjusts navigation key mappings to align with the active wrap mode.
- Generates undo points on common punctuation during Insert mode, including deletions via line <C-U> and word <C-W>.
- Maintains buffer-scoped configuration, largely preserving global settings.
- Includes support for Vim’s Conceal feature, which hides markup defined by Syntax plugins (e.g., _ and * for styled text in _Markdown_).
- Provides display support for mode indicators (e.g., ␍ and ⤸) in the status line.
- Developed purely in Vimscript with no external dependencies.
Additionally, when using hard line break mode:
- Utilizes Vim’s autoformat feature during text insertion, excluding tables and code blocks where it is not desired.
- An optional key mapping is available to temporarily suspend autoformat for the current Insert operation.
For features like spell-check, distraction-free editing, and others, Vim’s customization capabilities are extensive. Users can configure Vim and leverage its rich plugin ecosystem to complete their editing environment.
Why Use Vim for Writing?
Given the abundance of word processing applications, including those tailored for writers, the choice of a modal editor like Vim might seem unconventional. However, several compelling reasons exist:
- Hands can remain in a neutral ‘home’ position, minimizing the need to reach for a mouse, track pad, or arrow keys.
- Features minimal chording and numerous mnemonic-friendly commands.
- Offers sophisticated capabilities for navigating and manipulating text.
- Highly configurable, allowing for the creation of a personalized workflow with many excellent plugins.
- Avoids proprietary format lock-in.
While these points are valid, they may not be enough to persuade a writer to switch from a familiar word processor. A more compelling reason lies in Vim’s command sequences, which can appeal to a writer’s appreciation for language and writing tools.
Consider ‘cas’, for example. This command can be seen as a mnemonic for Change Around Sentence to replace an existing sentence. A deeper understanding reveals that such commands possess their own grammar, composed of nouns, verbs, and modifiers. These elements serve as composable building blocks for a domain-specific language designed for text manipulation, which can become a powerful tool for self-expression. For more information on vi-style editing, refer to:
- Learn to speak vim – verbs, nouns, and modifiers! (December 2011)
- Your problem with Vim is that you don’t grok vi (December 2011)
- Intro to Vim’s Grammar (January 2013)
- Why Atom Can’t Replace Vim, Learning the lesson of vi (March 2014)
- Language of Vim/Neovim (January 2015)
Installation
Installation can be done using a preferred Vim package manager, such as Pathogen, Vundle, or Plug. For recent versions of Vim or Neovim, native package support is also an option. (Refer to :help packages for details.)
For those new to Vim, it is advisable to become familiar with Vim basics through available tutorials before installing this plugin.
Configuration
Initializing by Command
Pencil can be manually enabled, disabled, or toggled using commands:
- Pencil – Initializes pencil with auto-detection for the current buffer.
- NoPencil (or PencilOff) – Removes navigation mappings and restores the buffer to global settings.
- TogglePencil (or PencilToggle) – Toggles the plugin state; if active, it turns off, and if inactive, it initializes with auto-detection.
If auto-detection does not perform as expected, a command can be invoked to set the behavior for the current buffer:
- SoftPencil (or PencilSoft) – Initializes pencil in soft line wrap mode.
- HardPencil (or PencilHard) – Initializes pencil in hard line break mode, including Vim’s autoformat.
Initializing by File Type
Initializing pencil by file type is optional but automatically configures buffers for prose editing.
To add support for desired file types, include the following in the .vimrc file:
set nocompatible filetype plugin on " may already be in your .vimrc augroup pencil autocmd! autocmd FileType markdown,mkd call pencil#init() autocmd FileType text call pencil#init() augroup END
Multiple prose-oriented plugins can be initialized together:
augroup pencil autocmd! autocmd FileType markdown,mkd call pencil#init() \ | call lexical#init() \ | call litecorrect#init() \ | call textobj#quote#init() \ | call textobj#sentence#init() augroup END
A list of other prose-oriented plugins is available in the See also section.
Hard Line Breaks or Soft Line Wrap?
Coders are typically more familiar with hard line breaks, while writers often prefer soft line wrap. This plugin accommodates both conventions, allowing each buffer to be configured independently.
In most scenarios, a default can be set to suit preferences, with auto-detection handling specific cases.
let g:pencil#wrapModeDefault = 'soft' " default is 'hard' augroup pencil autocmd! autocmd FileType markdown,mkd call pencil#init() autocmd FileType text call pencil#init({'wrap': 'hard'}) augroup END
In the example above, for markdown buffers, the plugin will auto-detect the line wrap approach, defaulting to soft line wrap. For text buffers, it will initialize with hard line breaks, even if auto-detection might suggest soft line wrap.
Automatic Formatting
The ‘autoformat’ feature is exclusive to HardPencil (hard line break) mode.
When inserting text in HardPencil mode, Vim’s autoformat feature is enabled by default, offering benefits similar to soft line wrap.
To set the default behavior in the .vimrc file:
let g:pencil#autoformat = 1 " 0=disable, 1=enable (def)
This default can be overridden during initialization, as shown:
augroup pencil autocmd! autocmd FileType markdown call pencil#init({'wrap': 'hard', 'autoformat': 1}) autocmd FileType text call pencil#init({'wrap': 'hard', 'autoformat': 0}) ... augroup END
In this example, markdown and text buffers will use hard line breaks, but text buffers will have autoformat disabled.
Suspend Automatic Formatting for the Insert
There are two key situations where autoformat (when enabled for the buffer) is temporarily disabled for the current Insert operation:
First, pencil’s ‘blacklisting’ feature: when used with popular prose-oriented syntax plugins, pencil suspends autoformat upon entering Insert mode from within a code block or table.
Second, if blacklisting is insufficient, an optional buffer-scoped ‘modifier’ key can be mapped to suspend autoformat during the next Insert:
let g:pencil#map#suspend_af = 'K' " default is no mapping
With the mapping above, using Ko enters Insert mode on a new line with autoformat suspended for that Insert. Using o by itself retains autoformat.
By default, no modifier key is mapped.
(Refer to the advanced section for details on blacklisting implementation and configuration).
Manual Formatting
Reliance on Vim’s autoformat is not exclusive; paragraphs can be manually reformatted using standard Vim commands:
- gqap – Formats the current paragraph (see :help gq for details).
- vapJgqap – Merges two paragraphs (current and next) and formats them.
- ggVGgq or :g/^/norm gqq – Formats all paragraphs in the buffer.
These operations can optionally be mapped to underutilized keys in the .vimrc file:
nnoremap <silent> Q gqap xnoremap <silent> Q gq nnoremap <silent> <leader>Q vapJgqap
Alternatively, one might wish to ‘unformat’ (i.e., remove hard line breaks) when using soft line wrap.
- vipJ – Joins all lines in the current paragraph.
- :%norm vipJ – Unformats all paragraphs in the buffer.
Default Textwidth
The textwidth used in HardPencil (hard line break) mode can be configured when no textwidth is set globally, locally, or via modeline. It defaults to 74, but this value can be changed in the .vimrc file:
let g:pencil#textwidth = 74
Sentence Spacing
By default, when formatting text (e.g., through gwip), only one space is inserted after a period (.), exclamation point (!), or question mark (?). This default can be changed:
let g:pencil#joinspaces = 0 " 0=one_space (def), 1=two_spaces
Cursor Wrap
By default, h/l and the left/right cursor keys move to the previous/next line after reaching the first/last character in a line with a hard break. To retain Vim’s default behavior, set the cursorwrap value to 0 in the .vimrc file:
let g:pencil#cursorwrap = 1 " 0=disable, 1=enable (def)
Concealing Markup
Pencil enables Vim’s Conceal feature, though support among Syntax and Colorscheme plugins varies.
Pencil’s default settings for conceal can be modified in the .vimrc file:
let g:pencil#conceallevel = 3 " 0=disable, 1=one char, 2=hide char, 3=hide all (def) let g:pencil#concealcursor = 'c' " n=normal, v=visual, i=insert, c=command (def)
For more details on Vim’s Conceal feature, refer to:
:help conceallevel :help concealcursor
Concealing Styled Text in Markdown
Syntax plugins like tpope/vim-markdown support concealing markup characters when displaying _italic_, **bold**, and ***bold italic*** styled text.
To use Vim’s Conceal feature with Markdown, the following are required:
-
tpope/vim-markdown, as it is currently the only Markdown syntax plugin that supports conceal.
-
A monospaced font (such as Cousine) that includes italic, bold, and bold italic style variants for styled text.
-
A colorscheme (such as preservim/vim-colors-pencil) that supports Markdown-specific highlight groups for styled text.
With these in place, the _ and * markup should only be visible on the cursor line and in visual selections.
Terminal users: Consult terminal documentation to configure support for bold and italic styles.
Status Line Indicator
The status line can display the wrap mode for pencil buffers. For example, ␍ indicates HardPencil (hard line break) mode. To configure the status line and ruler, add the following to the .vimrc file:
set statusline=%<%f\ %h%m%r%w\ \ %{PencilMode()}\ %=\ col\ %c%V\ \ line\ %l\,%L\ %P set rulerformat=%-12.(%l,%c%V%)%{PencilMode()}\ %P
Alternatively, if bling/vim-airline is used:
let g:airline_section_x = '%{PencilMode()}'
The default indicators now include ‘auto’ when Vim’s autoformat is active in hard line break mode. If autoformat is suspended for the Insert, the ‘hard’ indicator will be shown.
let g:pencil#mode_indicators = {'hard': 'H', 'auto': 'A', 'soft': 'S', 'off': '',}
If Unicode is detected, the default indicators are:
let g:pencil#mode_indicators = {'hard': '␍', 'auto': 'ª', 'soft': '⤸', 'off': '',}
Custom indicators can be specified in the .vimrc file if the default ones are not preferred.
Note that PencilMode() will return blank for buffers where pencil has not been initialized.
Advanced Pencil
Advanced Initialization
Initialization statements can be refactored into a function within the .vimrc file to set up a buffer for writing:
function! Prose() call pencil#init() call lexical#init() call litecorrect#init() call textobj#quote#init() call textobj#sentence#init() " manual reformatting shortcuts nnoremap <buffer> <silent> Q gqap xnoremap <buffer> <silent> Q gq nnoremap <buffer> <silent> <leader>Q vapJgqap " force top correction on most recent misspelling nnoremap <buffer> <c-s> [s1z=<c-o> inoremap <buffer> <c-s> <c-g>u<Esc>[s1z=`]A<c-g>u " replace common punctuation iabbrev <buffer> -- – iabbrev <buffer> --- — iabbrev <buffer> << « iabbrev <buffer> >> » " open most folds setlocal foldlevel=6 " replace typographical quotes (reedes/vim-textobj-quote) map <silent> <buffer> <leader>qc <Plug>ReplaceWithCurly map <silent> <buffer> <leader>qs <Plug>ReplaceWithStraight " highlight words (reedes/vim-wordy) noremap <silent> <buffer> <F8> :<C-u>NextWordy<cr> xnoremap <silent> <buffer> <F8> :<C-u>NextWordy<cr> inoremap <silent> <buffer> <F8> <C-o>:NextWordy<cr> endfunction " automatically initialize buffer by file type autocmd FileType markdown,mkd,text call Prose() " invoke manually by command for other file types command! -nargs=0 Prose call Prose()
For fine-grained control, pencil and other configuration settings can be overridden when initializing buffers by file type:
augroup pencil autocmd! autocmd FileType markdown,mkd call pencil#init() \ | call litecorrect#init() \ | setl spell spl=en_us fdl=4 noru nonu nornu \ | setl fdo+=search autocmd Filetype git,gitsendemail,*commit*,*COMMIT* \ call pencil#init({'wrap': 'hard', 'textwidth': 72}) \ | call litecorrect#init() \ | setl spell spl=en_us et sw=2 ts=2 noai autocmd Filetype mail call pencil#init({'wrap': 'hard', 'textwidth': 60}) \ | call litecorrect#init() \ | setl spell spl=en_us et sw=2 ts=2 noai nonu nornu autocmd Filetype html,xml call pencil#init({'wrap': 'soft'}) \ | call litecorrect#init() \ | setl spell spl=en_us et sw=2 ts=2 augroup END
Configurable options for pencil#init() include: autoformat, concealcursor, conceallevel, cursorwrap, joinspaces, textwidth, and wrap. These are detailed above.
Autoformat Manual Control
The ‘autoformat’ feature is exclusive to HardPencil (hard line break) mode.
To suspend autoformat for the next Insert, refer to the section above.
When manual control over autoformat for the current buffer is needed, commands are available:
- PFormat – Enables autoformat for the buffer (can still be disabled via blacklisting).
- PFormatOff – Disables autoformat for the buffer.
- PFormatToggle – Toggles autoformat (enables if disabled, etc.).
A key can be mapped in the .vimrc file to toggle Vim’s autoformat:
noremap <silent> <F7> :<C-u>PFormatToggle<cr> inoremap <silent> <F7> <C-o>:PFormatToggle<cr>
Autoformat Blacklisting (and Whitelisting)
The ‘autoformat’ feature is exclusive to HardPencil (hard line break) mode.
When editing formatted text, such as a table or code block, Vim’s autoformat can disrupt formatting. In these situations, autoformat should be suspended for the duration of the Insert.
Upon entering Insert mode, pencil determines the highlight group at the cursor position. If that group is blacklisted, pencil suspends autoformat for the Insert. For instance, when editing a ‘markdown’ buffer, autoformat is suspended if Insert mode is invoked from within a markdownFencedCodeBlock highlight group.
Blacklists are now declared by file type. The default blacklists (and whitelists) are defined in the plugin/pencil.vim module. An excerpt showing the configuration for the ‘markdown’ file type is:
let g:pencil#autoformat_config = { \ 'markdown': { \ 'black': [ \ 'htmlH[0-9]', \ 'markdown(Code|H[0-9]|Url|IdDeclaration|Link|Rule|Highlight[A-Za-z0-9]+)', \ 'markdown(FencedCodeBlock|InlineCode)', \ 'mkd(Code|Rule|Delimiter|Link|ListItem|IndentCode)', \ 'mmdTable[A-Za-z0-9]*', \ ], \ 'white': [ \ 'markdown(Code|Link)', \ ], \ }, [snip] \ }
The whitelist overrides the blacklist, enabling Vim’s autoformat if text that would typically be blacklisted does not dominate the entire line. This allows autoformat to function with inline code and links.
Auto-Detecting Wrap Mode
If a wrap mode was not explicitly specified during initialization, pencil attempts to detect it.
It first checks for a textwidth (or tw) specified in a modeline. If not found, pencil then samples lines from the beginning of the buffer.
Detect via modeline
The accuracy of wrap mode detection can be improved by providing pencil with an explicit hint.
At the bottom of this document, an unusual code snippet is present:
<!-- vim: set tw=73 :-->
This is an optional ‘modeline’ that instructs Vim to execute the following command upon loading the file into a buffer:
:set textwidth=73
This tells pencil to assume hard line breaks, regardless of whether soft line wrap is the default editing mode for ‘markdown’ buffers.
Soft wrap mode can be explicitly specified by setting a textwidth of 0:
<!-- vim: set tw=0 :-->
Note that if the modelines feature is disabled (e.g., for security reasons), the textwidth will still be set by this plugin.
Detect via sampling
If no modeline with a textwidth is found, pencil samples the initial lines from the buffer, searching for excessively long ones.
Two settings can be added to the .vimrc file to adjust this behavior.
The maximum number of lines to sample from the start of the buffer:
let g:pencil#softDetectSample = 20
Setting this value to 0 disables detection via line sampling.
When the number of bytes on a sampled line exceeds this next value, pencil assumes soft line wrap.
let g:pencil#softDetectThreshold = 130
If no such lines are found, pencil reverts to the default wrap mode.
See Also
- To Vim – Writer and psychologist Ian Hocking discusses using Vim for writing.
-
– Video tutorial by Shawn Biddle.
- Vim for Writers – A guide to Vim basics tailored for writers.
Bloggers and developers have discussed pencil and related tools:
- Reed Esau’s growing list of Vim plugins for writers (2014) – by @pengwynn
- Distraction Free Writing in Vim (2014) – by @tlattimore
- Safari Blog: Turning vim into an IDE through vim plugins (2014) – by @jameydeorio
- Quick tops for writing prose with Vim (2014) – by @benoliver999
- UseVim: Reed Esau’s Writing Plugins (2015) – by @alexyoung
- Tomasino Labs: Vim in Context (2015) – by @jamestomasino
Other plugins of particular interest to writers include:
- danielbmarques/vim-ditto – Highlights repeated words.
- tpope/vim-abolish – Facilitates searching for, substituting, and abbreviating multiple variants of a word.
- tommcdo/vim-exchange – An easy text exchange operator for Vim.
- junegunn/limelight.vim – A focus mode that brightens the current paragraph.
- junegunn/goyo.vim – A distraction-free editing mode.
Markdown syntax plugins:
Markdown users typically do not need to install a syntax plugin unless they desire the latest version of Pope’s syntax highlighting:
- tpope/vim-markdown – (Recommended) The latest version of Pope’s syntax plugin, which is included with Vim.
Those who use tables and footnotes may consider installing this plugin:
Alternatives to Tim Pope’s syntax highlighting include:
Note that the plasticboy and gabrielelana plugins may incorrectly reformat bulleted lists when Vim’s autoformat is active in pencil’s HardPencil mode.
If the pencil plugin proves useful, consider exploring these other plugins originally developed by @reedes:
- vim-colors-pencil – A color scheme for Vim inspired by IA Writer.
- vim-lexical – Enhances Vim’s spell-check and thesaurus/dictionary completion.
- vim-litecorrect – Provides lightweight auto-correction for Vim.
- vim-textobj-quote – Extends Vim to support typographic (‘curly’) quotes.
- vim-textobj-sentence – Improves upon Vim’s native sentence motion command.
- vim-thematic – Modifies Vim’s appearance to suit specific tasks and environments.
- vim-wheel – Offers screen-anchored cursor movement for Vim.
- vim-wordy – Identifies usage problems in writing.
- vim-wordchipper – A powerful tool for shredding text in Insert mode.
For those not impressed by pencil, vim-pandoc offers prose-oriented features with its own Markdown variant.
Future Development
If a problem is identified or an idea for improving pencil arises, it can be reported as an issue, or a pull request can be submitted.

