Skip to content

Instantly share code, notes, and snippets.

@mg979
Last active September 15, 2021 17:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mg979/b5bef1a64f7ce57fba45a83f6ea147d9 to your computer and use it in GitHub Desktop.
Save mg979/b5bef1a64f7ce57fba45a83f6ea147d9 to your computer and use it in GitHub Desktop.
" ========================================================================///
" Description: simple bookmarks system using uppercase marks and quickfix
" File: projectmarks.vim
" Author: Gianmaria Bajo <mg1979.git@gmail.com>
" Credits: https://www.reddit.com/r/vim/comments/pngb4j/what_is_the_best_way_to_manage_bookmarks_per/
" License: MIT
" Created: mer 15 settembre 2021 17:00:32
" Modified: mer 15 settembre 2021 17:00:32
" ========================================================================///
" GUARD {{{1
if !exists('*bufadd') || exists('g:loaded_projectmarks')
finish
endif
let g:loaded_projectmarks = 1
let s:save_cpo = &cpo
set cpo&vim
" }}}
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Command: ProjectMarks [!]
"
" Creates or updates a .projectmarks file, that stores uppercase marks from
" files belonging to the current root directory.
" When this file exists, it is updated on every BufWritePost, or after the user
" MarkChanged autocommand.
"
" After the command is run, the quickfix list is populated with the uppercase
" marks belonging to the project.
"
" If ProjectMarks is called with BANG, the .projectmarks file is deleted, and
" the project won't be tracked anymore.
"
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
command! -bang ProjectMarks if <bang>0 | silent! call delete('.projectmarks')
\| else | call s:update_projectmarks(1) | endif
" -----------------------------------------------------------------------------
augroup projectmarks
au!
au BufEnter,WinEnter * if getcwd() != s:cwd | call s:set_marks() | endif
au BufWritePost * call s:update_projectmarks(0)
au User MarkChanged call s:update_projectmarks(0)
au VimEnter * call s:set_marks()
augroup END
" -----------------------------------------------------------------------------
let s:cwd = getcwd()
let s:entry = { l, c, f -> {'line': l, 'col': c, 'file': f} }
" -----------------------------------------------------------------------------
fun! s:set_marks()
let s:cwd = getcwd()
if !filereadable('.projectmarks')
return
endif
let dict = json_decode(join(readfile('.projectmarks')))
for k in keys(dict)
let m = dict[k]
call setpos("'". k, [bufadd(m.file), m.line, m.col, 0])
endfor
endfun
" -----------------------------------------------------------------------------
fun! s:update_projectmarks(qf)
if !a:qf && !filereadable('.projectmarks')
return
endif
let s:cwd = getcwd()
let marks = filter(split(execute('marks'), '\n'), 'v:val =~ "^\\s*\\u"')
let dict = {}
for m in marks
let l = split(m)
let [m, l, c, pos] = [l[0], l[1], l[2], l[3:]]
if getpos("'" . m)[0] == bufnr()
" mark is in this file
let dict[m] = s:entry(l, c, expand('%:p'))
elseif filereadable(join(pos))
" mark is in another file
if fnamemodify(join(pos), ':p') =~ getcwd()
let dict[m] = s:entry(l, c, join(pos))
endif
endif
endfor
call writefile([json_encode(dict)], '.projectmarks')
if a:qf
let qflines = []
for k in keys(dict)
let m = dict[k]
let qflines += [printf("%s:%s:%s:%s", m.file, m.line, m.col, 'Mark '.k)]
endfor
lgetexpr qflines
call setloclist(0, [], 'a', {'title': 'Project marks'})
endif
endfun
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Restore previous external compatibility options {{{1
let &cpo = s:save_cpo
unlet s:save_cpo
" vim: et sw=4 ts=4 sts=4 fdm=marker
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment