commit
dff977f50d
5 changed files with 448 additions and 0 deletions
@ -0,0 +1,5 @@ |
|||||
|
# notecrate |
||||
|
|
||||
|
## Requirements |
||||
|
|
||||
|
|
@ -0,0 +1,363 @@ |
|||||
|
function! notecrate#get_visual_selection() " {{{ |
||||
|
let [line_start, column_start] = getpos("'<")[1:2] |
||||
|
let [line_end, column_end] = getpos("'>")[1:2] |
||||
|
let lines = getline(line_start, line_end) |
||||
|
if len(lines) == 0 |
||||
|
return '' |
||||
|
endif |
||||
|
let lines[-1] = lines[-1][: column_end - (&selection == 'inclusive' ? 1 : 2)] |
||||
|
let lines[0] = lines[0][column_start - 1:] |
||||
|
return join(lines, "\n") |
||||
|
endfunction |
||||
|
|
||||
|
" }}} |
||||
|
function! notecrate#get_word_at_cursor() " {{{ |
||||
|
let l:word = expand('<cWORD>') |
||||
|
return l:word |
||||
|
endfunction |
||||
|
" }}} |
||||
|
function! notecrate#get_link_at_cursor() " {{{ |
||||
|
let l:regex = '\[\([^\]]*\)\](\([^)]*\))' |
||||
|
let l:line = getline('.') |
||||
|
let l:cursor = col('.') - 1 |
||||
|
let l:match = matchstrpos(l:line, l:regex, 0) |
||||
|
while 1 |
||||
|
if (l:match[1] == -1) |
||||
|
return '' |
||||
|
elseif l:match[1] <= l:cursor && l:cursor < l:match[2] |
||||
|
break |
||||
|
endif |
||||
|
let l:match = matchstrpos(l:line, l:regex, l:match[2] + 1) |
||||
|
endwhile |
||||
|
let l:matches = matchlist(l:match[0], l:regex) |
||||
|
return {'text': l:matches[1], 'dest': l:matches[2]} |
||||
|
endfunction |
||||
|
|
||||
|
" }}} |
||||
|
function! notecrate#generate_filename() " {{{ |
||||
|
return strftime("%Y%m%d%H%M%S") . ".md" |
||||
|
endfunction |
||||
|
|
||||
|
" }}} |
||||
|
function! notecrate#apply_template(title) " {{{ |
||||
|
let l:template = "# " . a:title . "\n\n\n---\n\n" |
||||
|
call setreg("l", l:template) |
||||
|
silent execute 'normal "lP4j' |
||||
|
call notecrate#update_backlinks() |
||||
|
endfunction |
||||
|
|
||||
|
" }}} |
||||
|
function! notecrate#convert() " {{{ |
||||
|
execute "normal! :w!\<CR>:!pushd " . b:notecrate_dir . "; bash convert.sh;\<CR>" |
||||
|
endfunction |
||||
|
|
||||
|
" }}} |
||||
|
function! notecrate#save() " {{{ |
||||
|
execute "normal! :!cd " . b:notecrate_dir . "; git add -A; git commit -m \"autocommit\"; git push;\<CR>" |
||||
|
endfunction |
||||
|
|
||||
|
" }}} |
||||
|
function! notecrate#todo_filter_view() " {{{ |
||||
|
execute "normal! :!cd " . b:notecrate_dir . "; git add -A; git commit -m \"autocommit\"; git push;\<CR>" |
||||
|
endfunction |
||||
|
|
||||
|
" }}} |
||||
|
function! notecrate#follow_link() " {{{ |
||||
|
let l:link = notecrate#get_link_at_cursor()" |
||||
|
if type(l:link) == 4 |
||||
|
if l:link['dest'] =~ '^.*\.md$' |
||||
|
call notecrate#open_note(l:link['dest']) |
||||
|
else |
||||
|
silent execute "open " . l:link['dest'] |
||||
|
endif |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
" }}} |
||||
|
function! notecrate#new_note(title, filename) " {{{ |
||||
|
let l:filename = expand('%:t') |
||||
|
while !isdirectory(expand(b:notecrate_dir)) |
||||
|
let choice = confirm('', b:notecrate_dir . " does not exist. Create? &Yes\n&No\n") |
||||
|
if choice == 1 |
||||
|
silent execute "!mkdir " . b:notecrate_dir |
||||
|
else |
||||
|
return 0 |
||||
|
endif |
||||
|
endwhile |
||||
|
let l:path = b:notecrate_dir . "/" . a:filename |
||||
|
call add(b:notecrate_history, l:filename) |
||||
|
silent execute "normal! :w\<CR>:e " . l:path . "\<CR>" |
||||
|
call notecrate#apply_template(a:title) |
||||
|
call notecrate#update_backlinks() |
||||
|
endfunction |
||||
|
|
||||
|
" }}} |
||||
|
function! notecrate#new_note_from_prompt() " {{{ |
||||
|
let l:title = input("Name of new note? ") |
||||
|
let l:filename = notecrate#generate_filename() |
||||
|
call notecrate#new_note(l:title, l:filename) |
||||
|
endfunction |
||||
|
|
||||
|
" }}} |
||||
|
function! notecrate#new_note_from_selection() " {{{ |
||||
|
let l:title = notecrate#get_visual_selection() |
||||
|
let l:filename = notecrate#generate_filename() |
||||
|
silent execute "normal! :'<,'>s/\\%V.*\\%V/[" . l:title . "](" . l:filename . ")/e\<CR>" |
||||
|
call notecrate#new_note(l:title, l:filename) |
||||
|
endfunction |
||||
|
|
||||
|
" }}} |
||||
|
function! notecrate#open_note(filename) " {{{ |
||||
|
let l:filename = expand('%:t') |
||||
|
let l:path = b:notecrate_dir . "/" . a:filename |
||||
|
if !filereadable(expand(l:path)) |
||||
|
echo "Note does't exist!" |
||||
|
return |
||||
|
endif |
||||
|
call add(b:notecrate_history, l:filename) |
||||
|
silent execute "e " . l:path |
||||
|
call notecrate#update_backlinks() |
||||
|
silent execute "normal! /^#\<CR>" |
||||
|
endfunction |
||||
|
|
||||
|
" }}} |
||||
|
function! notecrate#open_index() " {{{ |
||||
|
while !isdirectory(expand(b:notecrate_dir)) |
||||
|
let choice = confirm('', b:notecrate_dir . " does not exist. Create? &Yes\n&No\n") |
||||
|
if choice == 1 |
||||
|
silent execute "!mkdir " . b:notecrate_dir |
||||
|
else |
||||
|
return 0 |
||||
|
endif |
||||
|
endwhile |
||||
|
let l:filename = "index.md" |
||||
|
let l:path = b:notecrate_dir . "/" . l:filename |
||||
|
if !filereadable(expand(l:path)) |
||||
|
echo "Note does't exist!" |
||||
|
return |
||||
|
endif |
||||
|
silent execute "e " . l:path |
||||
|
call notecrate#update_backlinks() |
||||
|
silent execute "normal! /^#\<CR>" |
||||
|
endfunction |
||||
|
|
||||
|
" }}} |
||||
|
function! notecrate#open_previous() " {{{ |
||||
|
if len(b:notecrate_history) == 0 |
||||
|
return |
||||
|
endif |
||||
|
let l:filename = remove(b:notecrate_history, -1) |
||||
|
call notecrate#open_note(l:filename) |
||||
|
call remove(b:notecrate_history, -1) |
||||
|
endfunction |
||||
|
|
||||
|
" }}} |
||||
|
function! notecrate#get_title(filename) " {{{ |
||||
|
let l:regex = '^# \(\S.*\)$' |
||||
|
let l:path = b:notecrate_dir . "/" . a:filename |
||||
|
let l:lines = readfile(expand(l:path)) |
||||
|
let l:line = matchstr(l:lines, l:regex) |
||||
|
if l:line != "" |
||||
|
return matchlist(l:line, l:regex)[1] |
||||
|
endif |
||||
|
return '' |
||||
|
endfunction |
||||
|
|
||||
|
" }}} |
||||
|
function! notecrate#get_id(filename) " {{{ |
||||
|
return = matchstr(a:filename, '^.*\(\.md$\)\@=') |
||||
|
endfunction |
||||
|
|
||||
|
" }}} |
||||
|
function! notecrate#fzf_sink(sink_function) " {{{ |
||||
|
" let l:additional_options = get(a:, 1, {}) |
||||
|
let l:preview_options = { |
||||
|
\ 'sink' : function(a:sink_function), |
||||
|
\ 'down' : '~40%', |
||||
|
\ 'dir' : b:notecrate_dir, |
||||
|
\ 'options' : ['--exact', '--tiebreak=end'] |
||||
|
\ } |
||||
|
" call fzf#vim#ag("^(?=.)", fzf#vim#with_preview(l:preview_options)) |
||||
|
call fzf#vim#ag("^# ", fzf#vim#with_preview(l:preview_options)) |
||||
|
endfunction |
||||
|
|
||||
|
" }}} |
||||
|
function! notecrate#search_open() " {{{ |
||||
|
call notecrate#fzf_sink('notecrate#open_from_fzf') |
||||
|
endfunction |
||||
|
function! notecrate#open_from_fzf(line) |
||||
|
let filename = substitute(a:line, ":[0-9]\*:[0-9]\*:.\*$", "", "") |
||||
|
call notecrate#open_note(filename) |
||||
|
endfunction |
||||
|
|
||||
|
" }}} |
||||
|
function! notecrate#search_insert_link() " {{{ |
||||
|
call notecrate#fzf_sink('notecrate#insert_link_from_fzf') |
||||
|
endfunction |
||||
|
function! notecrate#insert_link_from_fzf(line) |
||||
|
let l:filename = substitute(a:line, ":[0-9]\*:[0-9]\*:.\*$", "", "") |
||||
|
let l:title = notecrate#get_title(filename) |
||||
|
execute "normal! a[" . l:title . "](" . l:filename . ")\<Esc>" |
||||
|
endfunction |
||||
|
|
||||
|
" }}} |
||||
|
function! notecrate#search_insert_link_selection() " {{{ |
||||
|
call notecrate#fzf_sink('notecrate#insert_link_from_fzf_selection') |
||||
|
endfunction |
||||
|
function! notecrate#insert_link_from_fzf_selection(line) |
||||
|
let l:filename = substitute(a:line, ":[0-9]\*:[0-9]\*:.\*$", "", "") |
||||
|
let l:title = notecrate#get_visual_selection() |
||||
|
silent execute "normal! :'<,'>s/\\%V.*\\%V/[" . l:title . "](" . l:filename . ")/e\<CR>" |
||||
|
endfunction |
||||
|
|
||||
|
" }}} |
||||
|
function! notecrate#grep(pattern) " {{{ |
||||
|
let l:files = [] |
||||
|
try |
||||
|
silent execute 'vimgrep /' . a:pattern . '/j ' . b:notecrate_dir . '/*.md' |
||||
|
catch /^Vim\%((\a\+)\)\=:E480/ " No Match |
||||
|
endtry |
||||
|
for d in getqflist() |
||||
|
let l:filename = fnamemodify(bufname(d.bufnr), ":t") |
||||
|
call add(l:files, l:filename) |
||||
|
endfor |
||||
|
call uniq(l:files) |
||||
|
return l:files |
||||
|
endfunction |
||||
|
|
||||
|
" }}} |
||||
|
function! notecrate#grep_links(pattern) " {{{ |
||||
|
let l:files = notecrate#grep(a:pattern) |
||||
|
let l:links = [] |
||||
|
for filename in l:files |
||||
|
if filename != "index.md" |
||||
|
let l:title = notecrate#get_title(filename) |
||||
|
call add(l:links, "* [" . l:title . "](" . filename . ")") |
||||
|
endif |
||||
|
endfor |
||||
|
return sort(l:links) |
||||
|
endfunction |
||||
|
|
||||
|
" }}} |
||||
|
function! notecrate#update_backlinks() " {{{ |
||||
|
let l:filename = expand('%:t') |
||||
|
if l:filename == "index.md" |
||||
|
return |
||||
|
endif |
||||
|
let l:pattern = '\[[^\]]*\](' . l:filename . ')\(\(.*\n\)*---\)\@=' |
||||
|
let l:links = notecrate#grep_links(l:pattern) |
||||
|
let l:backlinks = "---\n\n" |
||||
|
if len(l:links) == 0 |
||||
|
let l:backlinks = l:backlinks . "* [Index](index.md)" |
||||
|
else |
||||
|
let l:backlinks = l:backlinks . join(uniq(l:links), "\n") . "\n\n* [Index](index.md)" |
||||
|
endif |
||||
|
let l:oldreg = getreg("0") |
||||
|
call setreg("l", l:backlinks) |
||||
|
silent execute "normal! /^---\<CR>vG$\"lp" |
||||
|
call setreg("0", l:oldreg) |
||||
|
call setreg("", l:oldreg) |
||||
|
endfunction |
||||
|
|
||||
|
" }}} |
||||
|
function! notecrate#delete_links(filename) " {{{ |
||||
|
execute "!" . g:gsed_command . " -i 's/\\[\\([^]]*\\)\\](" . a:filename . ")/\\1/g' " . b:notecrate_dir . "/*md" |
||||
|
endfunction |
||||
|
|
||||
|
" }}} |
||||
|
function! notecrate#delete_note() " {{{ |
||||
|
let l:filename = expand('%:t') |
||||
|
let l:path = b:notecrate_dir . "/" . l:filename |
||||
|
let choice = confirm('', "Delete " . l:filename . "? &Yes\n&No\n") |
||||
|
if choice == 1 |
||||
|
call delete(l:path) |
||||
|
call notecrate#delete_links(l:filename) |
||||
|
silent execute "!rm " l:path |
||||
|
silent execute "normal :bp!\<CR>" |
||||
|
endif |
||||
|
endfunction |
||||
|
|
||||
|
" }}} |
||||
|
function! notecrate#indent_level(lnum) " {{{ |
||||
|
return indent(a:lnum) / &shiftwidth |
||||
|
endfunction |
||||
|
|
||||
|
" }}} |
||||
|
function! notecrate#heading_depth(lnum) " {{{ |
||||
|
let l:depth=0 |
||||
|
let l:thisLine = getline(a:lnum) |
||||
|
if l:thisLine =~ '^#\+\s\+' |
||||
|
let l:hashCount = len(matchstr(thisLine, '^#\{1,6}')) |
||||
|
if l:hashCount > 0 |
||||
|
let l:depth = hashCount - 1 |
||||
|
endif |
||||
|
elseif l:thisLine != '' |
||||
|
let l:nextLine = getline(a:lnum + 1) |
||||
|
if l:nextLine =~ '^=\+\s*$' |
||||
|
let l:depth = 1 |
||||
|
elseif l:nextLine =~ '^-\+\s*$' |
||||
|
let l:depth = 2 |
||||
|
endif |
||||
|
endif |
||||
|
return l:depth |
||||
|
endfunction |
||||
|
|
||||
|
" }}} |
||||
|
function! notecrate#nested_markdown_folds(lnum) " {{{ |
||||
|
let l:thisLine = getline(a:lnum) |
||||
|
let l:thisDepth = notecrate#heading_depth(a:lnum) |
||||
|
let l:thisIndent = notecrate#indent_level(a:lnum) |
||||
|
let l:prevLine = getline(a:lnum - 1) |
||||
|
let l:prevIndent = notecrate#indent_level(a:lnum - 1) |
||||
|
let l:nextLine = getline(a:lnum + 1) |
||||
|
let l:nextIndent = notecrate#indent_level(a:lnum + 1) |
||||
|
let l:nextDepth = notecrate#heading_depth(a:lnum + 1) |
||||
|
|
||||
|
if l:thisLine =~ '^\s*<' && l:prevLine =~ '^\s*$' |
||||
|
return 1 |
||||
|
endif |
||||
|
|
||||
|
if l:thisLine =~ '^\s*$' && l:prevLine =~ '^\s*<' |
||||
|
return 0 |
||||
|
endif |
||||
|
|
||||
|
if l:nextLine =~ '^---$' || l:thisLine =~ '^---$' |
||||
|
return 0 |
||||
|
endif |
||||
|
|
||||
|
if l:thisLine =~ '^\s*$' && l:nextDepth > 0 |
||||
|
return -1 |
||||
|
endif |
||||
|
|
||||
|
if l:thisDepth > 0 |
||||
|
return ">".l:thisDepth |
||||
|
endif |
||||
|
|
||||
|
if l:nextIndent == l:thisIndent |
||||
|
return "=" |
||||
|
endif |
||||
|
|
||||
|
if l:nextIndent > l:thisIndent |
||||
|
let l:dif = l:nextIndent - l:thisIndent |
||||
|
return "a".l:dif |
||||
|
endif |
||||
|
|
||||
|
if l:nextIndent < l:thisIndent |
||||
|
let l:dif = l:thisIndent - l:nextIndent |
||||
|
return "s".l:dif |
||||
|
endif |
||||
|
|
||||
|
endfunction |
||||
|
|
||||
|
" }}} |
||||
|
function! notecrate#fold_text() " {{{ |
||||
|
if getline(v:foldstart) =~ "^\s*<" |
||||
|
return "<>" . repeat(" ", winwidth(0)) |
||||
|
endif |
||||
|
let l:ret = repeat(" ", indent(v:foldstart)) . trim(getline(v:foldstart))[0:-1] . " +" . repeat(" ", winwidth(0)) |
||||
|
let l:ret = substitute(l:ret, ' \S\+:\S\+', '', 'g') |
||||
|
let l:ret = substitute(l:ret, '\*\*', '', 'g') |
||||
|
return l:ret |
||||
|
endfunction |
||||
|
|
||||
|
" }}} |
@ -0,0 +1,34 @@ |
|||||
|
setlocal textwidth=79 |
||||
|
setlocal autowriteall |
||||
|
setlocal comments+=b:* |
||||
|
setlocal foldlevel=3 |
||||
|
setlocal formatoptions=cro |
||||
|
|
||||
|
command! SearchOpen :call notecrate#base#search_open() |
||||
|
command! SearchInsertLink :call notecrate#base#search_insert_link() |
||||
|
command! UpdateBacklinks :call notecrate#base#update_backlinks() |
||||
|
command! NewNote :call notecrate#base#new_note_from_prompt() |
||||
|
command! DeleteNote :call notecrate#base#delete_note() |
||||
|
command! Convert :call notecrate#base#convert() |
||||
|
command! Save :call notecrate#base#save() |
||||
|
|
||||
|
" inoremap <buffer> <Esc> <Esc>mmgqis`m |
||||
|
nnoremap <buffer> <leader>c :Convert<CR> |
||||
|
nnoremap <buffer> <leader>o :SearchOpen<CR> |
||||
|
nnoremap <buffer> <leader>i :SearchInsertLink<CR> |
||||
|
nnoremap <buffer> <leader>b :UpdateBacklinks<CR> |
||||
|
nnoremap <buffer> <leader>n :NewNote<CR> |
||||
|
nnoremap <buffer> <leader>d :DeleteNote<CR> |
||||
|
nnoremap <buffer> <leader>s :Convert<CR>:Save<CR> |
||||
|
nnoremap <buffer> <CR> :call notecrate#base#follow_link()<CR> |
||||
|
vnoremap <buffer> <CR> :call notecrate#base#new_note_from_selection()<CR> |
||||
|
nnoremap <buffer> <backspace> :call notecrate#base#open_previous()<CR> |
||||
|
nnoremap <buffer> <S-j> /\[[^\]]*\]([^)]*)<CR>:noh<CR> |
||||
|
nnoremap <buffer> <S-l> /\[[^\]]*\]([^)]*)<CR>:noh<CR> |
||||
|
nnoremap <buffer> <Tab> /\[[^\]]*\]([^)]*)<CR>:noh<CR> |
||||
|
nnoremap <buffer> <S-Tab> /\[[^\]]*\]([^)]*)<CR>NN:noh<CR> |
||||
|
nnoremap <buffer> <S-h> /\[[^\]]*\]([^)]*)<CR>NN:noh<CR> |
||||
|
nnoremap <buffer> <S-k> /\[[^\]]*\]([^)]*)<CR>NN:noh<CR> |
||||
|
vnoremap <buffer> <leader>i :call notecrate#base#search_insert_link_selection()<CR> |
||||
|
inoremap <buffer> <Tab> <C-t> |
||||
|
inoremap <buffer> <S-Tab> <C-d> |
@ -0,0 +1,9 @@ |
|||||
|
if !exists("g:notecrate_dirs") |
||||
|
let g:notecrate_dirs = { |
||||
|
\ "notes": { "prefix": "n", "dir": "~/notecrate"} |
||||
|
\ } |
||||
|
endif |
||||
|
for [key, value] in items(g:notecrate_dirs) |
||||
|
execute "autocmd BufRead,BufNewFile " . value["dir"] . "/*.md set filetype=notecrate syntax=notecrate" |
||||
|
execute "normal! :nnoremap <leader>w" . value["prefix"] . " :e " . value["dir"] . "/index.md<CR>:let b:notecrate_dir = \"" . value["dir"] . "\"<CR>:let b:notecrate_history = []<CR>\<CR>" |
||||
|
endfor |
@ -0,0 +1,37 @@ |
|||||
|
setlocal foldmethod=expr |
||||
|
setlocal foldexpr=notecrate#base#nested_markdown_folds(v:lnum) |
||||
|
setlocal foldtext=notecrate#base#fold_text() |
||||
|
setlocal conceallevel=2 |
||||
|
set comments=b:* |
||||
|
setlocal nowrap |
||||
|
|
||||
|
syn match NotecrateLinkInternal /\(\](\)\@<=[^()]*\()\)\@=/ |
||||
|
syn match NotecrateLinkConceal /!*\[\+\([^\]]*](\)\@=/ conceal |
||||
|
syn match NotecrateLinkConceal /\]\+\((\)\@=/ conceal |
||||
|
syn match NotecrateLinkConceal /\(\[[^\]]*\]\)\@<=([^)]*)/ conceal contains=NotecrateLinkInternal |
||||
|
syn match NotecrateLink /\(\[\)\@<=[^\[\]]*\(\](\)\@=/ |
||||
|
syn match NotecrateLinkImage /\(!\[\+\)\@<=[^\[\]]*\(\]\+\)\@=/ |
||||
|
syn match NotecrateHeader1 /\(^# \)\@<=.*/ |
||||
|
syn match NotecrateHeader2 /\(^##\+ \)\@<=.*/ |
||||
|
syn match NotecrateRule /^---\+/ |
||||
|
syn region NotecrateFrontCustomMatter start=/\%^---/ end=/^---/ |
||||
|
syn region NotecrateCode start=/^```/ end=/^```/ |
||||
|
" syn match NotecrateBoldConceal /\*\*/ conceal containedin=ALL |
||||
|
syn match NotecrateBoldConceal /\*\*/ containedin=ALL |
||||
|
syn region NotecrateBold start=/\*\*/ end=/\*\*/ contains=NotecrateBoldConceal keepend |
||||
|
syn match NotecrateQuote /^>.*$/ |
||||
|
syn match NotecrateTag /#[^# ]\S*/ |
||||
|
|
||||
|
hi def link NotecrateBold base2 |
||||
|
hi def link NotecrateTag cyanu |
||||
|
hi def link NotecrateCode red |
||||
|
hi def link NotecrateFrontCustomMatter base01 |
||||
|
hi def link NotecrateHeader1 base3u |
||||
|
hi def link NotecrateHeader2 base1u |
||||
|
hi def link NotecrateLink blueu |
||||
|
hi def link NotecrateLinkConceal blue |
||||
|
hi def link NotecrateLinkImage redu |
||||
|
hi def link NotecrateLinkInternal orangeu |
||||
|
hi def link NotecrateList base2 |
||||
|
hi def link NotecrateQuote cyan |
||||
|
hi def link NotecrateRule base01 |
Reference in new issue