mirror of
https://github.com/amix/vimrc
synced 2025-07-03 14:14:59 +08:00
Cleaning deps.
This commit is contained in:
1221
sources_non_forked/vim-notes/autoload/xolox/notes.vim
Normal file
1221
sources_non_forked/vim-notes/autoload/xolox/notes.vim
Normal file
File diff suppressed because it is too large
Load Diff
84
sources_non_forked/vim-notes/autoload/xolox/notes/html.vim
Normal file
84
sources_non_forked/vim-notes/autoload/xolox/notes/html.vim
Normal file
@ -0,0 +1,84 @@
|
||||
" Vim auto-load script
|
||||
" Author: Peter Odding <peter@peterodding.com>
|
||||
" Last Change: June 23, 2013
|
||||
" URL: http://peterodding.com/code/vim/notes/
|
||||
|
||||
if !exists('g:notes_markdown_program')
|
||||
let g:notes_markdown_program = 'markdown'
|
||||
endif
|
||||
|
||||
function! xolox#notes#html#view() " {{{1
|
||||
" Convert the current note to a web page and show the web page in a browser.
|
||||
" Requires [Markdown] [markdown] to be installed; you'll get a warning if it
|
||||
" isn't.
|
||||
"
|
||||
" [markdown]: http://en.wikipedia.org/wiki/Markdown
|
||||
try
|
||||
" Convert the note's text to HTML using Markdown.
|
||||
let starttime = xolox#misc#timer#start()
|
||||
let note_title = xolox#notes#current_title()
|
||||
let filename = xolox#notes#title_to_fname(note_title)
|
||||
let note_text = join(getline(1, '$'), "\n")
|
||||
let raw_html = xolox#notes#html#convert_note(note_text)
|
||||
let styled_html = xolox#notes#html#apply_template({
|
||||
\ 'encoding': &encoding,
|
||||
\ 'title': note_title,
|
||||
\ 'content': raw_html,
|
||||
\ 'version': g:xolox#notes#version,
|
||||
\ 'date': strftime('%A %B %d, %Y at %H:%M'),
|
||||
\ 'filename': fnamemodify(filename, ':~'),
|
||||
\ })
|
||||
let filename = s:create_temporary_file(note_title)
|
||||
if writefile(split(styled_html, "\n"), filename) != 0
|
||||
throw printf("Failed to write HTML file! (%s)", filename)
|
||||
endif
|
||||
" Open the generated HTML in a web browser.
|
||||
call xolox#misc#open#url('file://' . filename)
|
||||
call xolox#misc#timer#stop("notes.vim %s: Rendered HTML preview in %s.", g:xolox#notes#version, starttime)
|
||||
catch
|
||||
call xolox#misc#msg#warn("notes.vim %s: %s at %s", g:xolox#notes#version, v:exception, v:throwpoint)
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
function! xolox#notes#html#convert_note(note_text) " {{{1
|
||||
" Convert a note's text to a web page (HTML) using the [Markdown text
|
||||
" format] [markdown] as an intermediate format. This function takes the text
|
||||
" of a note (the first argument) and converts it to HTML, returning a
|
||||
" string.
|
||||
if !executable(g:notes_markdown_program)
|
||||
throw "HTML conversion requires the `markdown' program! On Debian/Ubuntu you can install it by executing `sudo apt-get install markdown'."
|
||||
endif
|
||||
let markdown = xolox#notes#markdown#convert_note(a:note_text)
|
||||
let result = xolox#misc#os#exec({'command': g:notes_markdown_program, 'stdin': markdown})
|
||||
let html = join(result['stdout'], "\n")
|
||||
return html
|
||||
endfunction
|
||||
|
||||
function! xolox#notes#html#apply_template(variables) " {{{1
|
||||
" The vim-notes plug-in contains a web page template that's used to provide
|
||||
" a bit of styling when a note is converted to a web page and presented to
|
||||
" the user. This function takes the original HTML produced by [Markdown]
|
||||
" [markdown] (the first argument) and wraps it in the configured template,
|
||||
" returning the final HTML as a string.
|
||||
let filename = expand(g:notes_html_template)
|
||||
call xolox#misc#msg#debug("notes.vim %s: Reading web page template from %s ..", g:xolox#notes#version, filename)
|
||||
let template = join(readfile(filename), "\n")
|
||||
let output = substitute(template, '{{\(.\{-}\)}}', '\= s:template_callback(a:variables)', 'g')
|
||||
return output
|
||||
endfunction
|
||||
|
||||
function! s:template_callback(variables) " {{{1
|
||||
" Callback for xolox#notes#html#apply_template().
|
||||
let key = xolox#misc#str#trim(submatch(1))
|
||||
return get(a:variables, key, '')
|
||||
endfunction
|
||||
|
||||
function! s:create_temporary_file(note_title) " {{{1
|
||||
" Create a temporary filename for a note converted to an HTML document,
|
||||
" based on the title of the note.
|
||||
if !exists('s:temporary_directory')
|
||||
let s:temporary_directory = xolox#misc#path#tempdir()
|
||||
endif
|
||||
let filename = xolox#misc#str#slug(a:note_title) . '.html'
|
||||
return xolox#misc#path#merge(s:temporary_directory, filename)
|
||||
endfunction
|
@ -0,0 +1,94 @@
|
||||
" Vim auto-load script
|
||||
" Author: Peter Odding <peter@peterodding.com>
|
||||
" Last Change: June 23, 2013
|
||||
" URL: http://peterodding.com/code/vim/notes/
|
||||
|
||||
function! xolox#notes#markdown#view() " {{{1
|
||||
" Convert the current note to a Markdown document and show the converted text.
|
||||
let note_text = join(getline(1, '$'), "\n")
|
||||
let markdown_text = xolox#notes#markdown#convert_note(note_text)
|
||||
vnew
|
||||
call setline(1, split(markdown_text, "\n"))
|
||||
setlocal filetype=markdown
|
||||
endfunction
|
||||
|
||||
function! xolox#notes#markdown#convert_note(note_text) " {{{1
|
||||
" Convert a note's text to the [Markdown text format] [markdown]. The syntax
|
||||
" used by vim-notes has a lot of similarities with Markdown, but there are
|
||||
" some notable differences like the note title and the way code blocks are
|
||||
" represented. This function takes the text of a note (the first argument)
|
||||
" and converts it to the Markdown format, returning a string.
|
||||
"
|
||||
" [markdown]: http://en.wikipedia.org/wiki/Markdown
|
||||
let starttime = xolox#misc#timer#start()
|
||||
let blocks = xolox#notes#parser#parse_note(a:note_text)
|
||||
call map(blocks, 'xolox#notes#markdown#convert_block(v:val)')
|
||||
let markdown = join(blocks, "\n\n")
|
||||
call xolox#misc#timer#stop("notes.vim %s: Converted note to Markdown in %s.", g:xolox#notes#version, starttime)
|
||||
return markdown
|
||||
endfunction
|
||||
|
||||
function! xolox#notes#markdown#convert_block(block) " {{{1
|
||||
" Convert a single block produced by `xolox#misc#notes#parser#parse_note()`
|
||||
" (the first argument, expected to be a dictionary) to the [Markdown text
|
||||
" format] [markdown]. Returns a string.
|
||||
if a:block.type == 'title'
|
||||
let text = s:make_urls_explicit(a:block.text)
|
||||
return printf("# %s", text)
|
||||
elseif a:block.type == 'heading'
|
||||
let marker = repeat('#', 1 + a:block.level)
|
||||
let text = s:make_urls_explicit(a:block.text)
|
||||
return printf("%s %s", marker, text)
|
||||
elseif a:block.type == 'code'
|
||||
let comment = "<!-- An innocent comment to force Markdown out of list parsing mode. See also http://meta.stackoverflow.com/a/99637 -->"
|
||||
let text = xolox#misc#str#indent(xolox#misc#str#dedent(a:block.text), 4)
|
||||
return join([comment, text], "\n\n")
|
||||
elseif a:block.type == 'divider'
|
||||
return '* * *'
|
||||
elseif a:block.type == 'list'
|
||||
let items = []
|
||||
if a:block.ordered
|
||||
let counter = 1
|
||||
for item in a:block.items
|
||||
let indent = repeat(' ', item.indent * 4)
|
||||
let text = s:make_urls_explicit(item.text)
|
||||
call add(items, printf("%s%d. %s", indent, counter, text))
|
||||
let counter += 1
|
||||
endfor
|
||||
else
|
||||
for item in a:block.items
|
||||
let indent = repeat(' ', item.indent * 4)
|
||||
let text = s:make_urls_explicit(item.text)
|
||||
call add(items, printf("%s- %s", indent, text))
|
||||
endfor
|
||||
endif
|
||||
return join(items, "\n\n")
|
||||
elseif a:block.type == 'block-quote'
|
||||
let lines = []
|
||||
for line in a:block.lines
|
||||
let prefix = repeat('>', line.level)
|
||||
call add(lines, printf('%s %s', prefix, line.text))
|
||||
endfor
|
||||
return join(lines, "\n")
|
||||
elseif a:block.type == 'paragraph'
|
||||
let text = s:make_urls_explicit(a:block.text)
|
||||
if len(text) <= 50 && text =~ ':$'
|
||||
let text = printf('**%s**', text)
|
||||
endif
|
||||
return text
|
||||
else
|
||||
let msg = "Encountered unsupported block: %s!"
|
||||
throw printf(msg, string(a:block))
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:make_urls_explicit(text) " {{{1
|
||||
" In the vim-notes syntax, URLs are implicitly hyperlinks.
|
||||
" In Markdown syntax they have to be wrapped in <markers>.
|
||||
return substitute(a:text, g:xolox#notes#url_pattern, '\= s:url_callback(submatch(0))', 'g')
|
||||
endfunction
|
||||
|
||||
function! s:url_callback(url)
|
||||
let label = substitute(a:url, '^\w\+:\(//\)\?', '', '')
|
||||
return printf('[%s](%s)', label, a:url)
|
||||
endfunction
|
333
sources_non_forked/vim-notes/autoload/xolox/notes/parser.vim
Normal file
333
sources_non_forked/vim-notes/autoload/xolox/notes/parser.vim
Normal file
@ -0,0 +1,333 @@
|
||||
" Vim auto-load script
|
||||
" Author: Peter Odding <peter@peterodding.com>
|
||||
" Last Change: July 18, 2013
|
||||
" URL: http://peterodding.com/code/vim/notes/
|
||||
|
||||
function! xolox#notes#parser#parse_note(text) " {{{1
|
||||
" Parser for the note taking syntax used by vim-notes.
|
||||
let starttime = xolox#misc#timer#start()
|
||||
let context = s:create_parse_context(a:text)
|
||||
let note_title = context.next_line()
|
||||
let blocks = [{'type': 'title', 'text': note_title}]
|
||||
while context.has_more()
|
||||
let chr = context.peek(1)
|
||||
if chr == "\n"
|
||||
" Ignore empty lines.
|
||||
call context.next(1)
|
||||
continue
|
||||
elseif chr == '#'
|
||||
let block = s:parse_heading(context)
|
||||
elseif chr == '>'
|
||||
let block = s:parse_block_quote(context)
|
||||
elseif chr == '{' && context.peek(3) == "\{\{\{"
|
||||
let block = s:parse_code_block(context)
|
||||
else
|
||||
let lookahead = s:match_bullet_or_divider(context, 0)
|
||||
if !empty(lookahead)
|
||||
if lookahead.type =~ 'list'
|
||||
let block = s:parse_list(context)
|
||||
elseif lookahead.type == 'divider'
|
||||
let block = s:parse_divider(context)
|
||||
else
|
||||
let msg = "Programming error! Unsupported lookahead: %s."
|
||||
throw printf(msg, string(lookahead))
|
||||
endif
|
||||
else
|
||||
let block = s:parse_paragraph(context)
|
||||
endif
|
||||
endif
|
||||
" Don't include empty blocks in the output.
|
||||
if !empty(block)
|
||||
call add(blocks, block)
|
||||
endif
|
||||
endwhile
|
||||
call xolox#misc#timer#stop("notes.vim %s: Parsed note into %i blocks in %s.", g:xolox#notes#version, len(blocks), starttime)
|
||||
return blocks
|
||||
endfunction
|
||||
|
||||
function! xolox#notes#parser#view_parse_nodes() " {{{1
|
||||
" Parse the current note and show the parse nodes in a temporary buffer.
|
||||
let note_text = join(getline(1, '$'), "\n")
|
||||
let parse_nodes = xolox#notes#parser#parse_note(note_text)
|
||||
vnew
|
||||
call setline(1, map(parse_nodes, 'string(v:val)'))
|
||||
setlocal filetype=vim nomodified nowrap
|
||||
endfunction
|
||||
|
||||
function! s:create_parse_context(text) " {{{1
|
||||
" Create an object to encapsulate the lowest level of parser state.
|
||||
let context = {'text': a:text, 'index': 0}
|
||||
" The has_more() method returns 1 (true) when more input is available, 0
|
||||
" (false) otherwise.
|
||||
function context.has_more()
|
||||
return self.index < len(self.text)
|
||||
endfunction
|
||||
" The peek() method returns the next character without consuming it.
|
||||
function context.peek(n)
|
||||
if self.has_more()
|
||||
return self.text[self.index : self.index + (a:n - 1)]
|
||||
endif
|
||||
return ''
|
||||
endfunction
|
||||
" The next() method returns the next character and consumes it.
|
||||
function context.next(n)
|
||||
let result = self.peek(a:n)
|
||||
let self.index += a:n
|
||||
return result
|
||||
endfunction
|
||||
" The next_line() method returns the current line and consumes it.
|
||||
function context.next_line()
|
||||
let line = ''
|
||||
while self.has_more()
|
||||
let chr = self.next(1)
|
||||
if chr == "\n" || chr == ""
|
||||
" We hit the end of line or input.
|
||||
return line
|
||||
else
|
||||
" The line continues.
|
||||
let line .= chr
|
||||
endif
|
||||
endwhile
|
||||
return line
|
||||
endfunction
|
||||
return context
|
||||
endfunction
|
||||
|
||||
function! s:match_bullet_or_divider(context, consume_lookahead) " {{{1
|
||||
" Check whether the current line starts with a list bullet.
|
||||
let result = {}
|
||||
let context = copy(a:context)
|
||||
let line = context.next_line()
|
||||
let bullet = matchstr(line, s:bullet_pattern)
|
||||
if !empty(bullet)
|
||||
" Disambiguate list bullets from horizontal dividers.
|
||||
if line =~ '^\s\+\*\s\*\s\*$'
|
||||
let result.type = 'divider'
|
||||
else
|
||||
" We matched a bullet! Now we still need to distinguish ordered from
|
||||
" unordered list items.
|
||||
if bullet =~ '\d'
|
||||
let result.type = 'ordered-list'
|
||||
else
|
||||
let result.type = 'unordered-list'
|
||||
endif
|
||||
let indent = matchstr(bullet, '^\s*')
|
||||
let result.indent = len(indent)
|
||||
" Since we already skipped the whitespace and matched the bullet, it's
|
||||
" very little work to mark our position for the benefit of the caller.
|
||||
if a:consume_lookahead
|
||||
let a:context.index += len(bullet)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
return result
|
||||
endfunction
|
||||
|
||||
function! s:match_line(context) " {{{1
|
||||
" Get the text of the current line, stopping at end of the line or just
|
||||
" before the start of a code block marker, whichever comes first.
|
||||
let line = ''
|
||||
while a:context.has_more()
|
||||
let chr = a:context.peek(1)
|
||||
if chr == '{' && a:context.peek(3) == "\{\{\{"
|
||||
" XXX The start of a code block implies the end of whatever came before.
|
||||
" The marker above contains back slashes so that Vim doesn't apply
|
||||
" folding because of the marker :-).
|
||||
return line
|
||||
elseif chr == "\n"
|
||||
call a:context.next(1)
|
||||
return line . "\n"
|
||||
else
|
||||
let line .= a:context.next(1)
|
||||
endif
|
||||
endwhile
|
||||
" We hit the end of the input.
|
||||
return line
|
||||
endfunction
|
||||
|
||||
function! s:parse_heading(context) " {{{1
|
||||
" Parse the upcoming heading in the input stream.
|
||||
let level = 0
|
||||
while a:context.peek(1) == '#'
|
||||
let level += 1
|
||||
call a:context.next(1)
|
||||
endwhile
|
||||
let text = xolox#misc#str#trim(s:match_line(a:context))
|
||||
return {'type': 'heading', 'level': level, 'text': text}
|
||||
endfunction
|
||||
|
||||
function! s:parse_block_quote(context) " {{{1
|
||||
" Parse the upcoming block quote in the input stream.
|
||||
let lines = []
|
||||
while a:context.has_more()
|
||||
if a:context.peek(1) != '>'
|
||||
break
|
||||
endif
|
||||
let line = s:match_line(a:context)
|
||||
let level = len(matchstr(line, '^>\+'))
|
||||
let text = matchstr(line, '^>\+\s*\zs.\{-}\ze\_s*$')
|
||||
call add(lines, {'level': level, 'text': text})
|
||||
endwhile
|
||||
return {'type': 'block-quote', 'lines': lines}
|
||||
endfunction
|
||||
|
||||
function! s:parse_code_block(context) " {{{1
|
||||
" Parse the upcoming code block in the input stream.
|
||||
let language = ''
|
||||
let text = ''
|
||||
" Skip the start marker.
|
||||
call a:context.next(3)
|
||||
" Get the optional language name.
|
||||
while a:context.peek(1) =~ '\w'
|
||||
let language .= a:context.next(1)
|
||||
endwhile
|
||||
" Skip the whitespace separating the start marker and/or language name from
|
||||
" the text.
|
||||
while a:context.peek(1) =~ '[ \t]'
|
||||
call a:context.next(1)
|
||||
endwhile
|
||||
" Get the text inside the code block.
|
||||
while a:context.has_more()
|
||||
let chr = a:context.next(1)
|
||||
if chr == '}' && a:context.peek(2) == '}}'
|
||||
call a:context.next(2)
|
||||
break
|
||||
endif
|
||||
let text .= chr
|
||||
endwhile
|
||||
" Strip trailing whitespace.
|
||||
let text = substitute(text, '\_s\+$', '', '')
|
||||
return {'type': 'code', 'language': language, 'text': text}
|
||||
endfunction
|
||||
|
||||
function! s:parse_divider(context) " {{{1
|
||||
" Parse the upcoming horizontal divider in the input stream.
|
||||
call a:context.next_line()
|
||||
return {'type': 'divider'}
|
||||
endfunction
|
||||
|
||||
function! s:parse_list(context) " {{{1
|
||||
" Parse the upcoming sequence of list items in the input stream.
|
||||
let list_type = 'unknown'
|
||||
let items = []
|
||||
let lines = []
|
||||
let indent = 0
|
||||
" Outer loop to consume one or more list items.
|
||||
while a:context.has_more()
|
||||
let lookahead = s:match_bullet_or_divider(a:context, 1)
|
||||
if !empty(lookahead)
|
||||
" Save the previous list item with the old indent level.
|
||||
call s:save_item(items, lines, indent)
|
||||
let lines = []
|
||||
" Set the new indent level (three spaces -> one level).
|
||||
let indent = lookahead.indent / 3
|
||||
" The current line starts with a list bullet.
|
||||
if list_type == 'unknown'
|
||||
" The first bullet determines the type of list.
|
||||
let list_type = lookahead.type
|
||||
endif
|
||||
endif
|
||||
let line = s:match_line(a:context)
|
||||
call add(lines, line)
|
||||
if line[-1:] != "\n"
|
||||
" XXX When match_line() returns a line that doesn't end in a newline
|
||||
" character, it means either we hit the end of the input or the current
|
||||
" line continues in a code block (which is not ours to parse :-).
|
||||
break
|
||||
elseif line =~ '^\_s*$'
|
||||
" For now an empty line terminates the list item.
|
||||
" TODO Add support for list items with multiple paragraphs of text.
|
||||
break
|
||||
endif
|
||||
endwhile
|
||||
call s:save_item(items, lines, indent)
|
||||
return {'type': 'list', 'ordered': (list_type == 'ordered-list'), 'items': items}
|
||||
endfunction
|
||||
|
||||
function! s:save_item(items, lines, indent)
|
||||
let text = join(a:lines, "\n")
|
||||
if text =~ '\S'
|
||||
let text = xolox#misc#str#compact(text)
|
||||
call add(a:items, {'text': text, 'indent': a:indent})
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:parse_paragraph(context) " {{{1
|
||||
" Parse the upcoming paragraph in the input stream.
|
||||
let lines = []
|
||||
while a:context.has_more()
|
||||
if !empty(s:match_bullet_or_divider(a:context, 0))
|
||||
" If the next line starts with a list bullet it shouldn't
|
||||
" be included in the paragraph we're currently parsing.
|
||||
break
|
||||
else
|
||||
let line = s:match_line(a:context)
|
||||
call add(lines, line)
|
||||
if line =~ '^\_s*$'
|
||||
" An empty line marks the end of the paragraph.
|
||||
break
|
||||
elseif line[-1:] != "\n"
|
||||
" XXX When match_line() returns a line that doesn't end in a newline
|
||||
" character, it means either we hit the end of the input or the current
|
||||
" line continues in a code block (which is not ours to parse :-).
|
||||
break
|
||||
endif
|
||||
endif
|
||||
endwhile
|
||||
" Don't include empty paragraphs in the output.
|
||||
let text = join(lines, "\n")
|
||||
if text =~ '\S'
|
||||
return {'type': 'paragraph', 'text': xolox#misc#str#compact(text)}
|
||||
else
|
||||
return {}
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:generate_list_item_bullet_pattern() " {{{1
|
||||
" Generate a regular expression that matches any kind of list bullet.
|
||||
let choices = copy(g:notes_unicode_bullets)
|
||||
for bullet in g:notes_ascii_bullets
|
||||
call add(choices, xolox#misc#escape#pattern(bullet))
|
||||
endfor
|
||||
call add(choices, '\d\+[[:punct:]]\?')
|
||||
return join(choices, '\|')
|
||||
endfunction
|
||||
|
||||
let s:bullet_pattern = '^\s*\(' . s:generate_list_item_bullet_pattern() . '\)\s\+'
|
||||
|
||||
function! xolox#notes#parser#run_tests() " {{{1
|
||||
" Tests for the note taking syntax parser.
|
||||
call xolox#misc#test#reset()
|
||||
call xolox#misc#test#wrap('xolox#notes#parser#test_parsing_of_note_titles')
|
||||
call xolox#misc#test#wrap('xolox#notes#parser#test_parsing_of_headings')
|
||||
call xolox#misc#test#wrap('xolox#notes#parser#test_parsing_of_paragraphs')
|
||||
call xolox#misc#test#wrap('xolox#notes#parser#test_parsing_of_code_blocks')
|
||||
call xolox#misc#test#wrap('xolox#notes#parser#test_parsing_of_list_items')
|
||||
call xolox#misc#test#wrap('xolox#notes#parser#test_parsing_of_block_quotes')
|
||||
call xolox#misc#test#summarize()
|
||||
endfunction
|
||||
|
||||
function! xolox#notes#parser#test_parsing_of_note_titles()
|
||||
call xolox#misc#test#assert_equals([{'type': 'title', 'text': 'Just the title'}], xolox#notes#parser#parse_note('Just the title'))
|
||||
endfunction
|
||||
|
||||
function! xolox#notes#parser#test_parsing_of_headings()
|
||||
call xolox#misc#test#assert_equals([{'type': 'title', 'text': 'Just the title'}, {'type': 'heading', 'level': 1, 'text': 'This is a heading'}], xolox#notes#parser#parse_note("Just the title\n\n# This is a heading"))
|
||||
endfunction
|
||||
|
||||
function! xolox#notes#parser#test_parsing_of_paragraphs()
|
||||
call xolox#misc#test#assert_equals([{'type': 'title', 'text': 'Just the title'}, {'type': 'paragraph', 'text': 'This is a paragraph'}], xolox#notes#parser#parse_note("Just the title\n\nThis is a paragraph"))
|
||||
call xolox#misc#test#assert_equals([{'type': 'title', 'text': 'Just the title'}, {'type': 'paragraph', 'text': 'This is a paragraph'}, {'type': 'paragraph', 'text': "And here's another paragraph!"}], xolox#notes#parser#parse_note("Just the title\n\nThis is a paragraph\n\n\n\nAnd here's another paragraph!"))
|
||||
endfunction
|
||||
|
||||
function! xolox#notes#parser#test_parsing_of_code_blocks()
|
||||
call xolox#misc#test#assert_equals([{'type': 'title', 'text': 'Just the title'}, {'type': 'code', 'language': '', 'text': "This is a code block\nwith two lines"}], xolox#notes#parser#parse_note("Just the title\n\n{{{ This is a code block\nwith two lines }}}"))
|
||||
endfunction
|
||||
|
||||
function! xolox#notes#parser#test_parsing_of_list_items()
|
||||
call xolox#misc#test#assert_equals([{'type': 'title', 'text': 'Just the title'}, {'type': 'list', 'ordered': 1, 'items': [{'indent': 0, 'text': 'item one'}, {'indent': 0, 'text': 'item two'}, {'indent': 0, 'text': 'item three'}]}], xolox#notes#parser#parse_note("Just the title\n\n1. item one\n2. item two\n3. item three"))
|
||||
endfunction
|
||||
|
||||
function! xolox#notes#parser#test_parsing_of_block_quotes()
|
||||
call xolox#misc#test#assert_equals([{'type': 'title', 'text': 'Just the title'}, {'type': 'block-quote', 'lines': [{'level': 1, 'text': 'block'}, {'level': 2, 'text': 'quoted'}, {'level': 1, 'text': 'text'}]}], xolox#notes#parser#parse_note("Just the title\n\n> block\n>> quoted\n> text"))
|
||||
endfunction
|
100
sources_non_forked/vim-notes/autoload/xolox/notes/recent.vim
Normal file
100
sources_non_forked/vim-notes/autoload/xolox/notes/recent.vim
Normal file
@ -0,0 +1,100 @@
|
||||
" Vim auto-load script
|
||||
" Author: Peter Odding <peter@peterodding.com>
|
||||
" Last Change: May 16, 2013
|
||||
" URL: http://peterodding.com/code/vim/notes/
|
||||
|
||||
function! xolox#notes#recent#show(bang, title_filter) " {{{1
|
||||
call xolox#misc#msg#info("notes.vim %s: Generating overview of recent notes ..", g:xolox#notes#version)
|
||||
" Show generated note listing all notes by last modified time.
|
||||
let starttime = xolox#misc#timer#start()
|
||||
let bufname = '[Recent Notes]'
|
||||
" Prepare a buffer to hold the list of recent notes.
|
||||
call xolox#misc#buffer#prepare({
|
||||
\ 'name': bufname,
|
||||
\ 'path': xolox#misc#path#merge($HOME, bufname)})
|
||||
" Filter notes by pattern (argument)?
|
||||
let notes = []
|
||||
let title_filter = '\v' . a:title_filter
|
||||
for [fname, title] in items(xolox#notes#get_fnames_and_titles(0))
|
||||
if title =~? title_filter
|
||||
call add(notes, [getftime(fname), title])
|
||||
endif
|
||||
endfor
|
||||
" Start note with "You have N note(s) [matching filter]".
|
||||
let readme = "You have "
|
||||
if empty(notes)
|
||||
let readme .= "no notes"
|
||||
elseif len(notes) == 1
|
||||
let readme .= "one note"
|
||||
else
|
||||
let readme .= len(notes) . " notes"
|
||||
endif
|
||||
if a:title_filter != ''
|
||||
let quote_format = xolox#notes#unicode_enabled() ? '‘%s’' : "`%s'"
|
||||
let readme .= " matching " . printf(quote_format, a:title_filter)
|
||||
endif
|
||||
" Explain the sorting of the notes.
|
||||
if empty(notes)
|
||||
let readme .= "."
|
||||
elseif len(notes) == 1
|
||||
let readme .= ", it's listed below."
|
||||
else
|
||||
let readme .= ". They're listed below grouped by the day they were edited, starting with your most recently edited note."
|
||||
endif
|
||||
" Add the generated text to the buffer.
|
||||
call setline(1, ["Recent notes", "", readme])
|
||||
" Reformat the text in the buffer to auto-wrap.
|
||||
normal Ggqq
|
||||
" Sort, group and format the list of (matching) notes.
|
||||
let last_date = ''
|
||||
let list_item_format = xolox#notes#unicode_enabled() ? ' • %s' : ' * %s'
|
||||
call sort(notes)
|
||||
call reverse(notes)
|
||||
let lines = []
|
||||
for [ftime, title] in notes
|
||||
let date = xolox#notes#friendly_date(ftime)
|
||||
if date != last_date
|
||||
call add(lines, '')
|
||||
call add(lines, substitute(date, '^\w', '\u\0', '') . ':')
|
||||
let last_date = date
|
||||
endif
|
||||
call add(lines, printf(list_item_format, title))
|
||||
endfor
|
||||
" Add the formatted list of notes to the buffer.
|
||||
call setline(line('$') + 1, lines)
|
||||
" Load the notes file type.
|
||||
call xolox#notes#set_filetype()
|
||||
let &l:statusline = bufname
|
||||
" Change the status line
|
||||
" Lock the buffer contents.
|
||||
call xolox#misc#buffer#lock()
|
||||
" And we're done!
|
||||
call xolox#misc#timer#stop("notes.vim %s: Generated %s in %s.", g:xolox#notes#version, bufname, starttime)
|
||||
endfunction
|
||||
|
||||
function! xolox#notes#recent#track() " {{{1
|
||||
let fname = expand('%:p')
|
||||
let indexfile = expand(g:notes_recentindex)
|
||||
call xolox#misc#msg#debug("notes.vim %s: Recording '%s' as most recent note in %s ..", g:xolox#notes#version, fname, indexfile)
|
||||
if writefile([fname], indexfile) == -1
|
||||
call xolox#misc#msg#warn("notes.vim %s: Failed to record most recent note in %s!", g:xolox#notes#version, indexfile)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! xolox#notes#recent#edit(bang) " {{{1
|
||||
" Edit the most recently edited (not necessarily changed) note.
|
||||
let indexfile = expand(g:notes_recentindex)
|
||||
call xolox#misc#msg#debug("notes.vim %s: Recalling most recent note from %s ..", g:xolox#notes#version, indexfile)
|
||||
try
|
||||
let fname = readfile(indexfile)[0]
|
||||
if empty(fname)
|
||||
throw "The index of recent notes is empty?!"
|
||||
endif
|
||||
catch
|
||||
call xolox#misc#msg#warn("notes.vim %s: Failed to recall most recent note from %s: %s", g:xolox#notes#version, indexfile, v:exception)
|
||||
return
|
||||
endtry
|
||||
call xolox#misc#msg#info("notes.vim %s: Editing most recent note '%s' ..", g:xolox#notes#version, fname)
|
||||
execute 'edit' . a:bang fnameescape(fname)
|
||||
call xolox#notes#set_filetype()
|
||||
endfunction
|
201
sources_non_forked/vim-notes/autoload/xolox/notes/tags.vim
Normal file
201
sources_non_forked/vim-notes/autoload/xolox/notes/tags.vim
Normal file
@ -0,0 +1,201 @@
|
||||
" Vim auto-load script
|
||||
" Author: Peter Odding <peter@peterodding.com>
|
||||
" Last Change: May 5, 2013
|
||||
" URL: http://peterodding.com/code/vim/notes/
|
||||
|
||||
if !exists('s:currently_tagged_notes')
|
||||
let s:currently_tagged_notes = {} " The in-memory representation of tags and the notes in which they're used.
|
||||
let s:previously_tagged_notes = {} " Copy of index as it is / should be now on disk (to detect changes).
|
||||
let s:last_disk_sync = 0 " Whether the on-disk representation of the tags has been read.
|
||||
let s:buffer_name = 'Tagged Notes' " The buffer name for the list of tagged notes.
|
||||
let s:loading_index = 0
|
||||
endif
|
||||
|
||||
function! xolox#notes#tags#load_index() " {{{1
|
||||
if s:loading_index
|
||||
" Guard against recursive calls.
|
||||
return s:currently_tagged_notes
|
||||
endif
|
||||
let starttime = xolox#misc#timer#start()
|
||||
let indexfile = expand(g:notes_tagsindex)
|
||||
let lastmodified = getftime(indexfile)
|
||||
if lastmodified == -1
|
||||
let s:loading_index = 1
|
||||
call xolox#notes#tags#create_index()
|
||||
let s:loading_index = 0
|
||||
elseif lastmodified > s:last_disk_sync
|
||||
let s:currently_tagged_notes = {}
|
||||
for line in readfile(indexfile)
|
||||
let filenames = split(line, "\t")
|
||||
if len(filenames) > 1
|
||||
let tagname = remove(filenames, 0)
|
||||
let s:currently_tagged_notes[tagname] = filenames
|
||||
endif
|
||||
endfor
|
||||
let s:previously_tagged_notes = deepcopy(s:currently_tagged_notes)
|
||||
let s:last_disk_sync = lastmodified
|
||||
call xolox#misc#timer#stop("notes.vim %s: Loaded tags index in %s.", g:xolox#notes#version, starttime)
|
||||
endif
|
||||
return s:currently_tagged_notes
|
||||
endfunction
|
||||
|
||||
function! xolox#notes#tags#create_index() " {{{1
|
||||
let exists = filereadable(expand(g:notes_tagsindex))
|
||||
let starttime = xolox#misc#timer#start()
|
||||
let filenames = xolox#notes#get_fnames(0)
|
||||
let s:currently_tagged_notes = {}
|
||||
for idx in range(len(filenames))
|
||||
if filereadable(filenames[idx])
|
||||
let title = xolox#notes#fname_to_title(filenames[idx])
|
||||
call xolox#misc#msg#info("notes.vim %s: Scanning note %i/%i: %s", g:xolox#notes#version, idx + 1, len(filenames), title)
|
||||
call xolox#notes#tags#scan_note(title, join(readfile(filenames[idx]), "\n"))
|
||||
endif
|
||||
endfor
|
||||
if xolox#notes#tags#save_index()
|
||||
let s:previously_tagged_notes = deepcopy(s:currently_tagged_notes)
|
||||
call xolox#misc#timer#stop('notes.vim %s: %s tags index in %s.', g:xolox#notes#version, exists ? "Updated" : "Created", starttime)
|
||||
else
|
||||
call xolox#misc#msg#warn("notes.vim %s: Failed to save tags index as %s!", g:xolox#notes#version, g:notes_tagsindex)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! xolox#notes#tags#save_index() " {{{1
|
||||
let indexfile = expand(g:notes_tagsindex)
|
||||
let existingfile = filereadable(indexfile)
|
||||
let nothingchanged = (s:currently_tagged_notes == s:previously_tagged_notes)
|
||||
if existingfile && nothingchanged
|
||||
call xolox#misc#msg#debug("notes.vim %s: Index not dirty so not saved.", g:xolox#notes#version)
|
||||
return 1 " Nothing to be done
|
||||
else
|
||||
let lines = []
|
||||
for [tagname, filenames] in items(s:currently_tagged_notes)
|
||||
call add(lines, join([tagname] + filenames, "\t"))
|
||||
endfor
|
||||
let status = writefile(lines, indexfile) == 0
|
||||
if status
|
||||
call xolox#misc#msg#debug("notes.vim %s: Index saved to %s.", g:xolox#notes#version, g:notes_tagsindex)
|
||||
let s:last_disk_sync = getftime(indexfile)
|
||||
else
|
||||
call xolox#misc#msg#debug("notes.vim %s: Failed to save index to %s.", g:xolox#notes#version, g:notes_tagsindex)
|
||||
endif
|
||||
return status
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! xolox#notes#tags#scan_note(title, text) " {{{1
|
||||
" Add a note to the tags index.
|
||||
call xolox#notes#tags#load_index()
|
||||
" Don't scan tags inside code blocks.
|
||||
let text = substitute(a:text, '{{{\w\+\_.\{-}}}}', '', 'g')
|
||||
" Split everything on whitespace.
|
||||
for token in split(text)
|
||||
" Match words that start with @ and don't contain { (BibTeX entries).
|
||||
if token =~ '^@\w' && token !~ '{'
|
||||
" Strip any trailing punctuation.
|
||||
let token = substitute(token[1:], '[[:punct:]]*$', '', '')
|
||||
if token != ''
|
||||
if !has_key(s:currently_tagged_notes, token)
|
||||
let s:currently_tagged_notes[token] = [a:title]
|
||||
elseif index(s:currently_tagged_notes[token], a:title) == -1
|
||||
" Keep the tags sorted.
|
||||
call xolox#misc#list#binsert(s:currently_tagged_notes[token], a:title, 1)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
function! xolox#notes#tags#forget_note(title) " {{{1
|
||||
" Remove a note from the tags index.
|
||||
call xolox#notes#tags#load_index()
|
||||
for tagname in keys(s:currently_tagged_notes)
|
||||
call filter(s:currently_tagged_notes[tagname], "v:val != a:title")
|
||||
if empty(s:currently_tagged_notes[tagname])
|
||||
unlet s:currently_tagged_notes[tagname]
|
||||
endif
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
function! xolox#notes#tags#show_tags(minsize) " {{{1
|
||||
" TODO Mappings to "zoom" in/out (show only big tags).
|
||||
let starttime = xolox#misc#timer#start()
|
||||
call xolox#notes#tags#load_index()
|
||||
let lines = [s:buffer_name, '']
|
||||
if empty(s:currently_tagged_notes)
|
||||
call add(lines, "You haven't used any tags yet!")
|
||||
else
|
||||
" Create a dictionary with note titles as keys.
|
||||
let unmatched = {}
|
||||
for title in xolox#notes#get_titles(0)
|
||||
let unmatched[title] = 1
|
||||
endfor
|
||||
let totalnotes = len(unmatched)
|
||||
" Group matching notes and remove them from the dictionary.
|
||||
let grouped_notes = []
|
||||
let numtags = 0
|
||||
for tagname in sort(keys(s:currently_tagged_notes), 1)
|
||||
let numnotes = len(s:currently_tagged_notes[tagname])
|
||||
if numnotes >= a:minsize
|
||||
let matched_notes = s:currently_tagged_notes[tagname]
|
||||
for title in matched_notes
|
||||
if has_key(unmatched, title)
|
||||
unlet unmatched[title]
|
||||
endif
|
||||
endfor
|
||||
call add(grouped_notes, {'name': tagname, 'notes': matched_notes})
|
||||
let numtags += 1
|
||||
endif
|
||||
endfor
|
||||
" Add a "fake tag" with all unmatched notes.
|
||||
if !empty(unmatched)
|
||||
call add(grouped_notes, {'name': "Unmatched notes", 'notes': keys(unmatched)})
|
||||
endif
|
||||
" Format the results as a note.
|
||||
let bullet = xolox#notes#get_bullet('*')
|
||||
for group in grouped_notes
|
||||
let tagname = group['name']
|
||||
let friendly_name = xolox#notes#tags#friendly_name(tagname)
|
||||
let numnotes = len(group['notes'])
|
||||
if numnotes >= a:minsize
|
||||
call extend(lines, ['', printf('# %s (%i note%s)', friendly_name, numnotes, numnotes == 1 ? '' : 's'), ''])
|
||||
for title in group['notes']
|
||||
let lastmodified = xolox#notes#friendly_date(getftime(xolox#notes#title_to_fname(title)))
|
||||
call add(lines, ' ' . bullet . ' ' . title . ' (last edited ' . lastmodified . ')')
|
||||
endfor
|
||||
endif
|
||||
endfor
|
||||
if a:minsize <= 1
|
||||
let message = printf("You've used %i %s in %i %s",
|
||||
\ numtags, numtags == 1 ? "tag" : "tags",
|
||||
\ totalnotes, totalnotes == 1 ? "note" : "notes")
|
||||
else
|
||||
let message = printf("There %s %i %s that %s been used at least %s times",
|
||||
\ numtags == 1 ? "is" : "are", numtags,
|
||||
\ numtags == 1 ? "tag" : "tags",
|
||||
\ numtags == 1 ? "has" : "have", a:minsize)
|
||||
endif
|
||||
let message .= ", " . (numtags == 1 ? "it's" : "they're")
|
||||
let message .= " listed below. Tags and notes are sorted alphabetically and after each note is the date when it was last modified."
|
||||
if !empty(unmatched)
|
||||
if a:minsize <= 1
|
||||
let message .= " At the bottom is a list of untagged notes."
|
||||
else
|
||||
let message .= " At the bottom is a list of unmatched notes."
|
||||
endif
|
||||
endif
|
||||
if numtags > 1 && !(&foldmethod == 'expr' && &foldenable)
|
||||
let message .= " You can enable text folding to get an overview of just the tag names and how many times they've been used."
|
||||
endif
|
||||
call insert(lines, message, 2)
|
||||
endif
|
||||
call xolox#misc#buffer#prepare(s:buffer_name)
|
||||
call setline(1, lines)
|
||||
call xolox#misc#buffer#lock()
|
||||
call xolox#notes#set_filetype()
|
||||
setlocal nospell wrap
|
||||
call xolox#misc#timer#stop('notes.vim %s: Generated [%s] in %s.', g:xolox#notes#version, s:buffer_name, starttime)
|
||||
endfunction
|
||||
|
||||
function! xolox#notes#tags#friendly_name(tagname) " {{{1
|
||||
return substitute(a:tagname, '\(\U\)\(\u\)', '\1 \2', 'g')
|
||||
endfunction
|
Reference in New Issue
Block a user