diff --git a/etc/soft/nvim/+plugins/vim-signature/.gitignore b/etc/soft/nvim/+plugins/vim-signature/.gitignore new file mode 100644 index 0000000..0a56e3f --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-signature/.gitignore @@ -0,0 +1 @@ +/doc/tags diff --git a/etc/soft/nvim/+plugins/vim-signature/LICENSE b/etc/soft/nvim/+plugins/vim-signature/LICENSE new file mode 100644 index 0000000..d0aa2f7 --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-signature/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Kartik Shenoy + +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. + diff --git a/etc/soft/nvim/+plugins/vim-signature/README.md b/etc/soft/nvim/+plugins/vim-signature/README.md new file mode 100644 index 0000000..f3d2df8 --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-signature/README.md @@ -0,0 +1,97 @@ +#### 2017-09-23: +Changed the default value of `g:SignatureForceRemoveGlobal` to 0 since using `:wviminfo!`/`:wshada!` is a very heavy hammer and because it goes against a \*vim default. + +#### 2016-07-08: +Signature used to have a mapping conflict with NERDTree as both try to map the `m` key. +To get around this, I used to delete maps whenever I detected someone entering the NERDTree pane and recreate the maps upon exit. +However, this had a lot of issues and as of [cfa6452](https://github.com/kshenoy/vim-signature/commit/cfa64525305dbb8cec7eefc16e4ea460f007cd33) I've decided to remove any code that was intended to work around this since it wasn't working anyways. Refer to the discussion [here](https://github.com/kshenoy/vim-signature/issues/3#issuecomment-222565292) for more details. +Sorry for any inconvenience. If anyone has any ideas or suggestions please let me know. + +# vim-signature +vim-signature is a plugin to place, toggle and display marks. + +Apart from the above, you can also +* Navigate forward/backward by position/alphabetical order +* Displaying multiple marks (upto 2, limited by the signs feature) +* Placing custom signs !@#$%^&*() as visual markers + + +### Screenshots +![vim-signature_marks_markers](https://github.com/kshenoy/vim-signature/blob/images/screens/vim-signature_marks_markers.png?raw=true) +Displays the marks as signs. Also place visual markers + +![Mark jumps](https://github.com/kshenoy/vim-signature/blob/images/screens/vim-signature_mark_jumps.gif?raw=true) +Alphabetical mark traversal and more. + +![Dynamic Highlighting](https://github.com/kshenoy/vim-signature/blob/images/screens/vim-signature_dynamic_hl.png?raw=true) + +Also supports dynamic highlighting of signs. In the image above the marks are colored according to the state of the line as indicated by gitgutter. + +NOTE: This feature is disabled by default + +More screenshots [here](http://imgur.com/a/3KQyt) + +### Vim.org mirror +If you like the plugin, spread the love and rate at http://www.vim.org/scripts/script.php?script_id=4118 + + +## Requirements +Requires Vim to be compiled with +signs to display marks. + + +## Installation +I recommend using a plugin manager to do the grunt work for you. +If for some reason, you do not want to use any of them, then unzip the contents of the .zip file to your ~/.vim directory. + +Once that's done, out of the box, the followings mappings are defined + +```` + mx Toggle mark 'x' and display it in the leftmost column + dmx Remove mark 'x' where x is a-zA-Z + + m, Place the next available mark + m. If no mark on line, place the next available mark. Otherwise, remove (first) existing mark. + m- Delete all marks from the current line + m Delete all marks from the current buffer + ]` Jump to next mark + [` Jump to prev mark + ]' Jump to start of next line containing a mark + [' Jump to start of prev line containing a mark + `] Jump by alphabetical order to next mark + `[ Jump by alphabetical order to prev mark + '] Jump by alphabetical order to start of next line having a mark + '[ Jump by alphabetical order to start of prev line having a mark + m/ Open location list and display marks from current buffer + + m[0-9] Toggle the corresponding marker !@#$%^&*() + m Remove all markers of the same type + ]- Jump to next line having a marker of the same type + [- Jump to prev line having a marker of the same type + ]= Jump to next line having a marker of any type + [= Jump to prev line having a marker of any type + m? Open location list and display markers from current buffer + m Remove all markers +```` + +This will allow the use of default behavior of m to set marks and, if the line +already contains the mark, it'll be unset. +The default behavior of `]'`, `['`, ``]` `` and ``[` `` is supported and enhanced by +wrapping around when beginning or end of file is reached. + +The command `:SignatureToggle` can be used to show/hide the signs. +Note that this does not delete any of the marks but only hides them. +This is a buffer-specific command. + +If for some reason, the marks and their sign displays go out of sync, +use `:SignatureRefresh` to refresh them. + +For more details on customization refer the help + + +## Thanks to... +* Sergey Khorev for [mark-tools](http://www.vim.org/scripts/script.php?script_id=2929) +* Zak Johnson for [vim-showmarks](https://github.com/zakj/vim-showmarks) + + +## ToDo: +* Tie the Signature functions to vim commands that affect mark placement diff --git a/etc/soft/nvim/+plugins/vim-signature/after/plugin/signature.vim b/etc/soft/nvim/+plugins/vim-signature/after/plugin/signature.vim new file mode 100644 index 0000000..a0fe03a --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-signature/after/plugin/signature.vim @@ -0,0 +1,38 @@ +" vim: fdm=marker:et:ts=4:sw=2:sts=2 + +" Maintainer: Kartik Shenoy +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +" Exit if the signs feature is not available or if the app has already been loaded (or "compatible" mode set) +if ( !has('signs') + \ || &cp + \ ) + finish +endif + +"" Exit if vim-signature is not loaded +if !exists('g:loaded_Signature') + finish +endif + +if exists('g:loaded_gitgutter') + if g:SignatureMarkTextHLDynamic + unlet g:SignatureMarkTextHL + let g:SignatureMarkTextHL = function("signature#sign#GetGitGutterHLGroup") + endif + if g:SignatureMarkerTextHLDynamic + unlet g:SignatureMarkerTextHL + let g:SignatureMarkerTextHL = function("signature#sign#GetGitGutterHLGroup") + endif +endif + +if exists('g:loaded_signify') + if g:SignatureMarkTextHLDynamic + unlet g:SignatureMarkTextHL + let g:SignatureMarkTextHL = function("signature#sign#GetSignifyHLGroup") + endif + if g:SignatureMarkerTextHLDynamic + unlet g:SignatureMarkerTextHL + let g:SignatureMarkerTextHL = function("signature#sign#GetSignifyHLGroup") + endif +endif diff --git a/etc/soft/nvim/+plugins/vim-signature/autoload/signature/mark.vim b/etc/soft/nvim/+plugins/vim-signature/autoload/signature/mark.vim new file mode 100644 index 0000000..3389aae --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-signature/autoload/signature/mark.vim @@ -0,0 +1,427 @@ +" vim: fdm=marker:et:ts=4:sw=2:sts=1 +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +function! signature#mark#Toggle(mark) " {{{1 + " Description: mark = 'next' : Place new mark on current line else toggle specified mark on current line + " Arguments: mark [a-z,A-Z] + + if a:mark == "next" + " Place new mark + let l:marks_list = signature#mark#GetList('free', 'buf_all') + if empty(l:marks_list) + if (!g:SignatureRecycleMarks) + " No marks available and mark re-use not in effect + call s:ReportNoAvailableMarks() + return + endif + " Remove a local mark + let l:marks_list = signature#mark#GetList('used', 'buf_curr')[0] + call signature#mark#Remove(l:marks_list[0]) + endif + call s:Place(l:marks_list[0]) + + else + " Toggle Mark + let l:used_marks = filter(signature#mark#GetList('used', 'buf_all'), 'v:val[0] ==# a:mark') + if (len(l:used_marks) > 0) + let l:mark_pos = l:used_marks[0][1] + let l:mark_buf = l:used_marks[0][2] + + if (l:mark_buf == bufnr('%')) + " If the mark is not in use in current buffer then it's a global ==> Don't worry about deleting it + if ( (l:mark_pos == line('.')) + \ && !g:SignatureForceMarkPlacement + \ ) + " Mark is present on the current line. Remove it and return + call signature#mark#Remove(a:mark) + call signature#sign#ToggleDummy() + return + else + " Mark is present elsewhere in the current buffer ==> Remove it and fall-through to place new mark. + " If g:SignatureForceMarkPlacement is set, we remove and re-place it so that the sign string can be true + " to the order in which the marks were placed. + " For eg. if we place 'a, 'b and then 'a again, the sign string changes from "ab" to "ba" + " Ask for confirmation before moving mark + if (g:SignatureDeleteConfirmation) + let choice = confirm("Mark '" . a:mark . "' has been used elsewhere. Reuse it?", "&Yes\n&No", 1) + if choice == 2 | return | endif + endif + call signature#mark#Remove(a:mark) + endif + endif + endif + + " Place new mark + call s:Place(a:mark) + endif +endfunction + + +function! signature#mark#Remove(mark) " {{{1 + " Description: Remove 'mark' and its associated sign. If called without an argument, obtain it from the user + " Arguments: mark = [a-z,A-Z] + + if !signature#utils#IsValidMark(a:mark) + return + endif + + let l:lnum = line("'" . a:mark) + call signature#sign#Remove(a:mark, l:lnum) + execute 'delmarks ' . a:mark + call s:ForceGlobalRemoval(a:mark) +endfunction + + +function! s:Place(mark) " {{{1 + " Description: Place new mark at current cursor position + " Arguments: mark = [a-z,A-Z] + " If a line is deleted or mark is manipulated using any non-signature method then b:sig_marks can go out of sync + " Thus, we forcibly remove signs for the mark present on any line before proceeding + call signature#sign#Remove(a:mark, 0) + execute 'normal! m' . a:mark + call signature#sign#Place(a:mark, line('.')) +endfunction + + +function! signature#mark#ToggleAtLine() " {{{1 + " Description: If no mark on current line, add one. If marks are on the current line, remove one. + let l:marks_here = filter(signature#mark#GetList('used', 'buf_curr'), 'v:val[1] == ' . line('.')) + if empty(l:marks_here) + " Set up for adding a mark + call signature#mark#Toggle('next') + else + " Delete first mark + call signature#mark#Remove(l:marks_here[0][0]) + endif +endfunction + + +function! signature#mark#Purge(mode) " {{{1 + " Description: Delete all marks from current line + " Arguments: mode = 'line' : Delete all marks from current line + " 'all' : Delete all marks used in the buffer + + let l:used_marks = signature#mark#GetList('used', 'buf_curr') + if (a:mode ==? 'line') + call filter(l:used_marks, 'v:val[1] == ' . line('.')) + endif + + if ( !empty(l:used_marks) + \ && g:SignaturePurgeConfirmation + \ ) + let l:msg = 'Are you sure you want to delete all marks' . (a:mode ==? 'line' ? ' from the current line' : '') . '?' + let l:ans = confirm(l:msg . ' This cannot be undone.', "&Yes\n&No", 1) + if (l:ans != 1) | return | endif + endif + + for i in l:used_marks + call signature#mark#Remove(i[0]) + endfor + + " If marks are modified using any non-signature method, b:sig_marks can go out of sync + if (a:mode ==? 'all') + for l:lnum in keys(b:sig_marks) + call signature#sign#Unplace(l:lnum) + endfor + endif + call signature#sign#ToggleDummy() +endfunction + + +function! signature#mark#Goto(dir, loc, mode) " {{{1 + " Arguments: + " dir = next : Jump forward + " prev : Jump backward + " loc = line : Jump to first column of line with mark + " spot : Jump to exact column of the mark + " mode = pos : Jump to next mark by position + " alpha : Jump to next mark by alphabetical order + " global : Jump only to global marks (applies to all buffers and alphabetical order) + + let l:mark = "" + let l:dir = a:dir + + if a:mode ==? "global" + let l:mark = s:GotoByAlphaGlobal(a:dir) + elseif a:mode ==? "alpha" + let l:mark = s:GotoByAlpha(a:dir) + elseif a:mode ==? "pos" + let l:mark = s:GotoByPos(a:dir) + endif + + " NOTE: If l:mark is an empty string then no movement will be made + if l:mark == "" | return | endif + + if a:loc ==? "line" + execute "normal! '" . l:mark + elseif a:loc ==? "spot" + execute 'normal! `' . l:mark + endif +endfunction + + +function! s:GotoByPos(dir) " {{{1 + " Description: Jump to next/prev mark by location. + " Arguments: dir = next : Jump forward + " prev : Jump backward + + " We need at least one mark to be present. If not, then return an empty string so that no movement will be made + if empty(b:sig_marks) | return "" | endif + + let l:lnum = line('.') + + " Get list of line numbers of lines with marks. + if a:dir ==? "next" + let l:targ = min(sort(keys(b:sig_marks), "signature#utils#NumericSort")) + let l:mark_lnums = sort(keys(filter(copy(b:sig_marks), 'v:key > l:lnum')), "signature#utils#NumericSort") + elseif a:dir ==? "prev" + let l:targ = max(sort(keys(b:sig_marks), "signature#utils#NumericSort")) + let l:mark_lnums = reverse(sort(keys(filter(copy(b:sig_marks), 'v:key < l:lnum')), "signature#utils#NumericSort")) + endif + + let l:targ = (empty(l:mark_lnums) ? (b:SignatureWrapJumps ? l:targ : "") : l:mark_lnums[0]) + if empty(l:targ) | return "" | endif + + let l:mark = signature#utils#GetChar(b:sig_marks[l:targ], 0) + return l:mark +endfunction + + +function! s:GotoByAlpha(dir) " {{{1 + " Description: Jump to next/prev mark by alphabetical order. Direction specified as input argument + + let l:used_marks = signature#mark#GetList('used', 'buf_curr') + let l:line_marks = filter(copy(l:used_marks), 'v:val[1] == ' . line('.')) + + " If there is only one mark in the current file, then return the same + if (len(l:used_marks) == 1) + return l:used_marks[0][0] + endif + + " Since we can place multiple marks on a line, to jump by alphabetical order we need to know what the current mark is. + " This information is kept in the b:sig_GotoByAlpha_CurrMark variable. For instance, if we have marks a, b and c + " on the current line and b:sig_GotoByAlpha_CurrMark has the value 'a' then we jump to 'b' and set the value of + " the variable to 'b'. Reinvoking this function will thus now jump to 'c' + if empty(l:line_marks) + if exists('b:sig_GotoByAlpha_CurrMark') + unlet b:sig_GotoByAlpha_CurrMark + endif + " If there are no marks present on the current line then call GotoByPos to jump to the next line with a mark + return s:GotoByPos(a:dir) + endif + + if (( len(l:line_marks) == 1 ) || !exists('b:sig_GotoByAlpha_CurrMark') || (b:sig_GotoByAlpha_CurrMark ==? "")) + let b:sig_GotoByAlpha_CurrMark = l:line_marks[0][0] + endif + + for i in range( 0, len(l:used_marks) - 1 ) + if l:used_marks[i][0] ==# b:sig_GotoByAlpha_CurrMark + if a:dir ==? "next" + if (( i != len(l:used_marks)-1 ) || b:SignatureWrapJumps) + let b:sig_GotoByAlpha_CurrMark = l:used_marks[(i+1)%len(l:used_marks)][0] + endif + elseif a:dir ==? "prev" + if ((i != 0) || b:SignatureWrapJumps) + let b:sig_GotoByAlpha_CurrMark = l:used_marks[i-1][0] + endif + endif + return b:sig_GotoByAlpha_CurrMark + endif + endfor +endfunction + + +function! s:GotoByAlphaGlobal(dir) " {{{1 + " Description: Jump to next/prev Global mark in any buffer by alphabetical order. + " Direction is specified as input argument + + let l:used_marks = signature#mark#GetList('used', 'buf_all', 'global') + let l:line_marks = filter(copy(l:used_marks), 'v:val[1] == ' . line('.')) + + " If there is only one mark in the current file, return it + if (len(l:used_marks) == 1) + return l:used_marks[0][0] + endif + " If current line does not have a global mark on it then return the first used global mark + if empty(l:line_marks) + if exists('b:sig_GotoByAlphaGlobal_CurrMark') + unlet b:sig_GotoByAlphaGlobal_CurrMark + endif + return l:used_marks[0][0] + endif + + " Since we can place multiple marks on a line, to jump by alphabetical order we need to know what the current mark is. + " This information is kept in the b:sig_GotoByAlphaGlobal_CurrMark variable. For instance, if we have marks A, B & C + " on the current line and b:sig_GotoByAlphaGlobal_CurrMark has the value 'A' then we jump to 'B' and set the value of + " the variable to 'B'. Reinvoking this function will thus now jump to 'C' + if ( (len(l:line_marks) == 1) + \ || !exists('b:sig_GotoByAlpha_CurrMark') + \ || (b:sig_GotoByAlphaGlobal_CurrMark ==? "") + \ ) + let b:sig_GotoByAlphaGlobal_CurrMark = l:line_marks[0][0] + endif + + for i in range( 0, len(l:used_marks) - 1 ) + if l:used_marks[i][0] ==# b:sig_GotoByAlphaGlobal_CurrMark + if a:dir ==? "next" + if (( i != len(l:used_marks)-1 ) || b:SignatureWrapJumps) + let b:sig_GotoByAlphaGlobal_CurrMark = l:used_marks[(i+1)%len(l:used_marks)][0] + endif + elseif a:dir ==? "prev" + if ((i != 0) || b:SignatureWrapJumps) + let b:sig_GotoByAlphaGlobal_CurrMark = l:used_marks[i-1][0] + endif + endif + return b:sig_GotoByAlphaGlobal_CurrMark + endif + endfor +endfunction + + +function! signature#mark#GetList(mode, scope, ...) " {{{1 + " Arguments: mode = 'used' : Returns list of [ [used marks, line no., buf no.] ] + " 'free' : Returns list of [ free marks ] + " scope = 'buf_curr' : Limits scope to current buffer i.e used/free marks in current buffer + " 'buf_all' : Set scope to all buffers i.e used/free marks from all buffers + " [type] = 'global' : Return only global marks + + let l:marks_list = [] + let l:line_tot = line('$') + let l:buf_curr = bufnr('%') + let l:type = (a:0 ? a:1 : "") + + " Respect order specified in g:SignatureIncludeMarks + for i in split(b:SignatureIncludeMarks, '\zs') + if (i =~# "[A-Z]") + let [ l:buf, l:line, l:col, l:off ] = getpos( "'" . i ) + let l:marks_list = add(l:marks_list, [i, l:line, l:buf]) + elseif (l:type !=? "global") + let l:marks_list = add(l:marks_list, [i, line("'" .i), l:buf_curr]) + endif + endfor + + if (a:mode ==? 'used') + if (a:scope ==? 'buf_curr') + call filter( l:marks_list, '(v:val[2] == l:buf_curr) && (v:val[1] > 0)' ) + else + call filter( l:marks_list, 'v:val[1] > 0' ) + endif + else + if (a:scope ==? 'buf_all') + call filter( l:marks_list, 'v:val[1] == 0' ) + else + call filter( l:marks_list, '(v:val[1] == 0) || (v:val[2] != l:buf_curr)' ) + endif + call map( l:marks_list, 'v:val[0]' ) + endif + + return l:marks_list +endfunction + + +function! s:ForceGlobalRemoval(mark) " {{{1 + " Description: Edit viminfo/shada file to forcibly delete Global mark since vim's handling is iffy + " Arguments: mark - The mark to delete + + if ( (a:mark !~# '[A-Z]') + \ || !g:SignatureForceRemoveGlobal + \ ) + return + endif + + if has('nvim') + wshada! + else + wviminfo! + endif +endfunction + + +function! s:ReportNoAvailableMarks() " {{{1 + if g:SignatureErrorIfNoAvailableMarks + echoe "Signature: No free marks left." + else + echohl WarningMsg + echomsg "Signature: No free marks left." + echohl None + endif +endfunction + + +function! signature#mark#List(scope, ...) " {{{1 + " Description: Opens and populates location list with marks + " Arguments: scope = 0 : List local and global marks from current buffer + " 1 : List only global marks from all buffers + " [context] = 0 : Adds context around the mark + + let l:list = [] + let l:buf_curr = bufnr('%') + let l:list_sep = {'bufnr': '', 'lnum' : ''} + + let l:SignatureIncludeMarks = (a:scope == 0 ? b:SignatureIncludeMarks : g:SignatureIncludeMarks) + for i in split(l:SignatureIncludeMarks, '\zs') + let [l:bufnr, l:lnum, l:col, l:off] = getpos( "'" . i ) + + " Local marks set the buffer no. to 0, replace it with the actual buffer number + let l:bufnr = (l:bufnr == 0 ? l:buf_curr : l:bufnr) + + " Check that + " 1. Mark is set (lnum > 0) + " 2. If buf_all = 0, filter out global marks from other buffers + " 3. If buf_all = 1, filter out local marks from current buffer + if ( (l:lnum == 0) + \ || ( (a:scope == 0) + \ && (l:bufnr != l:buf_curr) + \ ) + \ || ( (a:scope == 1) + \ && (i =~# "[a-z]") + \ ) + \ ) + "echom 'DEBUG: Skipping mark ' . i + continue + endif + + " If the buffer is not loaded, what's the point of showing empty context? + let l:context = (bufloaded(l:bufnr) && a:0 ? a:1 : 0) + + for context_lnum in range(l:lnum - l:context, l:lnum + l:context) + let l:text = get(getbufline(l:bufnr, context_lnum), 0, "") + if (!bufloaded(l:bufnr)) + " Buffer is not loaded, hence we won't be able to get the line. Opening the file should fix it + let l:text = "~~~ File is not loaded into memory. Open file and rerun to see the line ~~~" + elseif (l:text == "") + " Line does not exist. Possibly because context_lnum > total no. of lines + "echom 'DEBUG: Skipping line=' . context_lnum . ' for mark=' . i . " because line doesn't exist in buffer=" . l:bufnr + continue + endif + + if (context_lnum < l:lnum) | let l:text = '-: ' . l:text + elseif (context_lnum > l:lnum) | let l:text = '+: ' . l:text + else | let l:text = i . ': ' . l:text + endif + + let l:list = add(l:list, + \ { 'text' : l:text, + \ 'bufnr': l:bufnr, + \ 'lnum' : context_lnum, + \ 'col' : l:col, + \ 'type' : 'm' + \ } + \ ) + endfor + + " Add separator when showing context + "if (a:context > 0) + " let l:list = add(l:list, l:list_sep) + "endif + endfor + + " Remove the redundant separator at the end when showing context + "if ( (a:context > 0) + " \ && (len(l:list) > 0) + " \ ) + " call remove(l:list, -1) + "endif + + call setloclist(0, l:list) | lopen +endfunction diff --git a/etc/soft/nvim/+plugins/vim-signature/autoload/signature/marker.vim b/etc/soft/nvim/+plugins/vim-signature/autoload/signature/marker.vim new file mode 100644 index 0000000..153eb5f --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-signature/autoload/signature/marker.vim @@ -0,0 +1,174 @@ +" vim: fdm=marker:et:ts=4:sw=2:sts=1 +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +function! signature#marker#Toggle(marker) " {{{1 + " Description: Toggle marker on current line + " Arguments: marker [!@#$%^&*()] + + let l:lnum = line('.') + " If marker is found on current line, remove it, else place it + if ( (get(b:sig_markers, l:lnum, "") =~# escape(a:marker, '$^')) + \ && !g:SignatureForceMarkerPlacement + \ ) + call signature#sign#Remove(a:marker, l:lnum) + call signature#sign#ToggleDummy() + else + call signature#sign#Place(a:marker, l:lnum) + endif +endfunction + + +function! signature#marker#Remove(lnum, marker) " {{{1 + " Description: Remove marker from specified line number + " Arguments: lnum - Line no. to delete marker from. If is 0, removes marker from current line + " a:2 - Marker to delete. If not specified, obtains input from user + + if (get(b:sig_markers, a:lnum, '') =~ a:marker) + call signature#sign#Remove(a:marker, a:lnum) + endif +endfunction + + +function! signature#marker#Purge(...) " {{{1 + " Description: If argument is given, removes marker only of the specified type else all markers are removed + + if empty(b:sig_markers) | return | endif + if g:SignaturePurgeConfirmation + let choice = confirm('Are you sure you want to delete all markers? This cannot be undone.', '&Yes\n&No', 1) + if choice == 2 | return | endif + endif + + if a:0 > 0 + let l:markers = [ a:1 ] + else + let l:markers = split(b:SignatureIncludeMarkers, '\zs') + endif + + for l:marker in l:markers + for l:lnum in keys(filter(copy(b:sig_markers), 'v:val =~# l:marker')) + call signature#marker#Remove(l:lnum, l:marker) + endfor + endfor + call signature#sign#ToggleDummy() +endfunction + + +function! signature#marker#Goto( dir, marker_num, count ) " {{{1 + " Description: Jump to next/prev marker by location. + " Arguments: dir = next : Jump forward + " prev : Jump backward + " marker = same : Jump to a marker of the same type + " any : Jump to a marker of any type + " [0-9] : Jump to the corresponding marker + + let l:lnum = line('.') + + let l:marker = '' + if (a:marker_num =~ '\v<[0-9]>') + let l:marker = split(b:SignatureIncludeMarkers, '\zs')[a:marker_num] + elseif ( (a:marker_num ==? 'same') + \ && has_key(b:sig_markers, l:lnum) + \ ) + let l:marker = signature#utils#GetChar(b:sig_markers[l:lnum], 0) + endif + + " Get list of line numbers of lines with markers. + " If current line has a marker, filter out line numbers of other markers ... + if (l:marker != '') + let l:marker_lnums = sort(keys(filter(copy(b:sig_markers), + \ 'signature#utils#GetChar(v:val, 0) == l:marker')), "signature#utils#NumericSort") + else + let l:marker_lnums = sort(keys(b:sig_markers), "signature#utils#NumericSort") + endif + + if (a:dir ==? 'next') + let l:marker_lnums = filter(copy(l:marker_lnums), ' v:val > l:lnum') + \ + filter(copy(l:marker_lnums), '(v:val <= l:lnum) && b:SignatureWrapJumps') + elseif (a:dir ==? 'prev') + call reverse(l:marker_lnums) + let l:marker_lnums = filter(copy(l:marker_lnums), ' v:val < l:lnum') + \ + filter(copy(l:marker_lnums), '(v:val >= l:lnum) && b:SignatureWrapJumps') + endif + + if (len(l:marker_lnums) == 0) + return + endif + + let l:count = (a:count == 0 ? 1 : a:count) + if (b:SignatureWrapJumps) + let l:count = l:count % len(l:marker_lnums) + elseif (l:count > len(l:marker_lnums)) + let l:count = 0 + endif + + let l:targ = l:marker_lnums[l:count - 1] + execute 'normal! ' . l:targ . 'G' +endfunction + + +function! signature#marker#List(...) " {{{1 + " Description: Opens and populates location list with markers from current buffer + " Show all markers in location list if no argument is provided + " Argument: [markers] = 0-9 or any of the specified symbols : List only the specified markers + " [context] = 0 (default) : Adds context around marker + " To show all markers with 1 line of context call using arguments ("", 1) + + let l:markers = (a:0 && (a:1 != "") ? a:1 : b:SignatureIncludeMarkers) + let l:context = (a:0 > 1 ? a:2 : 0) + + if (l:markers =~ '^\d$') + if ( ( (l:markers == 0) + \ && (len(b:SignatureIncludeMarkers) != 10) + \ ) + \ || (l:markers > len(b:SignatureIncludeMarkers)) + \ ) + echoe "Signature: No corresponding marker exists for " . l:markers + return + endif + let l:markers = split(b:SignatureIncludeMarkers, '\zs')[l:markers] + endif + + let l:lines_tot = line('$') + let l:buf_curr = bufnr('%') + let l:list_sep = {'bufnr': '', 'lnum' : ''} + let l:list = [] + + " Markers not specified in b:SignatureIncludeMarkers won't be present in b:sig_markers and hence get filtered out + for l:lnum in sort(keys(filter(copy(b:sig_markers), 'v:val =~ "[" . l:markers . "]"'))) + + for context_lnum in range(l:lnum - l:context, l:lnum + l:context) + if ( (context_lnum < 1) + \ || (context_lnum > lines_tot) + \ ) + continue + endif + + if (context_lnum < l:lnum) | let l:text = '-' . ": " . getline(context_lnum) + elseif (context_lnum > l:lnum) | let l:text = '+' . ": " . getline(context_lnum) + else | let l:text = b:sig_markers[l:lnum] . ": " . getline(context_lnum) + endif + + let l:list = add(l:list, + \ { 'text' : l:text, + \ 'bufnr': l:buf_curr, + \ 'lnum' : context_lnum, + \ 'type' : 'M' + \ } + \ ) + endfor + + " Add separator when showing context + "if (a:context > 0) + " let l:list = add(l:list, l:list_sep) + "endif + endfor + + " Remove the redundant separator at the end when showing context + "if ( (a:context > 0) + " \ && (len(l:list) > 0) + " \ ) + " call remove(l:list, -1) + "endif + + call setloclist(0, l:list,) | lopen +endfunction diff --git a/etc/soft/nvim/+plugins/vim-signature/autoload/signature/sign.vim b/etc/soft/nvim/+plugins/vim-signature/autoload/signature/sign.vim new file mode 100644 index 0000000..251efc2 --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-signature/autoload/signature/sign.vim @@ -0,0 +1,375 @@ +" vim: fdm=marker:et:ts=4:sw=2:sts=2 +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +function! signature#sign#Place(sign, lnum) "{{{1 + " Description: Place signs for marks/markers on the specified line number + " Arguments: + " sign : The mark/marker whose sign is to be placed + " lnum : Line number on/from which the sign is to be placed/removed + + "echom "DEBUG: sign = " . a:sign . ", lnum = " . a:lnum + + " If Signature is not enabled, return + if !b:sig_enabled | return | endif + + " FIXME: Highly inefficient. Needs work + " Place sign only if there are no signs from other plugins (eg. syntastic) + "let l:present_signs = s:GetInfo(1) + "if ( b:SignatureDeferPlacement + " \ && has_key(l:present_signs, a:lnum) + " \ && (l:present_signs[a:lnum]['name'] !~# '^sig_Sign_') + " \ ) + " return + "endif + + if signature#utils#IsValidMarker(a:sign) + let b:sig_markers[a:lnum] = a:sign . get(b:sig_markers, a:lnum, "") + elseif signature#utils#IsValidMark(a:sign) + let b:sig_marks[a:lnum] = a:sign . get(b:sig_marks, a:lnum, "") + else + echoerr "Unexpected sign found: " . a:sign + endif + "}}}3 + + call s:RefreshLine(a:lnum) +endfunction + + +function! signature#sign#Remove(sign, lnum) "{{{1 + " Description: Remove signs for marks/markers from the specified line number + " Arguments: + " sign : The mark/marker whose sign is to be placed/removed/toggled + " lnum : Line number from which the sign is to be removed + " If sign is a marker and lnum is 0, the sign will be removed from all lines + " If sign is a mark and lnum is 0, the lnum will be found and the sign will be removed from that line + + "echom "DEBUG: sign = " . a:sign . ", lnum = " . a:lnum + + " If Signature is not enabled, return + if !b:sig_enabled | return | endif + + " Remove sign for markers + if signature#utils#IsValidMarker(a:sign) + let b:sig_markers[a:lnum] = substitute(b:sig_markers[a:lnum], "\\C" . escape( a:sign, '$^' ), "", "") + + " If there are no markers on the line, delete signs on that line + if b:sig_markers[a:lnum] == "" + call remove(b:sig_markers, a:lnum) + endif + call s:RefreshLine(a:lnum) + + " Remove sign for marks + else + " For marks, if a:lnum == 0, find out the line where the mark was placed + if a:lnum == 0 + let l:arr = keys(filter(copy(b:sig_marks), 'v:val =~# a:sign')) + if empty(l:arr) | return | endif + else + let l:arr = [a:lnum] + endif + if (v:version >= 800) + call assert_true(len(l:arr) == 1, "Multiple marks found where one was expected") + elseif (len(l:arr) != 1) + echoerr "Multiple marks found where one was expected" + endif + + for l:lnum in l:arr + " FIXME: Placed guard to avoid triggering issue #53 + if has_key(b:sig_marks, l:lnum) + let b:sig_marks[l:lnum] = substitute(b:sig_marks[l:lnum], "\\C" . a:sign, "", "") + " If there are no marks on the line, delete signs on that line + if b:sig_marks[l:lnum] == "" + call remove(b:sig_marks, l:lnum) + endif + endif + call s:RefreshLine(l:lnum) + endfor + endif +endfunction + + +function! s:EvaluateHL(expr, lnum, ...) "{{{1 + " Description: If expr points to a function, call it and use its output as the highlight group. + " If it is a string, use it directly. + " If the optional argument is specified, use it as a fallback. If not, return an empty string + + if type(a:expr) == type("") + return a:expr + elseif type(a:expr) == type(function("tr")) + let l:retval = a:expr(a:lnum) + if (l:retval != "") + return l:retval + endif + endif + + return (a:0 > 0 ? a:1 : "") +endfunction + + +function! s:RefreshLine(lnum) "{{{1 + " Description: Decides what the sign string should be based on if there are any marks or markers (using b:sig_marks + " and b:sig_markers) on the current line and the value of b:SignaturePrioritizeMarks. + " Arguments: + " lnum : Line number for which the sign string is to be modified + + let l:id = abs(a:lnum * 1000 + bufnr('%')) + let l:str = "" + + " Place the sign + if ( has_key(b:sig_marks, a:lnum) + \ && ( b:SignaturePrioritizeMarks + \ || !has_key(b:sig_markers, a:lnum) + \ ) + \ ) + let l:SignatureMarkTextHL = s:EvaluateHL(g:SignatureMarkTextHL, a:lnum, "SignatureMarkText") + let l:SignatureMarkLineHL = s:EvaluateHL(g:SignatureMarkLineHL, a:lnum, "SignatureMarkLine") + let l:str = substitute(b:SignatureMarkOrder, "\m", signature#utils#GetChar(b:sig_marks[a:lnum], 0), '') + let l:str = substitute(l:str, "\p", signature#utils#GetChar(b:sig_marks[a:lnum], 1), '') + + execute 'sign define Signature_' . l:str . ' text=' . l:str . ' texthl=' . l:SignatureMarkTextHL . ' linehl=' . l:SignatureMarkLineHL + + elseif has_key(b:sig_markers, a:lnum) + let l:SignatureMarkerTextHL = s:EvaluateHL(g:SignatureMarkerTextHL, a:lnum, "SignatureMarkerText") + let l:SignatureMarkerLineHL = s:EvaluateHL(g:SignatureMarkerLineHL, a:lnum, "SignatureMarkerLine") + + " Since the same marker can be placed on multiple lines, we can't use the same sign for all of them. + " This is because if dynamic highlighting of markers is enabled then the sign placed on eg. a modified line should + " be highlighted differently than the one placed on an unchanged line. + " In order to support this, I append the name of the TextHL and LineHL group to the name of the sign. + let l:txt = signature#utils#GetChar(b:sig_markers[a:lnum], 0) + let l:str = l:txt . '_' . l:SignatureMarkerTextHL . '_' . l:SignatureMarkerLineHL + + execute 'sign define Signature_' . l:str . ' text=' . l:txt . ' texthl=' . l:SignatureMarkerTextHL . ' linehl=' . l:SignatureMarkerLineHL + else + call signature#sign#Unplace(a:lnum) + endif + + if (l:str != "") + execute 'sign place ' . l:id . ' line=' . a:lnum . ' name=Signature_' . l:str . ' buffer=' . bufnr('%') + endif + + " If there is only 1 mark/marker in the file, place a dummy to prevent flickering of the gutter when it is moved + " If there are no signs left, remove the dummy + call signature#sign#ToggleDummy() +endfunction + + +function! signature#sign#Refresh(...) "{{{1 + " Description: Add signs for new marks/markers and remove signs for deleted marks/markers + " Arguments: Specify an argument to force a sign refresh + + call s:InitializeVars(a:0 && a:1) + " If Signature is not enabled, return + if !b:sig_enabled | return | endif + + for i in signature#mark#GetList('free', 'buf_curr') + " ... remove it + call signature#sign#Remove(i, 0) + endfor + + " Add signs for marks ... + for [l:mark, l:lnum, _] in signature#mark#GetList('used', 'buf_curr') + " ... if mark is not present in our b:sig_marks list or if it is present but at the wrong line, + " remove the old sign and add a new one + if ( !has_key(b:sig_marks, l:lnum) + \ || (b:sig_marks[l:lnum] !~# l:mark) + \ || a:0 + \ ) + call signature#sign#Remove(l:mark, 0) + call signature#sign#Place (l:mark, l:lnum) + endif + endfor + + call signature#sign#ToggleDummy() + + " We do not add signs for markers as SignRefresh is executed periodically and we don't have a way to determine if the + " marker already has a sign or not +endfunction + + +function! signature#sign#Unplace(lnum) "{{{1 + " Description: Remove the sign from the specified line number + " FIXME: Clean-up. Undefine the sign + let l:id = abs(a:lnum * 1000 + bufnr('%')) + silent! execute 'sign unplace ' . l:id +endfunction + + +function! signature#sign#ToggleDummy(...) "{{{1 + " Description: Places a dummy sign to prevent flickering of the gutter when the mark is moved or the line containing + " a mark/marker is deleted and then the delete is undone + " Arguments: (optional) 0 : force remove + " 1 : force place + + let l:place = a:0 ? a:1 : (len(b:sig_marks) + len(b:sig_markers) == 1) && !b:sig_DummyExists + let l:remove = a:0 ? !a:1 : (len(b:sig_marks) + len(b:sig_markers) == 0) && b:sig_DummyExists + + if (l:place) + sign define Signature_Dummy + execute 'sign place 666 line=1 name=Signature_Dummy buffer=' . bufnr('%') + let b:sig_DummyExists = 1 + elseif (l:remove) + silent! execute 'sign unplace 666 buffer=' . bufnr('%') + let b:sig_DummyExists = 0 + endif +endfunction + + +function! s:GetInfo(...) "{{{1 + " Description: Returns a dic of filenames, each of which is a dic of line numbers on which signs are placed + " Arguments: filename (optional). + " If filename is provided, the return value will contain signs only present in the given file + " Eg. { + " 'vimrc': { + " '711': { + " 'id': '1422', + " 'name': 'sig_Sign_1422' + " }, + " '676': { + " 'id': '1352', + " 'name': 'sig_Sign_1352' + " } + " } + " } + + " Redirect the input to a variable + redir => l:sign_str + silent! sign place + redir END + + " Create a Hash of files to store the info. + let l:signs_dic = {} + " The file that is currently being processed is stored into l:file + let l:match_file = "" + let l:file_found = 0 + + " Split the string into an array of sentences and filter out empty lines + for i in filter( split( l:sign_str, '\n' ), 'v:val =~ "^[S ]"' ) + let l:temp_file = matchstr( i, '\v(Signs for )@<=\S+:@=' ) + + if l:temp_file != "" + let l:match_file = l:temp_file + let l:signs_dic[l:match_file] = {} + elseif l:match_file != "" + " Get sign info + let l:info_match = matchlist( i, '\vline\=(\d+)\s*id\=(\S+)\s*name\=(\S+)' ) + if !empty( l:info_match ) + let l:signs_dic[l:match_file][l:info_match[1]] = { + \ 'id' : l:info_match[2], + \ 'name' : l:info_match[3], + \ } + endif + endif + endfor + + if a:0 + "" Search for the full path first in the hash ... + "let l:curr_filepath = expand('%:p') + "if has_key( l:signs_dic, l:curr_filepath ) + " return filter( l:signs_dic, 'v:key ==# l:curr_filepath' )[l:curr_filepath] + "else + " ... if no entry is found for the full path, search for the filename in the hash ... + " Since we're searching for the current file, if present in the hash, it'll be as a filename and not the full path + let l:curr_filename = expand('%:t') + if has_key( l:signs_dic, l:curr_filename ) + return filter( l:signs_dic, 'v:key ==# l:curr_filename' )[l:curr_filename] + endif + + " ... if nothing is found, then return an empty hash to indicate that no signs are present in the current file + return {} + endif + + return l:signs_dic +endfunction + + +function! signature#sign#GetGitGutterHLGroup(lnum) "{{{1 + " Description: This returns the highlight group used by vim-gitgutter depending on how the line was edited + + let l:current_bufnr = bufnr('%') + let l:line_state = filter(copy(gitgutter#diff#process_hunks(l:current_bufnr, gitgutter#hunk#hunks(l:current_bufnr))), 'v:val[0] == a:lnum') + + if len(l:line_state) == 0 + return "" + endif + + if (l:line_state[0][1]) =~ 'added' | return 'GitGutterAdd' + elseif (l:line_state[0][1]) =~ 'modified_removed' | return 'GitGutterChangeDelete' + elseif (l:line_state[0][1]) =~ 'modified' | return 'GitGutterChange' + elseif (l:line_state[0][1]) =~ 'removed' | return 'GitGutterDelete' + endif +endfunction + + +function! signature#sign#GetSignifyHLGroup(lnum) "{{{1 + " Description: This returns the highlight group used by vim-signify depending on how the line was edited + " Thanks to @michaelmior + + if !exists('b:sy') + return "" + endif + call sy#sign#get_current_signs(b:sy) + + if has_key(b:sy.internal, a:lnum) + let l:line_state = b:sy.internal[a:lnum]['type'] + if l:line_state =~ 'SignifyAdd' | return 'SignifySignAdd' + elseif l:line_state =~ 'SignifyChange' | return 'SignifySignChange' + elseif l:line_state =~ 'SignifyDelete' | return 'SignifySignDelete' + end + endif + + return "" +endfunction + + +" function! signature#sign#GetMarkSignLine(mark) "{{{1 +" if !signature#utils#IsValidMark(a:mark) +" echoe "Signature: Invalid mark " . a:mark +" return +" endif + +" let l:sign_info=filter(split(execute('sign place'), '\n'), +" \ 'v:val =~ "\\vSignature_(.?' . a:mark . '|' . a:mark . '.?)$"') + +" if (len(l:sign_info) != 1) +" echoe "Signature: Expected single match, found " . len(l:sign_info) +" return +" endif + +" return matchstr(l:sign_info[0], '\v(line\=)@<=\d+') +" endfunction + + +function! s:InitializeVars(...) "{{{1 + " Description: Initialize variables + " Arguments: Specify an argument to re-init + + if !exists('b:sig_marks') + " b:sig_marks = { lnum => signs_str } + let b:sig_marks = {} + else + " Lines can be removed using an external tool. Hence, we need to filter out marks placed on line numbers that are + " now greater than the total number of lines in the file. + let l:line_tot = line('$') + call filter( b:sig_marks, 'v:key <= l:line_tot' ) + endif + + if !exists('b:sig_markers') + " b:sig_markers = { lnum => marker } + let b:sig_markers = {} + else + " Lines can be removed using an external tool. Hence, we need to filter out marks placed on line numbers that are + " now greater than the total number of lines in the file. + let l:line_tot = line('$') + call filter( b:sig_markers, 'v:key <= l:line_tot' ) + endif + + call signature#utils#Set('b:sig_DummyExists' , 0 , a:0 && a:1) + call signature#utils#Set('b:sig_enabled' , g:SignatureEnabledAtStartup, a:0 && a:1) + call signature#utils#Set('b:SignatureIncludeMarks' , g:SignatureIncludeMarks , a:0 && a:1) + call signature#utils#Set('b:SignatureIncludeMarkers' , g:SignatureIncludeMarkers , a:0 && a:1) + call signature#utils#Set('b:SignatureMarkOrder' , g:SignatureMarkOrder , a:0 && a:1) + call signature#utils#Set('b:SignaturePrioritizeMarks', g:SignaturePrioritizeMarks , a:0 && a:1) + call signature#utils#Set('b:SignatureDeferPlacement' , g:SignatureDeferPlacement , a:0 && a:1) + call signature#utils#Set('b:SignatureWrapJumps' , g:SignatureWrapJumps , a:0 && a:1) +endfunction diff --git a/etc/soft/nvim/+plugins/vim-signature/autoload/signature/utils.vim b/etc/soft/nvim/+plugins/vim-signature/autoload/signature/utils.vim new file mode 100644 index 0000000..f5ee734 --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-signature/autoload/signature/utils.vim @@ -0,0 +1,195 @@ +" vim: fdm=marker:et:ts=4:sw=2:sts=2 +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +function! signature#utils#Set(var, value, ...) " {{{1 + " Description: Assign value to var if var is unset or if an optional 3rd arg is provided to force + + if (!exists(a:var) || a:0 && a:1) + if type(a:value) + execute 'let' a:var '=' string(a:value) + else + execute 'let' a:var '=' a:value + endif + endif + return a:var +endfunction + + +function! signature#utils#NumericSort(x, y) " {{{1 + return a:x - a:y +endfunction + + +function! s:Map(mode, key, map_lhs_default, map_rhs) " {{{1 + let l:map_lhs = get(g:SignatureMap, a:key, a:map_lhs_default) + if (l:map_lhs ==? '') + return + endif + if (a:mode ==? 'create') + silent! execute 'nnoremap ' . l:map_lhs . ' ' . ':call signature#' . a:map_rhs . '' + elseif (a:mode ==? 'remove') + silent! execute 'nunmap ' . l:map_lhs + endif +endfunction + +function! signature#utils#Maps(mode) " {{{1 + " We create separate mappings for PlaceNextMark, mark#Purge('all') and PurgeMarkers instead of combining it with + " Leader/Input as if the user chooses to use some weird key like or for any of these 3, we need to be able + " to identify it. Eg. the nr2char(getchar()) will fail if the user presses a + let l:SignatureMapLeader = get(g:SignatureMap, 'Leader', 'm') + if (l:SignatureMapLeader == "") + echoe "Signature: g:SignatureMap.Leader shouldn't be left blank" + endif + call s:Map(a:mode, 'Leader' , l:SignatureMapLeader , 'utils#Input()' ) + call s:Map(a:mode, 'PlaceNextMark' , l:SignatureMapLeader . "," , 'mark#Toggle("next")' ) + call s:Map(a:mode, 'ToggleMarkAtLine' , l:SignatureMapLeader . "." , 'mark#ToggleAtLine()' ) + call s:Map(a:mode, 'PurgeMarksAtLine' , l:SignatureMapLeader . "-" , 'mark#Purge("line")' ) + call s:Map(a:mode, 'PurgeMarks' , l:SignatureMapLeader . "", 'mark#Purge("all")' ) + call s:Map(a:mode, 'PurgeMarkers' , l:SignatureMapLeader . "" , 'marker#Purge()' ) + call s:Map(a:mode, 'DeleteMark' , "dm" , 'utils#Remove(v:count)' ) + call s:Map(a:mode, 'GotoNextLineAlpha', "']" , 'mark#Goto("next", "line", "alpha")' ) + call s:Map(a:mode, 'GotoPrevLineAlpha', "'[" , 'mark#Goto("prev", "line", "alpha")' ) + call s:Map(a:mode, 'GotoNextSpotAlpha', "`]" , 'mark#Goto("next", "spot", "alpha")' ) + call s:Map(a:mode, 'GotoPrevSpotAlpha', "`[" , 'mark#Goto("prev", "spot", "alpha")' ) + call s:Map(a:mode, 'GotoNextLineByPos', "]'" , 'mark#Goto("next", "line", "pos")' ) + call s:Map(a:mode, 'GotoPrevLineByPos', "['" , 'mark#Goto("prev", "line", "pos")' ) + call s:Map(a:mode, 'GotoNextSpotByPos', "]`" , 'mark#Goto("next", "spot", "pos")' ) + call s:Map(a:mode, 'GotoPrevSpotByPos', "[`" , 'mark#Goto("prev", "spot", "pos")' ) + call s:Map(a:mode, 'GotoNextMarker' , "]-" , 'marker#Goto("next", "same", v:count)') + call s:Map(a:mode, 'GotoPrevMarker' , "[-" , 'marker#Goto("prev", "same", v:count)') + call s:Map(a:mode, 'GotoNextMarkerAny', "]=" , 'marker#Goto("next", "any", v:count)') + call s:Map(a:mode, 'GotoPrevMarkerAny', "[=" , 'marker#Goto("prev", "any", v:count)') + call s:Map(a:mode, 'ListBufferMarks' , 'm/' , 'mark#List(0, 0)' ) + call s:Map(a:mode, 'ListBufferMarkers', 'm?' , 'marker#List(v:count, 0)' ) +endfunction + + +function! signature#utils#Input() " {{{1 + " Description: Grab input char + + if &ft ==# "netrw" + " Workaround for #104 + return + endif + + " Obtain input from user ... + let l:in = nr2char(getchar()) + + " ... if the input is not a number eg. '!' ==> Delete all '!' markers + if signature#utils#IsValidMarker(l:in) + return signature#marker#Purge(l:in) + endif + + " ... but if input is a number, convert it to corresponding marker before proceeding + if match(l:in, '\d') >= 0 + let l:char = signature#utils#GetChar(b:SignatureIncludeMarkers, l:in) + else + let l:char = l:in + endif + + if signature#utils#IsValidMarker(l:char) + return signature#marker#Toggle(l:char) + elseif signature#utils#IsValidMark(l:char) + return signature#mark#Toggle(l:char) + else + " l:char is probably one of `'[]<> or a space from the gap in b:SignatureIncludeMarkers + execute 'normal! m' . l:in + endif +endfunction + + +function! signature#utils#Remove(lnum) " {{{1 + " Description: Obtain mark or marker from the user and remove it. + " There can be multiple markers of the same type on different lines. If a line no. is provided + " (non-zero), delete the marker from the specified line else delete it from the current line + " NOTE: lnum is meaningless for a mark and will be ignored + " Arguments: lnum - Line no. to delete the marker from + + let l:char = nr2char(getchar()) + + if (l:char =~ '^\d$') + let l:lnum = (a:lnum == 0 ? line('.') : a:lnum) + let l:char = split(b:SignatureIncludeMarkers, '\zs')[l:char] + call signature#marker#Remove(lnum, l:char) + elseif (l:char =~? '^[a-z]$') + call signature#mark#Remove(l:char) + endif +endfunction + + +function! signature#utils#Toggle() " {{{1 + " Description: Toggles and refreshes sign display in the buffer. + + let b:sig_enabled = !b:sig_enabled + + if b:sig_enabled + " Signature enabled ==> Refresh signs + call signature#sign#Refresh() + + " Add signs for markers ... + for i in keys(b:sig_markers) + call signature#sign#Place(b:sig_markers[i], i) + endfor + else + " Signature disabled ==> Remove signs + for l:lnum in keys(b:sig_markers) + call signature#sign#Unplace(l:lnum) + endfor + for l:lnum in keys(b:sig_marks) + call signature#sign#Unplace(l:lnum) + endfor + " Force removal. Simply toggling doesn't work as we check whether b:sig_markers and b:sig_marks are empty before + " removing the dummy and b:sig_markers won't be empty + call signature#sign#ToggleDummy(0) + unlet b:sig_marks + endif +endfunction + + +function! signature#utils#SetupHighlightGroups() " {{{1 + " Description: Sets up the highlight groups + + function! CheckAndSetHL(curr_hl, prefix, attr, targ_color) + let l:curr_color = synIDattr(synIDtrans(hlID(a:curr_hl)), a:attr, a:prefix) + + if ( ( (l:curr_color == "") + \ || (l:curr_color < 0) + \ ) + \ && (a:targ_color != "") + \ && (a:targ_color >= 0) + \ ) + " echom "DEBUG: HL=" . a:curr_hl . " (" . a:prefix . a:attr . ") Curr=" . l:curr_color . ", To=" . a:targ_color + execute 'highlight ' . a:curr_hl . ' ' . a:prefix . a:attr . '=' . a:targ_color + endif + endfunction + + let l:prefix = (has('gui_running') || (has('termguicolors') && &termguicolors) ? 'gui' : 'cterm') + let l:sign_col_color = synIDattr(synIDtrans(hlID('SignColumn')), 'bg', l:prefix) + + call CheckAndSetHL('SignatureMarkText', l:prefix, 'fg', 'Red') + call CheckAndSetHL('SignatureMarkText', l:prefix, 'bg', l:sign_col_color) + call CheckAndSetHL('SignatureMarkerText', l:prefix, 'fg', 'Green') + call CheckAndSetHL('SignatureMarkerText', l:prefix, 'bg', l:sign_col_color) + + delfunction CheckAndSetHL +endfunction + + +function! signature#utils#IsValidMark(mark) " {{{1 + return (b:SignatureIncludeMarks =~# a:mark) +endfunction + + +function! signature#utils#IsValidMarker(marker) " {{{1 + return ( (b:SignatureIncludeMarkers =~# a:marker) + \ && (a:marker != ' ') + \ ) +endfunction + + +function! signature#utils#GetChar(string, pos) " {{{1 + if a:pos > strchars(a:string) - 1 | return "" | endif + let pattern = '.\{-' . a:pos . '}\(.\).*' + return substitute(a:string, pattern, '\1', '') +endfunction + diff --git a/etc/soft/nvim/+plugins/vim-signature/doc/signature.txt b/etc/soft/nvim/+plugins/vim-signature/doc/signature.txt new file mode 100644 index 0000000..43c3fe3 --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-signature/doc/signature.txt @@ -0,0 +1,408 @@ +*signature.txt* A plugin to toggle, display and navigate marks + + _________.__ __ ~ + / _____/|__| ____ ____ _____ _/ |_ __ __ _______ ____ ~ + \_____ \ | | / ___\ / \ \__ \ \ __\| | \\_ __ \_/ __ \ ~ + / \| | / /_/ >| | \ / __ \_ | | | | / | | \/\ ___/ ~ + /_______ /|__| \___ / |___| /(____ / |__| |____/ |__| \___ > ~ + \/ /_____/ \/ \/ \/ ~ + + +============================================================================== +Contents *Signature* + + 1. Mappings |SignatureMappings| + 2. Commands |SignatureCommands| + 3. Customization |SignatureCustomization| + 4. Contributing |SignatureContributing| + 5. Credits |SignatureCredits| + 6. License |SignatureLicense| + + +============================================================================== +1. Mappings *SignatureMappings* + +Out of the box, the followings mappings are defined by default + + mx Toggle mark 'x' and display it in the leftmost column + dmx Remove mark 'x' where x is a-zA-Z + + m, Place the next available mark + m. If no mark on line, place the next available mark. Otherwise, + remove (first) existing mark. + m- Delete all marks from the current line + m Delete all marks from the current buffer + ]` Jump to next mark + [` Jump to prev mark + ]' Jump to start of next line containing a mark + [' Jump to start of prev line containing a mark + `] Jump by alphabetical order to next mark + `[ Jump by alphabetical order to prev mark + '] Jump by alphabetical order to start of next line having a mark + '[ Jump by alphabetical order to start of prev line having a mark + m/ Open location list and display marks from current buffer + + m[0-9] Toggle the corresponding marker !@#$%^&*() + m Remove all markers of the same type + ]- Jump to next line having a marker of the same type + [- Jump to prev line having a marker of the same type + ]= Jump to next line having a marker of any type + [= Jump to prev line having a marker of any type + m? Open location list and display markers from current buffer + m Remove all markers + +This will allow the use of default behavior of m to set marks and, if +the line already contains the mark, it'll be unset. The default behavior +of ]', [', ]` and [` is supported and enhanced by wrapping around when +beginning or end of file is reached. ]-, [-, ]= and [= also accept a count. + +To directly jump to a given marker, the following maps can be used +> + nnoremap [1 :call signature#marker#Goto('prev', 1, v:count) + nnoremap ]1 :call signature#marker#Goto('next', 1, v:count) + nnoremap [2 :call signature#marker#Goto('prev', 2, v:count) + nnoremap ]2 :call signature#marker#Goto('next', 2, v:count) +< +etc. These are not defined by default + + +============================================================================== +2. Commands *SignatureCommands* + +*:SignatureToggleSigns* + Toggle the display of signs. This won't affect the marks or the mappings. + +*:SignatureRefresh* + Force the display of signs in the buffer to refresh. Use this to correct + the signs if things go awry + +*:SignatureListBufferMarks* [n] + List all the marks used in the current buffer in the location list + Accepts an optional argument to provide 'n' lines of context + +*:SignatureListGlobalMarks* [n] + List only the global marks used in all buffers in the location list + Accepts an optional argument to provide 'n' lines of context + +*:SignatureListMarkers* [marker] [n] + List all instances of the specified marker(s) used in the current buffer + in the location list. If no argument is given, it lists all markers + Accepts an optional argument to provide 'n' lines of context +> + :SignatureListMarkers : List all markers + :SignatureListMarkers 1 : List only the '!' marker + :SignatureListMarkers @ : List only the '@' marker + :SignatureListMarkers 0, 2 : List only ) marker with 2 lines of context + :SignatureListMarkers '', 2 : List all markers with 2 lines of context + :SignatureListMarkers '!@', 2 : List only the '!' and '@' markers and show + 2 lines of context around them +< + +============================================================================== +3. Customization *SignatureCustomization* + + *g:SignatureMap* + Type: Dictionary, Default: + To set up your own mappings copy the following dictionary and edit it +> + let g:SignatureMap = { + \ 'Leader' : "m", + \ 'PlaceNextMark' : "m,", + \ 'ToggleMarkAtLine' : "m.", + \ 'PurgeMarksAtLine' : "m-", + \ 'DeleteMark' : "dm", + \ 'PurgeMarks' : "m", + \ 'PurgeMarkers' : "m", + \ 'GotoNextLineAlpha' : "']", + \ 'GotoPrevLineAlpha' : "'[", + \ 'GotoNextSpotAlpha' : "`]", + \ 'GotoPrevSpotAlpha' : "`[", + \ 'GotoNextLineByPos' : "]'", + \ 'GotoPrevLineByPos' : "['", + \ 'GotoNextSpotByPos' : "]`", + \ 'GotoPrevSpotByPos' : "[`", + \ 'GotoNextMarker' : "]-", + \ 'GotoPrevMarker' : "[-", + \ 'GotoNextMarkerAny' : "]=", + \ 'GotoPrevMarkerAny' : "[=", + \ 'ListBufferMarks' : "m/", + \ 'ListBufferMarkers' : "m?" + \ } +< + By default, it defines the mappings as shown in |signature-mappings| + To disable a map entirely, specify it as an empty string. + If a key is not specified, the default value will be picked up. + These same characters will be used to invoke the shortcuts. + + + *g:SignatureIncludeMarks* + String, Default : 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' + + Specify the marks that can be controlled by this plugin. + Only supports Alphabetical marks at the moment. + 'b:SignatureIncludeMarks' can be set separately for buffer-specific marks. + + + *g:SignatureIncludeMarkers* + String, Default : ')!@#$%^&*(' + + Specify the symbols that can be used by the plugin to be placed by 0-9. + Note that there's a 1:1 correspondence between the symbols and 0-9. + This string must be at most 10 chars long. Extra char will be ignored. + Also, this string must not include any alphabetical characters `[a-zA-Z]` + However, it can contain spaces to indicate blanks. Eg. + `m0` will place `)` by default + `m1` will place `!` by default + `m2` will place `@` by default etc. + + If set to `')!'`, `m0` and `m1` will behave as described above but `m[2-9]` will + not be handled by this plugin. + + If set to `' !'` (note the space before !), only `m1` will have any affect + while `m[0,2-9]` will not have any affect + + An example of a use case is for keyboards with alternate layouts wherein + the symbols associated with 0-9 could be different than the default. + 'b:SignatureIncludeMarkers' can be specified separately for each buffer + + + *g:SignatureMap['Leader']* + String, Default: 'm' + + Set the key used to toggle marks and markers. + For eg. If this key is set to `m`, + `ma` will toggle the mark 'a' on the current line + `m,` will place the next available mark + `m.` will place the next available mark if there are no + marks already on the line; otherwise, will remove + first mark from line + `m` will delete all marks + `m1` will toggle the marker '!' + `m!` will remove all the '!' markers + `m` will remove all markers + + NOTE: Currently, either marks or markers can be displayed in front of a + line. Both can't be displayed simultaenously. + + To set this to mapleader or maplocalleader + + `let g:SignatureMap['Leader'] = ''` + `let g:SignatureMap['Leader'] = ''` + + + *g:SignatureWrapJumps* + Boolean, Default : 1 + + Specify if jumping to marks should wrap-around. + b:SignatureWrapJumps can be set to specify buffer-specific settings. + + + *g:SignatureMarkOrder* + String, Default : "\p\m" + + Signature allows you to display upto marks in front of a line. This controls + the order in which marks are displayed. + '\m' indicates the current or latest mark placed on the line + '\p' indicates the previous mark placed on the line + + For eg, + `g:SignatureMarkOrder="\m."` : Display last mark with '.' suffixed + `g:SignatureMarkOrder="_\m"` : Display last mark with '_' prefixed + `g:SignatureMarkOrder=">"` : Display only a ">" for a line with a mark. + The mark is not displayed + `g:SignatureMarkOrder="\m\p"` : Display last two marks placed + + NOTE: The signs feature allows only 2 characters to be displayed. This limit + is imposed by vim itself and not by the plugin + + + *g:SignatureMarkTextHL* + String, Default : 'SignatureMarkText' + + The highlight group used for mark signs. This can be set either to a string + or to a |Funcref|. + + If it holds a string, it must be an expression suitable for passing to + |eval()|. In the simple case, it can be the name of a highlight group. It can + also hold more complicated expressions, in which case the expression `a:lnum` + may be helpful. It holds the number of the line where the current mark is to + be highlighted. + + If it holds a |Funcref|, then the function will be called with one argument, + the line number of the mark to be highlighted. The function should return + the name of a highlight group. + + Example using a string: + `let g:SignatureMarkTextHL = "Exception"` + + Example of |Funcref|: + `function Example(lineno)` + `return "Exception"` + `endfunction` + `let g:SignatureMarkTextHL = function("Example")` + + By default, this is set to SignatureMarkText which is a highlight group + that is linked to Exception + + *g:SignatureMarkTextHLDynamic* + Boolean, Default: 0 + + Highlight signs of marks dynamically based upon state indicated by + vim-gitgutter. Setting this to `1` prior to plugin initialization overwrites + |g:SignatureMarkTextHL|. + + vim-signify is not supported at the moment. For details, refer + https://github.com/kshenoy/vim-signature/issues/93#issuecomment-195672354 + + *g:SignatureMarkLineHL* + String, Default : 'SignatureMarkLine' + + The highlight group used for hightlighting lines having marks. This can be a + string or |Funcref|. SignatureMarkLine links to Normal by default. + See |g:SignatureMarkTextHL| for details. + + + *g:SignatureMarkerTextHL* + String, Default : 'SignatureMarkerText' + + The highlight group used for marker signs. This can be a string or |Funcref|. + SignatureMarkText links to WarningMsg by default. + See |g:SignatureMarkTextHL| for details. + + + *g:SignatureMarkerTextHLDynamic* + Boolean, Default: 0 + + Highlight signs of markers dynamically based upon state indicated by + vim-gitgutter or vim-signify. Setting this to `1` prior to plugin + initialization overwrites |g:SignatureMarkerTextHL|. + + + *g:SignatureMarkerLineHL* + String, Default : '' + + The highlight group used for hightlighting lines having markers. This can be + a string or a |Funcref|. SignatureMarkerLine links to Normal by default. + See |g:SignatureMarkTextHL| for details. + + + *g:SignatureDeleteConfirmation* + Boolean, Default: 0 + + An option for the more clumsy-fingered of us. Asks for confirmation before + moving/replacing/overwriting any marks + + + *g:SignaturePurgeConfirmation* + Boolean, Default: 0 + + Similar to g:SignatureDeleteConfirmation. Asks for confirmation before + deleting all marks/markers + + + *g:SignaturePeriodicRefresh* + Boolean, Default: 1 + + Enable the display to refresh periodically. Generally a good thing to have. + This makes use of the CursorHold autocmd event to execute periodically. + The frequency of this event can be controlled by changing the value of the + updatetime variable in milliseconds + `set updatetime = 100` + + + *g:SignaturePrioritizeMarks* + Boolean, Default: 1 + + When a line has both marks and markers, display the sign for marks. If set + to 0, it will display the sign for markers instead + + + *g:SignatureEnabledAtStartup* + Boolean, Default: 1 + + Control if the signs should be shown by default. If set to 0, the signs + won't be visible until `:SignatureToggleSigns` has been called + + + *g:SignatureDeferPlacement* + Boolean, Default: 1 + + NOTE: Not supported currently. Code was highly inefficient. + Check if any other plugin has already placed a sign and if set to 1, + Signature will hold off from placing a sign. If set to 0, Signature will + overwrite any signs that are already present. + + + *g:SignatureUnconditionallyRecycleMarks* + Boolean, Default: 0 + + Controls behavior when trying to place next available mark and all marks + have been used. If set to 0, then either an error or warning message will be + emitted, depending on the setting of |g:SignatureErrorIfNoAvailableMarks|. + If set to 1, then the first local mark (e.g., 'a') will be removed from its + existing location and applied to the current line. + + + *g:SignatureErrorIfNoAvailableMarks* + Boolean, Default: 1 + + Controls behavior when unable to place a new mark. If set to 1, then an + error is raised. If set to 0, then just a warning message. + + + *g:SignatureForceRemoveGlobal* + Boolean, Default: 0 + + Vim's handling of global marks is a bit iffy. This option forces the removal + of global marks by deleting it from the viminfo (or neovim's shada) file. + + Note that this is a very heavy hammer since it affects other things too. + Refer 'viminfo' or 'shada' for more information on features that could be + affected. + + + *g:SignatureForceMarkPlacement* + Boolean, Default: 0 + + When set to 1, will always place marks instead of toggling them + + + *g:SignatureForceMarkerPlacement* + Boolean, Default: 0 + + When set to 1, will always place markers instead of toggling them + + +============================================================================== +4. Contributing *SignatureContributing* + + Please post any issues and all your suggestions on Github + https://github.com/kshenoy/vim-signature + + Show some love by spreading the word and rating on + http://www.vim.org/scripts/script.php?script_id=4118 + + +============================================================================== +5. Credits *SignatureCredits* + +A great thanks to these guys for providing the idea and inspiration to develop +Signature + +* Sergey Khorev for mark-tools + http://www.vim.org/scripts/script.php?script_id=2929 + +* Zak Johnson for vim-showmarks + https://github.com/zakj/vim-showmarks + +I'd also like to thank Steve J. Losh for learningvimscriptthehardway.com +without whose detailed guide this plugin would not have seen the light of day. + + +============================================================================== +6. License *SignatureLicense* + +Signature is MIT/X11 licensed + + +vim:tw=78:ts=2:et:sts=2:sw=2:ft=help diff --git a/etc/soft/nvim/+plugins/vim-signature/plugin/signature.vim b/etc/soft/nvim/+plugins/vim-signature/plugin/signature.vim new file mode 100644 index 0000000..f8376b9 --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-signature/plugin/signature.vim @@ -0,0 +1,69 @@ +" vim: fdm=marker:et:ts=4:sw=2:sts=2 + +" Description: vim-signature is a plugin to toggle, display and navigate marks. +" +" Maintainer: Kartik Shenoy +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +" Exit if the signs feature is not available or if the app has already been loaded (or "compatible" mode set) +if !has('signs') || &cp + finish +endif +if exists('g:loaded_Signature') + finish +endif +let g:loaded_Signature = 1 + + +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +"" Global variables {{{1 +" +call signature#utils#Set('g:SignaturePrioritizeMarks', 1 ) +call signature#utils#Set('g:SignatureIncludeMarks', 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') +call signature#utils#Set('g:SignatureIncludeMarkers', ')!@#$%^&*(' ) +call signature#utils#Set('g:SignatureMarkTextHL', "SignatureMarkText" ) +call signature#utils#Set('g:SignatureMarkTextHLDynamic', 0 ) +call signature#utils#Set('g:SignatureMarkLineHL', "SignatureMarkLine" ) +call signature#utils#Set('g:SignatureMarkerTextHL', "SignatureMarkerText" ) +call signature#utils#Set('g:SignatureMarkerTextHLDynamic', 0 ) +call signature#utils#Set('g:SignatureMarkerLineHL', "SignatureMarkerLine" ) +call signature#utils#Set('g:SignatureWrapJumps', 1 ) +call signature#utils#Set('g:SignatureMarkOrder', "\p\m" ) +call signature#utils#Set('g:SignatureDeleteConfirmation', 0 ) +call signature#utils#Set('g:SignaturePurgeConfirmation', 0 ) +call signature#utils#Set('g:SignaturePeriodicRefresh', 1 ) +call signature#utils#Set('g:SignatureEnabledAtStartup', 1 ) +call signature#utils#Set('g:SignatureDeferPlacement', 1 ) +call signature#utils#Set('g:SignatureRecycleMarks', 0 ) +call signature#utils#Set('g:SignatureErrorIfNoAvailableMarks', 1 ) +call signature#utils#Set('g:SignatureForceRemoveGlobal', 0 ) +call signature#utils#Set('g:SignatureForceMarkPlacement', 0 ) +call signature#utils#Set('g:SignatureForceMarkerPlacement', 0 ) +call signature#utils#Set('g:SignatureMap', {} ) + + +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +"" Commands, Autocmds and Maps {{{1 +" +call signature#utils#Maps('create') + +if has('autocmd') + augroup sig_autocmds + autocmd! + + " This needs to be called upon loading a colorscheme + " VimEnter is kind of a backup if no colorscheme is explicitly loaded and the default is used + autocmd VimEnter,ColorScheme * call signature#utils#SetupHighlightGroups() + + " This is required to remove signs for global marks that were removed when in another window + autocmd BufEnter,CmdwinEnter * call signature#sign#Refresh() + + autocmd CursorHold * if (g:SignaturePeriodicRefresh) | call signature#sign#Refresh() | endif + augroup END +endif + +command! -nargs=0 SignatureToggleSigns call signature#utils#Toggle() +command! -nargs=0 SignatureRefresh call signature#sign#Refresh(1) +command! -nargs=? SignatureListBufferMarks call signature#mark#List(0, ) +command! -nargs=? SignatureListGlobalMarks call signature#mark#List(1, ) +command! -nargs=* SignatureListMarkers call signature#marker#List()