1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-01-23 07:20:04 +08:00

feat(bookmarks): add new bookmark plugin

This commit is contained in:
Eric Wong 2024-03-29 00:02:30 +08:00
parent ea2dea6fdc
commit 180493c1b5
33 changed files with 239 additions and 2509 deletions

View File

@ -26,7 +26,7 @@ function! SpaceVim#layers#tools#plugins() abort
call add(plugins, [g:_spacevim_root_dir . 'bundle/calendar.vim',{ 'on_cmd' : 'Calendar'}])
call add(plugins, ['junegunn/limelight.vim', { 'on_cmd' : 'Limelight'}])
call add(plugins, ['junegunn/goyo.vim', { 'on_cmd' : 'Goyo', 'loadconf' : 1}])
call add(plugins, [g:_spacevim_root_dir . 'bundle/vim-bookmarks',
call add(plugins, [g:_spacevim_root_dir . 'bundle/bookmarks.vim',
\ {'merged': 0,
\ 'loadconf_before' : 1}])
if s:CMP.has('python3')

View File

@ -0,0 +1,6 @@
{
"name": "bookmarks",
"description": "bookmark plugin for neovim and vim.",
"author": "Eric Wong"
}

View File

@ -0,0 +1,122 @@
if exists('s:bookmarks')
finish
endif
let s:FILE = SpaceVim#api#import('file')
let s:NT = SpaceVim#api#import('notify')
let s:bookmarks = bookmarks#cache#read()
function! bookmarks#toggle() abort
let file = s:FILE.unify_path(expand('%'), ':p')
let lnum = line('.')
if has_key(s:bookmarks, file) && has_key(s:bookmarks[file], lnum)
call bookmarks#delete(file, lnum)
else
call bookmarks#add(file, lnum, getline('.'))
endif
endfunction
function! bookmarks#annotate() abort
let annotation = input('Annotation:')
if !empty(annotation)
let file = s:FILE.unify_path(expand('%'), ':p')
let lnum = line('.')
call bookmarks#add(file, lnum, annotation)
else
call s:NT.notify('empty annotation, skipped!')
endif
endfunction
function! bookmarks#get_all_bookmarks() abort
return deepcopy(s:bookmarks)
endfunction
function! bookmarks#add(file, lnum, text, ...) abort
if !has_key(s:bookmarks, a:file)
let s:bookmarks[a:file] = {}
endif
let s:bookmarks[a:file][a:lnum] = {
\ 'text' : a:text,
\ 'file' : a:file,
\ 'lnum' : a:lnum,
\ 'signid' : bookmarks#sign#add(a:file, a:lnum)
\ }
call bookmarks#cache#write(s:bookmarks)
endfunction
function! bookmarks#delete(file, lnum) abort
if has_key(s:bookmarks, a:file) && has_key(s:bookmarks[a:file], a:lnum)
exe 'sign unplace ' . s:bookmarks[a:file][a:lnum].signid
unlet s:bookmarks[a:file][a:lnum]
call bookmarks#cache#write(s:bookmarks)
endif
endfunction
function! s:jump_to_bookmark(bookmark) abort
exe 'e ' . a:bookmark.file
exe a:bookmark.lnum
endfunction
function! bookmarks#next() abort
let file = s:FILE.unify_path(expand('%'), ':p')
if has_key(s:bookmarks, file)
for lnum in keys(s:bookmarks[file])
if lnum > line('.')
call s:jump_to_bookmark(s:bookmarks[file][lnum])
endif
endfor
endif
endfunction
function! bookmarks#showall() abort
let qf = []
for [f, nrs] in items(s:bookmarks)
for [nr, bm] in items(nrs)
call add(qf, {
\ 'filename' : f,
\ 'lnum' : nr,
\ 'text' : bm.text,
\ })
endfor
endfor
call setqflist([], 'r', {
\ 'title' : 'Bookmarks',
\ 'items' : qf,
\ })
botright copen
endfunction
function! bookmarks#on_enter_buffer() abort
if get(b:, 'bookmarks_init', v:false) || empty(bufname()) || !empty(&buftype)
return
endif
let file = s:FILE.unify_path(expand('%'), ':p')
if has_key(s:bookmarks, file)
for lnum in keys(s:bookmarks[file])
let s:bookmarks[file][lnum].signid = bookmarks#sign#add(file, lnum)
endfor
endif
let b:bookmarks_init = v:true
endfunction
function! bookmarks#clear() abort
let file = s:FILE.unify_path(expand('%'), ':p')
if has_key(s:bookmarks, file)
for lnum in keys(s:bookmarks[file])
call bookmarks#delete(file, lnum)
endfor
endif
endfunction

View File

@ -0,0 +1,19 @@
let s:cache_path = g:spacevim_data_dir . 'SpaceVim/bookmarks.json'
function! bookmarks#cache#write(data) abort
call writefile([json_encode(a:data)], s:cache_path)
endfunction
function! bookmarks#cache#read() abort
if filereadable(s:cache_path)
let data = join(readfile(s:cache_path), '')
if data !=# ''
return json_decode(data)
else
return {}
endif
else
return {}
endif
endfunction

View File

@ -0,0 +1,8 @@
let s:LOGGER = SpaceVim#logger#derive('bookmarks')
function! bookmarks#logger#info(msg) abort
call s:LOGGER.info(a:msg)
endfunction

View File

@ -0,0 +1,19 @@
"=============================================================================
" sign.vim --- sign for bookmarks
" Copyright (c) 2016-2019 Wang Shidong & Contributors
" Author: Wang Shidong < wsdjeg@outlook.com >
" URL: https://spacevim.org
" License: GPLv3
"=============================================================================
let s:sign_name = 'bookmarks'
call sign_define(s:sign_name, {
\ 'text' : '=>',
\ 'texthl' : 'Normal'
\ })
function! bookmarks#sign#add(file, lnum) abort
return sign_place(0, '', s:sign_name, a:file, {'lnum':a:lnum} )
endfunction

View File

@ -0,0 +1,30 @@
*bookmarks.txt* bookmark plugin for neovim and vim.
Eric Wong *bookmarks*
==============================================================================
CONTENTS *bookmarks-contents*
1. Commands.............................................|bookmarks-commands|
==============================================================================
COMMANDS *bookmarks-commands*
:BookmarkToggle *:BookmarkToggle*
toggle bookmark of cursor position
:BookmarkAnnotate *:BookmarkAnnotate*
Add bookmark with annotation
:BookmarkNext *:BookmarkNext*
Jump to next bookmark in current buffer.
:BookmarkPrev *:BookmarkPrev*
Jump to previous bookmark in current buffer.
:BookmarkClear *:BookmarkClear*
clear all bookmarks in current buffer.
:BookmarkShowAll *:BookmarkShowAll*
show all bookmarks in quickfix windows.
vim:tw=78:ts=8:ft=help:norl:

View File

@ -0,0 +1,24 @@
""
" toggle bookmark of cursor position
command! BookmarkToggle call bookmarks#toggle()
""
" Add bookmark with annotation
command! BookmarkAnnotate call bookmarks#annotate()
""
" Jump to next bookmark in current buffer.
command! BookmarkNext call bookmarks#next()
""
" Jump to previous bookmark in current buffer.
command! BookmarkPrev call bookmarks#previous()
""
" clear all bookmarks in current buffer.
command! BookmarkClear call bookmarks#clear()
""
" show all bookmarks in quickfix windows.
command! BookmarkShowAll call bookmarks#showall()
augroup bookmarks
autocmd!
autocmd BufEnter * call bookmarks#on_enter_buffer()
augroup END

View File

@ -1,5 +1,5 @@
{
"name": "git",
"description": "Git support in vim",
"author": "Wang Shidong"
"author": "Wang Shidong & Mattes Groeger"
}

View File

@ -1,42 +0,0 @@
# Contributing
If you'd like to contribute to the project, you can use the usual github pull-request flow:
1. Fork the project
2. Make your change/addition, preferably in a separate branch
3. Test the new behaviour and make sure all existing tests pass
4. Issue a pull request with a description of your feature/bugfix
## Github Issues
When reporting a bug make sure you search the existing github issues for the same/similar issues. If you find one, feel free to add a `+1` comment with any additional information that may help us solve the issue.
When creating a new issue be sure to state the following:
* Steps to reproduce the bug
* The version of vim you are using
* The version of vim-bookmarks you are using
## Coding Conventions
* Use 2 space indents
* Don't use abbreviated keywords - e.g. use `endfunction`, not `endfun` (there's always room for more fun!)
* Don't use `l:` prefixes for variables unless actually required (i.e. almost never)
* Code for maintainability
## Testing
This project uses [vim-flavor](https://github.com/kana/vim-flavor) and [vim-vspec](https://github.com/kana/vim-vspec) to test its behaviour. All logic is extracted into autoload files which are fully tested. The tests can be found in the `t` folder. The tests are written in vim script as well. Tests are also executed on Travis-CI to make sure there are no regressions.
Install bundler first:
```
$ gem install bundler
```
If you already have the `bundle` command (check it out with `which bundle`), you don't need this step. Afterwards, it should be as simple as:
```
$ bundle install
$ bundle exec vim-flavor test
```

View File

@ -1,21 +0,0 @@
The MIT License
Copyright (c) 2014 Mattes Groeger
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -1,317 +0,0 @@
## vim-bookmarks [![Build Status](https://travis-ci.org/MattesGroeger/vim-bookmarks.svg)](https://travis-ci.org/MattesGroeger/vim-bookmarks) [![Release](http://img.shields.io/github/release/MattesGroeger/vim-bookmarks.svg)](https://github.com/MattesGroeger/vim-bookmarks/releases) [![Release](http://img.shields.io/github/issues/MattesGroeger/vim-bookmarks.svg)](https://github.com/MattesGroeger/vim-bookmarks/issues)
This vim plugin allows toggling bookmarks per line. A quickfix window gives access to all bookmarks. Annotations can be added as well. These are special bookmarks with a comment attached. They are useful for preparing code reviews. All bookmarks will be restored on the next startup.
![Preview](https://raw.github.com/MattesGroeger/vim-bookmarks/master/preview.gif)
#### Bright Colors Example
[![Screenshot Bright Colors](https://raw.github.com/MattesGroeger/vim-bookmarks/master/screenshot-bright-small.png)](https://raw.github.com/MattesGroeger/vim-bookmarks/master/screenshot-bright.png)
```viml
highlight BookmarkSign ctermbg=NONE ctermfg=160
highlight BookmarkLine ctermbg=194 ctermfg=NONE
let g:bookmark_sign = '♥'
let g:bookmark_highlight_lines = 1
```
### Features
* Toggle bookmarks per line ⚑
* Add annotations per line ☰
* Navigate all bookmarks with quickfix window
* Bookmarks will be restored on next startup
* [Bookmarks per working directory](https://github.com/MattesGroeger/vim-bookmarks#bookmarks-per-working-directory) (optional)
* Fully customisable (signs, sign column, highlights, mappings)
* Integrates with [Unite's](https://github.com/Shougo/unite.vim) quickfix source if installed
* Integrates with [ctrlp.vim](https://github.com/ctrlpvim/ctrlp.vim) if installed
* Works independently from [vim marks](http://vim.wikia.com/wiki/Using_marks)
## Installation
Before installation, please check your Vim supports signs by running `:echo has('signs')`. `1` means you're all set; `0` means you need to install a Vim with signs support. If you're compiling Vim yourself you need the 'big' or 'huge' feature set. [MacVim][] supports signs.
Use your favorite plugin manager:
* [Pathogen][]
* `git clone https://github.com/MattesGroeger/vim-bookmarks.git ~/.vim/bundle/vim-bookmarks`
* [Vundle][]
1. Add `Plugin 'MattesGroeger/vim-bookmarks'` to .vimrc
2. Run `:PluginInstall`
* [NeoBundle][]
1. Add `NeoBundle 'MattesGroeger/vim-bookmarks'` to .vimrc
2. Run `:NeoBundleInstall`
* [vim-plug][vimplug]
1. Add `Plug 'MattesGroeger/vim-bookmarks'` to .vimrc
2. Run `:PlugInstall`
## Usage
After installation you can directly start using it. You can do this by either using the default shortcuts or the commands:
| Action | Shortcut | Command |
|-------------------------------------------------|-------------|------------------------------|
| Add/remove bookmark at current line | `mm` | `:BookmarkToggle` |
| Add/edit/remove annotation at current line | `mi` | `:BookmarkAnnotate <TEXT>` |
| Jump to next bookmark in buffer | `mn` | `:BookmarkNext` |
| Jump to previous bookmark in buffer | `mp` | `:BookmarkPrev` |
| Show all bookmarks (toggle) | `ma` | `:BookmarkShowAll` |
| Clear bookmarks in current buffer only | `mc` | `:BookmarkClear` |
| Clear bookmarks in all buffers | `mx` | `:BookmarkClearAll` |
| Move up bookmark at current line | `[count]mkk`| `:BookmarkMoveUp [<COUNT>]` |
| Move down bookmark at current line | `[count]mjj`| `:BookmarkMoveDown [<COUNT>]`|
| Move bookmark at current line to another line | `[count]mg` | `:BookmarkMoveToLine <LINE>` |
| Save all bookmarks to a file | | `:BookmarkSave <FILE_PATH>` |
| Load bookmarks from a file | | `:BookmarkLoad <FILE_PATH>` |
You can change the shortcuts as you like, just read on...
## Customization
### Key Bindings
You can overwrite any of the default mappings. Just put the following into your `~/.vimrc` and adjust as you like:
```viml
nmap <Leader><Leader> <Plug>BookmarkToggle
nmap <Leader>i <Plug>BookmarkAnnotate
nmap <Leader>a <Plug>BookmarkShowAll
nmap <Leader>j <Plug>BookmarkNext
nmap <Leader>k <Plug>BookmarkPrev
nmap <Leader>c <Plug>BookmarkClear
nmap <Leader>x <Plug>BookmarkClearAll
nmap <Leader>kk <Plug>BookmarkMoveUp
nmap <Leader>jj <Plug>BookmarkMoveDown
nmap <Leader>g <Plug>BookmarkMoveToLine
```
You can disable all default key bindings by setting the following in your `~/.vimrc`:
```viml
let g:bookmark_no_default_key_mappings = 1
```
### Colors
Overwrite the default hightlight groups by adding this to your colorscheme or `.vimrc`:
```viml
highlight BookmarkSign ctermbg=whatever ctermfg=whatever
highlight BookmarkAnnotationSign ctermbg=whatever ctermfg=whatever
highlight BookmarkLine ctermbg=whatever ctermfg=whatever
highlight BookmarkAnnotationLine ctermbg=whatever ctermfg=whatever
```
### Options
Put any of the following options into your `~/.vimrc` in order to overwrite the default behaviour.
| Option | Default | Description |
|------------------------------------------------|--------------------------|---------------------------------------------------------|
| `let g:bookmark_sign = '>>'` | ⚑ | Sets bookmark icon for sign column |
| `let g:bookmark_annotation_sign = '##'` | ☰ | Sets bookmark annotation icon for sign column |
| `let g:bookmark_save_per_working_dir = 1` | 0 | Save bookmarks per working dir, the folder you opened vim from |
| `let g:bookmark_auto_save = 0` | 1 | Enables/disables automatic saving for bookmarks |
| `let g:bookmark_manage_per_buffer = 1` | 0 | Save bookmarks when leaving a buffer, load when entering one |
| `let g:bookmark_auto_save_file = '/bookmarks'` | $HOME .'/.vim-bookmarks' | Sets file for auto saving (ignored when `bookmark_save_per_working_dir` is enabled) |
| `let g:bookmark_auto_close = 1` | 0 | Automatically close bookmarks split when jumping to a bookmark |
| `let g:bookmark_highlight_lines = 1` | 0 | Enables/disables line highlighting |
| `let g:bookmark_show_warning = 0` | 1 | Enables/disables warning when clearing all bookmarks |
| `let g:bookmark_show_toggle_warning = 0` | 1 | Enables/disables warning when toggling to clear a bookmark with annotation |
| `let g:bookmark_center = 1` | 0 | Enables/disables line centering when jumping to bookmark|
| `let g:bookmark_no_default_key_mappings = 1` | 0 | Prevent any default key mapping from being created|
| `let g:bookmark_location_list = 1` | 0 | Use the location list to show all bookmarks |
| `let g:bookmark_disable_ctrlp = 1` | 0 | Disable ctrlp interface when show all bookmarks |
### Bookmarks per working directory
This feature allows the grouping of bookmarks per root directory. This way bookmarks from other projects are not interfering. This is done by saving a file called `.vim-bookmarks` into the current working directory (the folder you opened vim from).
Whenever a vim instance is opened from the same root folder the bookmarks from that folder will be loaded. Note, that you can place your bookmarks in any file underneath the working directory, though.
In order to use this feature, put this into your `.vimrc`:
```viml
let g:bookmark_save_per_working_dir = 1
let g:bookmark_auto_save = 1
```
You should add the filename `.vim-bookmarks` to your (global) `.gitignore` file so it doesn't get checked into version control.
If you want to customize the location or filename you can define the following function in your `.vimrc`. The return value will be used to retrieve and save the bookmark positions. This way you can implement you custom strategy for determining the work dir location (e.g. inside the `.git` directory):
```viml
" Finds the Git super-project directory.
function! g:BMWorkDirFileLocation()
let filename = 'bookmarks'
let location = ''
if isdirectory('.git')
" Current work dir is git's work tree
let location = getcwd().'/.git'
else
" Look upwards (at parents) for a directory named '.git'
let location = finddir('.git', '.;')
endif
if len(location) > 0
return location.'/'.filename
else
return getcwd().'/.'.filename
endif
endfunction
```
### Bookmarks per buffer
This feature implies `bookmark_auto_save`. When configured bookmarks will be
loaded and saved on each buffer change. This allows working with different
buffers/tabs and keeping a different bookmark file for each one based on the
file open in the buffer. I.e., using the following function and having files
from different Git repositories open in different tabs will use a different
bookmarks file per Git repository.
This is different from how saving per working directory works because it allows
for having different bookmarks for different buffers/tabs open in the same
window without having the working directory change automatically when switching
between them.
The following function is similar to the one shown above (finds the .git folder
location, defaults to current file's directory) :
```viml
" Finds the Git super-project directory based on the file passed as an argument.
function! g:BMBufferFileLocation(file)
let filename = 'vim-bookmarks'
let location = ''
if isdirectory(fnamemodify(a:file, ":p:h").'/.git')
" Current work dir is git's work tree
let location = fnamemodify(a:file, ":p:h").'/.git'
else
" Look upwards (at parents) for a directory named '.git'
let location = finddir('.git', fnamemodify(a:file, ":p:h").'/.;')
endif
if len(location) > 0
return simplify(location.'/.'.filename)
else
return simplify(fnamemodify(a:file, ":p:h").'/.'.filename)
endif
endfunction
```
### Silent saving and loading
Call functions BookmarkSave, BookmarkLoad and BookmarkClearAll with the last argument set to 0 to perform these operations silently. You may use this to manage your bookmark list transparently from within your custom script.
## Unite Integration
![A screenshot of vim-bookmarks' Unite interface](./screenshot-unite-interface.png)
[Unite](https://github.com/Shougo/unite.vim) is a multi-purpose user-interface plugin platform. Vim-bookmarks provides a Unite source called `vim_bookmarks` so users who use Unite will handle bookmarks with the Unite interface.
Additionally, when showing all your bookmarks, Unite is detected and the plugin will open `:Unite vim_bookmarks` instead of Vim's quickfix window. Note that `g:bookmark_auto_close` is no longer applied. Once opened, the window is managed by Unite.
To set a global per-source context setting, that will apply to Unite's vim_bookmarks source everytime it's opened, you can add this to your `vimrc`:
```viml
call unite#custom#profile('source/vim_bookmarks', 'context', {
\ 'winheight': 13,
\ 'direction': 'botright',
\ 'start_insert': 0,
\ 'keep_focus': 1,
\ 'no_quit': 1,
\ })
```
With the Unite interface, when you select bookmarks, you can perform the following actions:
* Open the selected bookmarks in various ways (open to the right, open above, open in new tab, etc.)
* Yank the informations of selected bookmarks (path and line number, the line content, annotation, etc.)
* Highlight the lines of the selected bookmarks
* Replace the contents of selected bookmarks with [vim-qfreplace](https://github.com/thinca/vim-qfreplace) interface
* Delete the selected bookmarks
* And more...
See the screenshot below to get an idea of what you can do with the interface (the picture shows only a fraction, that means you can select even more actions):
![A screenshot of action list of vim-bookmarks' Unite interface](./screenshot-unite-interface-actions.png)
For more information about Unite, start reading `:help Unite`.
## CtrlP Integration
[ctrlp.vim](https://github.com/ctrlpvim/ctrlp.vim) is a Full path fuzzy file, buffer, mru, tag, ... finder for Vim.
Additionally, when showing all your bookmarks, CtrlP is detected and the plugin will open `:CtrlPBookmark` instead of Vim's quickfix window. Note that `g:bookmark_auto_close` is no longer applied. Once opened, the window is managed by CtrlP.
With the CtrlP interface, when you select bookmarks, you can perform the following actions:
* Open the selected bookmarks in various ways (open to the right, open above, open in new tab, etc.)
* And more...
## FAQ
> Why are the colours in the sign column weird?
Your colorscheme is configuring the `SignColumn` highlight group weirdly. To change that add this to your `.vimrc`: `highlight SignColumn ctermbg=whatever`.
> What happens if I also use another plugin which uses signs (e.g. Syntastic)?
Vim only allows one sign per line. Therefore bookmarks will override any existing sign. When removing the bookmark the original sign will show up again. In other words vim-bookmarks won't remove another plugin's signs.
> Why aren't any signs showing at all?
Make sure your vim supports signs: `:echo has('signs')` should give `1`
> How do I avoid keybinding conflicts with the Nerdtree plugin?
You could unbind the keys whenever Nerdtree becomes active (thanks to [@Nitive](https://github.com/Nitive)).
```viml
let g:bookmark_no_default_key_mappings = 1
function! BookmarkMapKeys()
nmap mm :BookmarkToggle<CR>
nmap mi :BookmarkAnnotate<CR>
nmap mn :BookmarkNext<CR>
nmap mp :BookmarkPrev<CR>
nmap ma :BookmarkShowAll<CR>
nmap mc :BookmarkClear<CR>
nmap mx :BookmarkClearAll<CR>
nmap mkk :BookmarkMoveUp
nmap mjj :BookmarkMoveDown
endfunction
function! BookmarkUnmapKeys()
unmap mm
unmap mi
unmap mn
unmap mp
unmap ma
unmap mc
unmap mx
unmap mkk
unmap mjj
endfunction
autocmd BufEnter * :call BookmarkMapKeys()
autocmd BufEnter NERD_tree_* :call BookmarkUnmapKeys()
```
> Why do my bookmarks disappear when running the `:make` command?
By default, the bookmark list is shown using the quickfix window, which can sometimes conflict with other commands. The location list may be used to show the bookmark list instead by setting the `g:bookmark_location_list` option documented above.
## Changelog
See the [release page](https://github.com/MattesGroeger/vim-bookmarks/releases) for all changes.
## Credits & Contribution
This plugin was developed by [Mattes Groeger][blog] under the [MIT License][license]. Pull requests are very welcome.
The following plugins were a great inspiration to me:
* [vmark.vim][vmark] by Michael Zhou
* [vim-gitgutter][gitgutter] by Andrew Stewart
[pathogen]: https://github.com/tpope/vim-pathogen
[vundle]: https://github.com/gmarik/vundle
[neobundle]: https://github.com/Shougo/neobundle.vim
[vimplug]: https://github.com/MattesGroeger/vim-plug
[macvim]: http://code.google.com/p/macvim/
[license]: https://github.com/MattesGroeger/vim-bookmarks/blob/master/LICENSE
[blog]: http://blog.mattes-groeger.de
[vmark]: http://www.vim.org/scripts/script.php?script_id=4076
[gitgutter]: https://github.com/airblade/vim-gitgutter

View File

@ -1,208 +0,0 @@
if !exists("g:line_map")
let g:line_map = {} " 'line_nr' => 'bookmark'
let g:sign_map = {} " 'sign_idx' => 'line_nr'
endif
" Bookmark Model {{{
function! bm#has_bookmarks_in_file(file)
if !has_key(g:line_map, a:file)
return 0
endif
return len(keys(g:line_map[a:file])) > 0
endfunction
function! bm#has_bookmark_at_line(file, line_nr)
if !has_key(g:line_map, a:file)
return 0
endif
return has_key(g:line_map[a:file], a:line_nr)
endfunction
function! bm#get_bookmark_by_line(file, line_nr)
return g:line_map[a:file][a:line_nr]
endfunction
function! bm#is_bookmark_has_annotation_by_line(file, line_nr)
return g:line_map[a:file][a:line_nr]['annotation'] !=# ""
endfunction
function! bm#get_bookmark_by_sign(file, sign_idx)
let line_nr = g:sign_map[a:file][a:sign_idx]
return bm#get_bookmark_by_line(a:file, line_nr)
endfunction
function! bm#add_bookmark(file, sign_idx, line_nr, content, ...)
if !has_key(g:line_map, a:file)
let g:line_map[a:file] = {}
let g:sign_map[a:file] = {}
endif
let annotation = a:0 ==# 1 ? a:1 : ""
let entry = {'sign_idx': a:sign_idx, 'line_nr': a:line_nr, 'content': a:content, 'annotation': annotation}
let g:line_map[a:file][a:line_nr] = entry
let g:sign_map[a:file][a:sign_idx] = a:line_nr
return entry
endfunction
function! bm#update_bookmark_for_sign(file, sign_idx, new_line_nr, new_content)
let bookmark = bm#get_bookmark_by_sign(a:file, a:sign_idx)
call bm#del_bookmark_at_line(a:file, bookmark['line_nr'])
call bm#add_bookmark(a:file, a:sign_idx, a:new_line_nr, a:new_content, bookmark['annotation'])
endfunction
function! bm#update_annotation(file, sign_idx, annotation)
let bookmark = bm#get_bookmark_by_sign(a:file, a:sign_idx)
let bookmark['annotation'] = a:annotation
endfunction
function! bm#next(file, current_line_nr)
let line_nrs = sort(bm#all_lines(a:file), "bm#compare_lines")
if empty(line_nrs)
return 0
endif
if a:current_line_nr >=# line_nrs[-1] || a:current_line_nr <# line_nrs[0]
return line_nrs[0] + 0
else
let idx = 0
let lines_count = len(line_nrs)
while idx <# lines_count-1
let cur_bookmark = line_nrs[idx]
let next_bookmark = line_nrs[idx+1]
if a:current_line_nr >=# cur_bookmark && a:current_line_nr <# next_bookmark
return next_bookmark + 0
endif
let idx = idx+1
endwhile
endif
return 0
endfunction
function! bm#prev(file, current_line_nr)
let line_nrs = sort(bm#all_lines(a:file), "bm#compare_lines")
if empty(line_nrs)
return 0
endif
let lines_count = len(line_nrs)
let idx = lines_count-1
if a:current_line_nr <=# line_nrs[0] || a:current_line_nr ># line_nrs[-1]
return line_nrs[idx] + 0
else
while idx >=# 0
let cur_bookmark = line_nrs[idx]
let next_bookmark = line_nrs[idx-1]
if a:current_line_nr <=# cur_bookmark && a:current_line_nr ># next_bookmark
return next_bookmark + 0
endif
let idx = idx-1
endwhile
endif
return 0
endfunction
function! bm#del_bookmark_at_line(file, line_nr)
let bookmark = bm#get_bookmark_by_line(a:file, a:line_nr)
unlet g:line_map[a:file][a:line_nr]
unlet g:sign_map[a:file][bookmark['sign_idx']]
if empty(g:line_map[a:file])
unlet g:line_map[a:file]
unlet g:sign_map[a:file]
endif
endfunction
function! bm#total_count()
return len(bm#location_list())
endfunction
function! bm#all_bookmarks_by_line(file)
if !has_key(g:line_map, a:file)
return {}
endif
return g:line_map[a:file]
endfunction
function! bm#all_lines(file)
if !has_key(g:line_map, a:file)
return []
endif
return keys(g:line_map[a:file])
endfunction
function! bm#location_list()
let files = sort(bm#all_files())
let locations = []
for file in files
let line_nrs = sort(bm#all_lines(file), "bm#compare_lines")
for line_nr in line_nrs
let bookmark = bm#get_bookmark_by_line(file, line_nr)
let content = bookmark['annotation'] !=# ''
\ ? "Annotation: ". bookmark['annotation']
\ : (bookmark['content'] !=# ""
\ ? bookmark['content']
\ : "empty line")
call add(locations, file .":". line_nr .":". content)
endfor
endfor
return locations
endfunction
function! bm#all_files()
return keys(g:line_map)
endfunction
function! bm#del_all()
for file in bm#all_files()
for line_nr in bm#all_lines(file)
call bm#del_bookmark_at_line(file, line_nr)
endfor
endfor
endfunction
function! bm#serialize()
let file_version = "let l:bm_file_version = 1"
let sessions = "let l:bm_sessions = {'default': {"
for file in bm#all_files()
let sessions .= "'". file ."': ["
for bm in values(bm#all_bookmarks_by_line(file))
let escaped_content = substitute(bm['content'], "'", "''", "g")
let escaped_annotation = substitute(bm['annotation'], "'", "''", "g")
let annotation = bm['annotation'] !=# "" ? ", 'annotation': '". escaped_annotation ."'" : ""
let sessions .= "{'sign_idx': ". bm['sign_idx'] .", 'line_nr': ". bm['line_nr'] .", 'content': '". escaped_content ."'". annotation ."},"
endfor
let sessions .= "],"
endfor
let sessions .= "}}"
let current_session = "let l:bm_current_session = 'default'"
return [file_version, sessions, current_session]
endfunction
function! bm#deserialize(data)
exec join(a:data, " | ")
let ses = l:bm_sessions["default"]
let result = []
for file in keys(ses)
for bm in ses[file]
let annotation = has_key(bm, 'annotation') ? bm['annotation'] : ''
call add(result,
\ extend(
\ copy(
\ bm#add_bookmark(file, bm['sign_idx'], bm['line_nr'], bm['content'], annotation)
\ ),
\ {'file': file}
\ ))
endfor
endfor
return result
endfunction
" }}}
" Private {{{
function! bm#compare_lines(line_str1, line_str2)
let line1 = str2nr(a:line_str1)
let line2 = str2nr(a:line_str2)
return line1 ==# line2 ? 0 : line1 > line2 ? 1 : -1
endfunc
" }}}

View File

@ -1,33 +0,0 @@
"=============================================================================
" log.vim --- log for bookmark
" Copyright (c) 2016-2019 Wang Shidong & Contributors
" Author: Wang Shidong < wsdjeg@outlook.com >
" URL: https://spacevim.org
" License: GPLv3
"=============================================================================
let s:LOG = SpaceVim#logger#derive('bookmark')
function! bm#info(log) abort
call s:LOG.info(a:log)
endfunction
function! bm#warn(log) abort
call s:LOG.warn(a:log)
endfunction
function! bm#error(log) abort
call s:LOG.error(a:log)
endfunction
function! bm#debug(log) abort
call s:LOG.debug(a:log)
endfunction

View File

@ -1,86 +0,0 @@
if !exists("g:bm_sign_init")
let g:bm_sign_init = 0
endif
" Sign {{{
function! bm_sign#lazy_init()
if g:bm_sign_init ==# 0
call bm_sign#init()
let g:bm_sign_init = 1
endif
endfunction
function! bm_sign#init()
call bm_sign#define_highlights()
sign define Bookmark texthl=BookmarkSign
sign define BookmarkAnnotation texthl=BookmarkAnnotationSign
execute "sign define Bookmark text=". g:bookmark_sign
execute "sign define BookmarkAnnotation text=". g:bookmark_annotation_sign
if g:bookmark_highlight_lines
sign define Bookmark linehl=BookmarkLine
sign define BookmarkAnnotation linehl=BookmarkAnnotationLine
else
sign define Bookmark linehl=
sign define BookmarkAnnotation linehl=
endif
endfunction
function! bm_sign#define_highlights()
highlight BookmarkSignDefault ctermfg=33 ctermbg=NONE
highlight BookmarkAnnotationSignDefault ctermfg=28 ctermbg=NONE
highlight BookmarkLineDefault ctermfg=232 ctermbg=33
highlight BookmarkAnnotationLineDefault ctermfg=232 ctermbg=28
highlight default link BookmarkSign BookmarkSignDefault
highlight default link BookmarkAnnotationSign BookmarkAnnotationSignDefault
highlight default link BookmarkLine BookmarkLineDefault
highlight default link BookmarkAnnotationLine BookmarkAnnotationLineDefault
endfunction
function! bm_sign#add(file, line_nr, is_annotation)
call bm_sign#lazy_init()
let sign_idx = g:bm_sign_index
call bm_sign#add_at(a:file, sign_idx, a:line_nr, a:is_annotation)
return sign_idx
endfunction
" add sign with certain index
function! bm_sign#add_at(file, sign_idx, line_nr, is_annotation)
call bm_sign#lazy_init()
let name = a:is_annotation ==# 1 ? "BookmarkAnnotation" : "Bookmark"
execute "sign place ". a:sign_idx ." line=" . a:line_nr ." name=". name ." file=". a:file
if (a:sign_idx >=# g:bm_sign_index)
let g:bm_sign_index = a:sign_idx + 1
endif
endfunction
function! bm_sign#update_at(file, sign_idx, line_nr, is_annotation)
call bm_sign#del(a:file, a:sign_idx)
call bm_sign#add_at(a:file, a:sign_idx, a:line_nr, a:is_annotation)
endfunction
function! bm_sign#del(file, sign_idx)
call bm_sign#lazy_init()
try
execute "sign unplace ". a:sign_idx ." file=". a:file
catch
endtry
endfunction
" Returns dict with {'sign_idx': 'line_nr'}
function! bm_sign#lines_for_signs(file)
call bm_sign#lazy_init()
let bufnr = bufnr(a:file)
let signs_raw = util#redir_execute(":sign place file=". a:file)
let lines = split(signs_raw, "\n")
let result = {}
for line in lines
let results = matchlist(line, 'line=\(\d\+\)\W\+id=\(\d\+\)\W\+name=bookmark\c')
if len(results) ># 0
let result[results[2]] = results[1]
endif
endfor
return result
endfunction
" }}}

View File

@ -1,73 +0,0 @@
if v:version < 700 || &cp
finish
endif
call add(g:ctrlp_ext_vars, {
\ 'init': 'ctrlp#bookmarks#init()',
\ 'accept': 'ctrlp#bookmarks#accept',
\ 'lname': 'vim-bookmarks',
\ 'sname': '',
\ 'type': 'line',
\ 'sort': 0,
\ 'specinput': 0,
\ })
function! ctrlp#bookmarks#init() abort
let l:text=[]
let l:files = sort(bm#all_files())
for l:file in l:files
let l:line_nrs = sort(bm#all_lines(l:file), "bm#compare_lines")
for l:line_nr in l:line_nrs
let l:bookmark = bm#get_bookmark_by_line(l:file, l:line_nr)
let l:detail = printf("%s", l:bookmark.annotation !~ '^\s*$' ?
\ l:bookmark.annotation
\ : l:bookmark.content !~ '^\s*$' ?
\ l:bookmark.content
\ : "EMPTY LINE")
call add(l:text, l:detail)
endfor
endfor
return l:text
endfunction
function! ctrlp#bookmarks#accept(mode, str) abort
if a:mode ==# 'e'
let l:HowToOpen='e'
elseif a:mode ==# 't'
let l:HowToOpen='tabnew'
elseif a:mode ==# 'v'
let l:HowToOpen='vsplit'
elseif a:mode ==# 'h'
let l:HowToOpen='sp'
endif
call ctrlp#exit()
let l:text=[]
let l:files = sort(bm#all_files())
for l:file in l:files
let l:line_nrs = sort(bm#all_lines(l:file), "bm#compare_lines")
for l:line_nr in l:line_nrs
let l:bookmark = bm#get_bookmark_by_line(l:file, l:line_nr)
if a:str ==# l:bookmark.annotation
execute l:HowToOpen." ".l:file
execute ":".l:line_nr
break
elseif a:str ==# l:bookmark.content
execute l:HowToOpen." ".l:file
execute ":".l:line_nr
break
elseif a:str ==# "EMPTY LINE"
execute l:HowToOpen." ".l:file
execute ":".l:line_nr
break
endif
endfor
endfor
endfunction
let s:id = g:ctrlp_builtins + len(g:ctrlp_ext_vars)
function! ctrlp#bookmarks#id() abort
return s:id
endfunction
" vim:nofen:fdl=0:ts=2:sw=2:sts=2

View File

@ -1,34 +0,0 @@
let s:save_cpo = &cpo
set cpo&vim
function! s:format_bookmark(candidate) " {{{
let file = a:candidate.action__path
let line_nr = a:candidate.action__line
let bookmark = a:candidate.action__bookmark
return printf("%s:%d | %s", file, line_nr,
\ bookmark.annotation !=# ''
\ ? "Annotation: " . bookmark.annotation
\ : (bookmark.content !=# "" ? bookmark.content
\ : "empty line")
\ )
endfunction " }}}
let s:converter = {
\ 'name': 'converter_vim_bookmarks_short',
\ 'description': 'vim-bookmarks converter which show short informations',
\}
function! s:converter.filter(candidates, context) " {{{
for candidate in a:candidates
let candidate.abbr = s:format_bookmark(candidate)
endfor
return a:candidates
endfunction " }}}
function! unite#filters#converter_vim_bookmarks_long#define() " {{{
return s:converter
endfunction " }}}
call unite#define_filter(s:converter)
let &cpo = s:save_cpo
unlet s:save_cpo
"vim: sts=2 sw=2 smarttab et ai textwidth=0 fdm=marker

View File

@ -1,35 +0,0 @@
let s:save_cpo = &cpo
set cpo&vim
function! s:format_bookmark(candidate) " {{{
let file = a:candidate.action__path
let line_nr = a:candidate.action__line
let bookmark = a:candidate.action__bookmark
return printf("%s:%d | %s", pathshorten(file), line_nr,
\ bookmark.annotation !=# ''
\ ? "Annotation: " . bookmark.annotation
\ : (bookmark.content !=# "" ? bookmark.content
\ : "empty line")
\ )
endfunction " }}}
let s:converter = {
\ 'name': 'converter_vim_bookmarks_short',
\ 'description': 'vim-bookmarks converter which show short informations',
\}
function! s:converter.filter(candidates, context) " {{{
let candidates = copy(a:candidates)
for candidate in candidates
let candidate.abbr = s:format_bookmark(candidate)
endfor
return candidates
endfunction " }}}
function! unite#filters#converter_vim_bookmarks_short#define() " {{{
return s:converter
endfunction " }}}
call unite#define_filter(s:converter)
let &cpo = s:save_cpo
unlet s:save_cpo
"vim: sts=2 sw=2 smarttab et ai textwidth=0 fdm=marker

View File

@ -1,82 +0,0 @@
let s:save_cpo = &cpo
set cpo&vim
let s:kind = {
\ 'name': 'vim_bookmarks',
\ 'parents': ['jump_list'],
\ 'default_action': 'open',
\ 'action_table': {
\ 'delete': {
\ 'description': 'delete the selected bookmarks',
\ 'is_selectable': 1,
\ 'is_quit': 0,
\ },
\ 'yank': {
\ 'description': 'yank path and content of the selected bookmarks',
\ 'is_selectable': 1,
\ },
\ 'yank_path': {
\ 'description': 'yank path of the selected bookmarks',
\ 'is_selectable': 1,
\ },
\ 'yank_content': {
\ 'description': 'yank content of the selected bookmarks',
\ 'is_selectable': 1,
\ },
\ 'yank_annotation': {
\ 'description': 'yank annotation of the selected bookmarks',
\ 'is_selectable': 1,
\ },
\}}
function! s:yank(text)
let @" = a:text
echo 'Yanked: ' . a:text
if has('clipboard')
call setreg(v:register, a:text)
endif
endfunction
function! s:kind.action_table.delete.func(candidates) " {{{
for candidate in a:candidates
call bm_sign#del(
\ candidate.action__path,
\ candidate.action__bookmark.sign_idx,
\)
call bm#del_bookmark_at_line(
\ candidate.action__path,
\ candidate.action__line,
\)
endfor
call unite#force_redraw()
endfunction " }}}
function! s:kind.action_table.yank.func(candidates) " {{{
let text = join(map(copy(a:candidates),
\ 'v:val.word'), "\n")
call s:yank(text)
endfunction " }}}
function! s:kind.action_table.yank_path.func(candidates) " {{{
let text = join(map(copy(a:candidates),
\ 'v:val.action__path'), "\n")
call s:yank(text)
endfunction " }}}
function! s:kind.action_table.yank_content.func(candidates) " {{{
let text = join(map(copy(a:candidates),
\ 'v:val.action__bookmark.content'), "\n")
call s:yank(text)
endfunction " }}}
function! s:kind.action_table.yank_annotation.func(candidates) " {{{
let text = join(map(copy(a:candidates),
\ 'v:val.action__bookmark.annotation'), "\n")
call s:yank(text)
endfunction " }}}
function! unite#kinds#vim_bookmarks#define()
return s:kind
endfunction
call unite#define_kind(s:kind) " required for reloading
let &cpo = s:save_cpo
unlet s:save_cpo
"vim: sts=2 sw=2 smarttab et ai textwidth=0 fdm=marker

View File

@ -1,64 +0,0 @@
let s:save_cpo = &cpo
set cpo&vim
function! unite#sources#vim_bookmarks#define_highlights() abort " {{{
highlight default link BookmarkUnitePath Comment
highlight default link BookmarkUniteContent Normal
endfunction " }}}
let s:source = {
\ 'name': 'vim_bookmarks',
\ 'description': 'manipulate bookmarks of vim-bookmarks',
\ 'hooks': {},
\}
function! s:source.gather_candidates(args, context) abort " {{{
let files = sort(bm#all_files())
let candidates = []
for file in files
let line_nrs = sort(bm#all_lines(file), "bm#compare_lines")
for line_nr in line_nrs
let bookmark = bm#get_bookmark_by_line(file, line_nr)
call add(candidates, {
\ 'word': printf("%s:%d | %s", file, line_nr,
\ bookmark.annotation !=# ''
\ ? "Annotation: " . bookmark.annotation
\ : (bookmark.content !=# "" ? bookmark.content
\ : "empty line")
\ ),
\ 'kind': 'vim_bookmarks',
\ 'action__path': file,
\ 'action__line': line_nr,
\ 'action__bookmark': bookmark,
\})
endfor
endfor
return copy(candidates)
endfunction " }}}
function! s:source.hooks.on_syntax(args, context) abort " {{{
call unite#sources#vim_bookmarks#define_highlights()
highlight default link uniteSource__VimBookmarks_path BookmarkUnitePath
highlight default link uniteSource__VimBookmarks_content BookmarkUniteContent
execute 'syntax match uniteSource__VimBookmarks_path'
\ '/[^|]\+/'
\ 'contained containedin=uniteSource__VimBookmarks'
execute 'syntax match uniteSource__VimBookmarks_content'
\ '/|.*$/'
\ 'contained containedin=uniteSource__VimBookmarks'
endfunction " }}}
function! unite#sources#vim_bookmarks#define()
return s:source
endfunction
call unite#define_source(s:source) " Required for reloading
" define default converter
call unite#custom_source(
\ 'vim_bookmarks',
\ 'converters',
\ 'converter_vim_bookmarks_short')
let &cpo = s:save_cpo
unlet s:save_cpo
"vim: sts=2 sw=2 smarttab et ai textwidth=0 fdm=marker

View File

@ -1,6 +0,0 @@
function! util#redir_execute(command)
redir => output
silent execute a:command
redir END
return substitute(output, '^\n', '\1', '')
endfunction

View File

@ -1,356 +0,0 @@
*bookmarks.txt* A Vim plugin for using line-based bookmarks.
Vim Bookmarks
Author: Mattes Groeger <http://blog.mattes-groeger.de/>
Plugin Homepage: <https://github.com/MattesGroeger/vim-bookmarks>
===============================================================================
CONTENTS *BookmarksContents*
1. Introduction ................. |BookmarksIntroduction|
2. Installation ................. |BookmarksInstallation|
3. Usage ........................ |BookmarksUsage|
4. Commands ..................... |BookmarksCommands|
5. Customisation ................ |BookmarksCustomisation|
6. Extending .................... |BookmarksExtening|
7. Unite Integration ............ |BookmarksUniteIntegration|
8. CtrlP Integration ............ |BookmarksCtrlPIntegration|
9. FAQ .......................... |BookmarksFAQ|
===============================================================================
1. INTRODUCTION *BookmarksIntroduction*
*Bookmarks*
This vim plugin allows toggling bookmarks per line. A quickfix window gives
access to all bookmarks. Annotations can be added as well. These are special
bookmarks with a comment attached. They are useful for preparing code reviews.
All bookmarks will be restored on the next startup.
===============================================================================
2. INSTALLATION *BookmarksInstallation*
Use your favorite plugin manager:
Pathogen:
>
git clone https://github.com/MattesGroeger/vim-bookmarks.git \
~/.vim/bundle/vim-bookmarks
<
Vundle:
1. Add Plugin 'MattesGroeger/vim-bookmarks' to .vimrc
2. Run :PluginInstall
NeoBundle:
1. Add NeoBundle 'MattesGroeger/vim-bookmarks' to .vimrc
2. Run :NeoBundleInstall
vim-plug:
1. Add Plug 'MattesGroeger/vim-bookmarks' to .vimrc
2. Run :PlugInstall
===============================================================================
3. USAGE *BookmarksUsage*
You don't have to do anything: it just works.
===============================================================================
4. COMMANDS *BookmarksCommands*
Commands for using Bookmarks
:BookmarkToggle *:BookmarkToggle*
Add or remove bookmark at current line
:BookmarkAnnotate <TEXT> *:BookmarkAnnotate*
Add/edit/remove annotation at current line
:BookmarkNext *:BookmarkNext*
Jump to the next bookmark downwards
:BookmarkPrev *:BookmarkPrev*
Jump to the next bookmark upwards
:BookmarkShowAll *:BookmarkShowAll*
Show bookmarks across all buffers in new window (toggle)
:BookmarkClear *:BookmarkClear*
Removes bookmarks for current buffer
:BookmarkClearAll *:BookmarkClearAll*
Removes bookmarks for all buffer
:BookmarkMoveUp [<COUNT>] *:BookmarkMoveUp*
Move up the bookmark at current line by the specified amount of lines
(default: 1)
:BookmarkMoveDown [<COUNT>] *:BookmarkMoveDown*
Move down the bookmark at current line by the specified amount of lines
(default: 1)
:BookmarkMoveToLine <LINE> *:BookmarkMoveToLine*
Move the bookmark at current line to the specified <LINE>
:BookmarkSave <FILE_PATH> *:BookmarkSave*
Saves all bookmarks to a file so you can load them back in later
:BookmarkLoad <FILE_PATH> *:BookmarkLoad*
Loads bookmarks from a file (see :BookmarkSave)
===============================================================================
5. CUSTOMISATION *BookmarksCustomisation*
You can customise:
- The sign column's colours
- The signs' colours and symbols
- Line highlights
- Key mappings
- Whether or not line highlighting is on (defaults to off)
- Whether to close bookmarks split when jumping to a bookmark or not.
Please note that vim-bookmarks won't override any colours or highlights you've
set in your colorscheme.
SIGN COLUMN
The background colour of the sign column is controlled by the |hlSignColumn|
highlight group. This will be either set in your colorscheme or Vim's default.
To find out where it's set, and to what it's set, use:
>
:verbose highlight SignColumn
<
To change your sign column's appearance, update your colorscheme or |vimrc|
like this:
Desired appearance Command ~
Same as line number column highlight clear SignColumn
User-defined (terminal Vim) highlight SignColumn ctermbg={whatever}
User-defined (graphical Vim) highlight SignColumn guibg={whatever}
SIGNS' COLOURS AND SYMBOLS
To customise the colours, set up the following highlight groups in your
colorscheme or |vimrc|:
>
BookmarkSign " the sign
BookmarkAnnotationSign " the annotation sign
<
You can either set these with `highlight BookmarkSign {key}={arg}...` or link
them to existing highlight groups with, say:
>
highlight link BookmarkSign Todo
<
To customise the symbols, add the following to your |vimrc|:
>
let g:bookmark_sign = '>>'
let g:bookmark_annotation_sign = '##'
<
LINE HIGHLIGHTS
Similarly to the signs' colours, set up the following highlight group in your
colorscheme or |vimrc|:
>
BookmarkLine " the highlighted line
BookmarkAnnotationLine " the highlighted annotation line
<
KEY MAPPINGS
To change the default keys:
>
nmap <Leader><Leader> <Plug>BookmarkToggle
nmap <Leader>i <Plug>BookmarkAnnotate
nmap <Leader>a <Plug>BookmarkShowAll
nmap <Leader>j <Plug>BookmarkNext
nmap <Leader>k <Plug>BookmarkPrev
nmap <Leader>c <Plug>BookmarkClear
nmap <Leader>x <Plug>BookmarkClearAll
" these will also work with a [count] prefix
nmap <Leader>kk <Plug>BookmarkMoveUp
nmap <Leader>jj <Plug>BookmarkMoveDown
nmap <Leader>g <Plug>BookmarkMoveToLine
<
To prevent any default mappings from being created (default: 0):
>
let g:bookmark_no_default_key_mappings = 1
<
MORE OPTIONS
Change the following options in your |vimrc| to customize the plugin behaviour.
Save/show bookmarks per working directory/project (default 0):
>
let g:bookmark_save_per_working_dir = 1
<
When this option is enabled, a file called `.vim-bookmarks` will be stored in
the current working directory whenever you create bookmarks. You should add this
file to your (global) `.gitignore` file so it doesn't get checked into version
control.
Enable bookmark management on a per buffer basis:
>
let g:bookmark_manage_per_buffer = 1
<
This will save and load the bookmarks file whenever the buffer changes (e.g.,
switching tabs/buffers). It makes most sense when g:bookmark_save_per_working_dir
is turned on as well, or when a customizing function is used.
Disable auto saving (default 1):
>
let g:bookmark_auto_save = 0
<
Change file for auto saving (default $HOME .'/.vim-bookmarks'):
>
let g:bookmark_auto_save_file = '/tmp/my_bookmarks'
<
Turn on line highlighting (default 0):
>
let g:bookmark_highlight_lines = 1
<
Turn off the warning when clearing all bookmarks (default 1):
>
let g:bookmark_show_warning = 0
<
Turn off the warning when toggling to clear a bookmark with annotation (default 1):
>
let g:bookmark_show_toggle_warning = 0
<
Turn on vertical line centering when jumping to bookmark (default 0):
>
let g:bookmark_center = 1
<
Automatically close bookmarks split when jumping to a bookmark (default 0):
>
let g:bookmark_auto_close = 1
<
Use the location list to show all bookmarks (default 0):
>
let g:bookmark_location_list = 1
You can disable Ctrlp by setting (default 0)
>
let g:bookmark_disable_ctrlp = 1
<
===============================================================================
6. EXTENDING *BookmarksExtending*
You can implement automatic switching of bookmarks file on your desired event.
To do so, use functions BookmarkSave, BookmarkLoad and BookmarkClearAll with
the last argument set to 1. This will suppress any messages and prompts these
functions normally issue. The BookmarkLoad function will return 1 to indicate
that file loading was successful, and 0 for failure. An example script using
this feature is located in the 'examples/bm-autoload-example.vim' file.
===============================================================================
7. Unite Integration *BookmarksUniteIntegration*
Unite is a multi-purpose user-interface plugin platform. vim-bookmarks provide
an Unite source called *vim_bookmarks* so users who use Unite will handle
bookmarks with the Unite interface. When showing all your bookmarks, Unite is
detected and the plugin will open ':Unite vim_bookmarks' instead of Vim's
quickfix window. Note that |g:bookmark_auto_close| is no longer applied, once
opened, the window is managed by Unite.
To set a global per-source context setting, that will apply to Unite's quickfix
source everytime it's opened, you can add this to your |vimrc|:
>
call unite#custom#profile('source/vim_bookmarks', 'context', {
\ 'winheight': 13,
\ 'direction': 'botright',
\ 'start_insert': 0,
\ 'keep_focus': 1,
\ 'no_quit': 1,
\ })
<
With the Unite interface, when you select bookmarks, you can perform the
following actions.
- Open the selected bookmarks in various ways (open in right, open in above,
open in new tab, etc.)
- Yank the informations of selected bookmarks (path and line number, the line
content, annotation, etc.)
- Highlight the lines of the selected bookmarks
- Replace the contents of selected bookmarks with vim-qfreplace
- Delete the selected bookmarks
- And more!
For more information about Unite, start reading |:Unite|.
https://github.com/Shougo/unite.vim
https://github.com/thinca/vim-qfreplace
===============================================================================
8. CtrlP Integration *BookmarksCtrlPIntegration*
ctrlp.vim is a Full path fuzzy file, buffer, mru, tag, ... finder for Vim.
Additionally, when showing all your bookmarks, CtrlP is detected and the plugin
will open *:CtrlPBookmark* instead of Vim's quickfix window. Note that
|g:bookmark_auto_close| is no longer applied. Once opened, the window is managed
by CtrlP.
With the CtrlP interface, when you select bookmarks, you can perform the
following actions:
* Open the selected bookmarks in various ways (open to the right, open above,
open in new tab, etc.)
* And more...
For more information about CtrlP start reading |CtrlP@en|.
https://github.com/ctrlpvim/ctrlp.vim
===============================================================================
9. FAQ *BookmarksFAQ*
a. Why are the colours in the sign column weird?
Your colorscheme is configuring the |hl-SignColumn| highlight group weirdly.
Please see |BookmarksCustomisation| on customising the sign column.
b. What happens if I also use another plugin which uses signs (e.g. Syntastic)?
Vim only allows one sign per line. Therefore bookmarks will override any
existing sign. When removing the bookmark the original sign will show up
again. In other words vim-bookmarks won't remove another plugin's signs.
c. Why aren't any signs showing at all?
Make sure your vim supports signs. This should return "1":
>
:echo has('signs')
<
vim:ft=help:et:ts=2:sw=2:sts=2:norl

View File

@ -1,47 +0,0 @@
let s:autoload_roots = []
let s:last_root = ''
let s:last_file = ''
function! AddBookmarkRoot(root)
call add(s:autoload_roots, a:root)
endfunction
function! AutoloadBookmarks(file_name)
let root_is_found = 0
let found_root = 0
let name_len = strlen(a:file_name)
for root in s:autoload_roots
let root_len = strlen(root)
if (name_len > root_len && strpart(a:file_name, 0, root_len) == root)
let root_is_found = 1
let found_root = root
break
endif
endfor
if (root_is_found && found_root != s:last_root)
let s:last_file = found_root . '/.bookmarks'
let s:last_root = found_root
call BookmarkLoad(s:last_file, 0, 1)
augroup AutoSaveBookmarks
autocmd!
autocmd BufLeave * call s:remove_group()
augroup END
else
let s:last_root = ''
endif
endfunction
augroup AutoLoadBookmarks
autocmd!
autocmd BufEnter * call AutoloadBookmarks(expand("<afile>:p"))
augroup END
function! s:remove_group()
call BookmarkSave(s:last_file, 1)
augroup AutoSaveBookmarks
autocmd!
augroup END
endfunction

View File

@ -1,573 +0,0 @@
if exists('g:bm_has_any') || !has('signs') || &cp
finish
endif
scriptencoding utf-8
let g:bm_has_any = 0
let g:bm_sign_index = 9500
let g:bm_current_file = ''
" Configuration {{{
function! s:set(var, default)
if !exists(a:var)
if type(a:default)
execute 'let' a:var '=' string(a:default)
else
execute 'let' a:var '=' a:default
endif
endif
endfunction
call s:set('g:bookmark_highlight_lines', 0 )
call s:set('g:bookmark_sign', '⚑')
call s:set('g:bookmark_annotation_sign', '☰')
call s:set('g:bookmark_show_warning', 1 )
call s:set('g:bookmark_show_toggle_warning', 1 )
call s:set('g:bookmark_save_per_working_dir', 0 )
call s:set('g:bookmark_auto_save', 1 )
call s:set('g:bookmark_manage_per_buffer', 0 )
call s:set('g:bookmark_auto_save_file', $HOME .'/.vim-bookmarks')
call s:set('g:bookmark_auto_close', 0 )
call s:set('g:bookmark_center', 0 )
call s:set('g:bookmark_location_list', 0 )
call s:set('g:bookmark_disable_ctrlp', 0 )
function! s:init(file)
if g:bookmark_auto_save ==# 1 || g:bookmark_manage_per_buffer ==# 1
augroup bm_vim_enter
autocmd!
autocmd BufEnter * call s:set_up_auto_save(expand('<afile>:p'))
augroup END
endif
if a:file !=# ''
call s:set_up_auto_save(a:file)
elseif g:bookmark_manage_per_buffer ==# 0 && g:bookmark_save_per_working_dir ==# 0
call BookmarkLoad(s:bookmark_save_file(''), 1, 1)
endif
endfunction
" }}}
" Commands {{{
function! BookmarkToggle()
call s:refresh_line_numbers()
let file = expand("%:p")
if file ==# ""
return
endif
let current_line = line('.')
if bm#has_bookmark_at_line(file, current_line)
if g:bookmark_show_toggle_warning ==# 1 && bm#is_bookmark_has_annotation_by_line(file, current_line)
let delete = confirm("Delete Annotated bookmarks?", "&Yes\n&No", 2)
if (delete !=# 1)
echo "Ignore!"
return
endif
endif
call s:bookmark_remove(file, current_line)
echo "Bookmark removed"
else
call s:bookmark_add(file, current_line)
echo "Bookmark added"
endif
endfunction
command! ToggleBookmark call CallDeprecatedCommand('BookmarkToggle', [])
command! BookmarkToggle call BookmarkToggle()
function! BookmarkAnnotate(...)
call s:refresh_line_numbers()
let file = expand("%:p")
if file ==# ""
return
endif
let current_line = line('.')
let has_bm = bm#has_bookmark_at_line(file, current_line)
let bm = has_bm ? bm#get_bookmark_by_line(file, current_line) : 0
let old_annotation = has_bm ? bm['annotation'] : ""
let new_annotation = a:0 ># 0 ? a:1 : ""
" Get annotation from user input if not passed in
if new_annotation ==# ""
let input_msg = old_annotation !=# "" ? "Edit" : "Enter"
let new_annotation = input(input_msg ." annotation: ", old_annotation)
execute ":redraw!"
endif
" Nothing changed, bail out
if new_annotation ==# "" && old_annotation ==# new_annotation
return
" Update annotation
elseif has_bm
call bm#update_annotation(file, bm['sign_idx'], new_annotation)
let result_msg = (new_annotation ==# "")
\ ? "removed"
\ : old_annotation !=# ""
\ ? "updated: ". new_annotation
\ : "added: ". new_annotation
call bm_sign#update_at(file, bm['sign_idx'], bm['line_nr'], bm['annotation'] !=# "")
echo "Annotation ". result_msg
" Create bookmark with annotation
elseif new_annotation !=# ""
call s:bookmark_add(file, current_line, new_annotation)
echo "Bookmark added with annotation: ". new_annotation
endif
endfunction
command! -nargs=* Annotate call CallDeprecatedCommand('BookmarkAnnotate', [<q-args>, 0])
command! -nargs=* BookmarkAnnotate call BookmarkAnnotate(<q-args>, 0)
function! BookmarkClear()
call s:refresh_line_numbers()
let file = expand("%:p")
let lines = bm#all_lines(file)
for line_nr in lines
call s:bookmark_remove(file, line_nr)
endfor
echo "Bookmarks removed"
endfunction
command! ClearBookmarks call CallDeprecatedCommand('BookmarkClear', [])
command! BookmarkClear call BookmarkClear()
function! BookmarkClearAll(silent)
call s:refresh_line_numbers()
let files = bm#all_files()
let file_count = len(files)
let delete = 1
let in_multiple_files = file_count ># 1
let supports_confirm = has("dialog_con") || has("dialog_gui")
if (in_multiple_files && g:bookmark_show_warning ==# 1 && supports_confirm && !a:silent)
let delete = confirm("Delete ". bm#total_count() ." bookmarks in ". file_count . " buffers?", "&Yes\n&No")
endif
if (delete ==# 1)
call s:remove_all_bookmarks()
if (!a:silent)
execute ":redraw!"
echo "All bookmarks removed"
endif
endif
endfunction
command! ClearAllBookmarks call CallDeprecatedCommand('BookmarkClearAll', [0])
command! BookmarkClearAll call BookmarkClearAll(0)
function! BookmarkNext()
call s:refresh_line_numbers()
call s:jump_to_bookmark('next')
endfunction
command! NextBookmark call CallDeprecatedCommand('BookmarkNext')
command! BookmarkNext call BookmarkNext()
function! BookmarkPrev()
call s:refresh_line_numbers()
call s:jump_to_bookmark('prev')
endfunction
command! PrevBookmark call CallDeprecatedCommand('BookmarkPrev')
command! BookmarkPrev call BookmarkPrev()
command! CtrlPBookmark call ctrlp#init(ctrlp#bookmarks#id())
function! BookmarkShowAll()
if s:is_quickfix_win()
q
else
call s:refresh_line_numbers()
if exists(':Unite')
exec ":Unite vim_bookmarks"
elseif exists(':CtrlP') == 2 && g:bookmark_disable_ctrlp == 0
exec ":CtrlPBookmark"
elseif exists(':Leaderf')
exe ':Leaderf bookmarks'
else
let oldformat = &errorformat " backup original format
let &errorformat = "%f:%l:%m" " custom format for bookmarks
if g:bookmark_location_list
lgetexpr bm#location_list()
call setloclist(0, [], 'r', {'title': 'Bookmarks'})
belowright lopen
else
cgetexpr bm#location_list()
call setqflist([], 'r', {'title': 'Bookmarks'})
belowright copen
endif
augroup BM_AutoCloseCommand
autocmd!
autocmd WinLeave * call s:auto_close()
augroup END
let &errorformat = oldformat " re-apply original format
endif
endif
endfunction
command! ShowAllBookmarks call CallDeprecatedCommand('BookmarkShowAll')
command! BookmarkShowAll call BookmarkShowAll()
function! BookmarkSave(target_file, silent)
call s:refresh_line_numbers()
if (bm#total_count() > 0 || (!g:bookmark_save_per_working_dir && !g:bookmark_manage_per_buffer))
let serialized_bookmarks = bm#serialize()
call writefile(serialized_bookmarks, a:target_file)
if (!a:silent)
echo "All bookmarks saved"
endif
elseif (g:bookmark_save_per_working_dir || g:bookmark_manage_per_buffer)
call delete(a:target_file) " remove file, if no bookmarks
endif
endfunction
command! -nargs=1 SaveBookmarks call CallDeprecatedCommand('BookmarkSave', [<f-args>, 0])
command! -nargs=1 BookmarkSave call BookmarkSave(<f-args>, 0)
function! BookmarkLoad(target_file, startup, silent)
let supports_confirm = has("dialog_con") || has("dialog_gui")
let has_bookmarks = bm#total_count() ># 0
let confirmed = 1
if (supports_confirm && has_bookmarks && !a:silent)
let confirmed = confirm("Do you want to override your ". bm#total_count() ." bookmarks?", "&Yes\n&No")
endif
if (confirmed ==# 1)
call s:remove_all_bookmarks()
try
let data = readfile(a:target_file)
let new_entries = bm#deserialize(data)
if !a:startup
for entry in new_entries
call bm_sign#add_at(entry['file'], entry['sign_idx'], entry['line_nr'], entry['annotation'] !=# "")
endfor
if (!a:silent)
echo "Bookmarks loaded"
endif
return 1
endif
catch
if (!a:startup && !a:silent)
echo "Failed to load/parse file"
endif
return 0
endtry
endif
endfunction
command! -nargs=1 LoadBookmarks call CallDeprecatedCommand('BookmarkLoad', [<f-args>, 0, 0])
command! -nargs=1 BookmarkLoad call BookmarkLoad(<f-args>, 0, 0)
function! CallDeprecatedCommand(fun, args)
echo "Warning: Deprecated command, please use ':". a:fun ."' instead"
let Fn = function(a:fun)
return call(Fn, a:args)
endfunction
function! BookmarkModify(diff)
let current_line = line('.')
let new_line_nr = current_line + a:diff
call BookmarkMoveToLine(new_line_nr)
endfunction
function! BookmarkMoveToLine(target)
call s:refresh_line_numbers()
let file = expand("%:p")
if file ==# ""
return
endif
let current_line = line('.')
if a:target == current_line
return
endif
if bm#has_bookmark_at_line(file, current_line)
"ensure we're trying to move to a valid line nr
let max_line_nr = line('$')
if a:target <= 0 || a:target > max_line_nr
echo "Can't move bookmark beyond file bounds"
return
endif
if bm#has_bookmark_at_line(file, a:target)
echo "Hit another bookmark"
return
endif
let bookmark = bm#get_bookmark_by_line(file, current_line)
call bm_sign#update_at(file, bookmark['sign_idx'], a:target, bookmark['annotation'] !=# "")
let bufnr = bufnr(file)
let line_content = getbufline(bufnr, a:target)
let content = len(line_content) > 0 ? line_content[0] : ' '
call bm#update_bookmark_for_sign(file, bookmark['sign_idx'], a:target, content)
call cursor(a:target, 1)
normal! ^
else
return
endif
endfunction
command! -nargs=? BookmarkMoveUp call s:move_relative(<q-args>, -1)
command! -nargs=? BookmarkMoveDown call s:move_relative(<q-args>, 1)
command! -nargs=? BookmarkMoveToLine call s:move_absolute(<q-args>)
" }}}
" Private {{{
" arg is always a string
" direction is {-1,1}
function! s:move_relative(arg, direction)
if !s:has_bookmark_at_cursor()
echo 'No bookmark at current line'
return
endif
" '' => direction
" '0' => direction
" '\d+' => number * direction
" 'v:count' => v:count * direction
" negative/abc arg naturally rejected
if empty(a:arg)
let delta = a:direction
elseif a:arg =~# '\v^v:count1?$'
let delta = eval(a:arg) * a:direction
elseif a:arg =~# '\v^\d+$'
let delta = str2nr(a:arg) * a:direction
else
echo 'Invalid line count'
return
endif
let delta = (delta == 0) ? a:direction : delta
" at this point we're guaranteed to have integer target != 0
call BookmarkModify(delta)
endfunction
" arg is always a string
function! s:move_absolute(arg)
if !s:has_bookmark_at_cursor()
echo 'No bookmark at current line'
return
endif
" '' => prompt
" 'v:count' == 0 => prompt
" 'v:count' => use
" '\d+' => use
" negative/abc arg naturally rejected
if empty(a:arg)
let target = 0
elseif a:arg =~# '\v^v:count1?$'
let target = eval(a:arg)
elseif a:arg =~# '\v^\d+$'
let target = str2nr(a:arg)
else
echo 'Invalid line number'
return
endif
if target == 0
let target = input("Enter target line number: ")
" clear the line for subsequent messages
echo "\r"
" if 'abc<Esc>' or '<empty><Enter>' (indistinguishable), cancel with no error message
if empty(target)
return
endif
if target !~# '\v^\d+$'
echo "Invalid line number"
return
endif
let target = str2nr(target)
endif
" at this point we're guaranteed to have integer target > 0
call BookmarkMoveToLine(target)
endfunction
function! s:has_bookmark_at_cursor()
let file = expand("%:p")
let current_line = line('.')
if file ==# ""
return
endif
return bm#has_bookmark_at_line(file, current_line)
endfunction
function! s:lazy_init()
if g:bm_has_any ==# 0
augroup bm_refresh
autocmd!
autocmd ColorScheme * call bm_sign#define_highlights()
autocmd BufLeave * call s:refresh_line_numbers()
augroup END
let g:bm_has_any = 1
endif
endfunction
function! s:refresh_line_numbers()
call s:lazy_init()
let file = expand("%:p")
if file ==# "" || !bm#has_bookmarks_in_file(file)
return
endif
let bufnr = bufnr(file)
let sign_line_map = bm_sign#lines_for_signs(file)
for sign_idx in keys(sign_line_map)
let line_nr = sign_line_map[sign_idx]
let line_content = getbufline(bufnr, line_nr)
let content = len(line_content) > 0 ? line_content[0] : ' '
call bm#update_bookmark_for_sign(file, sign_idx, line_nr, content)
endfor
endfunction
function! s:bookmark_add(file, line_nr, ...)
let annotation = (a:0 ==# 1) ? a:1 : ""
let sign_idx = bm_sign#add(a:file, a:line_nr, annotation !=# "")
call bm#add_bookmark(a:file, sign_idx, a:line_nr, getline(a:line_nr), annotation)
endfunction
function! s:bookmark_remove(file, line_nr)
let bookmark = bm#get_bookmark_by_line(a:file, a:line_nr)
call bm_sign#del(a:file, bookmark['sign_idx'])
call bm#del_bookmark_at_line(a:file, a:line_nr)
endfunction
function! s:jump_to_bookmark(type)
let file = expand("%:p")
let line_nr = bm#{a:type}(file, line("."))
if line_nr ==# 0
echo "No bookmarks found"
else
call cursor(line_nr, 1)
normal! ^
if g:bookmark_center ==# 1
normal! zz
endif
let bm = bm#get_bookmark_by_line(file, line_nr)
let annotation = bm['annotation'] !=# "" ? " (". bm['annotation'] . ")" : ""
execute ":redraw!"
echo "Jumped to bookmark". annotation
endif
endfunction
function! s:remove_all_bookmarks()
let files = bm#all_files()
for file in files
let lines = bm#all_lines(file)
for line_nr in lines
call s:bookmark_remove(file, line_nr)
endfor
endfor
endfunction
function! s:startup_load_bookmarks(file)
call BookmarkLoad(s:bookmark_save_file(a:file), 1, 1)
call s:add_missing_signs(a:file)
endfunction
function! s:bookmark_save_file(file)
" Managing bookmarks per buffer implies saving them to a location based on the
" open file (working dir doesn't make much sense unless auto changing the
" working directory based on current file location is turned on - but this is
" a serious dependency to try and require), so the function used to customize
" the bookmarks file location must be based on the current file.
" For backwards compatibility reasons, a new function is used.
if (g:bookmark_manage_per_buffer ==# 1)
return exists("*g:BMBufferFileLocation") ? g:BMBufferFileLocation(a:file) : s:default_file_location()
elseif (g:bookmark_save_per_working_dir)
return exists("*g:BMWorkDirFileLocation") ? g:BMWorkDirFileLocation() : s:default_file_location()
else
return g:bookmark_auto_save_file
endif
endfunction
function! s:default_file_location()
return getcwd(). '/.vim-bookmarks'
endfunction
" should only be called from autocmd!
function! s:add_missing_signs(file)
let bookmarks = values(bm#all_bookmarks_by_line(a:file))
for bookmark in bookmarks
call bm_sign#add_at(a:file, bookmark['sign_idx'], bookmark['line_nr'], bookmark['annotation'] !=# "")
endfor
endfunction
function! s:is_quickfix_win()
return getbufvar(winbufnr('.'), '&buftype') == 'quickfix'
endfunction
function! s:auto_close()
if s:is_quickfix_win()
if (g:bookmark_auto_close)
" Setting 'splitbelow' before closing the quickfix window will ensure
" that its space is given back to the window above rather than to the
" window below.
let l:sb = &sb
set splitbelow
q
let &sb = l:sb
endif
call s:remove_auto_close()
endif
endfunction
function! s:remove_auto_close()
augroup BM_AutoCloseCommand
autocmd!
augroup END
endfunction
function! s:auto_save()
if g:bm_current_file !=# ''
call BookmarkSave(s:bookmark_save_file(g:bm_current_file), 1)
endif
augroup bm_auto_save
autocmd!
augroup END
endfunction
function! s:set_up_auto_save(file)
if g:bookmark_auto_save ==# 1 || g:bookmark_manage_per_buffer ==# 1
call s:startup_load_bookmarks(a:file)
let g:bm_current_file = a:file
augroup bm_auto_save
autocmd!
autocmd BufWinEnter * call s:add_missing_signs(expand('<afile>:p'))
autocmd BufLeave,VimLeave,BufReadPre * call s:auto_save()
augroup END
endif
endfunction
" }}}
" Maps {{{
function! s:register_mapping(command, shortcut, has_count)
if a:has_count
execute "nnoremap <silent> <Plug>". a:command ." :<C-u>". a:command ." v:count<CR>"
else
execute "nnoremap <silent> <Plug>". a:command ." :". a:command ."<CR>"
endif
if !hasmapto("<Plug>". a:command)
\ && !get(g:, 'bookmark_no_default_key_mappings', 0)
\ && maparg(a:shortcut, 'n') ==# ''
execute "nmap ". a:shortcut ." <Plug>". a:command
endif
endfunction
call s:register_mapping('BookmarkShowAll', 'ma', 0)
call s:register_mapping('BookmarkToggle', 'mm', 0)
call s:register_mapping('BookmarkAnnotate', 'mi', 0)
call s:register_mapping('BookmarkNext', 'mn', 0)
call s:register_mapping('BookmarkPrev', 'mp', 0)
call s:register_mapping('BookmarkClear', 'mc', 0)
call s:register_mapping('BookmarkClearAll', 'mx', 0)
call s:register_mapping('BookmarkMoveUp', 'mkk', 1)
call s:register_mapping('BookmarkMoveDown', 'mjj', 1)
call s:register_mapping('BookmarkMoveToLine', 'mg', 1)
" }}}
" Init {{{
if has('vim_starting')
autocmd VimEnter * call s:init(expand('<afile>:p'))
else
call s:init(expand('%:p'))
endif

View File

@ -1,176 +0,0 @@
" custom matchers
function! ToHaveBookmark(file, line)
return bm#has_bookmark_at_line(a:file, a:line)
endfunction
function! ToHaveBookmark_should_msg(file, line)
return a:file . ' should have a bookmark at line ' . a:line
endfunction
function! ToHaveBookmark_should_not_msg(file, line)
return a:file . ' should not have a bookmark at line ' . a:line
endfunction
call vspec#customize_matcher('to_have_bookmark_at', {
\ 'match': function('ToHaveBookmark'),
\ 'failure_message_for_should': function('ToHaveBookmark_should_msg'),
\ 'failure_message_for_should_not': function('ToHaveBookmark_should_not_msg')
\ })
function! ToHaveBookmarks(file)
return bm#has_bookmarks_in_file(a:file)
endfunction
function! ToHaveBookmarks_should_msg(file)
return a:file . ' should have bookmarks'
endfunction
function! ToHaveBookmarks_should_not_msg(file)
return a:file . ' should not have bookmarks'
endfunction
call vspec#customize_matcher('to_have_bookmarks', {
\ 'match': function('ToHaveBookmarks'),
\ 'failure_message_for_should': function('ToHaveBookmarks_should_msg'),
\ 'failure_message_for_should_not': function('ToHaveBookmarks_should_not_msg')
\ })
" source the plugin file
source plugin/bookmark.vim
describe 'BookmarkMove* commands'
before
edit! LICENSE
let g:file = expand('%:p')
end
it 'should work with and without arguments'
Expect g:file not to_have_bookmarks
normal 3G
BookmarkToggle
Expect g:file to_have_bookmark_at 3
BookmarkMoveUp
Expect g:file to_have_bookmark_at 2
BookmarkMoveDown 3
Expect g:file to_have_bookmark_at 5
BookmarkMoveDown
Expect g:file to_have_bookmark_at 6
BookmarkMoveDown 1
Expect g:file to_have_bookmark_at 7
BookmarkMoveUp 3
Expect g:file to_have_bookmark_at 4
" bad input
BookmarkMoveDown 2abc
Expect g:file not to_have_bookmark_at 2
BookmarkMoveUp xyz2
Expect g:file not to_have_bookmark_at 2
" invalid range
BookmarkMoveDown 999
Expect g:file to_have_bookmark_at 4
BookmarkMoveUp 999
Expect g:file to_have_bookmark_at 4
normal 10G
BookmarkToggle
Expect g:file to_have_bookmark_at 10
execute "BookmarkMoveToLine " . line('$')
Expect g:file to_have_bookmark_at line('$')
execute "normal :BookmarkMoveToLine\<CR>12\<CR>"
Expect g:file to_have_bookmark_at 12
execute "normal :BookmarkMoveToLine\<CR>13abc\<CR>"
Expect g:file not to_have_bookmark_at 13
" sadly this doesn't work in the test runner - possibly related to vspec-faq/c
" execute "normal :BookmarkMoveToLine\<CR>13\<Esc>"
" Expect g:file not to_have_bookmark_at 13
BookmarkMoveToLine 13abc
Expect g:file not to_have_bookmark_at 13
BookmarkMoveToLine 4
Expect g:file to_have_bookmark_at 12
normal 4G
BookmarkToggle
normal 12G
BookmarkToggle
Expect g:file not to_have_bookmarks
end
after
call BookmarkClear()
end
end
describe 'BookmarkMove* mappings'
before
edit! LICENSE
let g:file = expand('%:p')
end
it 'should move a bookmark when count is not specified'
Expect g:file not to_have_bookmarks
normal gg
normal mm
Expect g:file to_have_bookmark_at 1
normal mkk
Expect g:file to_have_bookmark_at 1
normal mjj
normal mjj
normal mjj
Expect g:file to_have_bookmark_at 4
normal mkk
normal mkk
Expect g:file to_have_bookmark_at 2
normal G
normal mm
Expect g:file to_have_bookmark_at line('$')
normal mjj
Expect g:file to_have_bookmark_at line('$')
execute "normal mg7abc\<CR>"
Expect g:file not to_have_bookmark_at 7
execute "normal mg7\<CR>"
Expect g:file to_have_bookmark_at 7
normal mm
normal 2G
normal mm
Expect g:file not to_have_bookmarks
end
it 'should respect [count] when specified'
Expect g:file not to_have_bookmarks
normal gg
normal mm
normal 2mjj
normal 3mjj
Expect g:file to_have_bookmark_at 6
normal 3mkk
normal mkk
Expect g:file to_have_bookmark_at 2
normal 999mkk
Expect g:file to_have_bookmark_at 2
normal 999mjj
Expect g:file to_have_bookmark_at 2
normal 5G
normal mm
Expect g:file to_have_bookmark_at 5
normal 2mg
Expect g:file to_have_bookmark_at 5
normal 1000mg
Expect g:file to_have_bookmark_at 5
normal 8mg
Expect g:file to_have_bookmark_at 8
normal 2G
normal mm
normal 8G
normal mm
Expect g:file not to_have_bookmarks
end
after
call BookmarkClear()
end
end

View File

@ -1,123 +0,0 @@
let g:bm_sign_index = 1
let g:bookmark_sign = 'xy'
let g:bookmark_annotation_sign = 'yz'
let g:bookmark_highlight_lines = 0
describe 'with uninitialized signs'
it 'should initialize'
call bm_sign#init()
Expect g:bm_sign_index ==# 1
Expect util#redir_execute(":sign list Bookmark") ==#
\ "sign Bookmark text=xy linehl= texthl=BookmarkSign"
Expect util#redir_execute(":sign list BookmarkAnnotation") ==#
\ "sign BookmarkAnnotation text=yz linehl= texthl=BookmarkAnnotationSign"
Expect split(util#redir_execute(":highlight BookmarkSignDefault"), '\n')[0] ==#
\ "BookmarkSignDefault xxx ctermfg=33"
Expect split(util#redir_execute(":highlight BookmarkAnnotationSignDefault"), '\n')[0] ==#
\ "BookmarkAnnotationSignDefault xxx ctermfg=28"
Expect split(util#redir_execute(":highlight BookmarkLineDefault"), '\n')[0] ==#
\ "BookmarkLineDefault xxx ctermfg=232 ctermbg=33"
Expect split(util#redir_execute(":highlight BookmarkAnnotationLineDefault"), '\n')[0] ==#
\ "BookmarkAnnotationLineDefault xxx ctermfg=232 ctermbg=28"
end
it 'should initialize with line highlight'
let g:bookmark_highlight_lines = 1
call bm_sign#init()
Expect util#redir_execute(":sign list Bookmark") ==#
\ "sign Bookmark text=xy linehl=BookmarkLine texthl=BookmarkSign"
end
end
describe "with initialized signs"
before
let g:bm_sign_index = 1
call bm_sign#init()
execute ":new"
execute ":e LICENSE"
let g:test_file = expand("%:p")
end
it 'should add signs'
Expect bm_sign#add(g:test_file, 2, 0) ==# 1
Expect bm_sign#add(g:test_file, 10, 1) ==# 2
let signs = util#redir_execute(":sign place file=". g:test_file)
let lines = bm_sign#lines_for_signs(g:test_file)
Expect g:bm_sign_index ==# 3
Expect len(split(signs, '\n')) ==# 4
Expect lines ==# {'1': '2', '2': '10'}
end
it 'should delete signs'
let idx1 = bm_sign#add(g:test_file, 2, 0)
let idx2 = bm_sign#add(g:test_file, 10, 0)
Expect idx1 ==# 1
Expect idx2 ==# 2
call bm_sign#del(g:test_file, idx1)
call bm_sign#del(g:test_file, idx2)
let signs = util#redir_execute(":sign place file=". g:test_file)
let lines = bm_sign#lines_for_signs(g:test_file)
Expect lines ==# {}
Expect len(split(signs, '\n')) ==# 1
end
it 'should not fail to delete signs from invalid buffer'
call bm_sign#del("invalid", 1)
end
after
execute ":q!"
end
end
describe "with added signs"
before
let g:bm_sign_index = 3
call bm_sign#init()
execute ":new"
execute ":e LICENSE"
let g:test_file = expand("%:p")
end
it 'should add sign with lower index'
call bm_sign#add_at(g:test_file, 1, 5, 0)
Expect g:bm_sign_index ==# 3
end
it 'should add sign with equal index'
call bm_sign#add_at(g:test_file, 3, 5, 0)
Expect g:bm_sign_index ==# 4
end
it 'should add sign with higher index'
call bm_sign#add_at(g:test_file, 4, 5, 0)
Expect g:bm_sign_index ==# 5
end
it 'should transform sign to annotation'
call bm_sign#add_at(g:test_file, 4, 5, 0)
call bm_sign#update_at(g:test_file, 4, 5, 1)
let signs = util#redir_execute(":sign place file=". g:test_file)
let lines = split(signs, "\n")
Expect match(lines, 'name=bookmarkannotation\c') ># 0
end
after
execute "sign unplace *"
execute ":q!"
end
end

View File

@ -1,206 +0,0 @@
describe 'empty model'
it 'should have no bookmarks'
Expect bm#has_bookmarks_in_file('foo') to_be_false
Expect bm#next('foo', 1) ==# 0
Expect bm#prev('foo', 1) ==# 0
end
it 'should add bookmark'
Expect bm#has_bookmarks_in_file('foo') to_be_false
Expect bm#has_bookmark_at_line('foo', 3) to_be_false
call bm#add_bookmark('foo', 1, 3, 'bar')
Expect bm#has_bookmarks_in_file('foo') to_be_true
Expect bm#has_bookmark_at_line('foo', 3) to_be_true
end
it 'should add bookmark with annotation'
call bm#add_bookmark('foo', 1, 3, 'bar', 'a remark')
Expect bm#get_bookmark_by_sign('foo', 1) ==# {'line_nr': 3, 'sign_idx': 1, 'content': 'bar', 'annotation': 'a remark'}
end
it 'should deserialize bookmarks'
let data = []
call add(data, "let l:bm_file_version = 1")
call add(data, "let l:bm_sessions = {'default': {'file1': [{'sign_idx': 99, 'line_nr': 1, 'content': 'foo ''test''', 'annotation': 'a note'},],'file2': [{'sign_idx': 50, 'line_nr': 12, 'content': 'bar'},{'sign_idx': 51, 'line_nr': 15, 'content': '''test'''},],}}")
call add(data, "let l:bm_current_session = 'default'")
let result = bm#deserialize(data)
Expect bm#has_bookmarks_in_file('file1') to_be_true
Expect bm#has_bookmark_at_line('file1', 1) to_be_true
Expect bm#location_list() ==# ["file1:1:Annotation: a note", "file2:12:bar", "file2:15:'test'"]
Expect len(result) ==# 3
Expect result ==# [{"file": "file1", "line_nr": 1, "sign_idx": 99, "content": "foo 'test'", "annotation": "a note"},
\{"file": "file2", "line_nr": 12, "sign_idx": 50, "content": "bar", "annotation": ""},
\{"file": "file2", "line_nr": 15, "sign_idx": 51, "content": "'test'", "annotation": ""}]
end
after
call bm#del_all()
end
end
describe 'model with bookmark'
before
call bm#add_bookmark('foo', 1, 3, 'bar', 'note')
end
it 'should get bookmark by line'
let bookmark = bm#get_bookmark_by_line('foo', 3)
Expect bookmark['line_nr'] ==# 3
Expect bookmark['sign_idx'] ==# 1
Expect bookmark['content'] ==# 'bar'
Expect bookmark['annotation'] ==# 'note'
end
it 'should get bookmark by sign'
let bookmark = bm#get_bookmark_by_sign('foo', 1)
Expect bookmark['line_nr'] ==# 3
Expect bookmark['sign_idx'] ==# 1
Expect bookmark['content'] ==# 'bar'
end
it 'should update bookmark'
call bm#update_bookmark_for_sign('foo', 1, 5, 'baz')
let bookmark = bm#get_bookmark_by_line('foo', 5)
Expect bookmark['line_nr'] ==# 5
Expect bookmark['sign_idx'] ==# 1
Expect bookmark['content'] ==# 'baz'
Expect bookmark['annotation'] ==# 'note'
Expect bookmark ==# bm#get_bookmark_by_sign('foo', 1)
end
it 'should update annotation'
call bm#update_annotation('foo', 1, 'awesome annotation')
let bookmark = bm#get_bookmark_by_line('foo', 3)
Expect bookmark['annotation'] ==# 'awesome annotation'
end
it 'should delete bookmark at line'
call bm#del_bookmark_at_line('foo', 3)
Expect bm#has_bookmark_at_line('foo', 3) to_be_false
end
after
call bm#del_all()
end
end
describe 'model with multiple bookmarks in different files'
before
call bm#add_bookmark('file3', 1, 10, 'file3/line10')
call bm#add_bookmark('file1', 1, 12, 'file1/line12')
call bm#add_bookmark('file2', 2, 34, 'file2/line34', 'an annotation')
call bm#add_bookmark('file1', 3, 2, 'file1/line2')
call bm#add_bookmark('file1', 4, 45, '''test''')
call bm#add_bookmark('file2', 5, 45, '')
end
it 'should return all bookmarks of file per line'
let dict1 = bm#all_bookmarks_by_line('file1')
let dict2 = bm#all_bookmarks_by_line('file2')
Expect len(keys(dict1)) ==# 3
Expect len(keys(dict2)) ==# 2
Expect dict1[12]['sign_idx'] ==# 1
Expect dict2[34]['sign_idx'] ==# 2
Expect dict1[2]['sign_idx'] ==# 3
Expect dict1[45]['sign_idx'] ==# 4
Expect dict2[45]['sign_idx'] ==# 5
end
it 'should return total count of bookmarks'
Expect bm#total_count() ==# 6
end
it 'should return all lines'
let lines = bm#all_lines('file1')
Expect lines ==# ['2', '12', '45']
end
it 'should return all files with bookmarks'
let files = bm#all_files()
Expect files ==# ['file1', 'file2', 'file3']
end
it 'should return next bookmark'
Expect bm#next('file1', 1) ==# 2
Expect bm#next('file1', 3) ==# 12
Expect bm#next('file1', 11) ==# 12
Expect bm#next('file1', 12) ==# 45
Expect bm#next('file1', 13) ==# 45
Expect bm#next('file1', 59) ==# 2
end
it 'should return previous bookmark'
Expect bm#prev('file1', 1) ==# 45
Expect bm#prev('file1', 3) ==# 2
Expect bm#prev('file1', 11) ==# 2
Expect bm#prev('file1', 12) ==# 2
Expect bm#prev('file1', 13) ==# 12
Expect bm#prev('file1', 59) ==# 45
end
it 'should return location list'
let locations = bm#location_list()
Expect len(locations) ==# 6
Expect locations[0] ==# 'file1:2:file1/line2'
Expect locations[1] ==# 'file1:12:file1/line12'
Expect locations[2] ==# 'file1:45:''test'''
Expect locations[3] ==# 'file2:34:Annotation: an annotation'
Expect locations[4] ==# 'file2:45:empty line'
Expect locations[5] ==# 'file3:10:file3/line10'
end
it 'should serialize'
exec join(bm#serialize(), " | ")
let s = l:bm_sessions["default"]
Expect l:bm_file_version ==# 1
Expect len(keys(l:bm_sessions)) ==# 1
Expect len(s) ==# 3
Expect len(s["file1"]) ==# 3
Expect len(s["file2"]) ==# 2
Expect len(s["file3"]) ==# 1
Expect s["file1"] ==# [{"line_nr": 2, "sign_idx": 3, "content": "file1/line2"}, {"line_nr": 12, "sign_idx": 1, "content": "file1/line12"}, {"line_nr": 45, "sign_idx": 4, "content": "'test'"}]
Expect s["file2"] ==# [{"line_nr": 34, "sign_idx": 2, "content": "file2/line34", "annotation": "an annotation"}, {"line_nr": 45, "sign_idx": 5, "content": ""}]
Expect s["file3"] ==# [{"line_nr": 10, "sign_idx": 1, "content": "file3/line10"}]
Expect l:bm_current_session ==# 'default'
end
after
call bm#del_all()
end
end
describe 'bm#del_all'
it 'should reset the model'
call bm#add_bookmark('file1', 1, 1, 'line1')
call bm#add_bookmark('file2', 2, 1, 'line1')
call bm#del_all()
Expect empty(g:line_map) to_be_true
Expect empty(g:sign_map) to_be_true
Expect bm#has_bookmarks_in_file('file1') to_be_false
Expect bm#has_bookmarks_in_file('file2') to_be_false
end
end

View File

@ -1,7 +0,0 @@
describe 'util'
it 'should return command output'
Expect util#redir_execute(":echo 'foo'") ==# 'foo'
end
end

View File

@ -44,7 +44,6 @@ In `bundle/` directory, there are two kinds of plugins: forked plugins without c
These plugins are changed based on a specific version of origin plugin.
- `vim-bookmarks`: based on [MattesGroeger/vim-bookmarks@3adeae1](https://github.com/MattesGroeger/vim-bookmarks/commit/3adeae10639edcba29ea80dafa1c58cf545cb80e)
- `delimitMate`: based on [Raimondi/delimitMate@537a1da](https://github.com/Raimondi/delimitMate/tree/537a1da0fa5eeb88640425c37e545af933c56e1b)
- `vim-toml`: based on [cespare/vim-toml@717bd87ef9](https://github.com/cespare/vim-toml/tree/717bd87ef928293e0cc6cfc12ebf2e007cb25311)
- `neoformat`: based on [neoformat@f1b6cd50](https://github.com/sbdchd/neoformat/tree/f1b6cd506b72be0a2aaf529105320ec929683920)

View File

@ -34,7 +34,7 @@ To use this configuration layer, update your custom configuration file with:
- `:Calendar`: open vim calendar
- `:UnstackFromText`: Call unstack with text as input.
This layer also includes `vim-bookmarks`, the following key binding can be used:
This layer also includes `bookmarks.vim`, the following key binding can be used:
| key binding | description |
| -------------- | ------------------------- |

View File

@ -17,23 +17,14 @@ local file = require('spacevim.api.file')
local function get_all_bookmarks()
local p = {}
local files = vim.fn['bm#all_files']()
local bookmarks = vim.fn['bookmarks#get_all_bookmarks']()
for _, k in ipairs(files) do
local line_nrs = vim.fn['bm#all_lines'](k)
for _, line_nr in ipairs(line_nrs) do
local bookmark = vim.fn['bm#get_bookmark_by_line'](k, line_nr)
local text = 'EMPTY LINE'
if #bookmark.annotation > 0 then
text = bookmark.annotation
elseif #bookmark.content > 0 then
text = bookmark.content
end
for f, l in pairs(bookmarks) do
for nr, b in pairs(l) do
table.insert(p, {
file = file.unify_path(k, ':.'),
linenr = line_nr,
text = text,
file = file.unify_path(f, ':.'),
linenr = nr,
text = b.text,
})
end
end
@ -75,7 +66,8 @@ local function show_changes(opts)
local entry = action_state.get_selected_entry()
actions.close(prompt_bufnr)
vim.cmd('e ' .. entry.value.file)
vim.api.nvim_win_set_cursor(0, { entry.value.linenr, 1 })
-- vim.api.nvim_win_set_cursor(0, { entry.value.linenr, 1 })
vim.cmd(entry.value.linenr)
end)
return true
end,