Skip to content

Commit 74e8455

Browse files
committed
Automatic completion of @tags inside notes (suggested by Lukas Muehlethaler)
1 parent 215fd1c commit 74e8455

File tree

5 files changed

+122
-4
lines changed

5 files changed

+122
-4
lines changed

README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ The notes.vim plug-in for the [Vim text editor] [vim] makes it easy to manage yo
1313
* A [Python 2] [python] script is included that accelerates keyword searches using an [SQLite] [sqlite] database
1414
* The `:RecentNotes` command lists your notes by modification date, starting with the most recently edited note
1515
* **Navigating between notes:** The included file type plug-in redefines [gf] [gf] to jump between notes and the syntax script highlights note names as hyper links
16-
* **Writing aids:** The included file type plug-in contains mappings for automatic curly quotes, arrows and list bullets and supports completion of note titles using Control-X Control-U
16+
* **Writing aids:** The included file type plug-in contains mappings for automatic curly quotes, arrows and list bullets and supports completion of note titles using Control-X Control-U and completion of tags using Control-X Control-O
1717
* **Embedded file types:** The included syntax script supports embedded highlighting using blocks marked with `{{{type … }}}` which allows you to embed highlighted code and configuration snippets in your notes
1818

1919
Here's a screen shot of the syntax mode using the [slate] [slate] color scheme:
@@ -80,6 +80,14 @@ When you execute this command it will start a new note with the selected text as
8080

8181
The `:DeleteNote` command deletes the current note, destroys the buffer and removes the note from the internal cache of filenames and note titles. This fails when changes have been made to the current buffer, unless you use `:DeleteNote!` which discards any changes.
8282

83+
### The `:IndexTaggedNotes` command
84+
85+
The notes plug-in defines an omni completion function that can be used to complete the names of tags. To trigger the omni completion you type Control-X Control-O. When you type `@` in insert mode the plug-in will automatically start omni completion.
86+
87+
The completion menu is populated from a text file listing all your tags, one on each line. The first time omni completion triggers, an index of tag names is generated and saved to the location set by `g:notes_tagsindex`. To update this tags index you need to execute the `:IndexTaggedNotes` command.
88+
89+
If you execute this command with a bang as in `:IndexTaggedNotes!` it wil open a split window with a cross reference of all the tags you've used and the files in which each tag has been used.
90+
8391
### The `:SearchNotes` command
8492

8593
This command wraps [:vimgrep] [vimgrep] and enables you to search through your notes using one or more keywords or a regular expression pattern. To search for a pattern you pass a single argument that starts/ends with a slash:

autoload/xolox/notes.vim

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,84 @@ function! xolox#notes#user_complete(findstart, base) " {{{1
174174
endif
175175
endfunction
176176

177+
function! xolox#notes#omni_complete(findstart, base) " {{{1
178+
if a:findstart
179+
" For now we assume omni completion was triggered by the mapping for
180+
" automatic tag completion. Eventually it might be nice to check for a
181+
" leading "@" here and otherwise make it complete e.g. note names, so that
182+
" there's only one way to complete inside notes and the plug-in is smart
183+
" enough to know what the user wants to complete :-)
184+
return col('.') - 1
185+
else
186+
let fname = expand(g:notes_tagsindex)
187+
if !filereadable(fname)
188+
return xolox#notes#index_tagged_notes(0)
189+
else
190+
return readfile(fname)
191+
endif
192+
endif
193+
endfunction
194+
195+
function! xolox#notes#index_tagged_notes(verbose) " {{{1
196+
let starttime = xolox#misc#timer#start()
197+
let notes = xolox#notes#get_fnames()
198+
let num_notes = len(notes)
199+
let known_tags = {}
200+
for idx in range(len(notes))
201+
let fname = notes[idx]
202+
call xolox#misc#msg#info("notes.vim %s: Scanning note %i of %i: %s", g:notes_version, idx + 1, num_notes, fname)
203+
let text = join(readfile(fname), "\n")
204+
" Strip code blocks from the text.
205+
let text = substitute(text, '{{{\w\+\_.\{-}}}}', '', 'g')
206+
for token in filter(split(text), 'v:val =~ "^@"')
207+
" Strip any trailing punctuation.
208+
let token = substitute(token, '[[:punct:]]*$', '', '')
209+
if token != ''
210+
if !a:verbose
211+
let known_tags[token] = 1
212+
else
213+
" Track the origins of tags.
214+
if !has_key(known_tags, token)
215+
let known_tags[token] = {}
216+
endif
217+
let known_tags[token][fname] = 1
218+
endif
219+
endif
220+
endfor
221+
endfor
222+
" Save the index of known tags as a text file.
223+
let fname = expand(g:notes_tagsindex)
224+
let tagnames = keys(known_tags)
225+
call sort(tagnames, 1)
226+
if writefile(tagnames, fname) != 0
227+
call xolox#misc#msg#warn("notes.vim %s: Failed to save tags index as %s!", g:notes_version, fname)
228+
else
229+
call xolox#misc#timer#stop('notes.vim %s: Indexed tags in %s.', g:notes_version, starttime)
230+
endif
231+
if !a:verbose
232+
return tagnames
233+
endif
234+
" If the user executed :IndexTaggedNotes! we show them the origins of tags,
235+
" because after the first time I tried the :IndexTaggedNotes command I was
236+
" immediately wondering where all of those false positives came from... This
237+
" doesn't give a complete picture (doing so would slow down the indexing
238+
" and complicate this code significantly) but it's better than nothing!
239+
let lines = ['All tags', '', printf("You have used %i tags in your notes, they're listed below.", len(known_tags))]
240+
let bullet = xolox#notes#insert_bullet('*')
241+
for tagname in tagnames
242+
call extend(lines, ['', '# ' . tagname, ''])
243+
let fnames = keys(known_tags[tagname])
244+
let titles = map(fnames, 'xolox#notes#fname_to_title(v:val)')
245+
call sort(titles, 1)
246+
for title in titles
247+
call add(lines, ' ' . bullet . ' ' . title)
248+
endfor
249+
endfor
250+
vnew
251+
call setline(1, lines)
252+
setlocal ft=notes nomod
253+
endfunction
254+
177255
function! xolox#notes#save() abort " {{{1
178256
" When the current note's title is changed, automatically rename the file.
179257
if &filetype == 'notes'

doc/notes.txt

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ notes in Vim:
4343

4444
- Writing aids: The included file type plug-in contains mappings for automatic
4545
curly quotes, arrows and list bullets and supports completion of note
46-
titles using Control-X Control-U
46+
titles using Control-X Control-U and completion of tags using Control-X
47+
Control-O
4748

4849
- Embedded file types: The included syntax script supports embedded
4950
highlighting using blocks marked with '{{{type … }}}' which allows you to
@@ -159,6 +160,23 @@ removes the note from the internal cache of filenames and note titles. This
159160
fails when changes have been made to the current buffer, unless you use
160161
':DeleteNote!' which discards any changes.
161162

163+
-------------------------------------------------------------------------------
164+
The *:IndexTaggedNotes* command
165+
166+
The notes plug-in defines an omni completion function that can be used to
167+
complete the names of tags. To trigger the omni completion you type Control-X
168+
Control-O. When you type '@' in insert mode the plug-in will automatically
169+
start omni completion.
170+
171+
The completion menu is populated from a text file listing all your tags, one
172+
on each line. The first time omni completion triggers, an index of tag names
173+
is generated and saved to the location set by 'g:notes_tagsindex'. To update
174+
this tags index you need to execute the |:IndexTaggedNotes| command.
175+
176+
If you execute this command with a bang as in ':IndexTaggedNotes!' it wil open
177+
a split window with a cross reference of all the tags you've used and the
178+
files in which each tag has been used.
179+
162180
-------------------------------------------------------------------------------
163181
The *:SearchNotes* command
164182

ftplugin/notes.vim

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
" Vim file type plug-in
22
" Author: Peter Odding <peter@peterodding.com>
3-
" Last Change: June 8, 2011
3+
" Last Change: July 9, 2011
44
" URL: http://peterodding.com/code/vim/notes/
55

66
if exists('b:did_ftplugin')
@@ -51,6 +51,14 @@ let b:undo_ftplugin .= ' includeexpr<'
5151
setlocal completefunc=xolox#notes#user_complete
5252
let b:undo_ftplugin .= ' completefunc<'
5353

54+
" Enable completion of tag names using C-x C-o. {{{1
55+
setlocal omnifunc=xolox#notes#omni_complete
56+
let b:undo_ftplugin .= ' omnifunc<'
57+
58+
" Automatic completion of tag names after typing "@". {{{1
59+
inoremap <buffer> <silent> @ <C-x><C-o>
60+
let b:undo_ftplugin .= ' | execute "iunmap <buffer> @"'
61+
5462
" Change double-dash to em-dash as it is typed. {{{1
5563
if xolox#notes#unicode_enabled()
5664
imap <buffer> --

plugin/notes.vim

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ if &cp || exists('g:loaded_notes')
1111
finish
1212
endif
1313

14-
let g:notes_version = '0.9.5'
14+
let g:notes_version = '0.10'
1515

1616
" Make sure the default paths below are compatible with Pathogen.
1717
let s:plugindir = expand('<sfile>:p:h') . '/../misc/notes'
@@ -41,13 +41,19 @@ if !exists('g:notes_suffix')
4141
let g:notes_suffix = ''
4242
endif
4343

44+
" Define the default location for the tag name index (used for completion).
45+
if !exists('g:notes_tagsindex')
46+
let g:notes_tagsindex = s:plugindir . '/tags.txt'
47+
endif
48+
4449
" User commands to create, delete and search notes.
4550
command! -bar -bang -nargs=? -complete=customlist,xolox#notes#cmd_complete Note call xolox#notes#edit(<q-bang>, <q-args>)
4651
command! -bar -bang -range NoteFromSelectedText call xolox#notes#from_selection(<q-bang>)
4752
command! -bar -bang DeleteNote call xolox#notes#delete(<q-bang>)
4853
command! -bang -nargs=? SearchNotes call xolox#notes#search(<q-bang>, <q-args>)
4954
command! -bar -bang RelatedNotes call xolox#notes#related(<q-bang>)
5055
command! -bar -bang -nargs=? RecentNotes call xolox#notes#recent(<q-bang>, <q-args>)
56+
command! -bar -bang IndexTaggedNotes call xolox#notes#index_tagged_notes(<q-bang> == '!')
5157

5258
" Automatic commands to enable the :edit note:… shortcut and load the notes file type.
5359

0 commit comments

Comments
 (0)