Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Support for nested list items with user defined bullets

  • Loading branch information...
commit 576333a5afcec24734c797736f84d8500bd62276 1 parent 48208ca
@xolox authored
View
39 README.md
@@ -53,20 +53,21 @@ If you set this option to the string `'no'` this feature will be completely disa
### The `g:notes_smart_quotes` option
-By default the notes plug-in automatically performs several substitutions on the text you type in insert mode. Here are those substitutions:
+By default the notes plug-in automatically performs several substitutions on the text you type in insert mode, for example regular quote marks are replaced with curly quotes. The full list of substitutions can be found below in the documentation on mappings. If you don't want the plug-in to perform these substitutions, you can set this option to zero like this:
- * `'` becomes `‘` or `’` depending on where you type it
- * `"` becomes `“` or `”` (same goes for these)
- * `--` becomes `—`
- * `->` becomes `→`
- * `<-` becomes `←`
- * the bullets `*`, `+` and `-` become `•`
+ :let g:notes_smart_quotes = 0
-If you don't want the plug-in to perform these substitutions, you can set this option to zero like this:
+### The `g:notes_ruler_text` option
- :let g:notes_smart_quotes = 0
+The text of the ruler line inserted when you type `***` in quick succession. It defaults to three asterisks separated by spaces, center aligned to the text width.
+
+### The `g:notes_list_bullets` option
+
+A list of characters used as list bullets. When you're using a Unicode encoding this defaults to `['•', '◦', '▸', '▹', '▪', '▫']`, otherwise it defaults to `['*', '-', '+']`.
+
+When you change the nesting level (indentation) of a line containing a bullet point using one of the mappings `Tab`, `Shift-Tab`, `Alt-Left` and `Alt-Right` the bullet point will be automatically changed to correspond to the new nesting level.
-If you type the three characters `***` in insert mode in quick succession, a horizontal ruler delimited by empty lines will be inserted. This mapping cannot be disabled simply because it seems unlikely to me that someone would want to type this actual text.
+The first level of list items gets the first bullet point in `g:notes_list_bullets`, the second level gets the second, etc. When you're indenting a list item to a level where the `g:notes_list_bullets` doesn't have enough bullets, the plug-in starts again at the first bullet in the list (in other words the selection of bullets wraps around).
### The `g:notes_shadowdir` option
@@ -174,6 +175,24 @@ The completion menu is populated from a text file listing all your tags, one on
If for any reason you want to recreate the list of tags you can execute the `:IndexTaggedNotes` command.
+## Mappings
+
+The following key mappings are defined inside notes.
+
+### Insert mode mappings
+
+ * `@` automatically triggers tag completion
+ * `'` becomes `‘` or `’` depending on where you type it
+ * `"` becomes `“` or `”` (same goes for these)
+ * `--` becomes `—`
+ * `->` becomes `→`
+ * `<-` becomes `←`
+ * the bullets `*`, `-` and `+` become `•`
+ * the three characters `***` in insert mode in quick succession insert a horizontal ruler delimited by empty lines
+ * `Tab` and `Alt-Right` increase indentation of list items (works on the current line and selected lines)
+ * `Shift-Tab` and `Alt-Left` decrease indentation of list items
+ * `Enter` on a line with only a list bullet removes the bullet and starts a new line below the current line
+
## Customizing the syntax highlighting of notes
The syntax mode for notes is written so you can override styles you don't like. To do so you can add lines such as the following to your [vimrc script] [vimrc]:
View
60 autoload/xolox/notes.vim
@@ -6,7 +6,7 @@
" Note: This file is encoded in UTF-8 including a byte order mark so
" that Vim loads the script using the right encoding transparently.
-let g:xolox#notes#version = '0.15.5'
+let g:xolox#notes#version = '0.16'
function! xolox#notes#shortcut() " {{{1
" The "note:" pseudo protocol is just a shortcut for the :Note command.
@@ -770,13 +770,31 @@ function! xolox#notes#get_bullet(chr)
return xolox#notes#unicode_enabled() ? '•' : a:chr
endfunction
-function! xolox#notes#indent_list(command, line1, line2) " {{{3
+function! xolox#notes#indent_list(direction, line1, line2) " {{{3
" Change indent of list items from {line1} to {line2} using {command}.
+ let indentstr = repeat(' ', &tabstop)
if a:line1 == a:line2 && getline(a:line1) == ''
- call setline(a:line1, repeat(' ', &tabstop))
+ call setline(a:line1, indentstr)
else
- execute a:line1 . ',' . a:line2 . 'normal' a:command
- if getline('.') =~ '\(•\|\*\)$'
+ " Regex to match a leading bullet.
+ let leading_bullet = xolox#notes#leading_bullet_pattern()
+ for lnum in range(a:line1, a:line2)
+ let line = getline(lnum)
+ " Calculate new nesting level, should not result in < 0.
+ let level = max([0, xolox#notes#get_list_level(line) + a:direction])
+ if a:direction == 1
+ " Indent the line.
+ let line = indentstr . line
+ else
+ " Unindent the line.
+ let line = substitute(line, '^' . indentstr, '', '')
+ endif
+ " Replace the bullet.
+ let bullet = g:notes_list_bullets[level % len(g:notes_list_bullets)]
+ call setline(lnum, substitute(line, leading_bullet, xolox#misc#escape#substitute(bullet), ''))
+ endfor
+ " Regex to match a trailing bullet.
+ if getline('.') =~ xolox#notes#trailing_bullet_pattern()
" Restore trailing space after list bullet.
call setline('.', getline('.') . ' ')
endif
@@ -784,9 +802,39 @@ function! xolox#notes#indent_list(command, line1, line2) " {{{3
normal $
endfunction
+function! xolox#notes#leading_bullet_pattern()
+ " Return a regular expression pattern that matches any leading list bullet.
+ let escaped_bullets = copy(g:notes_list_bullets)
+ call map(escaped_bullets, 'xolox#misc#escape#pattern(v:val)')
+ return '\(\_^\s*\)\@<=\(' . join(escaped_bullets, '\|') . '\)'
+endfunction
+
+function! xolox#notes#trailing_bullet_pattern()
+ " Return a regular expression pattern that matches any trailing list bullet.
+ let escaped_bullets = copy(g:notes_list_bullets)
+ call map(escaped_bullets, 'xolox#misc#escape#pattern(v:val)')
+ return '\(' . join(escaped_bullets, '\|') . '\|\*\)$'
+endfunction
+
+function! xolox#notes#get_comments_option()
+ " Get the value for the &comments option including user defined list bullets.
+ let items = copy(g:notes_list_bullets)
+ call map(items, '": " . v:val . " "')
+ call add(items, ':> ') " <- e-mail style block quotes.
+ return join(items, ',')
+endfunction
+
+function! xolox#notes#get_list_level(line)
+ " Get the nesting level of the list item on the given line. This will only
+ " work with the list item indentation style expected by the notes plug-in
+ " (that is, top level list items are indented with one space, each nested
+ " level below that is indented by pairs of three spaces).
+ return (len(matchstr(a:line, '^\s*')) - 1) / 3
+endfunction
+
function! xolox#notes#cleanup_list() " {{{3
" Automatically remove empty list items on Enter.
- if getline('.') =~ '^\s*\' . xolox#notes#get_bullet('*') . '\s*$'
+ if getline('.') =~ (xolox#notes#leading_bullet_pattern() . '\s*$')
let s:sol_save = &startofline
setlocal nostartofline " <- so that <C-u> clears the complete line
return "\<C-o>0\<C-o>d$\<C-o>o"
View
77 doc/notes.txt
@@ -128,29 +128,37 @@ automatically rename the file on disk to match the title.
The *g:notes_smart_quotes* option
By default the notes plug-in automatically performs several substitutions on
-the text you type in insert mode. Here are those substitutions:
-
- - ' becomes '‘' or '’' depending on where you type it
-
- - '"' becomes '“' or '”' (same goes for these)
+the text you type in insert mode, for example regular quote marks are replaced
+with curly quotes. The full list of substitutions can be found below in the
+documentation on mappings. If you don't want the plug-in to perform these
+substitutions, you can set this option to zero like this:
+>
+ :let g:notes_smart_quotes = 0
- - '--' becomes '—'
+-------------------------------------------------------------------------------
+The *g:notes_ruler_text* option
- - '->' becomes '->'
+The text of the ruler line inserted when you type '***' in quick succession.
+It defaults to three asterisks separated by spaces, center aligned to the text
+width.
- - '<-' becomes '←'
+-------------------------------------------------------------------------------
+The *g:notes_list_bullets* option
- - the bullets '*', '+' and '-' become '•'
+A list of characters used as list bullets. When you're using a Unicode
+encoding this defaults to '['•', '◦', '▸', '▹', '▪', '▫']', otherwise it
+defaults to '['*', '-', '+']'.
-If you don't want the plug-in to perform these substitutions, you can set this
-option to zero like this:
->
- :let g:notes_smart_quotes = 0
+When you change the nesting level (indentation) of a line containing a bullet
+point using one of the mappings 'Tab', 'Shift-Tab', 'Alt-Left' and 'Alt-Right'
+the bullet point will be automatically changed to correspond to the new
+nesting level.
-If you type the three characters '***' in insert mode in quick succession, a
-horizontal ruler delimited by empty lines will be inserted. This mapping
-cannot be disabled simply because it seems unlikely to me that someone would
-want to type this actual text.
+The first level of list items gets the first bullet point in
+|g:notes_list_bullets|, the second level gets the second, etc. When you're
+indenting a list item to a level where the |g:notes_list_bullets| doesn't have
+enough bullets, the plug-in starts again at the first bullet in the list (in
+other words the selection of bullets wraps around).
-------------------------------------------------------------------------------
The *g:notes_shadowdir* option
@@ -337,6 +345,41 @@ If for any reason you want to recreate the list of tags you can execute the
|:IndexTaggedNotes| command.
===============================================================================
+ *notes-mappings*
+Mappings ~
+
+The following key mappings are defined inside notes.
+
+-------------------------------------------------------------------------------
+ *notes-insert-mode-mappings*
+Insert mode mappings ~
+
+ - '@' automatically triggers tag completion
+
+ - ' becomes '‘' or '’' depending on where you type it
+
+ - '"' becomes '“' or '”' (same goes for these)
+
+ - '--' becomes '—'
+
+ - '->' becomes '->'
+
+ - '<-' becomes '←'
+
+ - the bullets '*', '-' and '+' become '•'
+
+ - the three characters '***' in insert mode in quick succession insert a
+ horizontal ruler delimited by empty lines
+
+ - 'Tab' and 'Alt-Right' increase indentation of list items (works on the
+ current line and selected lines)
+
+ - 'Shift-Tab' and 'Alt-Left' decrease indentation of list items
+
+ - 'Enter' on a line with only a list bullet removes the bullet and starts a
+ new line below the current line
+
+===============================================================================
Customizing the syntax highlighting of notes ~
The syntax mode for notes is written so you can override styles you don't
View
26 ftplugin/notes.vim
@@ -18,7 +18,7 @@ setlocal tabstop=3 shiftwidth=3 expandtab
let b:undo_ftplugin .= ' | set tabstop< shiftwidth< expandtab<'
" Automatic formatting for bulleted lists. {{{1
-let &l:comments = xolox#notes#unicode_enabled() ? ': • ,: * ,:> ' : ': * ,:> '
+let &l:comments = xolox#notes#get_comments_option()
setlocal formatoptions=tcron
let b:undo_ftplugin .= ' | set comments< formatoptions<'
@@ -79,28 +79,38 @@ endif
" Convert ASCII list bullets to Unicode bullets. {{{1
if g:notes_smart_quotes
+ imap <buffer> <expr> * xolox#notes#insert_bullet('*')
imap <buffer> <expr> - xolox#notes#insert_bullet('-')
imap <buffer> <expr> + xolox#notes#insert_bullet('+')
- imap <buffer> <expr> * xolox#notes#insert_bullet('*')
+ let b:undo_ftplugin .= ' | execute "iunmap <buffer> *"'
let b:undo_ftplugin .= ' | execute "iunmap <buffer> -"'
let b:undo_ftplugin .= ' | execute "iunmap <buffer> +"'
- let b:undo_ftplugin .= ' | execute "iunmap <buffer> *"'
endif
" Format three asterisks as a horizontal ruler. {{{1
inoremap <buffer> *** <C-o>:call xolox#notes#insert_ruler()<CR>
let b:undo_ftplugin .= ' | execute "iunmap <buffer> ***"'
-" Indent list items using <Tab>. {{{1
-imap <buffer> <silent> <Tab> <C-o>:call xolox#notes#indent_list('>>', line('.'), line('.'))<CR>
-smap <buffer> <silent> <Tab> <C-o>:<C-u>call xolox#notes#indent_list('>>', line("'<"), line("'>"))<CR><C-o>gv
+" Indent list items using <Tab> and <Shift-Tab>. {{{1
+imap <buffer> <silent> <Tab> <C-o>:call xolox#notes#indent_list(1, line('.'), line('.'))<CR>
+smap <buffer> <silent> <Tab> <C-o>:<C-u>call xolox#notes#indent_list(1, line("'<"), line("'>"))<CR><C-o>gv
let b:undo_ftplugin .= ' | execute "iunmap <buffer> <Tab>"'
let b:undo_ftplugin .= ' | execute "sunmap <buffer> <Tab>"'
-imap <buffer> <silent> <S-Tab> <C-o>:call xolox#notes#indent_list('<<', line('.'), line('.'))<CR>
-smap <buffer> <silent> <S-Tab> <C-o>:<C-u>call xolox#notes#indent_list('<<', line("'<"), line("'>"))<CR><C-o>gv
+imap <buffer> <silent> <S-Tab> <C-o>:call xolox#notes#indent_list(-1, line('.'), line('.'))<CR>
+smap <buffer> <silent> <S-Tab> <C-o>:<C-u>call xolox#notes#indent_list(-1, line("'<"), line("'>"))<CR><C-o>gv
let b:undo_ftplugin .= ' | execute "iunmap <buffer> <S-Tab>"'
let b:undo_ftplugin .= ' | execute "sunmap <buffer> <S-Tab>"'
+" Indent list items using <Alt-Left> and <Alt-Right>. {{{1
+imap <buffer> <silent> <A-Right> <C-o>:call xolox#notes#indent_list(1, line('.'), line('.'))<CR>
+smap <buffer> <silent> <A-Right> <C-o>:<C-u>call xolox#notes#indent_list(1, line("'<"), line("'>"))<CR><C-o>gv
+let b:undo_ftplugin .= ' | execute "iunmap <buffer> <A-Right>"'
+let b:undo_ftplugin .= ' | execute "sunmap <buffer> <A-Right>"'
+imap <buffer> <silent> <A-Left> <C-o>:call xolox#notes#indent_list(-1, line('.'), line('.'))<CR>
+smap <buffer> <silent> <A-Left> <C-o>:<C-u>call xolox#notes#indent_list(-1, line("'<"), line("'>"))<CR><C-o>gv
+let b:undo_ftplugin .= ' | execute "iunmap <buffer> <A-Left>"'
+let b:undo_ftplugin .= ' | execute "sunmap <buffer> <A-Left>"'
+
" Automatically remove empty list items on Enter. {{{1
inoremap <buffer> <silent> <expr> <CR> xolox#notes#cleanup_list()
View
9 plugin/notes.vim
@@ -60,6 +60,15 @@ if !exists('g:notes_ruler_text')
let g:notes_ruler_text = repeat(' ', ((&tw > 0 ? &tw : 79) - 5) / 2) . '* * *'
endif
+" Symbols used to denote list items with increasing nesting levels.
+if !exists('g:notes_list_bullets')
+ if xolox#notes#unicode_enabled()
+ let g:notes_list_bullets = ['•', '◦', '▸', '▹', '▪', '▫']
+ else
+ let g:notes_list_bullets = ['*', '-', '+']
+ endif
+endif
+
" User commands to create, delete and search notes.
command! -bar -bang -nargs=? -complete=customlist,xolox#notes#cmd_complete Note call xolox#notes#edit(<q-bang>, <q-args>)
command! -bar -bang -range NoteFromSelectedText call xolox#notes#from_selection(<q-bang>, 'edit')
View
2  syntax/notes.vim
@@ -32,7 +32,7 @@ syntax match notesTagName /\(^\|\s\)\@<=@\k\+/
highlight def link notesTagName Underlined
" Highlight list bullets and numbers. {{{2
-syntax match notesListBullet /^\s*\zs\(•\|\*\)/
+execute 'syntax match notesListBullet /' . escape(xolox#notes#leading_bullet_pattern(), '/') . '/'
highlight def link notesListBullet Comment
syntax match notesListNumber /^\s*\zs\d\+[[:punct:]]\?\ze\s/
highlight def link notesListNumber Comment
Please sign in to comment.
Something went wrong with that request. Please try again.