├── .gitignore ├── Makefile ├── README ├── autoload ├── DynamicSigns.vim └── DynamicSigns │ ├── 0.bmp │ ├── 1.bmp │ ├── 2.bmp │ ├── 3.bmp │ ├── 4.bmp │ ├── 5.bmp │ ├── 6.bmp │ ├── 7.bmp │ ├── 8.bmp │ ├── 9.bmp │ ├── A.bmp │ ├── B.bmp │ ├── C.bmp │ ├── D.bmp │ ├── E.bmp │ ├── F.bmp │ ├── G.bmp │ ├── H.bmp │ ├── I.bmp │ ├── J.bmp │ ├── K.bmp │ ├── L.bmp │ ├── M.bmp │ ├── N.bmp │ ├── O.bmp │ ├── P.bmp │ ├── Q.bmp │ ├── R.bmp │ ├── S.bmp │ ├── T.bmp │ ├── U.bmp │ ├── V.bmp │ ├── W.bmp │ ├── X.bmp │ ├── Y.bmp │ ├── Z.bmp │ ├── add.bmp │ ├── arrow-right.bmp │ ├── checkmark.bmp │ ├── delete.bmp │ ├── designkode_free_icon_set.zip │ ├── error.bmp │ ├── flag-yellow.bmp │ ├── license_designkode.txt │ ├── license_red-orb.txt │ ├── red-orb-alphabet-by-iconarchive.zip │ ├── stop.bmp │ ├── thumbtack-yellow.bmp │ └── warning.bmp ├── doc └── DynamicSigns.txt ├── plugin └── SignsPlugin.vim └── todo /.gitignore: -------------------------------------------------------------------------------- 1 | post.pl 2 | vim_passfile 3 | .*.un~ 4 | .*.sw* 5 | # ignore vimballs 6 | *.vba 7 | # ignore *.orig files 8 | *.orig 9 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SCRIPT=$(wildcard plugin/*.vim) 2 | AUTOL =$(wildcard autoload/*.vim) 3 | DOC=$(wildcard doc/*.txt) 4 | PLUGIN=$(shell basename "$$PWD") 5 | VERSION=$(shell sed -n '/Version:/{s/^.*\(\S\.\S\+\)$$/\1/;p}' $(SCRIPT)) 6 | 7 | .PHONY: $(PLUGIN).vmb README $(PLUGIN).zip 8 | 9 | all: vimball install 10 | 11 | convert-images: 12 | for item in autoload/DynamicSigns/*.bmp; do mogrify "$$item" -type palette -colors 256; done 13 | 14 | release: uninstall archive install README 15 | 16 | vimball: $(PLUGIN).vmb 17 | 18 | archive: $(PLUGIN).zip 19 | 20 | clean: 21 | find . -type f \( -name "*.vba" -o -name "*.orig" -o -name "*.~*" \ 22 | -o -name ".VimballRecord" -o -name ".*.un~" -o -name "*.sw*" -o \ 23 | -name tags -o -name "*.vmb" \) -delete 24 | 25 | dist-clean: clean 26 | 27 | install: 28 | vim -N -c':so %' -c':q!' $(PLUGIN).vmb 29 | 30 | uninstall: 31 | vim -N -c':RmVimball' -c':q!' $(PLUGIN).vmb 32 | 33 | undo: 34 | for i in */*.orig; do mv -f "$$i" "$${i%.*}"; done 35 | 36 | README: 37 | cp -f $(DOC) README 38 | 39 | $(PLUGIN).zip: 40 | -@/bin/sh -c "if [ -f $(PLUGIN).zip ]; then \ 41 | zip -u $(PLUGIN).zip ${SCRIPT} ${AUTOL} ${DOC} autoload/*/* ; \ 42 | else \ 43 | zip $(PLUGIN).zip ${SCRIPT} ${AUTOL} ${DOC} autoload/*/* ; \ 44 | fi " 45 | ln -f $(PLUGIN).zip $(PLUGIN)-$(VERSION).zip 46 | 47 | $(PLUGIN).vmb: 48 | rm -f $(PLUGIN).vmb 49 | vim -N -c 'ru! vimballPlugin.vim' -c ':call append("0", [ "$(SCRIPT)", "$(AUTOL)", "$(DOC)"])' -c '$$d' -c ":%MkVimball $(PLUGIN) ." -c':q!' 50 | 51 | release: version all 52 | 53 | version: 54 | perl -i.orig -pne 's/(let s:debug)\s*=\s*1/$$1 = 0/' ${AUTOL} 55 | perl -i.orig -pne 'if (/Version:/) {s/\.(\d*)/sprintf(".%d", 1+$$1)/e}' ${SCRIPT} ${AUTOL} 56 | perl -i -pne 'if (/GetLatestVimScripts:/) {s/(\d+)\s+:AutoInstall:/sprintf("%d :AutoInstall:", 1+$$1)/e}' ${SCRIPT} ${AUTOL} 57 | #perl -i -pne 'if (/Last Change:/) {s/\d+\.\d+\.\d\+$$/sprintf("%s", `date -R`)/e}' ${SCRIPT} 58 | perl -i -pne 'if (/Last Change:/) {s/(:\s+).*\n/sprintf(": %s", `date -R`)/e}' ${SCRIPT} ${AUTOL} 59 | perl -i.orig -pne 'if (/Version:/) {s/\.(\d+).*\n/sprintf(".%d %s", 1+$$1, `date -R`)/e}' ${DOC} 60 | VERSION=$(shell sed -n '/Version:/{s/^.*\(\S\.\S\+\)$$/\1/;p}' $(SCRIPT)) 61 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | *DynamicSigns.txt* - Using Signs for different things 2 | 3 | Author: Christian Brabandt 4 | Version: 0.2 Mon, 07 Jan 2019 5 | *SignsCopyright* 6 | Copyright: (c) 2009-2019 by Christian Brabandt 7 | The VIM LICENSE applies to DynamicSigns (see |copyright|) 8 | except use DynamicSigns instead of "Vim". 9 | NO WARRANTY, EXPRESS OR IMPLIED. USE AT-YOUR-OWN-RISK. 10 | 11 | =========================================================================== 12 | 1. Contents *Signs-content* 13 | 14 | 1. Contents...................................: |Signs-content| 15 | 2. Manual.....................................: |Signs-manual| 16 | 2.1 Display Indent Level.....................: |Signs-Indentation| 17 | 2.2 Display Whitespace Warnings..............: |Signs-Whitespace| 18 | 2.3 Display Marks............................: |Signs-Marks| 19 | 2.4 SignExpressions..........................: |Signs-Hook| 20 | 2.5 Display Signs for Quickfix items.........: |Signs-QF| 21 | 2.6 Display Signs to display changes.........: |Signs-Diff| 22 | 2.7 Alternating colors.......................: |Signs-Alternate| 23 | 2.8 ASCII Scrollbar..........................: |Signs-Scrollbar| 24 | 2.9 SignHighlighting.........................: |Signs-Highlight| 25 | 3. Autocommands...............................: |Signs-Autocommands| 26 | 4. Commands...................................: |Signs-Commands| 27 | 5. Icons......................................: |Signs-Icons| 28 | 6. Feedback...................................: |Signs-feedback| 29 | 7. History....................................: |Signs-history| 30 | 31 | ========================================================================== 32 | 2. Using the Signs Plugin *Signs-manual* 33 | 34 | Functionality 35 | 36 | This plugin enables you to use signs |sign-support| for different things. 37 | For example you can use signs to display Indentation-Levels, display line 38 | whitespace errors, display marks |mark-motion|, display the differences 39 | between the current editing file and the file on disk or whenever an 40 | expression evalutates true (similar to how fold-expressions work 41 | |fold-expr|) 42 | 43 | All you need to do, is configure the plugin by setting some configuration 44 | variables and run |:Signs| 45 | 46 | 47 | 2.1 Display Indentation Level *Signs-Indentation* 48 | ----------------------------- 49 | 50 | If you want the plugin to display the numeric indentation level, simply set 51 | the g:Signs_IndentationLevel variable like this in your |.vimrc|, e.g. like 52 | this: > 53 | 54 | let g:Signs_IndentationLevel = 1 55 | < 56 | 57 | By default, this displays the indentation level (e.g. the indentation 58 | divided by the 'tabstop' setting) as numeric values (actually it only 59 | displays levels 1-9 or '>9' for a larger indent. 60 | 61 | Run |:Signs| to display the signs for those lines. 62 | 63 | 2.2 Display Whitespace Warnings *Signs-Whitespace* 64 | ------------------------------- 65 | 66 | If you want the plugin to display the warnings for lines with whitespace 67 | errors, simply set the variable g:Signs_MixedIndentation like this in your 68 | |.vimrc|, e.g. > 69 | 70 | :let g:Signs_MixedIndentation = 1 71 | < 72 | 73 | By default, this display warning signs for each line where either the 74 | indentation consists of mixed whitespace (e.g. tabspace and blanks) or the 75 | line ends with trailing whitespace. 76 | 77 | Run |:Signs| to display the signs for those lines. 78 | 79 | 2.3 Display Marks *Signs-Marks* 80 | ----------------- 81 | If you want the plugin to display your marks, set the variable 82 | g:Signs_Bookmarks to 1 in your |.vimrc|, e.g. > 83 | 84 | :let g:Signs_Bookmarks = 1 85 | < 86 | This will display the marks a-z and A-Z, if they are in your current buffer. 87 | 88 | If this is enabled, |m| will be mapped to a function, that places the 89 | bookmarks in your buffer and sets the mark. (|:k| does not update the signs, 90 | Use |:Signs| or |:UpdateSigns| to manually update the view in case this is 91 | needed). 92 | 93 | *:SignExpression* 94 | 2.4 SignExpressions *Signs-Hook* 95 | ------------------- 96 | 97 | You can let Vim have an expression evaluated for each line in your current 98 | buffer. On each line, where this expression is true, Vim will place a sign 99 | for your. This enables you, to put e.g. a Sign on each line, that contains 100 | 'TODO'. 101 | 102 | To do this, run the command |:SignExpression| and give an expression as 103 | its argument, which will be evaluated for each line. Use the variable 104 | |v:lnum| in your expression for the current line. 105 | 106 | Say, you want to place a sign on each line, that contains 'TODO'. You simply 107 | enter > 108 | 109 | :SignExpression getline(v:lnum)=~'TODO'?'Warning':0 110 | 111 | This will place a sign on each line, that contains the word TODO 112 | This expression is window-local. 113 | 114 | As a special return value for the expression, you can return the type of sign 115 | that should be placed. Currently the following sign types are understood: > 116 | 117 | Warning 118 | OK 119 | Error 120 | Info 121 | Add 122 | Arrow 123 | Flag 124 | Delete 125 | Stop 126 | Line1 127 | Line2 128 | Line3 129 | Line4 130 | Line5 131 | Gutter1 132 | Gutter2 133 | Gutter3 134 | Gutter4 135 | Gutter5 136 | 1-99 137 | 0 138 | < 139 | All except for "Line" only draw a flag in the sign column while the sign types 140 | "Line1"-"Line5" highlights the complete line without displaying anything in 141 | the Sign Column. "Gutter1"-"Gutter5" highlights only the gutter column, but 142 | does not draw anything inside it. It uses the SignLine1-SignLine5 highlighting 143 | groups for highlighting (|Signs-Highlight|) 144 | 145 | The special return value 0 is meant to not place a sign, all other numbers 146 | simply stand for themselves, e.g. will draw the corresponding number. 147 | 148 | For example you want to highlight all Lines that contain the word 'TODO' with 149 | the todo sign. Therefore you call the command: > 150 | 151 | :SignExpression getline(v:lnum)=~'TODO'?'Todo':0 152 | 153 | Note, the Expression will be re-evaluated for that buffer on Changes to the 154 | buffer. 155 | 156 | *relativenumber_signs* 157 | 158 | Here is an example, on how to draw relative numbers but only every fifth line. 159 | First define a custom function like the following. You can usually just do 160 | that in your |.vimrc| > 161 | 162 | fu! CustomSignExpression(lnum, div) 163 | if a:lnum < line('w0') || a:lnum > line ('w$') 164 | return 0 165 | endif 166 | if !exists("#CustomSignExpression#CursorMoved") 167 | augroup CustomSignExpression 168 | au! 169 | au CursorMoved * :Signs 170 | au VimResized * :UpdateSigns 171 | augroup end 172 | endif 173 | let part=abs(a:lnum - line('.')) 174 | if part % a:div == 0 175 | return part > 99 ? 99 : part 176 | else 177 | return 0 178 | endif 179 | endfu 180 | 181 | Then you simply call: > 182 | :SignExpression CustomSignExpression(v:lnum, 5) 183 | 184 | This makes sure, the relative numbers will only be drawn on every fifth line. 185 | Adjust the second number if you want it at other intervals. The autocommand 186 | is there to make sure, it will be re-evaluated on cursor changes. By default, 187 | custom sign expressions are only evaluated once the text changes, but this is 188 | needed here, or else the relative line numbering will get out of sync soon. 189 | Note it is recommended to use the CustomSignExpression |augroup|, as this will 190 | be automatically cleaned up on the |:DisableSigns| command, if one exists, 191 | otherwise the autocommand will still trigger although it probably should not. 192 | 193 | 2.5 Display signs for quickfix items *Signs-QF* 194 | ------------------------------------ 195 | If you want the plugin to display signs next to each match when using the 196 | |quickfix| feature of vim, set the variable g:Signs_QFList, e.g. > 197 | 198 | :let g:Signs_QFList = 1 199 | < 200 | This will hook up an autocommand, that fires whenever the quickfix command 201 | (|:helpgrep|, |:make|, |:vimgrep|, etc has been executed and places a small 202 | sign next to each match. 203 | 204 | 2.6 Display Signs for viewing changes to the buffer *Signs-Diff* 205 | --------------------------------------------------- 206 | You can also set up the plugin to display small signs, that indicate, 207 | whether the current line has been modified/deleted/added compared to the 208 | version stored on disk. To enable this feature, set the g:Signs_Diff 209 | variable in your |.vimrc| like this: > 210 | 211 | :let g:Signs_Diff = 1 212 | < 213 | This will run a diff of your buffer and the version stored on disk and place 214 | a sign on each line that was modified. 215 | 216 | Run |:UpdateSigns| or |:Signs| to update displaying the signs in your 217 | buffer. 218 | 219 | 2.7 Alternating colors *Signs-Alternate* 220 | ---------------------- 221 | 222 | You can also set up the plugin to color the lines in your buffer in 223 | alternating colors. To do so, set the g:Signs_Alternate variable in your 224 | |.vimrc| like this: > 225 | 226 | :let g:Signs_Alternate = 1 227 | < 228 | This will display each evenly numbered line in one color and each oddly 229 | numbered line in a different color. 230 | 231 | Run |:UpdateSigns| or |:Signs| to update displaying the signs in your 232 | buffer. 233 | 234 | 2.8 ASCII Scrollbar *Signs-Scrollbar* 235 | ------------------- 236 | The DynamicSigns plugin can also emulate an ascii scrollbar. This is useful 237 | in terminal Vim, to visually indicate, where in the buffer on is. 238 | 239 | If you want to enable this, simply set the g:Signs_Scrollbar variable in 240 | your |.vimrc| like this: > 241 | 242 | :let g:Signs_Scrollbar = 1 243 | 244 | This will enable the Scrollbar and disable all other Sign features. 245 | 246 | Unfortunately, this does not work well with |folds| and therefore the 247 | scrollbar can't be displayed on a folded line. Also Linewrapping 'wrap' can 248 | disturb the display of the scrollbar. 249 | 250 | 2.9 Sign Highlighting *Signs-Highlight* 251 | --------------------- 252 | 253 | By default the plugin defines the following highlighting groups: > 254 | 255 | SignLine1 - gray 256 | SignLine2 - orange 257 | SignLine3 - blue 258 | SignLine4 - red 259 | SignLine5 - yellow 260 | 261 | You can however override those highlighting groups, by predefining them in 262 | your |.vimrc| to whatever you want. 263 | 264 | 3.0 Autocommands *:Signs-Autocommands* 265 | ---------------- 266 | This plugin installs some autocommands to update the signs dynamically. 267 | Basically it uses |BufWritePost| and |InsertLeave| autocommands to update 268 | displaying the signs. 269 | 270 | Theoretically, it could also use |CursorHold| and |CursorHoldI| 271 | autocommands, but that seems to slow down Vim a lot, when working with long 272 | buffers and also seems to interrupt the workflow too much. You can however 273 | force Vim to update the signs on those autocommands, by setting the variable 274 | g:Signs_CursorHold to 1, e.g. put > 275 | let g:Signs_CursorHold = 1 276 | < 277 | in your .vimrc 278 | 279 | When switching to the |:gui|, Vim will also updates the signs, so the gui 280 | version can use some nice lookings |Signs-Icons|. 281 | 282 | Last, when the using the quickfix feature together with the Signs 283 | (|Signs-QF|), this plugin also installs an |QuickFixCmdPost| autocommand, to 284 | be able to put signs on each line, where a warning/error is. 285 | 286 | =========================================================================== 287 | 288 | 4.0 Commands *:Signs-Commands* 289 | ------------ 290 | 291 | The plugin introduces the following commands: 292 | 293 | > 294 | :Signs 295 | 296 | Update the signs in the current buffer. According to your configuration runs 297 | through every line in your buffer and checks, if a sign has to be displayed. 298 | For performance reasons, it caches the values. 299 | 300 | > 301 | :UpdateSigns 302 | 303 | Discard the cache and update the signs for each line. 304 | 305 | > 306 | :DisableSigns 307 | 308 | Disable the Sign plugin. 309 | 310 | > 311 | :SignQF 312 | 313 | Display a quickfix list that contains all your signs in the current buffer. 314 | |Sign-QF| 315 | 316 | > 317 | :SignExpression expr 318 | 319 | Display a sign on each line, where expr evaluates to true |Signs-Hook| 320 | 321 | > 322 | :SignDiff 323 | 324 | Run a diff of the buffer and the file on disk and display signs for the 325 | changes |Signs-Diff| 326 | 327 | ============================================================================ 328 | 5. Icons *Signs-Icons* 329 | -------- 330 | 331 | The GTK version of Vim (and possibly also the Windows version) can also 332 | display graphical Signs. For this reason, this plugin includes some nice 333 | looking icons, that have been provided by 334 | http://www.designkode.com/blog/free-developer-icons 335 | 336 | "DesignKode is releasing this set of 40 free high quality icons for your web 337 | site and application GUI designs. All icons in this set are 32 x 32 pixel 338 | PNG image files. You may freely use these icons in your commercial or 339 | personal projects without attribution." 340 | 341 | (Source not available anymore, currently still available at the Internet 342 | Archive: 343 | https://web.archive.org/web/20111224161343/http://www.designkode.com/?download=Free%20Icons%20for%20Developers) 344 | 345 | The Bookmark icons are "Red Orb Alphabet Icons" and have been take from 346 | http://www.iconarchive.com/show/red-orb-alphabet-icons-by-iconarchive.html 347 | 348 | Those are licensed under a Creative Commons Attribution 3.0 License. 349 | 350 | The icons have been taken as is and only converted to a .bmp fileformat and a 351 | size of 16x16, so that the gtk and Windows built of gVim can display them. 352 | 353 | The autoload/DynamicSigns/ folder contains the original archive files with all 354 | icons. 355 | 356 | =========================================================================== 357 | 6. Feedback *Signs-Feedback* 358 | ----------- 359 | Feedback is always welcome. If you like the plugin, please rate it at the 360 | vim-page: 361 | http://www.vim.org/scripts/script.php?script_id=3965 362 | 363 | You can also follow the development of the plugin at github: 364 | http://github.com/chrisbra/DynamicSigns 365 | 366 | Please don't hesitate to report any bugs to the maintainer, mentioned in the 367 | third line of this document. 368 | 369 | ========================================================================== 370 | 4. History *Signs-history* 371 | 372 | 0.3: (unreleased) {{{1 373 | - Performance improvements to make updating the signs faster 374 | (could slow down saving considerably for large files) 375 | - Implement a Scrollbar |Signs-Scrollbar| 376 | - Function was called too early issue #2 377 | (https://github.com/chrisbra/DynamicSigns/issues/2, reported by 378 | Charles, thanks!) 379 | - Update SignExpressions on Changes to buffer or when switching to the gui 380 | - Do not clean the signs, when starting up 381 | - Make the |:SignExpression| command window-local 382 | 383 | 0.2: Mar 15, 2012 {{{1 384 | - Initial upload 385 | - development versions are available at the github repository 386 | - put plugin on a public repository (http://github.com/chrisbra/Signs) 387 | }}} 388 | =========================================================================== 389 | Modeline: 390 | vim:tw=78:ts=8:ft=help:et:fdm=marker:fdl=0:norl 391 | -------------------------------------------------------------------------------- /autoload/DynamicSigns.vim: -------------------------------------------------------------------------------- 1 | " DynamicSigns.vim - Using Signs for different things 2 | " --------------------------------------------------------------- 3 | "Author: Christian Brabandt 4 | "License: VIM License (see :h license) 5 | "URL: http://www.github.com/chrisbra/DynamicSigns 6 | "Documentation: DynamicSigns.txt 7 | "Version: 0.1 8 | "Last Change: Thu, 15 Mar 2012 23:37:37 +0100 9 | "GetLatestVimScripts: 3965 1 :AutoInstall: DynamicSigns.vim 10 | 11 | "{{{1Scriptlocal variables 12 | fu! GetSID() 13 | return matchstr(expand(''), '\zs\d\+\ze_GetSID$') 14 | endfu 15 | " Check preconditions 16 | scriptencoding utf-8 17 | let s:plugin = fnamemodify(expand(""), ':t:r') 18 | let s:i_path = fnamemodify(expand(""), ':p:h'). '/'. s:plugin. '/' 19 | let s:execute = exists("*execute") 20 | let s:sign_api = v:version > 801 || (v:version == 801 && has("patch614")) 21 | let s:sign_api_group = 'DynamicSigns' 22 | 23 | let s:sid = GetSID() 24 | delf GetSID "not needed anymore 25 | 26 | fu! Check() "{{{1 27 | " Check for the existence of unsilent 28 | if exists(":unsilent") 29 | let s:echo_cmd='unsilent echomsg' 30 | else 31 | let s:echo_cmd='echomsg' 32 | endif 33 | 34 | if !has("signs") 35 | call add(s:msg, "Sign Support support not available" . 36 | \ "in your Vim version.") 37 | call add(s:msg, "Signs plugin will not be working!") 38 | call WarningMsg() 39 | throw 'Signs:abort' 40 | endif 41 | 42 | let s:sign_prefix = (s:sign_api ? '' : s:sid) 43 | let s:id_hl = {} 44 | let s:id_hl.Line = "DiffAdd" 45 | let s:id_hl.Error = "Error" 46 | let s:id_hl.Check = "User1" 47 | let s:id_hl.LineEven = get(g:, "g:DynamicSigns_Even", Color("Even")) 48 | let s:id_hl.LineOdd = get(g:, "g:DynamicSigns_Odd", Color("Odd")) 49 | let s:id_hl.Warning = "WarningMsg" 50 | let s:id_hl.Mark = 'DynamicSignsHighlightMarks' 51 | 52 | " highlight line 53 | " TODO: simplify, a simple `:hi default should work! 54 | if !hlexists("SignLine1") || empty(synIDattr(hlID("SignLine1"), "ctermbg")) 55 | exe "hi default SignLine1 ctermbg=238 guibg=#403D3D" 56 | endif 57 | if !hlexists("SignLine2") || empty(synIDattr(hlID("SignLine2"), "ctermbg")) 58 | exe "hi default SignLine2 ctermbg=208 guibg=#FD971F" 59 | endif 60 | if !hlexists("SignLine3") || empty(synIDattr(hlID("SignLine3"), "ctermbg")) 61 | exe "hi default SignLine3 ctermbg=24 guibg=#13354A" 62 | endif 63 | if !hlexists("SignLine4") || empty(synIDattr(hlID("SignLine4"), "ctermbg")) 64 | exe "hi default SignLine4 ctermbg=1 guibg=Red" 65 | endif 66 | if !hlexists("SignLine5") || empty(synIDattr(hlID("SignLine5"), "ctermbg")) 67 | exe "hi default SignLine5 ctermbg=190 guibg=#DFFF00" 68 | endif 69 | if !hlexists("DynamicSignsHighlightMarks") 70 | hi default link DynamicSignsHighlightMarks Visual 71 | endif 72 | 73 | if exists("+signcolumn") 74 | let s:unset_signcolumn=1 75 | set signcolumn=yes 76 | endif 77 | 78 | " Undefine Signs 79 | if exists("s:precheck") 80 | " just started up, there shouldn't be any signs yet 81 | call DynamicSigns#CleanUp() 82 | endif 83 | " Define Signs 84 | call DefineSigns() 85 | endfu 86 | fu! Color(name) "{{{1 87 | let definition = '' 88 | let termmode=!empty(&t_Co) && &t_Co < 88 && !&tgc 89 | if a:name == 'Even' 90 | if &bg == 'dark' 91 | if termmode 92 | let definition .= ' ctermbg=DarkGray' 93 | else 94 | let definition .= ' ctermbg='. (&t_Co == 88 ? '80' : '234'). ' guibg=#292929' 95 | endif 96 | else 97 | if termmode 98 | let definition .= ' ctermbg=LightGrey' 99 | else 100 | let definition .= ' ctermbg='. (&t_Co == 88 ? '86' : '245') . ' guibg=#525252' 101 | endif 102 | endif 103 | exe "hi default LineEven" definition 104 | return 'LineEven' 105 | else 106 | if &bg == 'dark' 107 | if termmode 108 | let definition .= ' ctermbg=LightGray' 109 | else 110 | let definition .= ' ctermbg='. (&t_Co == 88 ? '86' : '245') . ' guibg=#525252' 111 | endif 112 | else 113 | if termmode 114 | let definition .= ' ctermbg=LightGrey' 115 | else 116 | let definition .= ' ctermbg='. (&t_Co == 88 ? '80' : '234') . ' guibg=#292929' 117 | endif 118 | endif 119 | exe "hi default LineOdd" definition 120 | return 'LineOdd' 121 | endif 122 | endfu 123 | fu! WarningMsg() "{{{1 124 | redraw! 125 | if !empty(s:msg) 126 | let msg=["Signs.vim: " . s:msg[0]] + (len(s:msg) > 1 ? s:msg[1:] : []) 127 | echohl WarningMsg 128 | for mess in msg 129 | exe s:echo_cmd "mess" 130 | endfor 131 | echohl Normal 132 | let s:msg=[] 133 | endif 134 | endfu 135 | fu! Init(...) "{{{1 136 | " Message queue, that will be displayed. 137 | let s:msg = [] 138 | 139 | " Setup configuration variables: 140 | let s:MixedIndentation = get(g:, "Signs_MixedIndentation", 0) 141 | let s:IndentationLevel = get(g:, "Signs_IndentationLevel", 0) 142 | let s:BookmarkSigns = get(g:, "Signs_Bookmarks", 0) 143 | let s:AlternatingSigns = get(g:, "Signs_Alternate", 0) 144 | let s:SignHook = get(w:, "Signs_Hook", "") 145 | let s:SignQF = get(g:, "Signs_QFList", 0) 146 | let s:SignDiff = get(g:, "Signs_Diff", 0) 147 | let s:Bookmarks = split("abcdefghijklmnopqrstuvwxyz" . 148 | \ "ABCDEFGHIJKLMNOPQRSTUVWXYZ", '\zs') 149 | 150 | " Don't draw an ascii scrollbar in the gui, because it does not look nice 151 | " and the gui can display its own scrollbar 152 | let s:SignScrollbar = get(g:, "Signs_Scrollbar", 0) && !has("gui_running") 153 | 154 | let s:Sign_CursorHold = get(g:, "Signs_CursorHold", 0) 155 | let s:debug = get(g:, "Signs_Debug", 0) 156 | let s:ignore = split(get(g:, 'Signs_Ignore', ''), ',') 157 | 158 | if !exists("s:gui_running") 159 | let s:gui_running = has("gui_running") 160 | endif 161 | 162 | " Highlighting for the bookmarks 163 | if !exists("s:BookmarkSignsHL") 164 | let s:BookmarkSignsHL = {} 165 | endif 166 | 167 | " Only check the first time this file is loaded 168 | " or Signs shall be cleared first or 169 | " GUI has started (use icons then) 170 | " It should not be neccessary to check every time 171 | if !exists("s:precheck") || 172 | \ (exists("a:1") && a:1) || 173 | \ s:gui_running != has("gui_running") 174 | call Check() 175 | let s:precheck=1 176 | endif 177 | 178 | " Cache Configuration 179 | if !exists("s:CacheOpts") 180 | let s:CacheOpts = {} 181 | endif 182 | 183 | " Need to redefine existing Signs? 184 | if get(g:, "NoUtf8Signs", 0) != get(s:CacheOpts, 'NoUtf8Signs', 0) 185 | call DynamicSigns#CleanUp() 186 | call DefineSigns() 187 | endif 188 | 189 | " Create CursorMoved autocommands 190 | if s:SignScrollbar 191 | call DoSignScrollbarAucmd(1) 192 | endif 193 | 194 | " This is needed, to not mess with signs placed by the user 195 | let s:Signs = ReturnSigns(bufnr('')) 196 | call AuCmd(1) 197 | endfu 198 | fu! NextID() "{{{1 199 | " Not used for sign api 200 | let b:sign_count= get(b:, 'sign_count', 0) + 1 201 | return (s:sign_prefix . b:sign_count) + 0 202 | endfu 203 | fu! ReturnSignDef() "{{{1 204 | if s:sign_api 205 | return filter(sign_getdefined(), {i,v -> v.name =~ '^DSign'}) 206 | endif 207 | let a = Redir(':sil sign list') 208 | let b = split(a, "\n")[2:] 209 | call map(b, 'split(v:val)[1]') 210 | return filter(b, 'v:val=~''^DSign''') 211 | endfu 212 | fu! ReturnSigns(buffer) "{{{1 213 | if s:sign_api 214 | return sign_getplaced(a:buffer, {'group': s:sign_api_group})[0].signs 215 | endif 216 | let lang=v:lang 217 | if lang isnot# 'C' 218 | sil lang mess C 219 | endif 220 | let a = Redir(':sil sign place buffer='.a:buffer) 221 | let b = split(a, "\n")[2:] 222 | " Remove old deleted Signs 223 | call RemoveDeletedSigns(filter(copy(b), 224 | \ 'matchstr(v:val, ''deleted'')')) 225 | call filter(b, 'matchstr(v:val, ''id=\zs''.s:sign_prefix.''\d\+'')') 226 | if lang != 'C' 227 | exe "sil lang mess" lang 228 | endif 229 | return b 230 | endfu 231 | fu! RemoveDeletedSigns(list) "{{{1 232 | " not used for sign_api 233 | " but just in case 234 | if s:sign_api 235 | call add(s:msg, 'Using wrong function for Sign-API') 236 | call WarningMsg() 237 | return 238 | endif 239 | for sign in a:list 240 | let id=matchstr(sign, 'id=\zs\d\+') 241 | exe "sil sign unplace" id "buffer=". bufnr('') 242 | endfor 243 | endfu 244 | fu! AuCmd(arg) "{{{1 245 | " Don't update signs for 246 | " marks on insertleave 247 | if a:arg 248 | augroup Signs 249 | autocmd! 250 | au InsertLeave * :call DynamicSigns#UpdateWindowSigns('marks') 251 | au GUIEnter * call DynamicSigns#ForceUpdate() 252 | au BufWinEnter,VimEnter * 253 | \ call DynamicSigns#UpdateWindowSigns('') 254 | au BufWritePost * 255 | \ call DynamicSigns#UpdateWindowSigns('marks') 256 | exe s:SignQF ? 257 | \ "au QuickFixCmdPost * :call DynamicSigns#QFSigns()" : '' 258 | if exists("s:Sign_CursorHold") && s:Sign_CursorHold 259 | au CursorHold,CursorHoldI * 260 | \ call DynamicSigns#UpdateWindowSigns('marks') 261 | endif 262 | " make sure, sign expression is reevaluated on changes to 263 | " the buffer 264 | au TextChanged * call DynamicSigns#UpdateWindowSigns('diff,marks,indentation') 265 | au CursorMoved * call DynamicSigns#UpdateWindowSigns('diff,whitespace') 266 | augroup END 267 | else 268 | augroup Signs 269 | autocmd! 270 | augroup END 271 | augroup! Signs 272 | if exists("#CustomSignExpression") 273 | augroup CustomSignExpression 274 | au! 275 | augroup end 276 | augroup! CustomSignExpression 277 | endif 278 | endif 279 | endfu 280 | fu! DoSignScrollbarAucmd(arg) "{{{1 281 | if a:arg 282 | augroup SignsScrollbar 283 | autocmd! 284 | au CursorMoved,CursorMovedI,VimResized,BufEnter * 285 | \ :call DynamicSigns#UpdateScrollbarSigns() 286 | augroup END 287 | else 288 | augroup SignsScrollbar 289 | autocmd! 290 | augroup END 291 | augroup! SignsScrollbar 292 | endif 293 | endfu 294 | fu! Redir(args) "{{{1 295 | if s:execute 296 | let a=execute(a:args) 297 | else 298 | redir => a | exe a:args |redir end 299 | endif 300 | return a 301 | endfu 302 | fu! UnPlaceSigns() "{{{1 303 | if s:sign_api 304 | call sign_unplace(s:sign_api_group, {'buffer': bufnr('')}) 305 | return 306 | endif 307 | let a = Redir(':sil sign place buffer='.bufnr('')) 308 | let b=split(a,"\n")[1:] 309 | if empty(b) 310 | return 311 | endif 312 | let c=filter(copy(b), 'v:val !~ "id=". s:sign_prefix || v:val =~ ''Deleted'' ') 313 | if empty(c) 314 | " Can unplace all signs 315 | if v:version > 703 || (v:version = 703 && has("patch596")) 316 | exe "sign unplace * bufnr=". bufnr('%') 317 | else 318 | for id in b 319 | exe "sign unplace" id 320 | endfor 321 | endif 322 | else 323 | let b=filter(b, 'v:val =~ "id=".s:sign_prefix') 324 | let b=map(b, 'matchstr(v:val, ''id=\zs\d\+'')') 325 | for id in b 326 | exe "sign unplace" id 327 | endfor 328 | endif 329 | endfu 330 | fu! UnMatchHL() "{{{1 331 | if exists("s:BookmarkSignsHL") 332 | for value in values(s:BookmarkSignsHL) 333 | sil! call matchdelete(value) 334 | endfor 335 | endif 336 | if exists("s:MixedIndentationHL") 337 | sil! call matchdelete(s:MixedIndentationHL) 338 | endif 339 | let s:BookmarkSignsHL = {} 340 | endfu 341 | fu! DoBookmarkHL() "{{{1 342 | if get(s:, "BookmarkSigns", 0) 343 | if !exists("s:BookmarkSignsHL") 344 | let s:BookmarkSignsHL = {} 345 | endif 346 | let PlacedSigns = copy(s:Signs) 347 | if s:sign_api 348 | call filter(PlacedSigns, {i,v -> v.name =~ 'DSignBookmark\(.\)'}) 349 | call map(PlacedSigns, {i,v -> matchadd(s:id_hl.Mark, GetPattern(v.name[-1]))}) 350 | return 351 | endif 352 | let PlacedSigns = copy(s:Signs) 353 | let pat = 'id='.s:sign_prefix.'\d\+[^0-9=]*=DSignBookmark\(.\)' 354 | let Sign = matchlist(PlacedSigns, pat) 355 | while (!empty(Sign)) 356 | let s:BookmarkSignsHL[Sign[1]] = matchadd(s:id_hl.Mark, 357 | \ GetPattern(Sign[1])) 358 | call remove(PlacedSigns, match(PlacedSigns, pat)) 359 | let Sign = matchlist(PlacedSigns, pat) 360 | endw 361 | endif 362 | endfu 363 | fu! GetLineForSign(sign) "{{{1 364 | " not used for Sign-API 365 | return matchstr(a:sign, '^\s*\w\+=\zs\d\+\ze\D') + 0 366 | endfunction 367 | fu! UnplaceSignSingle(sign) "{{{1 368 | if s:sign_api 369 | call sign_unplace(s:sign_api_group, {'buffer': bufnr(''), 'id': a:sign.id}) 370 | return 371 | endif 372 | let line = GetLineForSign(a:sign) 373 | if line <= 0 374 | return 375 | endif 376 | let oldcursor = winsaveview() 377 | call cursor(line, 0) 378 | " Vim errors, if the line does not contain a sign 379 | sil! sign unplace 380 | call winrestview(oldcursor) 381 | endfu 382 | fu! PlaceSignSingle(line, name, ...) "{{{1 383 | " safety check 384 | if a:line == 0 385 | return 386 | endif 387 | " Places a single sign 388 | let bufnr=get(a:000, 0, bufnr('')) 389 | if s:sign_api 390 | call sign_place(0, s:sign_api_group, a:name, bufnr, {'lnum': a:line}) 391 | else 392 | exe "sign place ". NextID(). " line=" . a:line. " name=". a:name. " buffer=" . bufnr 393 | endif 394 | endfu 395 | fu! SignName(sign) 396 | if s:sign_api 397 | return a:sign.name 398 | else 399 | return matchstr(a:sign, 'name=\zs\S\+\ze') 400 | endif 401 | endfu 402 | fu! GetMarks() "{{{1 403 | let marks={} 404 | let t = [] 405 | for mark in s:Bookmarks 406 | let t = getpos("'".mark) 407 | if t[1] > 0 && (t[0] == bufnr("%") || t[0] == 0) 408 | let marks[mark] = t[1] 409 | endif 410 | endfor 411 | return marks 412 | endfu 413 | fu! SkipFoldedLines(lineend, range) "{{{1 414 | let range = a:range 415 | if a:lineend == -1 416 | return 417 | endif 418 | call filter(range, 'v:val >= a:lineend') 419 | endfu 420 | fu! PlaceSigns(...) "{{{1 421 | try 422 | let DiffSigns = (s:SignDiff ? ReturnDiffSigns() : {}) 423 | catch /DiffError/ 424 | call WarningMsg() 425 | return 426 | endtry 427 | if !DoSigns() 428 | return 429 | endif 430 | let s:bookmarks = {} 431 | if s:BookmarkSigns 432 | let s:bookmarks = GetMarks() 433 | endif 434 | let first = !exists("a:1") ? 1 : a:1 435 | let last = !exists("a:2") ? line('$') : a:2 436 | let range = range(first, last) 437 | for line in range 438 | let did_place_sign = 0 439 | " Place alternating Signs "{{{3 440 | " don't skip folded lines 441 | if match(s:ignore, 'alternate') == -1 && 442 | \ PlaceAlternatingSigns(line) 443 | continue 444 | endif 445 | " Skip folded lines 446 | if foldclosed(line) != -1 "{{{3 447 | call SkipFoldedLines(foldclosedend(line), range) 448 | continue 449 | endif 450 | " Place Diff Signs "{{{3 451 | if match(s:ignore, 'diff') == -1 && 452 | \ PlaceDiffSigns(line, DiffSigns) 453 | continue 454 | endif 455 | " Place Bookmarks "{{{3 456 | if match(s:ignore, 'marks') == -1 && 457 | \ PlaceBookmarks(line) 458 | continue 459 | endif 460 | " Custom Sign Hooks "{{{3 461 | if match(s:ignore, 'expression') == -1 462 | let i = PlaceSignHook(line) 463 | if i > 0 464 | continue 465 | elseif i < 0 466 | " Evaluating expression failed, avoid 467 | " generating more errors for the rest of the lines 468 | return 469 | endif 470 | endif 471 | " Place signs for mixed indentation rules "{{{3 472 | if match(s:ignore, 'whitespace') == -1 && 473 | \ PlaceMixedWhitespaceSign(line) 474 | continue 475 | endif 476 | " Place signs for Indentation Level {{{3 477 | if match(s:ignore, 'indentation') == -1 && 478 | \ PlaceIndentationSign(line) 479 | continue 480 | endif 481 | endfor 482 | " Cache for configuration options 483 | call BufferConfigCache() 484 | endfu 485 | fu! GetSignDef(def) "{{{1 486 | " Returns sign definition as string for use as `:sign command` 487 | " not used when s:sign_api is defined 488 | return (has_key(a:def, 'text') ? ' text='.get(a:def, 'text', '') : ''). 489 | \ (has_key(a:def, 'texthl') ? ' texthl='.get(a:def, 'texthl', '') : ''). 490 | \ (has_key(a:def, 'icon') ? ' icon='.get(a:def, 'icon', '') : ''). 491 | \ (has_key(a:def, 'linehl') ? ' linehl='.get(a:def, 'linehl', '') : '') 492 | endfu 493 | fu! DefineSignIcons(def) "{{{1 494 | for def in keys(a:def) 495 | if s:sign_api 496 | let sign = a:def[def] 497 | try 498 | call sign_define(def, sign) 499 | catch /^Vim\%((\a\+)\)\=:E255/ 500 | " gvim can't read the icon 501 | " first undefine the sign 502 | call remove(sign, 'icon') 503 | call sign_define(key, sign) 504 | endtry 505 | continue 506 | endif 507 | try 508 | let cmd="sign define ". def. GetSignDef(a:def[def]) 509 | let path=matchstr(cmd, 'icon=\zs\S*') 510 | if !filereadable(path) 511 | let cmd=substitute(cmd, 'icon=\S*', '', '') 512 | endif 513 | exe cmd 514 | catch /^Vim\%((\a\+)\)\=:E255/ 515 | " gvim can't read the icon 516 | " first undefine the sign 517 | exe "sign undefine" matchstr(cmd, '^sign define \zs\S\+\ze') 518 | " redefine the sign without an icon 519 | exe substitute(cmd, 'icon=.*$', '', '') 520 | endtry 521 | endfor 522 | endfu 523 | fu! DefineSigns() "{{{1 524 | let icon = 0 525 | if (has("gui_gtk") || has("gui_win32") || has("win32") || has("win64")) 526 | \ && has("gui_running") 527 | let icon = 1 528 | endif 529 | 530 | let utf8signs = get(g:, "NoUtf8Signs", 1) 531 | 532 | if utf8signs && &enc != 'utf-8' 533 | let utf8signs = 0 534 | endif 535 | let def = {} 536 | 537 | " Indentlevel 538 | for item in range(1,9) 539 | let def["DSign".item] = { 540 | \ 'text': item, 541 | \ 'texthl': s:id_hl.Line, 542 | \ 'icon': icon ? (s:i_path. item. '.bmp') : ''} 543 | endfor 544 | 545 | " Indentlevel > 9 546 | let def["DSign10"] = { 547 | \ 'text': ">9", 548 | \ 'texthl': s:id_hl.Error, 549 | \ 'icon': icon ? (s:i_path. 'error.bmp') : ''} 550 | 551 | " Indentlevel < 1 552 | let def["DSign0"] = { 553 | \ 'text': "<1", 554 | \ 'texthl': s:id_hl.Warning, 555 | \ 'icon': icon ? (s:i_path. 'warning.bmp') : ''} 556 | 557 | " Mixed Indentation Error 558 | let def["DSignWSError"] = { 559 | \ 'text': "X", 560 | \ 'texthl': s:id_hl.Error, 561 | \ 'icon': icon ? (s:i_path. 'error.bmp') : ''} 562 | 563 | " Scrollbar 564 | let def["DSignScrollbar"] = { 565 | \ 'text': (utf8signs ? '██': '>>'), 566 | \ 'texthl': s:id_hl.Check} 567 | 568 | " Custom Signs Hooks 569 | for sign in ['OK', 'Warning', 'Error', 'Info', 'Add', 'Arrow', 'Flag', 'Delete', 'Stop'] 570 | \ + ['Line1', 'Line2', 'Line3', 'Line4', 'Line5'] 571 | \ + ['Gutter1', 'Gutter2', 'Gutter3', 'Gutter4', 'Gutter5'] 572 | \ + range(1,99) 573 | let icn = (icon ? s:i_path : '') 574 | let text = "" 575 | let texthl = '' 576 | let line = 0 577 | if sign =~# '^\d\+$' 578 | let icn = '' 579 | let text = sign 580 | let texthl = 'Normal' 581 | elseif sign == 'OK' 582 | let text = (utf8signs ? '✓' : 'OK') 583 | let icn = (empty(icn) ? '' : icn . 'checkmark.bmp') 584 | elseif sign == 'Warning' 585 | let text = (utf8signs ? '⚠' : '!') 586 | let icn = (empty(icn) ? '' : icn . 'warning.bmp') 587 | elseif sign == 'Error' 588 | let text = 'X' 589 | let icn = (empty(icn) ? '' : icn . 'error.bmp') 590 | elseif sign == 'Info' 591 | let text = (utf8signs ? 'ℹ' : 'I') 592 | let icn = (empty(icn) ? '' : icn . 'thumbtack-yellow.bmp') 593 | elseif sign == 'Add' 594 | let text = '+' 595 | let icn = (empty(icn) ? '' : icn . 'add.bmp') 596 | elseif sign == 'Arrow' 597 | let text = (utf8signs ? '→' : '->') 598 | let icn = (empty(icn) ? '' : icn . 'arrow-right.bmp') 599 | elseif sign == 'Flag' 600 | let text = (utf8signs ? '⚑' : 'F') 601 | let icn = (empty(icn) ? '' : icn . 'flag-yellow.bmp') 602 | elseif sign == 'Delete' 603 | let text = (utf8signs ? '‒' : '-') 604 | let icn = (empty(icn) ? '' : icn . 'delete.bmp') 605 | elseif sign == 'Stop' 606 | let text = 'ST' 607 | let icn = (empty(icn) ? '' : icn . 'stop.bmp') 608 | elseif sign =~# 'Line\d' 609 | let icn = '' 610 | let line = matchstr(sign, 'Line\zs\d')+0 611 | let texthl = 'Normal' 612 | elseif sign =~# 'Gutter\d' 613 | let icn = '' 614 | let text = "\u00a0" 615 | let texthl = 'SignLine'. matchstr(sign, 'Gutter\zs\d')+0 616 | endif 617 | let def["DSignCustom".sign] = { 618 | \ 'texthl': (empty(texthl) ? s:id_hl.Error : texthl)} 619 | if !empty(text) 620 | let def["DSignCustom".sign]["text"] = text 621 | endif 622 | if !empty(icn) 623 | let def["DSignCustom".sign]["icon"] = icn 624 | endif 625 | if line 626 | let def["DSignCustom".sign]["linehl"] = "SignLine". line 627 | endif 628 | endfor 629 | 630 | " Bookmark Signs 631 | for item in s:Bookmarks 632 | let icn = '' 633 | if item =~# "[a-z0-9]" && icon 634 | let icn = s:i_path.toupper(item).".bmp" 635 | endif 636 | let def["DSignBookmark".item] = { 637 | \ 'text': "'".item, 638 | \ 'texthl': s:id_hl.Line, 639 | \ 'icon': icn } 640 | endfor 641 | 642 | " Make Errors (quickfix list) 643 | if has("quickfix") 644 | let def["DSignQF"] = { 645 | \ 'text': "!", 646 | \ 'texthl': s:id_hl.Check, 647 | \ 'icon': (icon ? s:i_path. "arrow-right.bmp" : '')} 648 | endif 649 | 650 | " Diff Signs 651 | if has("diff") 652 | let def["DSignAdded"] = { 653 | \ 'text': "+", 654 | \ 'texthl': 'DiffAdd', 655 | \ 'icon': (icon ? s:i_path. "add.bmp" : '')} 656 | let def["DSignChanged"] = { 657 | \ 'text': "M", 658 | \ 'texthl': 'DiffAdd', 659 | \ 'icon': (icon ? s:i_path. "warning.bmp" : '')} 660 | let def["DSignDeleted"] = { 661 | \ 'text': "-", 662 | \ 'texthl': 'DiffDeleted', 663 | \ 'icon': (icon ? s:i_path. "delete.bmp" : '')} 664 | endif 665 | 666 | " Alternating Colors 667 | let def["DSignEven"] = { 668 | \ 'linehl': s:id_hl.LineEven} 669 | let def["DSignOdd"] = { 670 | \ 'linehl': s:id_hl.LineOdd} 671 | 672 | for name in keys(def) 673 | " remove empty keys from dictionary 674 | if v:version >= 800 675 | call filter(def[name], {key, val -> !empty(val)}) 676 | else 677 | call filter(def[name], '!empty(v:val)') 678 | endif 679 | endfor 680 | " Check for all the defined signs for accessibility of the icon 681 | " and define the signs then finally 682 | call DefineSignIcons(def) 683 | 684 | let s:SignDef = ReturnSignDef() 685 | endfu 686 | fu! ReturnDiffSigns() "{{{1 687 | let fname = expand('%') 688 | if !executable("diff") || 689 | \ empty(fname) || 690 | \ !has("diff") || 691 | \ !filereadable(fname) 692 | " nothing to do 693 | if &verbose > 0 694 | call add(s:msg, 'Diff not possible:' . 695 | \ (!executable("diff") ? ' No diff executable found!' : 696 | \ empty(fname) ? ' Current file has never been written!' : 697 | \ !filereadable(fname) ? ' '. fname. ' not readable!' : 698 | \ ' Vim was compiled without diff feature!')) 699 | endif 700 | throw "DiffError" 701 | endif 702 | let new_file = tempname() 703 | let cmd = "diff " 704 | if &dip =~ 'icase' 705 | let cmd .= "-i " 706 | endif 707 | if &dip =~ 'iwhite' 708 | let cmd .= "-b " 709 | endif 710 | let cmd .= shellescape(expand("%")) . " " . 711 | \ shellescape(new_file, 1) 712 | let contents = getline(1,'$') 713 | if &ff == 'dos' 714 | " write dos-files 715 | call map(contents, 'v:val . nr2char(13)') 716 | endif 717 | " Need to convert the data, so that diff won't complain 718 | if &fenc != &enc && has("iconv") 719 | call map(contents, 'iconv(v:val, &enc, &fenc)') 720 | endif 721 | call writefile(contents, new_file) 722 | let result = systemlist(cmd) 723 | 724 | if v:shell_error == -1 || (v:shell_error && v:shell_error != 1) 725 | call add(s:msg, "There was an error executing the diff command!") 726 | call add(s:msg, result[0]) 727 | throw "DiffError" 728 | endif 729 | call filter(result, 'v:val =~ ''^\d\+\(,\d\+\)\?[acd]\d\+\(,\d\+\)\?''') 730 | " Init result set 731 | let diffsigns = {} 732 | let diffsigns['a'] = [] 733 | let diffsigns['c'] = [] 734 | let diffsigns['d'] = [] 735 | " parse diff output 736 | for item in result 737 | let m = matchlist(item, '^\v%(\d+)%(,%(\d+))?([acd])(\d+)%(,?(\d+)?)') 738 | if empty(m) 739 | continue 740 | endif 741 | if m[2] == 0 742 | let m[2] = 1 743 | endif 744 | 745 | "call add(diffsigns[m[3]], range(m[1], empty(m[2]) ? m[1] : m[2])) 746 | let diffsigns[m[1]] = diffsigns[m[1]] + range(m[2], empty(m[3]) ? m[2] : m[3]) 747 | endfor 748 | return diffsigns 749 | endfu 750 | fu! UpdateView(force) "{{{1 751 | if !exists("b:dynamicsigns_tick") 752 | let b:dynamicsigns_tick = 0 753 | endif 754 | " Only update, if there have been changes to the buffer 755 | if b:dynamicsigns_tick != b:changedtick || a:force 756 | call DynamicSigns#Run() 757 | let b:dynamicsigns_tick = b:changedtick 758 | endif 759 | endfu 760 | fu! SignNameMatchesAny(pat) "{{{1 761 | " just check there exists any sign with 762 | " the given name, regardless of the line 763 | return SignNameMatches(a:pat, 0) 764 | endfu 765 | fu! SignNameMatches(pat, line) "{{{1 766 | " Return signs whose name matches pattern 767 | let line = a:line == 0 ? -1 : a:line 768 | if s:sign_api 769 | let id=0 770 | for sign in s:Signs 771 | if sign.name =~ a:pat && (line == -1 || sign.lnum == a:line) 772 | return id 773 | endif 774 | let id+=1 775 | endfor 776 | return -1 777 | " foobar 778 | else 779 | let idx1 = match(s:Signs, a:pat) 780 | if idx1 > -1 781 | if (line == -1) 782 | return idx1 783 | else 784 | return match(s:Signs, 'line='.a:line.'\D.*'. a:pat) 785 | endif 786 | endif 787 | endif 788 | return -1 789 | endfu 790 | fu! SignPattern(name) "{{{1 791 | " Generate a pattern that can be used for SignNameMatches 792 | if s:sign_api 793 | return a:name 794 | else 795 | return 'id='.s:sign_prefix.'\d\+.*='.a:name 796 | endif 797 | endfu 798 | fu! DoSigns() "{{{1 799 | " Returns true, if signs need to be processed by this plugin 800 | if !s:MixedIndentation && 801 | \ get(s:CacheOpts, 'MixedIndentation', 0) > 0 802 | if exists("s:MixedIndentationHL") 803 | call matchdelete(s:MixedIndentationHL) 804 | endif 805 | let pat = SignPattern('DSignWSError') 806 | let index = SignNameMatchesAny(pat) 807 | while index > -1 808 | call UnplaceSignSingle(s:Signs[index]) 809 | call remove(s:Signs, index) 810 | let index = SignNameMatchesAny(pat) 811 | endw 812 | 813 | elseif !s:IndentationLevel && 814 | \ get(s:CacheOpts, 'IndentationLevel', 0) > 0 815 | let pat = SignPattern('DSign\d\+') 816 | let index = SignNameMatchesAny(pat) 817 | while index > -1 818 | call UnplaceSignSingle(s:Signs[index]) 819 | call remove(s:Signs, index) 820 | let index = SignNameMatchesAny(pat) 821 | endw 822 | 823 | elseif !s:SignHook && 824 | \ get(s:CacheOpts, 'SignHook', 0) > 0 825 | let pat = SignPattern('DSignCustom') 826 | let index = SignNameMatchesAny(pat) 827 | while index > -1 828 | call UnplaceSignSingle(s:Signs[index]) 829 | call remove(s:Signs, index) 830 | let index = SignNameMatchesAny(pat) 831 | endw 832 | 833 | elseif !s:SignScrollbar && 834 | \ get(s:CacheOpts, 'SignScrollbar', 0) > 0 835 | let pat = SignPattern('DSignScrollbar') 836 | let index = SignNameMatchesAny(pat) 837 | while index > -1 838 | call UnplaceSignSingle(s:Signs[index]) 839 | call remove(s:Signs, index) 840 | let index = SignNameMatchesAny(pat) 841 | endw 842 | " remove autocommand 843 | call DoSignScrollbarAucmd(0) 844 | 845 | elseif !s:SignDiff && 846 | \ get(s:CacheOpts, 'SignDiff', 0) > 0 847 | let pat = SignPattern('DSign\(Add\|Change\|Delete\)') 848 | let index = SignNameMatchesAny(pat) 849 | while index > -1 850 | call UnplaceSignSingle(s:Signs[index]) 851 | call remove(s:Signs, index) 852 | let index = SignNameMatchesAny(pat) 853 | endw 854 | endif 855 | call DoSignBookmarks() 856 | 857 | if ( !s:MixedIndentation && 858 | \ !s:IndentationLevel && 859 | \ !s:BookmarkSigns && 860 | \ !s:SignHook && 861 | \ !s:SignDiff && 862 | \ !s:AlternatingSigns && 863 | \ !s:SignScrollbar) "return false, when s:SignScrollbar is set 864 | " update cache 865 | call BufferConfigCache() 866 | return 0 867 | else 868 | return 1 869 | endif 870 | endfu 871 | fu! DoSignBookmarks() "{{{1 872 | if s:BookmarkSigns != get(s:CacheOpts, 'BookmarkSigns', 0) 873 | let pat = SignPattern('DSignBookmark') 874 | let index = SignNameMatchesAny(pat) 875 | while index > -1 876 | call UnplaceSignSingle(s:Signs[index]) 877 | call remove(s:Signs, index) 878 | let index = SignNameMatchesAny(pat) 879 | endw 880 | if exists("s:BookmarkSignsHL") 881 | for value in values(s:BookmarkSignsHL) 882 | call matchdelete(value) 883 | call remove(s:BookmarkSignsHL, value) 884 | endfor 885 | endif 886 | endif 887 | return s:BookmarkSigns 888 | endfu 889 | fu! BufferConfigCache() "{{{1 890 | if !exists("s:CacheOpts") 891 | let s:CacheOpts = {} 892 | endif 893 | let s:CacheOpts.MixedIndentation = s:MixedIndentation 894 | let s:CacheOpts.IndentationLevel = s:IndentationLevel 895 | let s:CacheOpts.BookmarkSigns = s:BookmarkSigns 896 | let s:CacheOpts.SignScrollbar = s:SignScrollbar 897 | let s:CacheOpts.SignHook = s:SignHook 898 | let s:CacheOpts.SignDiff = s:SignDiff 899 | let s:CacheOpts.AlternatingSigns = s:AlternatingSigns 900 | let s:CacheOpts.NoUtf8Signs = get(g:, "NoUtf8Signs", 0) 901 | endfu 902 | fu! PlaceIndentationSign(line) "{{{1 903 | if get(s:, "IndentationLevel", 0) 904 | let indent = indent(a:line) 905 | let div = shiftwidth() 906 | 907 | let pat = SignPattern('DSign\d\+') 908 | let index = SignNameMatches(pat, a:line) 909 | if div > 0 && indent > 0 910 | if index < 0 911 | try 912 | let name = 'DSign'. (indent/div < 10 ? indent/div : '10') 913 | call PlaceSignSingle(a:line, name) 914 | catch 915 | call add(s:msg, "Error placing Indtation sign at line: " . a:line) 916 | if s:debug 917 | call add(s:msg, v:exception) 918 | endif 919 | endtry 920 | endif 921 | return 1 922 | elseif index >= 0 923 | "no more indentation Signs needed, remove 924 | call UnplaceSignSingle(s:Signs[index]) 925 | endif 926 | endif 927 | return 0 928 | endfu 929 | fu! PlaceScrollbarSigns() "{{{1 930 | " doesn't work well with folded lines, unfortunately 931 | " Disabled in the gui, only works with +float and when s:SignScrollbar 932 | " has been configured. 933 | if get(s:, "SignScrollbar", 0) && has('float') 934 | if !&lz 935 | let do_unset_lz = 1 936 | setl lz 937 | endif 938 | let curline = line('.') + 0.0 939 | let lastline = line('$') + 0.0 940 | let wheight = winheight(0) + 0.0 941 | let curperc = curline/lastline 942 | let tline = float2nr(round(wheight * curperc) + line('w0') -1) 943 | 944 | " safety check 945 | if line('$') < tline 946 | let tline = line('$') 947 | elseif line('w0') > tline 948 | let tline = line('w0') 949 | endif 950 | 951 | if (line('.') > line('$')/2 && tline > 1) 952 | let nline = tline - 1 953 | else 954 | let nline = tline + 1 955 | endif 956 | 957 | let wrap = search('\%>'. &tw. 'c', 'nW') 958 | if &wrap && index([nline, tline], wrap) > -1 959 | " Wrapping occurs, don't display 2 signs 960 | let wrap = 1 961 | else 962 | let wrap = 0 963 | endif 964 | 965 | " Place 2 Signs if no wrapping occurs, 966 | " so the scrollbar looks better 967 | for line in [tline, nline] 968 | call PlaceSignSingle(line, 'DSignScrollbar') 969 | if wrap 970 | break 971 | endif 972 | endfor 973 | let pat = SignPattern('DSignScrollbar') 974 | let index = SignNameMatchesAny(pat) 975 | while index > -1 976 | " unplace old signs 977 | call UnplaceSignSingle(s:Signs[index]) 978 | " update s:Signs 979 | call remove(s:Signs, index) 980 | let index = SignNameMatchesAny(pat) 981 | endw 982 | if exists("do_unset_lz") && do_unset_lz 983 | setl nolz 984 | unlet! do_unset_lz 985 | endif 986 | call BufferConfigCache() 987 | return 1 988 | endif 989 | return 0 990 | endfu 991 | fu! PlaceMixedWhitespaceSign(line) "{{{1 992 | if get(s:, "MixedIndentation", 0) 993 | let line = getline(a:line) 994 | if !exists("s:MixedWhitespacePattern") 995 | let pat1 = '\%(^\s\+\%(\t \)\|\%( \t\)\)' 996 | let pat2 = '\%(\S\zs\s\+$\)' 997 | "highlight non-breaking space, etc... 998 | let pat3 = '\%([\x0b\x0c\u00a0\u1680\u180e\u2000-\u200a\u2028\u202f\u205f\u3000\ufeff]\)' 999 | 1000 | let s:MixedWhitespacePattern = pat1. '\|'. pat2. '\|'. pat3 1001 | endif 1002 | if !exists("s:MixedIndentationHL") 1003 | let s:MixedIndentationHL = matchadd('Error', s:MixedWhitespacePattern) 1004 | endif 1005 | let pat = SignPattern('DSignWSError') 1006 | let index = SignNameMatches(pat, a:line) 1007 | if match(line, s:MixedWhitespacePattern) > -1 1008 | if index < 0 1009 | call PlaceSignSingle(a:line, 'DSignWSError') 1010 | endif 1011 | return 1 1012 | elseif index >= 0 1013 | " No more wrong indentation, remove sign 1014 | call UnplaceSignSingle(s:Signs[index]) 1015 | endif 1016 | endif 1017 | if !s:MixedIndentation 1018 | unlet! s:MixedIndentationHL 1019 | endif 1020 | return 0 1021 | endfu 1022 | fu! PlaceSignHook(line) "{{{1 1023 | if exists("s:SignHook") && !empty(s:SignHook) 1024 | try 1025 | let expr = substitute(s:SignHook, 'v:lnum', a:line, 'g') 1026 | let a = eval(expr) 1027 | let result = matchstr(a, 1028 | \'Warning\|OK\|Error\|Info\|Add\|Arrow\|Flag\|'. 1029 | \ 'Delete\|Stop\|Line\d\|Gutter\d\|\d\+') 1030 | if empty(result) 1031 | let result = 'Info' 1032 | endif 1033 | let pat = SignPattern('DSignCustom') 1034 | let index = SignNameMatches(pat, a:line) 1035 | if !empty(a) 1036 | if index > -1 1037 | let oldSignname = matchstr(SignName(s:Signs[index]), 'DSignCustom\zs\S\+\ze') 1038 | " need to unplace old signs 1039 | if oldSignname !=# result 1040 | call UnplaceSignSingle(s:Signs[index]) 1041 | else 1042 | return 1 1043 | endif 1044 | endif 1045 | call PlaceSignSingle(a:line, 'DSignCustom'.result) 1046 | elseif index >= 0 1047 | " Custom Sign no longer needed, remove it 1048 | call UnplaceSignSingle(s:Signs[index]) 1049 | return 0 1050 | endif 1051 | return 1 1052 | catch 1053 | let s:SignHook = '' 1054 | call add(s:msg, 'Error evaluating SignExpression at '. a:line) 1055 | call add(s:msg, v:exception) 1056 | call WarningMsg() 1057 | return -1 1058 | endtry 1059 | endif 1060 | endfu 1061 | fu! PlaceDiffSigns(line, DiffSigns) "{{{1 1062 | " Diff Signs 1063 | let did_place_sign = 0 1064 | if !empty(a:DiffSigns) && !empty(a:DiffSigns['a'] + a:DiffSigns['c'] + a:DiffSigns['d']) 1065 | let pat = SignPattern('DSignAdded') 1066 | let index = SignNameMatches(pat, a:line) 1067 | " Added Lines 1068 | let target=index(a:DiffSigns['a'], a:line) 1069 | if target > -1 1070 | if index < 0 1071 | call PlaceSignSingle(a:line, 'DSignAdded') 1072 | endif 1073 | let did_place_sign = 1 1074 | endif 1075 | if did_place_sign 1076 | return 1 1077 | endif 1078 | " Changed Lines 1079 | let pat = SignPattern('DSignChanged') 1080 | let index = SignNameMatches(pat, a:line) 1081 | let target=index(a:DiffSigns['c'], a:line) 1082 | if target > -1 1083 | if index < 0 1084 | call PlaceSignSingle(a:line, 'DSignChanged') 1085 | endif 1086 | let did_place_sign = 1 1087 | endif 1088 | if did_place_sign 1089 | return 1 1090 | endif 1091 | " Deleted Lines 1092 | let pat = SignPattern('DSignDeleted') 1093 | let index = SignNameMatches(pat, a:line) 1094 | let target=index(a:DiffSigns['d'], a:line) 1095 | if target > -1 1096 | if index < 0 1097 | call PlaceSignSingle(a:line, 'DSignDeleted') 1098 | endif 1099 | let did_place_sign = 1 1100 | endif 1101 | if did_place_sign 1102 | return 1 1103 | endif 1104 | 1105 | let index = SignNameMatches(SignPattern('DSign\([ACD]\)'), a:line) 1106 | if index > -1 1107 | " Diff Sign no longer needed, remove it 1108 | call UnplaceSignSingle(s:Signs[index]) 1109 | endif 1110 | endif 1111 | return 0 1112 | endfu 1113 | fu! PlaceAlternatingSigns(line) "{{{1 1114 | if !s:AlternatingSigns 1115 | return 0 1116 | endif 1117 | let pat = SignPattern('DSignScrollbar') 1118 | let suffix = (a:line %2 ? 'Odd' : 'Even') 1119 | let index1 = SignNameMatches(SignPattern('DSign'. suffix), a:line) 1120 | let index2 = SignNameMatches(SignPattern('DSign'), a:line) 1121 | if index1 == -1 1122 | if index2 > -1 1123 | " unplace previously place sign first 1124 | call UnplaceSignSingle(s:Signs[index2]) 1125 | endif 1126 | call PlaceSignSingle(a:line, 'DSign'.suffix) 1127 | return 1 1128 | endif 1129 | return 0 1130 | endfu 1131 | fu! PlaceBookmarks(line) "{{{1 1132 | " Place signs for bookmarks 1133 | if get(s:, "BookmarkSigns", 0) 1134 | let MarksOnLine = GetMarksOnLine(a:line) 1135 | if !empty(MarksOnLine) 1136 | let mark = MarksOnLine[0] 1137 | let name = 'DSignBookmark'.mark 1138 | let pat = SignPattern(name) 1139 | let index = SignNameMatches(pat, a:line) 1140 | if index > -1 1141 | " Mark Sign no longer needed, remove it 1142 | call UnplaceSignSingle(s:Signs[index]) 1143 | endif 1144 | call PlaceSignSingle(a:line, name) 1145 | let s:BookmarkSignsHL[mark] = matchadd(s:id_hl.Mark, GetPattern(mark)) 1146 | return 1 1147 | endif 1148 | endif 1149 | return 0 1150 | endfu 1151 | fu! GetMarksOnLine(line) "{{{1 1152 | return sort(keys(filter(copy(s:bookmarks), 'v:val==a:line'))) 1153 | endfu 1154 | fu! GetPattern(mark) "{{{1 1155 | let mark = a:mark 1156 | if mark != '.' 1157 | let mark = "'". a:mark 1158 | endif 1159 | let pos = getpos(mark) 1160 | if pos[0] == 0 || pos[0] == bufnr('%') 1161 | return '\%'.pos[1]. 'l\%'.pos[2].'c' 1162 | endif 1163 | return '' 1164 | endfu 1165 | fu! UpdateDiffSigns(DiffSigns) "{{{1 1166 | if empty(a:DiffSigns) 1167 | " nothing to do 1168 | return 1169 | endif 1170 | " TODO: - instead of unplacing all signs first and 1171 | " then placing the new signs, move existing 1172 | " signs around 1173 | let pat = SignPattern('DSign\(Added\|Changed\|Deleted\)') 1174 | let index = SignNameMatchesAny(pat) 1175 | while index > -1 1176 | call UnplaceSignSingle(s:Signs[index]) 1177 | call remove(s:Signs, index) 1178 | let index = SignNameMatchesAny(pat) 1179 | endw 1180 | for line in a:DiffSigns['a'] + a:DiffSigns['c'] + a:DiffSigns['d'] 1181 | call PlaceDiffSigns(line, a:DiffSigns) 1182 | endfor 1183 | endfu 1184 | fu! DynamicSigns#UpdateWindowSigns(ignorepat) "{{{1 1185 | " Only update all signs in the current window viewport 1186 | " if no signs have been placed, return early 1187 | if !exists("s:Signs") 1188 | let s:Signs=ReturnSigns(bufnr('')) 1189 | endif 1190 | if empty(s:Signs) 1191 | return 1192 | endif 1193 | let _a = winsaveview() 1194 | " remove old matches first... 1195 | call UnMatchHL() 1196 | if !exists("b:dynamicsigns_tick") 1197 | let b:dynamicsigns_tick = 0 1198 | endif 1199 | try 1200 | call Init() 1201 | let s:old_ignore = s:ignore 1202 | let s:ignore += split(a:ignorepat, ',') 1203 | catch 1204 | call WarningMsg() 1205 | call winrestview(_a) 1206 | return 1207 | endtry 1208 | " Only update, if there have been changes to the buffer 1209 | " or force parameter is set 1210 | if b:dynamicsigns_tick != b:changedtick 1211 | let b:dynamicsigns_tick = b:changedtick 1212 | " only run for at max 200 lines 1213 | if !s:SignScrollbar && line('w$') - line('w0') <= 200 1214 | call PlaceSigns(line('w0'), line('w$')) 1215 | endif 1216 | endif 1217 | if s:SignScrollbar 1218 | call DynamicSigns#UpdateScrollbarSigns() 1219 | endif 1220 | if s:SignHook && !empty(get(w:, 'Signs_Hook', '')) 1221 | let s:ignore = ['alternate', 'diff', 'marks', 'whitespace', 'indentation'] 1222 | exe printf(":%d,%dfolddoopen :call %d_PlaceSignHook(line('.'))", 1223 | \ line('w0'), line('w$'), s:sid) 1224 | "call DynamicSigns#Run() 1225 | endif 1226 | if s:BookmarkSigns 1227 | call DoBookmarkHL() 1228 | endif 1229 | if s:SignDiff 1230 | try 1231 | let DiffSigns = (s:SignDiff ? ReturnDiffSigns() : {}) 1232 | call UpdateDiffSigns(DiffSigns) 1233 | catch /DiffError/ 1234 | call WarningMsg() 1235 | endtry 1236 | endif 1237 | if s:AlternatingSigns 1238 | call PlaceSigns(line('w0'), line('w$')) 1239 | endif 1240 | let s:ignore = s:old_ignore 1241 | call winrestview(_a) 1242 | endfu 1243 | fu! DynamicSigns#UpdateScrollbarSigns() "{{{1 1244 | " When GuiEnter fires, we need to disable the scrollbar signs 1245 | call Init() 1246 | call DoSigns() 1247 | call PlaceScrollbarSigns() 1248 | endfu 1249 | fu! DynamicSigns#MapBookmark() "{{{1 1250 | let a = getchar() 1251 | if type(a) == type(0) 1252 | let char = nr2char(a) 1253 | else 1254 | let char = a 1255 | endif 1256 | " make sure, this is only called, when Bookmark Signs are enabled 1257 | " Since plugin is possibly not init yet, need to check both variables 1258 | if get(s:, "BookmarkSigns", 0) || get(g:, "Signs_Bookmarks", 0) 1259 | " Initilize variables 1260 | call Init() 1261 | if DoSignBookmarks() && index(s:Bookmarks, char) > -1 1262 | let name = 'DSignBookmark'.char 1263 | let cline = line('.') 1264 | let index = SignNameMatchesAny(SignPattern(name)) 1265 | " there was a sign defined for the mark 1266 | " First place the new sign 1267 | " don't unplace old signs first, that prevents flicker (e.g. first 1268 | " removing all signs, removes the sign column, than placing a sign adds 1269 | " the sign column again. 1270 | call PlaceSignSingle(cline, name) 1271 | let indx = [] 1272 | " unplace previous mark for this sign 1273 | let index = SignNameMatchesAny(SignPattern(name)) 1274 | while index > -1 1275 | call UnplaceSignSingle(s:Signs[index]) 1276 | call remove(s:Signs, index) 1277 | let index = SignNameMatchesAny(SignPattern(name)) 1278 | endw 1279 | " Refresh highlighting 1280 | sil! call matchdelete(s:BookmarkSignsHL[char]) 1281 | " Mark hasn't been plRefresh highlighting 1282 | let s:BookmarkSignsHL[char] = matchadd(s:id_hl.Mark, GetPattern('.')) 1283 | " Refresh highlighting 1284 | call BufferConfigCache() 1285 | endif 1286 | endif 1287 | return 'm'.char 1288 | endfu 1289 | fu! DynamicSigns#Update(...) "{{{1 1290 | if exists("s:SignScrollbar") && s:SignScrollbar 1291 | call DynamicSigns#UpdateScrollbarSigns() 1292 | else 1293 | call DynamicSigns#Run(0, line('w0'), line('w$')) 1294 | endif 1295 | endfu 1296 | fu! DynamicSigns#Run(...) "{{{1 1297 | set lz 1298 | let _a = winsaveview() 1299 | try 1300 | if exists("a:1") && a:1 == 1 1301 | unlet! s:precheck 1302 | endif 1303 | call Init() 1304 | catch /^Signs:/ 1305 | call WarningMsg() 1306 | return 1307 | endtry 1308 | if exists("a:2") && exists("a:3") 1309 | " only update signs in current window 1310 | " e.g. :UpdateSigns has been called 1311 | call PlaceSigns(a:2, a:3) 1312 | else 1313 | call PlaceSigns() 1314 | endif 1315 | set nolz 1316 | call winrestview(_a) 1317 | endfu 1318 | fu! DynamicSigns#CleanUp() "{{{1 1319 | " only delete signs, that have been set by this plugin 1320 | call UnPlaceSigns() 1321 | " remove placed highlighting 1322 | call UnMatchHL() 1323 | " undefine all signs 1324 | if exists("s:SignDef") 1325 | for sign in s:SignDef 1326 | if s:sign_api 1327 | call sign_undefine(sign.name) 1328 | else 1329 | exe "sil! sign undefine" sign 1330 | endif 1331 | endfor 1332 | endif 1333 | call AuCmd(0) 1334 | if exists("s:unset_signcolumn") 1335 | set signcolumn=auto 1336 | endif 1337 | unlet! s:precheck s:SignDef s:unset_signcolumn 1338 | redraw! 1339 | endfu 1340 | fu! DynamicSigns#PrepareSignExpression(arg) "{{{1 1341 | let w:Signs_Hook = a:arg 1342 | call Init() 1343 | let old_ignore = s:ignore 1344 | " only update the sign expression 1345 | let s:ignore = ['alternate', 'diff', 'marks', 'whitespace', 'indentation'] 1346 | call DynamicSigns#Run() 1347 | let s:ignore = old_ignore 1348 | endfu 1349 | fu! DynamicSigns#SignsQFList(local) "{{{1 1350 | if !has("quickfix") 1351 | return 1352 | endif 1353 | call Init() 1354 | let qflist = [] 1355 | if s:sign_api 1356 | for sign in sign_getplaced() 1357 | if empty(sign.signs) 1358 | continue 1359 | endif 1360 | for item in sign.signs 1361 | call add(qflist, {'bufnr': sign.bufnr, 'lnum':item.lnum, 1362 | \ 'text': getbufline(sign.bufnr, item.lnum)}) 1363 | endfor 1364 | endfor 1365 | else 1366 | let a = Redir(':sil sign place') 1367 | for sign in split(a, "\n") 1368 | if match(sign, '^Signs for \(.*\):$') >= 0 1369 | let fname = matchstr(sign, '^Signs for \zs.*\ze:$') 1370 | let file = readfile(fname) 1371 | elseif match(sign, '^\s\+\w\+=\d\+\s') >= 0 1372 | let line = matchstr(sign, '^\s*\w\+=\zs\d\+\ze\s') 1373 | call add(qflist, {'filename': fname, 'lnum': line, 1374 | \ 'text': file[line-1]}) 1375 | else 1376 | continue 1377 | endif 1378 | endfor 1379 | endif 1380 | if a:local 1381 | let func = 'setloclist' 1382 | let args = [0, qflist] 1383 | let open = 'lopen' 1384 | else 1385 | let func = 'setqflist' 1386 | let args = [qflist] 1387 | let open = 'copen' 1388 | endif 1389 | let s:no_qf_autocmd = 1 1390 | call call(func, args) 1391 | unlet s:no_qf_autocmd 1392 | exe open 1393 | endfu 1394 | fu! DynamicSigns#ForceUpdate() "{{{1 1395 | call UpdateView(1) 1396 | endfu 1397 | fu! DynamicSigns#QFSigns() "{{{1 1398 | if has("quickfix") 1399 | if exists("s:no_qf_autocmd") && s:no_qf_autocmd 1400 | " Don't run the autocommand 1401 | return 1402 | endif 1403 | call Init() 1404 | " Remove all previously placed QF Signs 1405 | exe "sign unplace " s:sign_prefix . '0' 1406 | for item in getqflist() 1407 | if item.bufnr == 0 1408 | continue 1409 | endif 1410 | call PlaceSignSingle(item.lnum, 'DSignQF', item.bufnr) 1411 | endfor 1412 | endif 1413 | endfu 1414 | " Modeline "{{{1 1415 | " vim: fdm=marker fdl=0 ts=4 sts=4 com+=l\:\" fdl=0 sw=4 noet 1416 | -------------------------------------------------------------------------------- /autoload/DynamicSigns/0.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/0.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/1.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/2.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/2.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/3.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/3.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/4.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/4.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/5.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/5.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/6.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/6.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/7.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/7.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/8.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/8.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/9.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/9.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/A.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/A.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/B.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/B.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/C.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/C.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/D.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/D.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/E.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/E.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/F.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/F.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/G.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/G.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/H.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/H.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/I.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/I.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/J.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/J.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/K.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/K.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/L.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/L.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/M.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/M.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/N.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/N.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/O.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/O.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/P.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/P.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/Q.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/Q.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/R.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/R.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/S.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/S.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/T.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/T.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/U.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/U.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/V.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/V.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/W.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/W.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/X.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/X.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/Y.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/Y.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/Z.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/Z.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/add.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/add.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/arrow-right.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/arrow-right.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/checkmark.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/checkmark.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/delete.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/delete.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/designkode_free_icon_set.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/designkode_free_icon_set.zip -------------------------------------------------------------------------------- /autoload/DynamicSigns/error.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/error.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/flag-yellow.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/flag-yellow.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/license_designkode.txt: -------------------------------------------------------------------------------- 1 | URL: http://www.designkode.com/blog/free-developer-icons 2 | License: Creative Commons (Attribution 3.0 Unported) 3 | "DesignKode is releasing this set of 40 free high quality icons for your web site and application GUI designs. All icons in this set are 32 x 32 pixel PNG image files. You may freely use these icons in your commercial or personal projects without attribution." 4 | -------------------------------------------------------------------------------- /autoload/DynamicSigns/license_red-orb.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/license_red-orb.txt -------------------------------------------------------------------------------- /autoload/DynamicSigns/red-orb-alphabet-by-iconarchive.zip: -------------------------------------------------------------------------------- 1 | No Cookies activated. -------------------------------------------------------------------------------- /autoload/DynamicSigns/stop.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/stop.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/thumbtack-yellow.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/thumbtack-yellow.bmp -------------------------------------------------------------------------------- /autoload/DynamicSigns/warning.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/DynamicSigns/2f040726484e0695c488d2f1a3c174b65384f326/autoload/DynamicSigns/warning.bmp -------------------------------------------------------------------------------- /doc/DynamicSigns.txt: -------------------------------------------------------------------------------- 1 | *DynamicSigns.txt* - Using Signs for different things 2 | 3 | Author: Christian Brabandt 4 | Version: 0.2 Mon, 07 Jan 2019 5 | *SignsCopyright* 6 | Copyright: (c) 2009-2019 by Christian Brabandt 7 | The VIM LICENSE applies to DynamicSigns (see |copyright|) 8 | except use DynamicSigns instead of "Vim". 9 | NO WARRANTY, EXPRESS OR IMPLIED. USE AT-YOUR-OWN-RISK. 10 | 11 | =========================================================================== 12 | 1. Contents *Signs-content* 13 | 14 | 1. Contents...................................: |Signs-content| 15 | 2. Manual.....................................: |Signs-manual| 16 | 2.1 Display Indent Level.....................: |Signs-Indentation| 17 | 2.2 Display Whitespace Warnings..............: |Signs-Whitespace| 18 | 2.3 Display Marks............................: |Signs-Marks| 19 | 2.4 SignExpressions..........................: |Signs-Hook| 20 | 2.5 Display Signs for Quickfix items.........: |Signs-QF| 21 | 2.6 Display Signs to display changes.........: |Signs-Diff| 22 | 2.7 Alternating colors.......................: |Signs-Alternate| 23 | 2.8 ASCII Scrollbar..........................: |Signs-Scrollbar| 24 | 2.9 SignHighlighting.........................: |Signs-Highlight| 25 | 3. Autocommands...............................: |Signs-Autocommands| 26 | 4. Commands...................................: |Signs-Commands| 27 | 5. Icons......................................: |Signs-Icons| 28 | 6. Feedback...................................: |Signs-feedback| 29 | 7. History....................................: |Signs-history| 30 | 31 | ========================================================================== 32 | 2. Using the Signs Plugin *Signs-manual* 33 | 34 | Functionality 35 | 36 | This plugin enables you to use signs |sign-support| for different things. 37 | For example you can use signs to display Indentation-Levels, display line 38 | whitespace errors, display marks |mark-motion|, display the differences 39 | between the current editing file and the file on disk or whenever an 40 | expression evalutates true (similar to how fold-expressions work 41 | |fold-expr|) 42 | 43 | All you need to do, is configure the plugin by setting some configuration 44 | variables and run |:Signs| 45 | 46 | 47 | 2.1 Display Indentation Level *Signs-Indentation* 48 | ----------------------------- 49 | 50 | If you want the plugin to display the numeric indentation level, simply set 51 | the g:Signs_IndentationLevel variable like this in your |.vimrc|, e.g. like 52 | this: > 53 | 54 | let g:Signs_IndentationLevel = 1 55 | < 56 | 57 | By default, this displays the indentation level (e.g. the indentation 58 | divided by the 'tabstop' setting) as numeric values (actually it only 59 | displays levels 1-9 or '>9' for a larger indent. 60 | 61 | Run |:Signs| to display the signs for those lines. 62 | 63 | 2.2 Display Whitespace Warnings *Signs-Whitespace* 64 | ------------------------------- 65 | 66 | If you want the plugin to display the warnings for lines with whitespace 67 | errors, simply set the variable g:Signs_MixedIndentation like this in your 68 | |.vimrc|, e.g. > 69 | 70 | :let g:Signs_MixedIndentation = 1 71 | < 72 | 73 | By default, this display warning signs for each line where either the 74 | indentation consists of mixed whitespace (e.g. tabspace and blanks) or the 75 | line ends with trailing whitespace. 76 | 77 | Run |:Signs| to display the signs for those lines. 78 | 79 | 2.3 Display Marks *Signs-Marks* 80 | ----------------- 81 | If you want the plugin to display your marks, set the variable 82 | g:Signs_Bookmarks to 1 in your |.vimrc|, e.g. > 83 | 84 | :let g:Signs_Bookmarks = 1 85 | < 86 | This will display the marks a-z and A-Z, if they are in your current buffer. 87 | 88 | If this is enabled, |m| will be mapped to a function, that places the 89 | bookmarks in your buffer and sets the mark. (|:k| does not update the signs, 90 | Use |:Signs| or |:UpdateSigns| to manually update the view in case this is 91 | needed). 92 | 93 | The position of the marks will be highlighted by using the 94 | `DynamicSignsHighlightMarks` highlighting group (by default, linked to 95 | |hl-Visual|. 96 | 97 | *:SignExpression* 98 | 2.4 SignExpressions *Signs-Hook* 99 | ------------------- 100 | 101 | You can let Vim have an expression evaluated for each line in your current 102 | buffer. On each line, where this expression is true, Vim will place a sign 103 | for your. This enables you, to put e.g. a Sign on each line, that contains 104 | 'TODO'. 105 | 106 | To do this, run the command |:SignExpression| and give an expression as 107 | its argument, which will be evaluated for each line. Use the variable 108 | |v:lnum| in your expression for the current line. 109 | 110 | Say, you want to place a sign on each line, that contains 'TODO'. You simply 111 | enter > 112 | 113 | :SignExpression getline(v:lnum)=~'TODO'?'Warning':0 114 | 115 | This will place a sign on each line, that contains the word TODO 116 | This expression is window-local. 117 | 118 | As a special return value for the expression, you can return the type of sign 119 | that should be placed. Currently the following sign types are understood: > 120 | 121 | Warning 122 | OK 123 | Error 124 | Info 125 | Add 126 | Arrow 127 | Flag 128 | Delete 129 | Stop 130 | Line1 131 | Line2 132 | Line3 133 | Line4 134 | Line5 135 | Gutter1 136 | Gutter2 137 | Gutter3 138 | Gutter4 139 | Gutter5 140 | 1-99 141 | 0 142 | < 143 | All except for "Line" only draw a flag in the sign column while the sign types 144 | "Line1"-"Line5" highlights the complete line without displaying anything in 145 | the Sign Column. "Gutter1"-"Gutter5" highlights only the gutter column, but 146 | does not draw anything inside it. It uses the SignLine1-SignLine5 highlighting 147 | groups for highlighting (|Signs-Highlight|) 148 | 149 | The special return value 0 is meant to not place a sign, all other numbers 150 | simply stand for themselves, e.g. will draw the corresponding number. 151 | 152 | For example you want to highlight all Lines that contain the word 'TODO' with 153 | the todo sign. Therefore you call the command: > 154 | 155 | :SignExpression getline(v:lnum)=~'TODO'?'Todo':0 156 | 157 | Note, the Expression will be re-evaluated for that buffer on Changes to the 158 | buffer. 159 | 160 | *relativenumber_signs* 161 | 162 | Here is an example, on how to draw relative numbers but only every fifth line. 163 | First define a custom function like the following. You can usually just do 164 | that in your |.vimrc| > 165 | 166 | fu! CustomSignExpression(lnum, div) 167 | if a:lnum < line('w0') || a:lnum > line ('w$') 168 | return 0 169 | endif 170 | if !exists("#CustomSignExpression#CursorMoved") 171 | augroup CustomSignExpression 172 | au! 173 | au CursorMoved * :Signs 174 | au VimResized * :UpdateSigns 175 | augroup end 176 | endif 177 | let part=abs(a:lnum - line('.')) 178 | if part % a:div == 0 179 | return part > 99 ? 99 : part 180 | else 181 | return 0 182 | endif 183 | endfu 184 | 185 | Then you simply call: > 186 | :SignExpression CustomSignExpression(v:lnum, 5) 187 | 188 | This makes sure, the relative numbers will only be drawn on every fifth line. 189 | Adjust the second number if you want it at other intervals. The autocommand 190 | is there to make sure, it will be re-evaluated on cursor changes. By default, 191 | custom sign expressions are only evaluated once the text changes, but this is 192 | needed here, or else the relative line numbering will get out of sync soon. 193 | Note it is recommended to use the CustomSignExpression |augroup|, as this will 194 | be automatically cleaned up on the |:DisableSigns| command, if one exists, 195 | otherwise the autocommand will still trigger although it probably should not. 196 | 197 | 2.5 Display signs for quickfix items *Signs-QF* 198 | ------------------------------------ 199 | If you want the plugin to display signs next to each match when using the 200 | |quickfix| feature of vim, set the variable g:Signs_QFList, e.g. > 201 | 202 | :let g:Signs_QFList = 1 203 | < 204 | This will hook up an autocommand, that fires whenever the quickfix command 205 | (|:helpgrep|, |:make|, |:vimgrep|, etc has been executed and places a small 206 | sign next to each match. 207 | 208 | 2.6 Display Signs for viewing changes to the buffer *Signs-Diff* 209 | --------------------------------------------------- 210 | You can also set up the plugin to display small signs, that indicate, 211 | whether the current line has been modified/deleted/added compared to the 212 | version stored on disk. To enable this feature, set the g:Signs_Diff 213 | variable in your |.vimrc| like this: > 214 | 215 | :let g:Signs_Diff = 1 216 | < 217 | This will run a diff of your buffer and the version stored on disk and place 218 | a sign on each line that was modified. 219 | 220 | Run |:UpdateSigns| or |:Signs| to update displaying the signs in your 221 | buffer. 222 | 223 | 2.7 Alternating colors *Signs-Alternate* 224 | ---------------------- 225 | 226 | You can also set up the plugin to color the lines in your buffer in 227 | alternating colors. To do so, set the g:Signs_Alternate variable in your 228 | |.vimrc| like this: > 229 | 230 | :let g:Signs_Alternate = 1 231 | < 232 | This will display each evenly numbered line in one color and each oddly 233 | numbered line in a different color. 234 | 235 | Run |:UpdateSigns| or |:Signs| to update displaying the signs in your 236 | buffer. 237 | 238 | The highlighting colors can be customized by defining the LineEven and LineOdd 239 | highlighting groups in your |.vimrc| > 240 | hi LineOdd ctermbg=52 guibg=#ff0000 241 | 242 | This will highlight odd lines in a red. 243 | 244 | 2.8 ASCII Scrollbar *Signs-Scrollbar* 245 | ------------------- 246 | The DynamicSigns plugin can also emulate an ascii scrollbar. This is useful 247 | in terminal Vim, to visually indicate, where in the buffer on is. 248 | 249 | If you want to enable this, simply set the g:Signs_Scrollbar variable in 250 | your |.vimrc| like this: > 251 | 252 | :let g:Signs_Scrollbar = 1 253 | 254 | This will enable the Scrollbar and disable all other Sign features. 255 | 256 | Unfortunately, this does not work well with |folds| and therefore the 257 | scrollbar can't be displayed on a folded line. Also Linewrapping 'wrap' can 258 | disturb the display of the scrollbar. 259 | 260 | 2.9 Sign Highlighting *Signs-Highlight* 261 | --------------------- 262 | 263 | By default the plugin defines the following highlighting groups: > 264 | 265 | SignLine1 - gray 266 | SignLine2 - orange 267 | SignLine3 - blue 268 | SignLine4 - red 269 | SignLine5 - yellow 270 | 271 | You can however override those highlighting groups, by predefining them in 272 | your |.vimrc| to whatever you want. 273 | 274 | 3.0 Autocommands *:Signs-Autocommands* 275 | ---------------- 276 | This plugin installs some autocommands to update the signs dynamically. 277 | Basically it uses |BufWritePost| and |InsertLeave| autocommands to update 278 | displaying the signs. 279 | 280 | Theoretically, it could also use |CursorHold| and |CursorHoldI| 281 | autocommands, but that seems to slow down Vim a lot, when working with long 282 | buffers and also seems to interrupt the workflow too much. You can however 283 | force Vim to update the signs on those autocommands, by setting the variable 284 | g:Signs_CursorHold to 1, e.g. put > 285 | let g:Signs_CursorHold = 1 286 | < 287 | in your .vimrc 288 | 289 | When switching to the |:gui|, Vim will also updates the signs, so the gui 290 | version can use some nice lookings |Signs-Icons|. 291 | 292 | Last, when the using the quickfix feature together with the Signs 293 | (|Signs-QF|), this plugin also installs an |QuickFixCmdPost| autocommand, to 294 | be able to put signs on each line, where a warning/error is. 295 | 296 | =========================================================================== 297 | 298 | 4.0 Commands *:Signs-Commands* 299 | ------------ 300 | 301 | The plugin introduces the following commands: 302 | 303 | > 304 | :Signs 305 | 306 | Update the signs in the current buffer. According to your configuration runs 307 | through every line in your buffer and checks, if a sign has to be displayed. 308 | For performance reasons, it caches the values. 309 | 310 | > 311 | :UpdateSigns 312 | 313 | Discard the cache and update the signs for each line. 314 | 315 | > 316 | :DisableSigns 317 | 318 | Disable the Sign plugin. 319 | 320 | > 321 | :SignQF 322 | 323 | Display a quickfix list that contains all your signs in the current buffer. 324 | |Sign-QF| (Use the `!` for using the location list, else it will use the 325 | global quickfix list). 326 | 327 | > 328 | :SignExpression expr 329 | 330 | Display a sign on each line, where expr evaluates to true |Signs-Hook| 331 | 332 | > 333 | :SignDiff 334 | 335 | Run a diff of the buffer and the file on disk and display signs for the 336 | changes |Signs-Diff| 337 | 338 | ============================================================================ 339 | 5. Icons *Signs-Icons* 340 | -------- 341 | 342 | The GTK version of Vim (and possibly also the Windows version) can also 343 | display graphical Signs. For this reason, this plugin includes some nice 344 | looking icons, that have been provided by 345 | http://www.designkode.com/blog/free-developer-icons 346 | 347 | "DesignKode is releasing this set of 40 free high quality icons for your web 348 | site and application GUI designs. All icons in this set are 32 x 32 pixel 349 | PNG image files. You may freely use these icons in your commercial or 350 | personal projects without attribution." 351 | 352 | (Source not available anymore, currently still available at the Internet 353 | Archive: 354 | https://web.archive.org/web/20111224161343/http://www.designkode.com/?download=Free%20Icons%20for%20Developers) 355 | 356 | The Bookmark icons are "Red Orb Alphabet Icons" and have been take from 357 | http://www.iconarchive.com/show/red-orb-alphabet-icons-by-iconarchive.html 358 | 359 | Those are licensed under a Creative Commons Attribution 3.0 License. 360 | 361 | The icons have been taken as is and only converted to a .bmp fileformat and a 362 | size of 16x16, so that the gtk and Windows built of gVim can display them. 363 | 364 | The autoload/DynamicSigns/ folder contains the original archive files with all 365 | icons. 366 | 367 | =========================================================================== 368 | 6. Feedback *Signs-Feedback* 369 | ----------- 370 | Feedback is always welcome. If you like the plugin, please rate it at the 371 | vim-page: 372 | http://www.vim.org/scripts/script.php?script_id=3965 373 | 374 | You can also follow the development of the plugin at github: 375 | http://github.com/chrisbra/DynamicSigns 376 | 377 | Please don't hesitate to report any bugs to the maintainer, mentioned in the 378 | third line of this document. 379 | 380 | ========================================================================== 381 | 4. History *Signs-history* 382 | 383 | 0.3: (unreleased) {{{1 384 | - Performance improvements to make updating the signs faster 385 | (could slow down saving considerably for large files) 386 | - Implement a Scrollbar |Signs-Scrollbar| 387 | - Function was called too early issue #2 388 | (https://github.com/chrisbra/DynamicSigns/issues/2, reported by 389 | Charles, thanks!) 390 | - Update SignExpressions on Changes to buffer or when switching to the gui 391 | - Do not clean the signs, when starting up 392 | - Make the |:SignExpression| command window-local 393 | 394 | 0.2: Mar 15, 2012 {{{1 395 | - Initial upload 396 | - development versions are available at the github repository 397 | - put plugin on a public repository (http://github.com/chrisbra/Signs) 398 | }}} 399 | =========================================================================== 400 | Modeline: 401 | vim:tw=78:ts=8:ft=help:et:fdm=marker:fdl=0:norl 402 | -------------------------------------------------------------------------------- /plugin/SignsPlugin.vim: -------------------------------------------------------------------------------- 1 | " DynamicSigns.vim - Using Signs 2 | " ----------------------------- 3 | " Version: 0.1 4 | " Maintainer: Christian Brabandt 5 | " Last Change: Thu, 15 Mar 2012 23:37:37 +0100 6 | " Script: https://www.vim.org/scripts/script.php?script_id=3965 7 | " Copyright: (c) 2009 - 2019 by Christian Brabandt 8 | " The VIM LICENSE applies to histwin.vim 9 | " (see |copyright|) except use "DynamicSigns" 10 | " instead of "Vim". 11 | " No warranty, express or implied. 12 | " *** *** Use At-Your-Own-Risk! *** *** 13 | " GetLatestVimScripts: 3965 1 :AutoInstall: DynamicSigns.vim 14 | " 15 | " Init: {{{1 16 | let s:cpo= &cpo 17 | if exists("g:loaded_Signs") || &cp 18 | finish 19 | endif 20 | set cpo&vim 21 | let g:loaded_Signs = 1 22 | 23 | fu! ActivateAuCmds() 24 | augroup Signs 25 | autocmd! 26 | au QuickFixCmdPost * :call DynamicSigns#QFSigns() 27 | augroup END 28 | endfu 29 | 30 | " ---------------------------------------------------------------------------- 31 | " Define the Mapping: "{{{2 32 | 33 | " marks: 34 | nnoremap DynamicSignsMapBookmark DynamicSigns#MapBookmark() 35 | if !hasmapto('DynamicSignsMapBookmark', 'n') && empty(maparg('m', 'n')) 36 | nmap m DynamicSignsMapBookmark 37 | endif 38 | 39 | " Define Commands "{{{1 40 | :com! Signs :call DynamicSigns#Run() 41 | :com! UpdateSigns :call DynamicSigns#Update() 42 | :com! DisableSigns :call DynamicSigns#CleanUp() 43 | :com! -bang SignQF :call DynamicSigns#SignsQFList(0) 44 | :com! -nargs=1 SignExpression 45 | \ :call DynamicSigns#PrepareSignExpression() 46 | :com! SignListExpression :echo get(w:, 'Signs_Hook', '') 47 | 48 | :com! SignDiff :let g:Signs_Diff=1| call DynamicSigns#Run(1) 49 | 50 | if get(g:, "Signs_QFList", 0) 51 | " prevent loading autoload file too early 52 | call ActivateAuCmds() 53 | endif 54 | 55 | if get(g:, "Signs_Scrollbar", 0) 56 | call DynamicSigns#UpdateScrollbarSigns() 57 | endif 58 | 59 | if (get(g:, "Signs_MixedIndentation", 0) || 60 | \ get(g:, "Signs_IndentationLevel", 0) || 61 | \ get(g:, "Signs_Bookmarks", 0) || 62 | \ get(g:, "Signs_Alternate", 0) || 63 | \ get(g:, "Signs_Hook", 0) || 64 | \ get(g:, "Signs_QFList", 0) || 65 | \ get(g:, "Signs_Diff", 0)) 66 | call DynamicSigns#Update() 67 | endif 68 | 69 | " Restore: "{{{1 70 | let &cpo=s:cpo 71 | unlet s:cpo 72 | " vim: ts=4 sts=4 fdm=marker com+=l\:\" 73 | -------------------------------------------------------------------------------- /todo: -------------------------------------------------------------------------------- 1 | -make signs work on Windows gvim (needs smaller icons and only 256color icons?) 2 | -other icons? 3 | --------------------------------------------------------------------------------