diff --git a/example_config.vim b/example_config.vim new file mode 100644 index 0000000000..7ca910c140 --- /dev/null +++ b/example_config.vim @@ -0,0 +1,62 @@ +set nu +set textwidth=79 +set colorcolumn=79 +set clipboard=unnamed + +if has('gui_running') + set lines=120 + set columns=120 +endif + +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +" => Wakatime +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +let g:wakatime_PythonBinary = '/usr/local/bin/python' + + +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +" => Nerd Tree +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +let g:NERDTreeWinPos = "left" +let g:NERDTreeWinSize = 25 +map nn +map nf + + +"""""""""""""""""""""""""""""" +" => Tagbar +"""""""""""""""""""""""""""""" +autocmd BufReadPost *.cpp,*.c,*.h,*.py call tagbar#autoopen() +autocmd BufReadPost *.html,*.js,*.css,.vimrc* call tagbar#CloseWindow() +nmap :TagbarToggle +let g:tagbar_sort = 0 +let g:tagbar_width = 29 +let g:tagbar_autofocus = 0 +let g:tagbar_show_linenumbers = 1 + + +"""""""""""""""""""""""""""""" +" => Syntastic +"""""""""""""""""""""""""""""" +set statusline+=%#warningmsg# +set statusline+=%{SyntasticStatuslineFlag()} +set statusline+=%* +let g:syntastic_always_populate_loc_list = 1 +let g:syntastic_auto_loc_list = 1 +let g:syntastic_check_on_open = 1 +let g:syntastic_check_on_wq = 0 +let g:syntastic_python_checkers=['python', 'flake8'] +let g:syntastic_python_flake8_post_args='--ignore=W391,E712' +let g:syntastic_html_checkers=[''] + +"""""""""""""""""""""""""""""" +" => ctrlsf.vim +"""""""""""""""""""""""""""""" +let g:ctrlsf_position = 'bottom' +nmap CtrlSFPrompt + +"""""""""""""""""""""""""""""" +" => vim-easymotion +"""""""""""""""""""""""""""""" +map / (easymotion-sn) +omap / (easymotion-tn) diff --git a/sources_non_forked/Dockerfile.vim/.gitignore b/sources_non_forked/Dockerfile.vim/.gitignore new file mode 100644 index 0000000000..3819313818 --- /dev/null +++ b/sources_non_forked/Dockerfile.vim/.gitignore @@ -0,0 +1,2 @@ +*.swp +*.swo diff --git a/sources_non_forked/Dockerfile.vim/LICENSE b/sources_non_forked/Dockerfile.vim/LICENSE new file mode 100644 index 0000000000..27856ca5fd --- /dev/null +++ b/sources_non_forked/Dockerfile.vim/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013 Eugene Kalinin + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/sources_non_forked/Dockerfile.vim/Makefile b/sources_non_forked/Dockerfile.vim/Makefile new file mode 100644 index 0000000000..1e327613dd --- /dev/null +++ b/sources_non_forked/Dockerfile.vim/Makefile @@ -0,0 +1,12 @@ +install: + @echo "Installation:" + @mkdir -p ~/.vim/syntax + @mkdir -p ~/.vim/ftdetect + @mkdir -p ~/.vim/snippets + @echo " * Dirs ... success." + @cp ./syntax/Dockerfile.vim ~/.vim/syntax/ + @echo " * Syntax ... success." + @cp ./ftdetect/Dockerfile.vim ~/.vim/ftdetect/ + @echo " * Filetype ... success." + @cp ./snippets/Dockerfile.snippets ~/.vim/snippets/ + @echo " * Snippets ... success." diff --git a/sources_non_forked/Dockerfile.vim/README.md b/sources_non_forked/Dockerfile.vim/README.md new file mode 100644 index 0000000000..f30f1d6ffe --- /dev/null +++ b/sources_non_forked/Dockerfile.vim/README.md @@ -0,0 +1,41 @@ +Dockerfile.vim +============== + +Vim syntax file for [Docker](http://docker.io/)'s [Dockerfile](http://docs.docker.com/reference/builder/) +and snippets for [snipMate](http://www.vim.org/scripts/script.php?script_id=2540). + +Screenshot +========== + +Here is an example in gnome-terminal with [vim-monokai](https://github.com/sickill/vim-monokai) color scheme: + + +![Vim & Dockerfile.vim ](https://raw.github.com/ekalinin/Dockerfile.vim/master/vim-dockerfile-example.png) + + + +Installation +============ + +````bash +$ git clone https://github.com/ekalinin/Dockerfile.vim.git +$ cd Dockerfile.vim +$ make install +```` + +####OR using Pathogen: +```bash +# Clone directly into the bundle folder. +git clone https://github.com/ekalinin/Dockerfile.vim.git bundle/Dockerfile +``` + +####OR using Vundle: +```bash +# near the top of your .vimrc +Plugin 'ekalinin/Dockerfile.vim' +``` + +License +======= + +See [LICENSE](https://github.com/ekalinin/Dockerfile.vim/blob/master/LICENSE) file. diff --git a/sources_non_forked/Dockerfile.vim/ftdetect/Dockerfile.vim b/sources_non_forked/Dockerfile.vim/ftdetect/Dockerfile.vim new file mode 100644 index 0000000000..ff20cd9125 --- /dev/null +++ b/sources_non_forked/Dockerfile.vim/ftdetect/Dockerfile.vim @@ -0,0 +1,4 @@ +" Dockerfile +autocmd BufRead,BufNewFile Dockerfile set ft=Dockerfile +autocmd BufRead,BufNewFile Dockerfile* setf Dockerfile +autocmd BufRead,BufNewFile *.dock setf Dockerfile diff --git a/sources_non_forked/Dockerfile.vim/snippets/Dockerfile.snippets b/sources_non_forked/Dockerfile.vim/snippets/Dockerfile.snippets new file mode 100644 index 0000000000..5f97a51063 --- /dev/null +++ b/sources_non_forked/Dockerfile.vim/snippets/Dockerfile.snippets @@ -0,0 +1,66 @@ +snippet F + FROM ${1:ubuntu} +snippet f + FROM ${1:ubuntu} +snippet M + MAINTAINER ${1:name} +snippet m + MAINTAINER ${1:name} +snippet R + RUN ${1:command} +snippet r + RUN ${1:command} +snippet C + CMD ${1:command} +snippet c + CMD ${1:command} +snippet CP + COPY ${1:src} ${2:dest} +snippet cp + COPY ${1:src} ${2:dest} +snippet EXP + EXPOSE ${1:port} +snippet exp + EXPOSE ${1:port} +snippet E + ENV ${1:key} ${2:value} +snippet e + ENV ${1:key} ${2:value} +snippet A + ADD ${1:src} ${2:dst} +snippet a + ADD ${1:src} ${2:dst} +snippet ENT + ENTRYPOINT ${1:command} +snippet ent + ENTRYPOINT ${1:command} +snippet V + VOLUME ["${1:path}"] +snippet v + VOLUME ["${1:path}"] +snippet U + USER ${1:name} +snippet u + USER ${1:name} +snippet W + WORKDIR ${1:path} +snippet w + WORKDIR ${1:path} +snippet upd + # update packages + RUN echo "deb http://archive.ubuntu.com/ubuntu ${1:precise} main universe" > /etc/apt/sources.list; \ + apt-get update && apt-get -y upgrade; \ + ${2} +snippet head + # ${1:Description} + # + # VERSION ${2:0.1.0} + ${3} +snippet O + ONBUILD ${1} +snippet o + ONBUILD ${1} +snippet L + LABEL ${1:label}="${2:value}" +snippet l + LABEL ${1:label}="${2:value}" diff --git a/sources_non_forked/Dockerfile.vim/syntax/Dockerfile.vim b/sources_non_forked/Dockerfile.vim/syntax/Dockerfile.vim new file mode 100644 index 0000000000..c5afa93caa --- /dev/null +++ b/sources_non_forked/Dockerfile.vim/syntax/Dockerfile.vim @@ -0,0 +1,61 @@ +" Vim syntax file +" Language: Dockerfile +" Maintainer: Eugene Kalinin +" Latest Revision: 11 September 2013 +" Source: http://docs.docker.io/en/latest/use/builder/ + +if exists("b:current_syntax") + finish +endif + +" case sensitivity (fix #17) +" syn case ignore + +" Keywords +syn keyword dockerfileKeywords FROM MAINTAINER RUN CMD COPY +syn keyword dockerfileKeywords EXPOSE ENV ADD ENTRYPOINT +syn keyword dockerfileKeywords VOLUME USER WORKDIR ONBUILD +syn keyword dockerfileKeywords LABEL + +" Bash statements +setlocal iskeyword+=- +syn keyword bashStatement add-apt-repository adduser apt-get aptitude apt-key autoconf bundle +syn keyword bashStatement cd chgrp chmod chown clear complete composer cp curl du echo egrep +syn keyword bashStatement expr fgrep find gem gnufind gnugrep gpg grep groupadd head less ln +syn keyword bashStatement ls make mkdir mv node npm pacman php python rails rm rmdir rpm ruby +syn keyword bashStatement sed sleep sort strip tail tailf touch useradd virtualenv yum +syn keyword bashStatement usermod bash cat a2ensite a2dissite a2enmod a2dismod apache2ctl +syn keyword bashStatement wget gzip + +" Strings +syn region dockerfileString start=/"/ skip=/\\"/ end=/"/ +syn region dockerfileString1 start=/'/ skip=/\\'/ end=/'/ + +" Emails +syn region dockerfileEmail start=// contains=@ oneline + +" Urls +syn match dockerfileUrl /\(http\|https\|ssh\|hg\|git\)\:\/\/[a-zA-Z0-9\/\-\.]\+/ + +" Task tags +syn keyword dockerfileTodo contained TODO FIXME XXX + +" Comments +syn region dockerfileComment start="#" end="\n" contains=dockerfileTodo + +" Highlighting +hi link dockerfileKeywords Keyword +hi link dockerfileString String +hi link dockerfileString1 String +hi link dockerfileComment Comment +hi link dockerfileEmail Identifier +hi link dockerfileUrl Identifier +hi link dockerfileTodo Todo +hi link bashStatement Function + +let b:current_syntax = "dockerfile" + +set commentstring=#\ %s + +" Enable automatic comment insertion +setlocal fo+=cro \ No newline at end of file diff --git a/sources_non_forked/Dockerfile.vim/vim-dockerfile-example.png b/sources_non_forked/Dockerfile.vim/vim-dockerfile-example.png new file mode 100644 index 0000000000..c82f871f84 Binary files /dev/null and b/sources_non_forked/Dockerfile.vim/vim-dockerfile-example.png differ diff --git a/sources_non_forked/ack.vim/README.md b/sources_non_forked/ack.vim/README.md index 59f00f1d38..c2e8706711 100644 --- a/sources_non_forked/ack.vim/README.md +++ b/sources_non_forked/ack.vim/README.md @@ -4,7 +4,7 @@ Run your favorite search tool from Vim, with an enhanced results list. This plugin was designed as a Vim frontend for the Perl module [App::Ack]. Ack can be used as a replacement for 99% of the uses of _grep_. The plugin allows -you to run ack from vim, and shows the results in a split window. +you to run ack from Vim, and shows the results in a split window. But here's a little secret for the Vim-seasoned: it's just a light wrapper for Vim's [grepprg] and the [quickfix] window for match results. This makes it easy @@ -28,13 +28,21 @@ It is recommended to use one of the popular plugin managers for Vim. There are many and you probably already have a preferred one, but a few examples for your copy-and-paste convenience: +#### Pathogen + + $ git clone https://github.com/mileszs/ack.vim.git ~/.vim/bundle/ack.vim + #### Vundle - Plugin 'mileszs/ack.vim' +```vim +Plugin 'mileszs/ack.vim' +``` #### NeoBundle - NeoBundle 'mileszs/ack.vim' +```vim +NeoBundle 'mileszs/ack.vim' +``` #### Manual (not recommended) @@ -127,6 +135,7 @@ Please see [the Github releases page][releases]. * Fix the quick help overlay clobbering the list mappings * Fix `:AckFile` when using Dispatch * Restore original `'makeprg'` and `'errorformat'` when using Dispatch +* Arrow keys also work for auto-preview (#158) * Internal refactoring and clean-up ## Credits diff --git a/sources_non_forked/ack.vim/autoload/ack.vim b/sources_non_forked/ack.vim/autoload/ack.vim index fd6e54ca8c..12237e4edd 100644 --- a/sources_non_forked/ack.vim/autoload/ack.vim +++ b/sources_non_forked/ack.vim/autoload/ack.vim @@ -27,11 +27,7 @@ function! ack#Ack(cmd, args) "{{{ endif " If no pattern is provided, search for the word under the cursor - if empty(a:args) - let l:grepargs = expand("") - else - let l:grepargs = a:args . join(a:000, ' ') - end + let l:grepargs = empty(a:args) ? expand("") : a:args . join(a:000, ' ') " NOTE: we escape special chars, but not everything using shellescape to " allow for passing arguments etc @@ -118,6 +114,8 @@ function! s:ApplyMappings() "{{{ if exists("g:ackpreview") " if auto preview in on, remap j and k keys nnoremap j j nnoremap k k + nmap j + nmap k endif endfunction "}}} @@ -157,17 +155,11 @@ function! s:QuickHelp() "{{{ execute 'edit' globpath(&rtp, 'doc/ack_quick_help.txt') silent normal gg - setlocal buftype=nofile - setlocal bufhidden=hide - setlocal noswapfile - setlocal nobuflisted - setlocal nomodifiable + setlocal buftype=nofile bufhidden=hide nobuflisted + setlocal nomodifiable noswapfile setlocal filetype=help - setlocal nonumber - setlocal norelativenumber - setlocal nowrap - setlocal foldlevel=20 - setlocal foldmethod=diff + setlocal nonumber norelativenumber nowrap + setlocal foldmethod=diff foldlevel=20 nnoremap ? :q!:call ack#ShowResults() endfunction "}}} diff --git a/sources_non_forked/ack.vim/doc/ack.txt b/sources_non_forked/ack.vim/doc/ack.txt index 71d7454871..bdef32278f 100644 --- a/sources_non_forked/ack.vim/doc/ack.txt +++ b/sources_non_forked/ack.vim/doc/ack.txt @@ -84,18 +84,23 @@ g:ackprg Default for ubuntu: "ack-grep" Default for other systems: "ack" -Use this option to specify the ack command and its options +Use this option to specify the search command and its default arguments. Example: > - let g:ackprg = "other-bin-ack" + let g:ackprg = "ag --vimgrep" < *g:ack_default_options* g:ack_default_options Default: " -s -H --nocolor --nogroup --column" -Use this option to specify the options used by ack +Use this option to specify the default arguments given to `ack`. This is only +used if |g:ackprg| has not been customized from the default--if you are using +a custom search program instead of Ack, set your preferred options in +|g:ackprg|. + +NOTE: This option may be deprecated in the future. ~ Example: > diff --git a/sources_non_forked/ack.vim/plugin/ack.vim b/sources_non_forked/ack.vim/plugin/ack.vim index 2cc4803624..da3ea9ab2b 100644 --- a/sources_non_forked/ack.vim/plugin/ack.vim +++ b/sources_non_forked/ack.vim/plugin/ack.vim @@ -71,8 +71,8 @@ command! -bang -nargs=* -complete=file LAckAdd call ack#Ack('lgrepadd -g', ) command! -bang -nargs=* -complete=help AckHelp call ack#AckHelp('grep', ) command! -bang -nargs=* -complete=help LAckHelp call ack#AckHelp('lgrep', ) -command! -bang -nargs=* -complete=help AckWindow call ack#AckWindow('grep', ) -command! -bang -nargs=* -complete=help LAckWindow call ack#AckWindow('lgrep', ) +command! -bang -nargs=* AckWindow call ack#AckWindow('grep', ) +command! -bang -nargs=* LAckWindow call ack#AckWindow('lgrep', ) let g:loaded_ack = 1 diff --git a/sources_non_forked/ctrlsf.vim/README.md b/sources_non_forked/ctrlsf.vim/README.md new file mode 100644 index 0000000000..549a8f05e4 --- /dev/null +++ b/sources_non_forked/ctrlsf.vim/README.md @@ -0,0 +1,278 @@ +# ctrlsf.vim + +An ack/ag powered code search and view tool, like ack.vim or `:vimgrep` but together with more context, and let you edit in-place with powerful edit mode. + +### Search and Explore + +![ctrlsf demo](http://i.imgur.com/NOy8gwj.gif) + +### Edit Mode (with [vim-multiple-cursors][7]) + +![ctrlsf_edit_demo](http://i.imgur.com/xMUm8Ii.gif) + +## Features + +- Search and display result in a user-friendly view with adjustable context. + +- Edit mode which is incredible useful when you are doing refactoring. (Inspired by [vim-ags][6]) + +- Preview mode for fast exploring. + +- Various options for customized search, view and edit. + +## Installation + +1. Make sure you have [ack][1] or [ag][2] installed. + +2. An easy way to install CtrlSF is using a package manager, like [pathogen][3], [vundle][4] or [neobundle][5]. + + In vundle: + + ```vim + Bundle 'dyng/ctrlsf.vim' + ``` + +3. Read *Basic Usage* for how to use. + +## Basic Usage + +1. Run `:CtrlSF [pattern]`, it will split a new window to show search result. + +2. Press `Enter` to open corresponding file, or press `q` to quit. + +3. Press `p` to explore file in a preview window if you only want a glance. + +4. You can edit search result as you like. Whenever you apply a change, you can save your change to actual file by `:w`. + +5. If you change your mind after saving, you can always undo it by pressing `u` and saving it again. + +6. `:CtrlSFOpen` can reopen CtrlSF window when you have closed CtrlSF window. It is free because it won't invoke a same but new search. A handy command `:CtrlSFToggle` is also available. + +## Key Maps + +In CtrlSF window: + +- `Enter` - Open corresponding file of current line in the window which CtrlSF is launched from. +- `t` - Like `Enter` but open file in a new tab. +- `p` - Like `Enter` but open file in a preview window. +- `O` - Like `Enter` but always leave CtrlSF window opening. +- `T` - Lkie `t` but focus CtrlSF window instead of new opened tab. +- `q` - Quit CtrlSF window. +- `` - Move cursor to next match. +- `` - Move cursor to previous match. + +In preview window: + +- `q` - Close preview window. + +Some default defined keys may comflict with keys you have been used to when you are editing. But don't worry, you can customize your mapping by setting `g:ctrlsf_mapping`. `:h g:ctrlsf_mapping` for more information. + +## Use Your Own Map + +There are also some useful maps need to be mentioned. + +- `CtrlSFPrompt` + + Input `:CtrlSF ` in command line for you, just a handy shortcut. + +- `CtrlSFVwordPath` + + Input `:CtrlSF foo ` in command line where `foo` is the current visual selected word, waiting for further input. + +- `CtrlSFVwordExec` + + Like `CtrlSFVwordPath`, but execute it immediately. + +- `CtrlSFCwordPath` + + Input `:CtrlSF foo ` in command line where `foo` is word under the cursor. + +- `CtrlSFPwordPath` + + Input `:CtrlSF foo ` in command line where `foo` is the last search pattern of vim. + +For a full list of maps, please refer to the document. + +I strongly recommend you should do some maps for a nicer user experience, because typing 8 characters for every single search is really boring and painful experience. Another reason is that **one of the most useful feature 'Search Visual Selected Word' can be accessed by map only.** + +Example: + +``` +nmap f CtrlSFPrompt +vmap f CtrlSFVwordPath +vmap F CtrlSFVwordExec +nmap n CtrlSFCwordPath +nmap p CtrlSFPwordPath +nnoremap o :CtrlSFOpen +nnoremap t :CtrlSFToggle +inoremap t :CtrlSFToggle +``` + +## Edit Mode + +1. Edit mode is not really a 'mode'. You don't need to press any key to enter edit mode, just edit the result directly. + +2. When your editing is done, save it and CtrlSF will ask you for confirmation, 'y' or just enter will make CtrlSF apply those changes to actual files. (You can turn off confirmation by setting `g:ctrlsf_confirm_save` to 0) + +3. Undo is the same as regular editing. You just need to press 'u' and save again. + +4. Finally I recommend using [vim-multiple-cursors][7] together with edit mode. + +### Limitation + +- You can modify or delete lines but **you can't insert**. (If it turns out that inserting is really needed, I'll implement it later.) + +- If a file's content varies from last search, CtrlSF will refuse to write your changes to that file (for safty concern). As a rule of thumb, invoke a new search before editing, or just run `:CtrlSFUpdate`. + +## Arguments + +CtrlSF has a lot of arguments you can use in search. Most arguments are similar to Ack/Ag's but not perfectly same. Here are some most frequently used arguments: + +- `-R` - Use regular expression pattern. +- `-I`, `-S` - Search case-insensitively (`-I`) or case-sensitively (`-S`). +- `-C`, `-A`, `-B` - Specify how many context lines to be printed, identical to their counterparts in Ag/Ack. + +Read `:h ctrlsf-arguments` for a full list of arguments. + +### Example + +- Search a regular expression pattern case-insensitively: + + ```vim + :CtrlSF -R -I foo.* + ``` + +- Search a pattern that contains space: + + ```vim + :CtrlSF 'def foo():' + ``` + +- Search a pattern with characters requiring escaping: + + ```vim + :CtrlSF '"foobar"' + " or + :CtrlSF \"foobar\" + ``` + +## Tips + +- CtrlSF searches pattern literally by default, which is different from Ack/Ag. If you need to search a regular expression pattern, run `:CtrlSF -R regex`. If you dislike this default behavior, turn it off by `let g:ctrlsf_regex_pattern = 1`. + +- By default, CtrlSF use working directory as search path when no path is specified. But CtrlSF can also use project root as its path if you set `g:ctrlsf_default_root` to `project`, CtrlSF does this by searching VCS directory (.git, .hg, etc.) upward from current file. It is usefule when you are working with files across multiple projects. + +- `-filetype` is useful when you only want to search in files of specific type. Read option `--type` in `ack`'s [manual][6] for more information. + +- Running `:CtrlSF` without any argument or pattern will use word under cursor. + +## Configuration + +- `g:ctrlsf_auto_close` defines if CtrlSF close itself when you are opening some file. By default CtrlSF window will close automatically but you can prevent it by setting `g:ctrlsf_auto_close` to 0. + + ```vim + let g:ctrlsf_auto_close = 0 + ``` + +- `g:ctrlsf_case_sensitive` defines default case-sensivivity in search. Possible values are `yes`, `no` and `smart`, `smart` works the same as it is in vim. The default value is `smart`. + + ```vim + let g:ctrlsf_case_sensitive = 'no' + ``` + +- `g:ctrlsf_context` defines how many context lines will be printed. Please read `ack`'s [manual][6] for acceptable format. The default value is `-C 3`, and you can set another value by + + ```vim + let g:ctrlsf_context = '-B 5 -A 3' + ``` +- `g:ctrlsf_default_root` defines how CtrlSF find search root when no explicit path is given. Two possible values are `cwd` and `project`. `cwd` means current working directory and `project` means project root. CtrlSF locates project root by searching VCS root (.git, .hg, .svn, etc.) + + ```vim + let g:ctrlsf_default_root = 'project' + ``` + +- `g:ctrlsf_indent` defines how many spaces are placed between line number and content. Default value is 4. + + ```vim + let g:ctrlsf_indent = 2 + ``` + +- `g:ctrlsf_mapping` defines maps used in result window and preview window. Value of this option is a dictionary, where key is a method and value is a key for mapping. An empty value can disable that method. You can just defind a subset of full dictionary, those not defined functionalities will use default key mapping. + + ```vim + let g:ctrlsf_mapping = { + \ "next": "n", + \ "prev": "N", + \ } + ``` + +- `g:ctrlsf_regex_pattern` defines CtrlSF using literal pattern or regular expression pattern as default. Default value is 0, which means literal pattern. + + ```vim + let g:ctrlsf_regex_pattern = 1 + ``` + +- `g:ctrlsf_position` defines where CtrlSf places its window. Possible values are `left`, `right`, `top` and `bottom`. If nothing specified, the default value is `left`. + + ```vim + let g:ctrlsf_position = 'bottom' + ``` + +- `g:ctrlsf_winsize` defines the width (if CtrlSF opens vertically) or height (if CtrlSF opens horizontally) of CtrlSF main window. You can specify it with percent value or absolute value. + + ```vim + let g:ctrlsf_winsize = '30%' + " or + let g:ctrlsf_winsize = '100' + ``` + +A full list of options can be found in `:help ctrlsf-options`. + +## For user comes from pre v1.0 + +### Difference between v1.0 and pre-v1.0 + +There are many features and changes introduced in v1.0, but the most important difference is **v1.0 breaks backward compatibility**. + +### Where and why backward compatibility is given up? + +CtrlSF is at first designed as a wrapper of ag/ack within vim, and the principle of interface design is *sticking to the interface of ag/ack running upon shell*. This fact lets user get access to all features of ag/ack, and it's easier to implement too. However I found it is not as useful as I thought, what's worse, this principle limits features I could add to CtrlSF and makes CtrlSF counter-intuitive sometimes. + +**So I want to change it.** + +Example: + +Case-insensitive searching in pre-v1.0 CtrlSF is like this + +```vim +CtrlSF -i foo +``` + +In v1.0, that will be replaced by + +```vim +CtrlSF -ignorecase foo +``` + +For those most frequently used arguments, an upper case short version is available + +```vim +CtrlSF -I foo +``` + +### Changelist + +- Brand new edit mode is added. +- Literal searching becomes default. +- Mapping becomes customizable. +- Smart case is added and turned on by default. +- `g:ctrlsf_leading_space` is replaced by `g:ctrlsf_indent`. +- etc... + +[1]: https://github.com/petdance/ack +[2]: https://github.com/ggreer/the_silver_searcher +[3]: https://github.com/tpope/vim-pathogen +[4]: https://github.com/gmarik/vundle +[5]: https://github.com/Shougo/neobundle.vim +[6]: https://github.com/gabesoft/vim-ags +[7]: https://github.com/terryma/vim-multiple-cursors diff --git a/sources_non_forked/ctrlsf.vim/Rakefile b/sources_non_forked/ctrlsf.vim/Rakefile new file mode 100644 index 0000000000..a4dbc02102 --- /dev/null +++ b/sources_non_forked/ctrlsf.vim/Rakefile @@ -0,0 +1,3 @@ +task :archive do + sh 'git archive --format=tar HEAD after autoload plugin doc syntax | gzip > ctrlsf.tar.gz' +end diff --git a/sources_non_forked/ctrlsf.vim/after/plugin/ctrlsf.vim b/sources_non_forked/ctrlsf.vim/after/plugin/ctrlsf.vim new file mode 100644 index 0000000000..c25307c934 --- /dev/null +++ b/sources_non_forked/ctrlsf.vim/after/plugin/ctrlsf.vim @@ -0,0 +1,35 @@ +" ============================================================================ +" Description: An ack/ag powered code search and view tool. +" Author: Ye Ding +" Licence: Vim licence +" Version: 1.10 +" ============================================================================ + +" Loading Guard {{{1 +if !exists('g:ctrlsf_debug') && exists('g:ctrlsf_tail_loaded') + finish +endif +let g:ctrlsf_tail_loaded = 1 +" }}} + +" Airline support {{{1 +func! CtrlSFStatusLine(...) + " main window + if bufname('%') == '__CtrlSF__' + let w:airline_section_a = 'CtrlSF' + let w:airline_section_b = '%{ctrlsf#utils#SectionB()}' + let w:airline_section_c = '%{ctrlsf#utils#SectionC()}' + let w:airline_section_x = '%{ctrlsf#utils#SectionX()}' + let w:airline_section_y = '' + endif + + " preview window + if bufname('%') == '__CtrlSFPreview__' + let w:airline_section_a = 'Preview' + let w:airline_section_c = '%{ctrlsf#utils#PreviewSectionC()}' + endif +endf + +if exists('g:loaded_airline') + call airline#add_statusline_func('CtrlSFStatusLine') +endif diff --git a/sources_non_forked/ctrlsf.vim/autoload/ctrlsf.vim b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf.vim new file mode 100644 index 0000000000..d2edd39c23 --- /dev/null +++ b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf.vim @@ -0,0 +1,260 @@ +" ============================================================================ +" Description: An ack/ag powered code search and view tool. +" Author: Ye Ding +" Licence: Vim licence +" Version: 1.10 +" ============================================================================ + +""""""""""""""""""""""""""""""""" +" Main +""""""""""""""""""""""""""""""""" + +" remember what user is searching +let s:current_query = '' + +" s:ExecSearch() +" +" Basic process: query, parse, render and display. +" +func! s:ExecSearch(args) abort + try + call ctrlsf#opt#ParseOptions(a:args) + catch /ParseOptionsException/ + return -1 + endtry + + if ctrlsf#backend#SelfCheck() < 0 + return -1 + endif + + let [success, output] = ctrlsf#backend#Run(a:args) + if !success + call ctrlsf#log#Error('Failed to call backend. Error messages: %s', + \ output) + return -1 + endif + + call ctrlsf#db#ParseAckprgResult(output) + call ctrlsf#win#OpenMainWindow() + call ctrlsf#win#Draw() + call ctrlsf#buf#ClearUndoHistory() + call cursor(1, 1) +endf + +" Search() +" +func! ctrlsf#Search(args) abort + let args = a:args + + " If no pattern is given, use word under the cursor + if empty(args) + let args = expand('') + endif + + let s:current_query = args + + call s:ExecSearch(s:current_query) +endf + +" Update() +" +func! ctrlsf#Update() abort + if empty(s:current_query) + return -1 + endif + call s:ExecSearch(s:current_query) +endf + +" Open() +" +func! ctrlsf#Open() abort + call ctrlsf#win#OpenMainWindow() +endf + +" Redraw() +" +func! ctrlsf#Redraw() abort + let [wlnum, lnum, col] = [line('w0'), line('.'), col('.')] + call ctrlsf#win#Draw() + call ctrlsf#win#MoveCursor(wlnum, lnum, col) +endf + +" Save() +" +func! ctrlsf#Save() + if !&l:modified + return + endif + + let changed = ctrlsf#edit#Save() + + if changed > 0 + " DO NOT redraw if it is an undo (then seq_last != seq_cur) + let undotree = undotree() + if undotree.seq_last == undotree.seq_cur + call ctrlsf#Redraw() + endif + + " reset 'modified' flag + setl nomodified + + " reload modified files + checktime + endif +endf + +" Quit() +" +func! ctrlsf#Quit() abort + call ctrlsf#preview#ClosePreviewWindow() + call ctrlsf#win#CloseMainWindow() +endf + +" Toggle() +" +func! ctrlsf#Toggle() abort + if ctrlsf#win#FindMainWindow() != -1 + call ctrlsf#Quit() + else + call ctrlsf#Open() + endif +endf + +" JumpTo() +" +func! ctrlsf#JumpTo(mode) abort + let [file, line, match] = ctrlsf#view#Reflect(line('.')) + + if empty(file) || empty(line) + return + endif + + let lnum = line.lnum + let col = empty(match)? 0 : match.col + + if a:mode ==# 'o' + call s:OpenFileInWindow(file, lnum, col, 1) + elseif a:mode ==# 'O' + call s:OpenFileInWindow(file, lnum, col, 2) + elseif a:mode ==# 't' + call s:OpenFileInTab(file, lnum, col, 1) + elseif a:mode ==# 'T' + call s:OpenFileInTab(file, lnum, col, 2) + elseif a:mode ==# 'p' + call s:PreviewFile(file, lnum, col) + endif +endf + +" s:NextMatch() +" +func! ctrlsf#NextMatch(forward) abort + let cur_vlnum = line('.') + let [vlnum, vcol] = ctrlsf#view#FindNextMatch(cur_vlnum, a:forward) + + if vlnum > 0 + if a:forward && vlnum <= cur_vlnum + redraw! + call ctrlsf#log#Notice("search hit BOTTOM, continuing at TOP") + elseif !a:forward && vlnum >= cur_vlnum + redraw! + call ctrlsf#log#Notice("search hit TOP, continuing at BOTTOM") + else + call ctrlsf#log#Clear() + endif + + call cursor(vlnum, vcol) + endif +endf + +" OpenFileInWindow() +" +" OpenFileInWindow() has 2 modes: +" +" 1. Open file in a window (usually the window where CtrlSF was launched), then +" close CtrlSF window depending on the value of 'g:ctrlsf_auto_close'. +" +" 2. Open file in a window like mode 1, but don't close CtrlSF no matter what +" 'g:ctrlsf_auto_close' is. +" +func! s:OpenFileInWindow(file, lnum, col, mode) abort + if a:mode == 1 && g:ctrlsf_auto_close + call ctrlsf#Quit() + endif + + let target_winnr = ctrlsf#win#FindTargetWindow(a:file) + if target_winnr == 0 + exec 'silent split ' . a:file + else + exec target_winnr . 'wincmd w' + + if bufname('%') !~# a:file + if &modified && !&hidden + exec 'silent split ' . a:file + else + exec 'silent edit ' . a:file + endif + endif + endif + + call ctrlsf#win#MoveCentralCursor(a:lnum, a:col) + + if g:ctrlsf_selected_line_hl =~ 'o' + call ctrlsf#hl#HighlightSelectedLine() + endif +endf + +" OpenFileInTab() +" OpenFileInTab() has 2 modes: +" +" 1. Open file in a new tab, close or leave CtrlSF window depending on value +" of 'g:ctrlsf_auto_close', and place cursor in the new tab. +" +" 2. Open file in a new tab like mode 1, but focus CtrlSF window instead, +" and never close CtrlSF window. +" +func! s:OpenFileInTab(file, lnum, col, mode) abort + if a:mode == 1 && g:ctrlsf_auto_close + call ctrlsf#Quit() + endif + + exec 'silen tabedit ' . a:file + + call ctrlsf#win#MoveCentralCursor(a:lnum, a:col) + + if g:ctrlsf_selected_line_hl =~ 'o' + call ctrlsf#hl#HighlightSelectedLine() + endif + + if a:mode == 2 + tabprevious + endif +endf + +" s:PreviewFile() +" +func! s:PreviewFile(file, lnum, col) abort + call ctrlsf#preview#OpenPreviewWindow() + + if !exists('b:ctrlsf_file') || b:ctrlsf_file !=# a:file + let b:ctrlsf_file = a:file + + call ctrlsf#buf#WriteFile(a:file) + + " trigger filetypedetect (syntax highlight) + exec 'doau filetypedetect BufRead ' . a:file + endif + + call ctrlsf#win#MoveCentralCursor(a:lnum, a:col) + + if g:ctrlsf_selected_line_hl =~ 'p' + call ctrlsf#hl#HighlightSelectedLine() + endif + + call ctrlsf#win#FocusMainWindow() +endf + +" ClearSelectedLine() +" +func! ctrlsf#ClearSelectedLine() abort + call ctrlsf#hl#ClearSelectedLine() +endf diff --git a/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/backend.vim b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/backend.vim new file mode 100644 index 0000000000..38676d0b16 --- /dev/null +++ b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/backend.vim @@ -0,0 +1,144 @@ +" ============================================================================ +" Description: An ack/ag powered code search and view tool. +" Author: Ye Ding +" Licence: Vim licence +" Version: 1.10 +" ============================================================================ + +" BuildCommand() +" +func! s:BuildCommand(args) abort + let tokens = [] + + " add executable file + call add(tokens, g:ctrlsf_ackprg) + + " If user has specified '-A', '-B' or '-C', then use it without complaint + " else use the default value 'g:ctrlsf_context' + let ctx_options = ctrlsf#opt#GetContext() + let context = '' + for opt in keys(ctx_options) + let context .= printf("--%s=%s ", opt, ctx_options[opt]) + endfo + call add(tokens, context) + + " ignorecase + let case_sensitive = ctrlsf#opt#GetCaseSensitive() + let case = '' + if case_sensitive ==# 'smartcase' + let case = '--smart-case' + elseif case_sensitive ==# 'ignorecase' + let case = '--ignore-case' + else + if g:ctrlsf_ackprg =~# 'ag' + let case = '--case-sensitive' + else + let case = '--no-smart-case' + endif + endif + call add(tokens, case) + + " regex + call add(tokens, ctrlsf#opt#GetRegex() ? '' : '--literal') + + " filetype + let filetype = ctrlsf#opt#GetOpt('filetype') + call add(tokens, empty(filetype) ? '' : '--' . filetype) + + " default + if g:ctrlsf_ackprg =~# 'ag' + call add(tokens, '--heading --group --nocolor --nobreak') + else + call add(tokens, '--heading --group --nocolor --nobreak --nocolumn') + endif + + " pattern (including escape) + call add(tokens, shellescape(ctrlsf#opt#GetOpt('pattern'))) + + " path (including escape) + if !empty(ctrlsf#opt#GetOpt('path')) + for path in ctrlsf#opt#GetOpt('path') + call add(tokens, shellescape(path)) + endfo + else + let path = { + \ 'project' : ctrlsf#fs#FindVcsRoot(), + \ 'cwd' : getcwd(), + \ }[g:ctrlsf_default_root] + " If project root is not found, use current file + if empty(path) + let path = expand('%:p') + endif + call add(tokens, path) + endif + + return join(tokens, ' ') +endf + +" SelfCheck() +" +func! ctrlsf#backend#SelfCheck() abort + if !exists('g:ctrlsf_ackprg') + call ctrlsf#log#Error("Option 'g:ctrlsf_ackprg' is not defined.") + return -99 + endif + + if empty(g:ctrlsf_ackprg) + call ctrlsf#log#Error("Can not find ack or ag on this system.") + return -99 + endif + + let prg = g:ctrlsf_ackprg + + if !executable(prg) + call ctrlsf#log#Error('Can not locate %s in PATH.', prg) + return -2 + endif +endf + +" Detect() +" +func! ctrlsf#backend#Detect() + if executable('ag') + return 'ag' + endif + + if executable('ack-grep') + return 'ack-grep' + endif + + if executable('ack') + return 'ack' + endif + + return '' +endf + +" Run() +" +" Execute Ack/Ag. +" +" Parameters +" {args} arguments for execution +" +" Returns +" [success/fail, output] +" +func! ctrlsf#backend#Run(args) abort + let command = s:BuildCommand(a:args) + call ctrlsf#log#Debug("ExecCommand: %s", command) + + " A windows user reports CtrlSF doesn't work well when 'shelltemp' is + " turned off. Although I can't reproduce it, I think forcing 'shelltemp' + " would not do something really bad. + let stmp_bak = &shelltemp + set shelltemp + let output = system(command) + let &shelltemp = stmp_bak + + if v:shell_error && !empty(output) + return [0, output] + else + return [1, output] + endif +endf diff --git a/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/buf.vim b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/buf.vim new file mode 100644 index 0000000000..d10f7a64a7 --- /dev/null +++ b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/buf.vim @@ -0,0 +1,55 @@ +" ============================================================================ +" Description: An ack/ag powered code search and view tool. +" Author: Ye Ding +" Licence: Vim licence +" Version: 1.10 +" ============================================================================ + +" WriteString() +" +" Write {content} to current buffer. +" +func! ctrlsf#buf#WriteString(content) abort + let modifiable_bak = getbufvar('%', '&modifiable') + setl modifiable + silent %delete _ + silent 0put =a:content + silent $delete _ " delete trailing empty line + call setbufvar('%', '&modifiable', modifiable_bak) + call setbufvar('%', '&modified', 0) +endf + +" WriteFile() +" +" Write (or read?) {file} to current buffer. +" +func! ctrlsf#buf#WriteFile(file) abort + let modifiable_bak = getbufvar('%', '&modifiable') + setl modifiable + silent %delete _ + exec 'silent 0read ' . a:file + silent $delete _ " delete trailing empty line + call setbufvar('%', '&modifiable', modifiable_bak) + call setbufvar('%', '&modified', 0) +endf + +" ClearUndoHistory() +" +func! ctrlsf#buf#ClearUndoHistory() abort + let modified_bak = getbufvar('%', '&modified') + let ul_bak = &undolevels + set undolevels=-1 + exe "normal a \\" + let &undolevels = ul_bak + unlet ul_bak + call setbufvar('%', '&modified', modified_bak) +endf + +" UndoAllChanges() +" +func! ctrlsf#buf#UndoAllChanges() abort + if &modified + earlier 1f + endif +endf + diff --git a/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/class/line.vim b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/class/line.vim new file mode 100644 index 0000000000..2d61bb51a9 --- /dev/null +++ b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/class/line.vim @@ -0,0 +1,12 @@ +" ============================================================================ +" Description: An ack/ag powered code search and view tool. +" Author: Ye Ding +" Licence: Vim licence +" Version: 1.10 +" ============================================================================ + +" Matched() +" +func! ctrlsf#class#line#Matched() abort dict + return !empty(self.match) +endf diff --git a/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/class/paragraph.vim b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/class/paragraph.vim new file mode 100644 index 0000000000..4c7522101f --- /dev/null +++ b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/class/paragraph.vim @@ -0,0 +1,36 @@ +" ============================================================================ +" Description: An ack/ag powered code search and view tool. +" Author: Ye Ding +" Licence: Vim licence +" Version: 1.10 +" ============================================================================ + +" Lnum() +" +func! ctrlsf#class#paragraph#Lnum() abort dict + return self.lines[0].lnum +endf + +" Vlnum() +" +func! ctrlsf#class#paragraph#Vlnum() abort dict + return self.lines[0].vlnum +endf + +" Range() +" +func! ctrlsf#class#paragraph#Range() abort dict + return len(self.lines) +endf + +" Matches() +" +func! ctrlsf#class#paragraph#Matches() abort dict + let matches = [] + for line in self.lines + if line.matched() + call add(matches, line.match) + endif + endfo + return matches +endf diff --git a/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/comp.vim b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/comp.vim new file mode 100644 index 0000000000..92d2a62591 --- /dev/null +++ b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/comp.vim @@ -0,0 +1,53 @@ +" ============================================================================ +" Description: An ack/ag powered code search and view tool. +" Author: Ye Ding +" Licence: Vim licence +" Version: 1.10 +" ============================================================================ + +" Completion() +" +func! ctrlsf#comp#Completion(arglead, cmdline, cursorpos) + if a:arglead =~# '^-' + return s:OptionComp(a:arglead, a:cmdline, a:cursorpos) + else + return s:PathComp(a:arglead, a:cmdline, a:cursorpos) + endif +endf + +" OptionComp() +" +func! s:OptionComp(arglead, cmdline, cursorpos) + let options = ctrlsf#opt#OptionNames() + return filter(options, "stridx(v:val, a:arglead) == 0") +endf + +" PathComp() +" +" We need a custom completion function because if we use '-comp=file' then vim +" regards CtrlSF expecting file arguments and expand '%' to current file, '#' +" to alternate file and so on automatically, which is not what we want. +" +func! s:PathComp(arglead, cmdline, cursorpos) + let path = a:arglead + let expanded = expand(path) + let is_glob = (expanded == a:arglead) ? 0 : 1 + + if is_glob + if expanded =~ '\n' + let candidate = split(expanded, '\n') + else + let candidate = [ expanded ] + endif + call map(candidate, 'fnamemodify(v:val, ":p:.")') + else + if isdirectory(path) && path !~ '/$' + let candidate = [ path . '/' ] + else + let candidate = split(glob(path . '*'), '\n') + call map(candidate, 'fnamemodify(v:val, ":.")') + endif + endif + + return candidate +endf diff --git a/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/db.vim b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/db.vim new file mode 100644 index 0000000000..615b91864b --- /dev/null +++ b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/db.vim @@ -0,0 +1,199 @@ +" ============================================================================ +" Description: An ack/ag powered code search and view tool. +" Author: Ye Ding +" Licence: Vim licence +" Version: 1.10 +" ============================================================================ + +" List of paragraphs, paragraph is main object which stores parsed query result +let s:resultset = [] + +" cache contains ALL cacheable result +let s:cache = {} + +""""""""""""""""""""""""""""""""" +" Getter +""""""""""""""""""""""""""""""""" + +func! ctrlsf#db#ResultSet() abort + return s:resultset +endf + +func! ctrlsf#db#FileSet() abort + " List of result files, generated by resultset + let fileset = [] + + if has_key(s:cache, 'fileset') + return s:cache['fileset'] + endif + + let cur_file = '' + for par in s:resultset + if cur_file !=# par.file + let cur_file = par.file + call add(fileset, { + \ "file": cur_file, + \ "paragraphs": [], + \ }) + endif + call add(fileset[-1].paragraphs, par) + endfo + + let s:cache['fileset'] = fileset + return fileset +endf + +func! ctrlsf#db#MatchList() abort + " List of matches, generated by resultset + let matchlist = [] + + if has_key(s:cache, 'matchlist') + return s:cache['matchlist'] + endif + + for par in s:resultset + call extend(matchlist, par.matches()) + endfo + + let s:cache['matchlist'] = matchlist + return matchlist +endf + +func! ctrlsf#db#MaxLnum() + if has_key(s:cache, 'maxlnum') + return s:cache['maxlnum'] + endif + + let max = 0 + for par in s:resultset + let mlnum = par.lnum() + par.range() - 1 + let max = mlnum > max ? mlnum : max + endfo + + let s:cache['maxlnum'] = max + return max +endf + +""""""""""""""""""""""""""""""""" +" Parser +""""""""""""""""""""""""""""""""" + +" s:ParseParagraph() +" +" Notice that some fields are initialized with -1, which will be populated +" in render processing. +func! s:ParseParagraph(buffer, file) abort + let paragraph = { + \ 'file' : a:file, + \ 'lnum' : function("ctrlsf#class#paragraph#Lnum"), + \ 'vlnum' : function("ctrlsf#class#paragraph#Vlnum"), + \ 'range' : function("ctrlsf#class#paragraph#Range"), + \ 'lines' : [], + \ 'matches' : function("ctrlsf#class#paragraph#Matches"), + \ } + + for line in a:buffer + let matched = matchlist(line, '\v^(\d+)([-:])(.*)$') + + " add matched line to match list + let match = {} + let mat_col = match(matched[3], ctrlsf#opt#GetOpt("_vimregex")) + 1 + if mat_col > 0 + let match = { + \ 'lnum' : matched[1], + \ 'vlnum' : -1, + \ 'col' : mat_col, + \ 'vcol' : -1 + \ } + endif + + " add line content + call add(paragraph.lines, { + \ 'matched' : function("ctrlsf#class#line#Matched"), + \ 'match' : match, + \ 'lnum' : matched[1], + \ 'vlnum' : -1, + \ 'content' : matched[3], + \ }) + endfo + + return paragraph +endf + +" ParseAckprgOutput() +" +func! ctrlsf#db#ParseAckprgResult(result) abort + " reset + let s:resultset = [] + call ctrlsf#db#ClearCache() + + let current_file = "" + let next_file = "" + + " ack/ag has a feature that if a single file is given as search path, then + " there will be no explicit filename in search result. + if len(ctrlsf#opt#GetOpt("path")) == 1 + let path = ctrlsf#opt#GetOpt("path")[0] + if getftype(path) == 'file' + let current_file = path + endif + endif + + let result_lines = split(a:result, '\n') + + let cur = 0 + while cur < len(result_lines) + let buffer = [] + let pre_ln = -1 + + while cur < len(result_lines) + let line = result_lines[cur] + let cur += 1 + + " don't rely on division line any longer. ignore it. + if line =~ '^--$' + continue + endif + + let matched = matchlist(line, '\v^(\d+)[-:]') + + " if line doesn't match [lnum:col] pattern, assume it is filename + if empty(matched) + let next_file = line + + if current_file !=# next_file + let cur -= 1 + break + else + continue + endif + endif + + " else regard this line as content line + let cur_ln = matched[0] + if (pre_ln == -1) || (cur_ln == pre_ln + 1) + let pre_ln = cur_ln + call add(buffer, line) + else + let cur -= 1 + break + endif + endwh + + if len(buffer) > 0 + let paragraph = s:ParseParagraph(buffer, current_file) + call add(s:resultset, paragraph) + endif + + let current_file = next_file + endwh +endf + +""""""""""""""""""""""""""""""""" +" Cache +""""""""""""""""""""""""""""""""" +" ClearCache +" +func! ctrlsf#db#ClearCache() abort + let s:cache = {} +endf diff --git a/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/edit.vim b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/edit.vim new file mode 100644 index 0000000000..8a0682b741 --- /dev/null +++ b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/edit.vim @@ -0,0 +1,225 @@ +" ============================================================================ +" Description: An ack/ag powered code search and view tool. +" Author: Ye Ding +" Licence: Vim licence +" Version: 1.10 +" ============================================================================ + +" s:DiffFile() +" +func! s:DiffFile(orig, modi) abort + if a:orig.file !=# a:modi.file + \ || len(a:orig.paragraphs) != len(a:modi.paragraphs) + throw 'InconsistentException' + endif + + let i = 0 + while i < len(a:orig.paragraphs) + let opar = a:orig.paragraphs[i] + let mpar = a:modi.paragraphs[i] + let i += 1 + + if opar.range() != mpar.range() + return 1 + endif + + let j = 0 + while j < opar.range() + if opar.lines[j].content !=# mpar.lines[j].content + return 1 + endif + + let j += 1 + endwh + endwh + + return 0 +endf + +" s:Diff() +" +" Return list of changed files. +" +func! s:Diff(orig, modi) abort + if len(a:orig) != len(a:modi) + throw 'InconsistentException' + endif + + let changed_files = [] + + let i = 0 + while i < len(a:orig) + let [file_orig, file_modi] = [a:orig[i], a:modi[i]] + let i += 1 + + if s:DiffFile(file_orig, file_modi) + call add(changed_files, { + \ "orig": file_orig, + \ "modi": file_modi + \ }) + endif + endwh + + return changed_files +endf + +" s:VerifyConsistent() +" +" Check if a file in resultset is different from its disk counterpart. +" +func! s:VerifyConsistent(buffer, orig) + for par in a:orig.paragraphs + for i in range(par.range()) + let ln = par.lnum() + i + let line = par.lines[i] + + if line.content !=# a:buffer[ln-1] + return 0 + endif + endfo + endfo + + return 1 +endf + +" s:WriteParagraph() +" +" Function which does two things: +" +" 1. modify, insert or/and delete lines in buffer +" 2. update resultset to represent modified content +" +func! s:WriteParagraph(buffer, orig, modi, offset) + let orig_count = a:orig.range() + let modi_count = a:modi.range() + let start_lnum = a:orig.lnum() + let start_vlnum = a:orig.vlnum() + + for i in range(modi_count) + let mline = a:modi.lines[i] + let ln = start_lnum + i + a:offset + let vln = start_vlnum + i + a:offset + + " create new line object + let line_obj = { + \ 'matched' : function("ctrlsf#class#line#Matched"), + \ 'match' : {}, + \ 'lnum' : ln, + \ 'vlnum' : vln, + \ 'content' : mline.content + \ } + + let mat_idx = match(line_obj.content, ctrlsf#opt#GetOpt("_vimregex")) + if mat_idx != -1 + let match = { + \ 'lnum' : line_obj.lnum, + \ 'vlnum' : line_obj.vlnum, + \ 'col' : mat_idx + 1, + \ 'vcol' : mat_idx + 1 + ctrlsf#view#Indent() + \ } + let line_obj.match = match + endif + + " copy created line object to an existing line or insert it as new + if i < orig_count + call ctrlsf#utils#Mirror(a:orig.lines[i], line_obj) + let a:buffer[ln-1] = line_obj.content + else + call add(a:orig.lines, line_obj) + call insert(a:buffer, line_obj.content, ln-1) + endif + endfo + + " remove deleted lines from paragraph + if orig_count > modi_count + for i in range(orig_count-1, modi_count, -1) + let ln = start_lnum + i + a:offset + call remove(a:orig.lines, i) + call remove(a:buffer, ln-1) + endfo + endif + + return modi_count - orig_count +endf + +" s:SaveFile() +" +func! s:SaveFile(orig, modi) abort + let file = a:orig.file + + try + let buffer = readfile(file) + catch + call ctrlsf#log#Error("Failed to open file %s", file) + return -1 + endtry + + " if file is changed after searching thus shows differences against + " resultset, skip writing and warn user. + if !s:VerifyConsistent(buffer, a:orig) + call ctrlsf#log#Error("File %s has been changed since last search. Skip + \ this file. Please run :CtrlsfUpdate to update your search result." + \ , file) + return -1 + endif + + let i = 0 + let offset = 0 + while i < len(a:orig.paragraphs) + let opar = a:orig.paragraphs[i] + let mpar = a:modi.paragraphs[i] + let i += 1 + + let offset += s:WriteParagraph(buffer, opar, mpar, offset) + endwh + + if writefile(buffer, file) == -1 + call ctrlsf#log#Error("Failed to write file %s", file) + else + call ctrlsf#log#Debug("Writing file %s succeed.", file) + endif +endf + +" Save() +" +func! ctrlsf#edit#Save() + let orig = ctrlsf#db#FileSet() + let modi = ctrlsf#view#Derender(getline(0, '$')) + + " clear cache (not very clean code I should say) + call ctrlsf#db#ClearCache() + + let changed = s:Diff(orig, modi) + + " prompt to confirm save + if g:ctrlsf_confirm_save + let mes = printf("%s files will be saved. Confirm? (Y/n)", len(changed)) + let confirm = input(mes) | redraw + if !(confirm ==? 'y' || confirm ==? '') + call ctrlsf#log#Info("Cancelled.") + return -1 + endif + endif + + if len(changed) == 0 + call ctrlsf#log#Warn("No file has been changed.") + return -1 + endif + + let [saved, skipped] = [0, 0] + for file in changed + if s:SaveFile(file.orig, file.modi) > -1 + let saved += 1 + else + let skipped += 1 + endif + endfo + + if skipped == 0 + call ctrlsf#log#Info("%s files are saved.", saved) + else + call ctrlsf#log#Info("%s files are saved (%s skipped).", saved, skipped) + endif + + return len(changed) +endf diff --git a/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/fs.vim b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/fs.vim new file mode 100644 index 0000000000..ccee691560 --- /dev/null +++ b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/fs.vim @@ -0,0 +1,26 @@ +" ============================================================================ +" Description: An ack/ag powered code search and view tool. +" Author: Ye Ding +" Licence: Vim licence +" Version: 1.10 +" ============================================================================ + +" Meta folder of several typical version control systems +let s:vcs_folder = ['.git', '.hg', '.svn', '.bzr', '_darcs'] + +" FindVcsRoot() +" +func! ctrlsf#fs#FindVcsRoot() abort + let vsc_dir = '' + for vcs in s:vcs_folder + let vsc_dir = finddir(vcs, expand('%:p:h').';') + if !empty(vsc_dir) + break + endif + endfo + + let root = empty(vsc_dir) ? '' : fnamemodify(vsc_dir, ':h') + call ctrlsf#log#Debug("ProjectRoot: %s", root) + + return root +endf diff --git a/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/hl.vim b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/hl.vim new file mode 100644 index 0000000000..0fba757f01 --- /dev/null +++ b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/hl.vim @@ -0,0 +1,35 @@ +" ============================================================================ +" Description: An ack/ag powered code search and view tool. +" Author: Ye Ding +" Licence: Vim licence +" Version: 1.10 +" ============================================================================ + +" HighlightMatch() +" +func! ctrlsf#hl#HighlightMatch(hlgroup) abort + if !exists('b:current_syntax') || b:current_syntax !~# 'ctrlsf' + return -1 + endif + + let regex = printf('/%s/', escape(ctrlsf#opt#GetOpt("_vimhlregex"), '/')) + call ctrlsf#log#Debug("HighlightRegex: %s", regex) + + exec printf('2match none | 2match %s %s', a:hlgroup, regex) +endf + +" HighlightSelectedLine() +" +func! ctrlsf#hl#HighlightSelectedLine() abort + " Clear previous highlight + silent! call matchdelete(b:ctrlsf_highlight_id) + + let pattern = '\%' . line('.') . 'l.*' + let b:ctrlsf_highlight_id = matchadd('ctrlsfSelectedLine', pattern, -1) +endf + +" ClearSelectedLine() +" +func! ctrlsf#hl#ClearSelectedLine() abort + silent! call matchdelete(b:ctrlsf_highlight_id) +endf diff --git a/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/lex.vim b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/lex.vim new file mode 100644 index 0000000000..dd2469517b --- /dev/null +++ b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/lex.vim @@ -0,0 +1,126 @@ +" ============================================================================ +" Description: An ack/ag powered code search and view tool. +" Author: Ye Ding +" Licence: Vim licence +" Version: 1.10 +" ============================================================================ + +" NextToken() +" +" Return next token of {chars}, which starts from {start}. +" +func! s:NextToken(chars, start) abort + let buffer = [] + let state_stack = ['normal'] + let start = a:start + + while start < len(a:chars) + let state = state_stack[-1] + let char = a:chars[start] + let start += 1 + + " char: [space] + if char ==# ' ' + if state == 'normal' + " ignore leading space + if !empty(buffer) + break + endif + elseif state == 'escape' + call add(buffer, char) + call remove(state_stack, -1) + else + call add(buffer, char) + endif + " char: " + elseif char ==# '"' + if state == 'normal' + " only quote as first character can start a string + if empty(buffer) + call add(state_stack, 'string_double') + else + call add(buffer, char) + endif + elseif state == 'string_single' + call add(buffer, char) + elseif state == 'string_double' + call remove(state_stack, -1) + break + elseif state == 'escape' + call add(buffer, char) + call remove(state_stack, -1) + endif + " char: ' + elseif char ==# "'" + if state == 'normal' + " only quote as first character can start a string + if empty(buffer) + call add(state_stack, 'string_single') + else + call add(buffer, char) + endif + elseif state == 'string_single' + call remove(state_stack, -1) + break + elseif state == 'string_double' + call add(buffer, char) + elseif state == 'escape' + call add(buffer, char) + call remove(state_stack, -1) + endif + " char: \ + elseif char ==# '\' + if state == 'normal' || state == 'string_double' + call add(state_stack, 'escape') + elseif state == 'string_single' + call add(buffer, char) + elseif state == 'escape' + call add(buffer, char) + call remove(state_stack, -1) + endif + " normal characters + else + " if a normal character follows a backslash, then treat that + " backslash as a plain character + if state == 'escape' + call add(buffer, '\') + call remove(state_stack, -1) + endif + call add(buffer, char) + endif + endwh + + if len(state_stack) != 1 || state_stack[-1] != 'normal' + call ctrlsf#log#Error("Unable to parse options: %s. Maybe you forgot + \ escaping.", string(join(a:chars, ''))) + throw "ParseOptionsException" + endif + + return [join(buffer, ''), start] +endf + +" Tokenize() +" +" Split string into a list of tokens. +" +" Examples: +" +" -I -C 2 path -> ['-I', '-C', '2', 'path'] +" -regex 'foo bar' -> ['-regex', 'foo bar'] +" foo\ bar -> ['foo bar'] +" +func! ctrlsf#lex#Tokenize(options_str) abort + let tokens = [] + let chars = split(a:options_str, '.\zs') + + let start = 0 + while start < len(chars) + let [token, start] = s:NextToken(chars, start) + if !empty(token) + call add(tokens, token) + endif + endwh + + call ctrlsf#log#Debug("Tokens: %s", string(tokens)) + return tokens +endf diff --git a/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/log.vim b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/log.vim new file mode 100644 index 0000000000..f7ea6aa746 --- /dev/null +++ b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/log.vim @@ -0,0 +1,72 @@ +" ============================================================================ +" Description: An ack/ag powered code search and view tool. +" Author: Ye Ding +" Licence: Vim licence +" Version: 1.10 +" ============================================================================ + +" s:Echo() +" +" Parameters +" {format} format same as printf() +" {argv} list of values that will be bound to format +" {hlgroup} highlight group used to print message +" {save} if save this message to history +" +func! s:Echo(format, argv, hlgroup, save) abort + let message = s:Printf(a:format, a:argv) + exec 'echohl ' . a:hlgroup + exec (a:save ? "echom" : "echo") . " message" + echohl None +endf + +" s:Printf() +" +func! s:Printf(format, argv) abort + if len(a:argv) == 0 + return a:format + else + let argv = map(copy(a:argv), 'string(v:val)') + exec 'return printf(a:format,' . join(argv, ',') . ')' + endif +endf + +" Clear() +" +" Clear printed messages. +" +func! ctrlsf#log#Clear() abort + echo "" +endf + +" Notice() +" +func! ctrlsf#log#Notice(format, ...) abort + call s:Echo(a:format, a:000, 'WarningMsg', 0) +endf + +" Debug() +" +func! ctrlsf#log#Debug(format, ...) abort + if g:ctrlsf_debug_mode + call s:Echo(a:format, a:000, 'None', 1) + endif +endf + +" Info() +" +func! ctrlsf#log#Info(format, ...) abort + call s:Echo(a:format, a:000, 'MoreMsg', 1) +endf + +" Warn() +" +func! ctrlsf#log#Warn(format, ...) abort + call s:Echo(a:format, a:000, 'WarningMsg', 1) +endf + +" Error() +" +func! ctrlsf#log#Error(format, ...) abort + call s:Echo(a:format, a:000, 'ErrorMsg', 1) +endf diff --git a/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/opt.vim b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/opt.vim new file mode 100644 index 0000000000..096b22687f --- /dev/null +++ b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/opt.vim @@ -0,0 +1,226 @@ +" ============================================================================ +" Description: An ack/ag powered code search and view tool. +" Author: Ye Ding +" Licence: Vim licence +" Version: 1.10 +" ============================================================================ + +" option list of CtrlSF +let s:option_list = { + \ '-after' : {'args': 1}, + \ '-before' : {'args': 1}, + \ '-context' : {'args': 1}, + \ '-filetype' : {'args': 1}, + \ '-ignorecase' : {'args': 0}, + \ '-literal' : {'args': 0}, + \ '-matchcase' : {'args': 0}, + \ '-regex' : {'args': 0}, + \ '-smartcase' : {'args': 0}, + \ '-A': {'fullname': '-after'}, + \ '-B': {'fullname': '-before'}, + \ '-C': {'fullname': '-context'}, + \ '-I': {'fullname': '-ignorecase'}, + \ '-L': {'fullname': '-literal'}, + \ '-R': {'fullname': '-regex'}, + \ '-S': {'fullname': '-matchcase'}, + \ } + +" default values to options +let s:default = { + \ 'filetype' : '', + \ 'pattern' : '', + \ 'path' : [], + \ } + +" options +let s:options = {} + +" OptionNames() +" +" Return ALL available options. It's useful for completion functions. +" +func! ctrlsf#opt#OptionNames() abort + return keys(s:option_list) +endf + +" IsOptGiven() +" +" Return whether user has given a specific option +" +func! ctrlsf#opt#IsOptGiven(name) abort + return has_key(s:options, a:name) +endf + +" GetOpt() +" +" Return option {name}, if not exists, return default value +" +func! ctrlsf#opt#GetOpt(name) abort + if has_key(s:options, a:name) + return s:options[a:name] + else + return get(s:default, 'a:name', '') + endif +endf + +" GetContext() +" +" Return a dict contains 'after', 'before' and/or 'context' +" +func! ctrlsf#opt#GetContext() abort + let options = {} + + " user specific + for opt in ['after', 'before', 'context'] + if ctrlsf#opt#IsOptGiven(opt) + let options[opt] = ctrlsf#opt#GetOpt(opt) + endif + endfo + + " if no user specific context, use default context + if empty(options) + return s:DefaultContext() + endif + + return options +endf + +let s:default_context = { 'conf': '', 'ctx': {} } +func! s:DefaultContext() abort + " if g:ctrlsf_context is not changed since last search, then return cached + " result. + if g:ctrlsf_context ==# s:default_context.conf + return s:default_context.ctx + endif + + let s:default_context['conf'] = g:ctrlsf_context + let s:default_context['ctx'] = s:ParseOptions(g:ctrlsf_context) + + return s:default_context.ctx +endf + +" GetCaseSensitive() +" +" Return 'smartcase', 'ignorecase' or 'matchcase'. +" +" If two or more flags are given at the same time, preferred by priority +" +" 'matchcase' > 'ignorecase' > 'smartcase' +" +func! ctrlsf#opt#GetCaseSensitive() abort + for opt in ['matchcase', 'ignorecase', 'smartcase'] + if ctrlsf#opt#IsOptGiven(opt) + return opt + endif + endfo + + " default + return { + \'smart' : 'smartcase', + \'yes' : 'matchcase', + \'no' : 'ignorecase', + \}[g:ctrlsf_case_sensitive] +endf + +" GetRegex() +" +" Return 1 or 0. +" +" If both of 'literal' and 'regex' are given, prefer 'literal' than 'regex'. +" +func! ctrlsf#opt#GetRegex() abort + if ctrlsf#opt#IsOptGiven('literal') + return 0 + elseif ctrlsf#opt#IsOptGiven('regex') + return 1 + else + return g:ctrlsf_regex_pattern + endif +endf + +""""""""""""""""""""""""""""""""" +" Option Parsing +""""""""""""""""""""""""""""""""" + +" s:ParseOptions() +" +" Create a dict contains parsed options +" +func! s:ParseOptions(options_str) abort + let options = {} + let tokens = ctrlsf#lex#Tokenize(a:options_str) + + let i = 0 + while i < len(tokens) + let token = tokens[i] + let i += 1 + + if !has_key(s:option_list, token) + if token =~# '^-' + call ctrlsf#log#Error("Unknown option '%s'. If you are user + \ from pre-v1.0, plaese be aware of that CtrlSF no longer + \ supports all options of ack and ag since v1.0. Read + \ manual for CtrlSF its own options.", token) + throw 'ParseOptionsException' + endif + + " resolve to PATTERN and PATH + if !has_key(options, 'pattern') + let options['pattern'] = token + else + if !has_key(options, 'path') + let options['path'] = [] + endif + call add(options['path'], token) + endif + + continue + endif + + let name = strpart(token, 1) + let opt = s:option_list[token] + if has_key(opt, 'fullname') + let name = strpart(opt.fullname, 1) + let opt = s:option_list[opt.fullname] + endif + + if opt.args == 0 + let options[name] = 1 + elseif opt.args == 1 + if tokens[i] =~# '\d\+' + let options[name] = str2nr(tokens[i]) + else + let options[name] = tokens[i] + endif + + let i += 1 + else + let argv = [] + for j in range(opt.args) + call add(argv, tokens[i]) + let i += 1 + endfo + + let options[name] = argv + endif + endwh + + call ctrlsf#log#Debug("ParsedResult: %s", string(options)) + return options +endf + +" ParseOptions() +" +func! ctrlsf#opt#ParseOptions(options_str) abort + let s:options = s:ParseOptions(a:options_str) + + " derivative options + + " vimregex + let s:options["_vimregex"] = ctrlsf#pat#Regex() + + " vimhlregex + let s:options["_vimhlregex"] = ctrlsf#pat#HighlightRegex() + + call ctrlsf#log#Debug("Options: %s", string(s:options)) +endf diff --git a/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/pat.vim b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/pat.vim new file mode 100644 index 0000000000..f4f124d694 --- /dev/null +++ b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/pat.vim @@ -0,0 +1,112 @@ +" ============================================================================ +" Description: An ack/ag powered code search and view tool. +" Author: Ye Ding +" Licence: Vim licence +" Version: 1.10 +" ============================================================================ + +" s:TranslateRegex() +" +" Translate perl-regex to vim-regex. +" +func! s:TranslateRegex(pattern) abort + let pattern = a:pattern + + " escape '@' and '%' (plain in perl regex but special in vim regex) + let pattern = escape(pattern, '@%') + + " non-capturing group + let pattern = substitute(pattern, '\v\(\?:(.{-})\)', '%(\1)', 'g') + + " case sensitive + let pattern = substitute(pattern, '\V(?i)', '\c', 'g') + let pattern = substitute(pattern, '\V(?-i)', '\C', 'g') + + " minimal matching + let pattern = substitute(pattern, '\V*?', '{-}', 'g') + let pattern = substitute(pattern, '\V+?', '{-1,}', 'g') + let pattern = substitute(pattern, '\V??', '{-0,1}', 'g') + let pattern = substitute(pattern, '\m{\(.\{-}\)}?', '{-\1}', 'g') + + " zero-length matching + let pattern = substitute(pattern, '\v\(\?\=(.{-})\)', '(\1)@=', 'g') + let pattern = substitute(pattern, '\v\(\?!(.{-})\)', '(\1)@!', 'g') + let pattern = substitute(pattern, '\v\(\?\<\=(.{-})\)', '(\1)@<=', 'g') + let pattern = substitute(pattern, '\v\(\?\(.{-})\)', '(\1)@>', 'g') + + return pattern +endf + +" Regex() +" +func! ctrlsf#pat#Regex() abort + let pattern = ctrlsf#opt#GetOpt('pattern') + + " ignore case + let case_sensitive = ctrlsf#opt#GetCaseSensitive() + let case = '' + if case_sensitive ==# 'ignorecase' + let case = '\c' + elseif case_sensitive ==# 'matchcase' + let case = '\C' + else "smartcase + let pat = ctrlsf#opt#GetOpt('pattern') + let case = (pat =~# '\u') ? '\C' : '\c' + endif + + " magic + let magic = ctrlsf#opt#GetRegex() ? '\v' : '\V' + + " literal + if ctrlsf#opt#GetRegex() + let pattern = s:TranslateRegex(pattern) + else + let pattern = escape(pattern, '\') + endif + + return printf('%s%s%s', magic, case, pattern) +endf + +" HighlightRegex() +" +func! ctrlsf#pat#HighlightRegex() abort + let base = ctrlsf#pat#Regex() + + let magic = strpart(base, 0, 2) + let case = strpart(base, 2, 2) + let pattern = strpart(base, 4) + + " sign (to prevent matching out of file body) + let sign = '' + if magic ==# '\v' + let sign = '(^\d+:.*)@<=' + else + let sign = '\(\^\d\+:\.\*\)\@<=' + endif + + return printf('%s%s%s%s', magic, case, sign, pattern) +endf + +" MatchPerLineRegex() +" +" Regular expression to match the matched word. Difference from HighlightRegex() +" is that this pattern only matches the first matched word in each line. +" +func! ctrlsf#pat#MatchPerLineRegex() abort + let base = ctrlsf#pat#Regex() + + let magic = strpart(base, 0, 2) + let case = strpart(base, 2, 2) + let pattern = strpart(base, 4) + + " sign (to prevent matching out of file body) + let sign = '' + if magic ==# '\v' + let sign = '^\d+:.{-}\zs' + else + let sign = '\^\d\+:\.\{-}\zs' + endif + + return printf('%s%s%s%s', magic, case, sign, pattern) +endf diff --git a/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/preview.vim b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/preview.vim new file mode 100644 index 0000000000..54abe0ef29 --- /dev/null +++ b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/preview.vim @@ -0,0 +1,85 @@ +" ============================================================================ +" Description: An ack/ag powered code search and view tool. +" Author: Ye Ding +" Licence: Vim licence +" Version: 1.10 +" ============================================================================ + +" preview buffer's name +let s:PREVIEW_BUF_NAME = "__CtrlSFPreview__" + +" OpenPreviewWindow() +" +func! ctrlsf#preview#OpenPreviewWindow() abort + " try to focus an existing preview window + if ctrlsf#preview#FocusPreviewWindow() != -1 + return + endif + + " backup width/height of other windows + " be sure doing this only when *opening new window* + call ctrlsf#win#BackupAllWinSize() + + if g:ctrlsf_position == "left" || g:ctrlsf_position == "right" + let ctrlsf_width = winwidth(0) + let winsize = min([&columns-ctrlsf_width, ctrlsf_width]) + else + let ctrlsf_height = winheight(0) + let winsize = min([&lines-ctrlsf_height, ctrlsf_height]) + endif + + let openpos = { + \ 'bottom': 'leftabove', 'right' : 'leftabove vertical', + \ 'top' : 'rightbelow', 'left' : 'rightbelow vertical'} + \[g:ctrlsf_position] . ' ' + exec 'silent keepalt ' . openpos . winsize . 'split ' . '__CtrlSFPreview__' + + call s:InitPreviewWindow() +endf + +" ClosePreviewWindow() +" +func! ctrlsf#preview#ClosePreviewWindow() abort + if ctrlsf#preview#FocusPreviewWindow() == -1 + return + endif + + close + + " restore width/height of other windows + call ctrlsf#win#RestoreAllWinSize() + + call ctrlsf#win#FocusMainWindow() +endf + +" InitPreviewWindow() +func! s:InitPreviewWindow() abort + setl buftype=nofile + setl bufhidden=unload + setl noswapfile + setl nobuflisted + setl nomodifiable + setl winfixwidth + setl winfixheight + + exec "nnoremap " . g:ctrlsf_mapping['pquit'] + \ . " :call ctrlsf#preview#ClosePreviewWindow()" + + augroup ctrlsfp + au! + au BufUnload unlet b:ctrlsf_file + augroup END +endf + +" FindPreviewWindow() +" +func! ctrlsf#preview#FindPreviewWindow() abort + return ctrlsf#win#FindWindow(s:PREVIEW_BUF_NAME) +endf + +" FocusPreviewWindow() +" +func! ctrlsf#preview#FocusPreviewWindow() abort + return ctrlsf#win#FocusWindow(s:PREVIEW_BUF_NAME) +endf + diff --git a/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/utils.vim b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/utils.vim new file mode 100644 index 0000000000..ccf89b6102 --- /dev/null +++ b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/utils.vim @@ -0,0 +1,70 @@ +" ============================================================================ +" Description: An ack/ag powered code search and view tool. +" Author: Ye Ding +" Licence: Vim licence +" Version: 1.10 +" ============================================================================ + +""""""""""""""""""""""""""""""""" +" Misc Functions +""""""""""""""""""""""""""""""""" +" Mirror() +" +" Make {dicta} as an exact shallow copy of {dictb} +" +func! ctrlsf#utils#Mirror(dicta, dictb) abort + for key in keys(a:dicta) + call remove(a:dicta, key) + endfo + + for key in keys(a:dictb) + let a:dicta[key] = a:dictb[key] + endfo + + return a:dicta +endf + +""""""""""""""""""""""""""""""""" +" Airline Support +""""""""""""""""""""""""""""""""" + +" SectionB() +" +" Show current search pattern +" +func! ctrlsf#utils#SectionB() + return 'Pattern: ' . ctrlsf#opt#GetOpt('pattern') +endf + +" SectionC() +" +" Show filename of which cursor is currently placed in +" +func! ctrlsf#utils#SectionC() + let [file, _, _] = ctrlsf#view#Reflect(line('.')) + return empty(file) ? '' : file +endf + +" SectionX() +" +" Show total number of matches and current matching +" +func! ctrlsf#utils#SectionX() + let [file, line, match] = ctrlsf#view#Reflect(line('.')) + if !empty(match) + let matchlist = ctrlsf#db#MatchList() + let total = len(matchlist) + let current = index(matchlist, match) + 1 + return current . '/' . total + else + return '' + endif +endf + +" PreviewSectionC() +" +" Show previewing file's name +" +func! ctrlsf#utils#PreviewSectionC() + return get(b:, 'ctrlsf_file', '') +endf diff --git a/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/view.vim b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/view.vim new file mode 100644 index 0000000000..9240de6461 --- /dev/null +++ b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/view.vim @@ -0,0 +1,212 @@ +" ============================================================================ +" Description: An ack/ag powered code search and view tool. +" Author: Ye Ding +" Licence: Vim licence +" Version: 1.10 +" ============================================================================ + +func! s:Summary(resultset) abort + let files = len(ctrlsf#db#FileSet()) + let matches = len(ctrlsf#db#MatchList()) + return [printf("%s matched lines across %s files", matches, files)] +endf + +func! s:Filename(paragraph) abort + " empty line + filename + return ["", a:paragraph.file . ":"] +endf + +func! s:Ellipsis() abort + return [repeat(".", 4)] +endf + +func! s:Line(line) abort + let out = a:line.lnum . (a:line.matched() ? ':' : '-') + let out .= repeat(' ', ctrlsf#view#Indent() - len(out)) + let out .= a:line.content + return [out] +endf + +func! ctrlsf#view#Indent() abort + let maxlnum = ctrlsf#db#MaxLnum() + return strlen(string(maxlnum)) + 1 + g:ctrlsf_indent +endf + +" Render() +" +" Return rendered view of current resultset. +" +func! ctrlsf#view#Render() abort + let resultset = ctrlsf#db#ResultSet() + let cur_file = '' + + let view = [] + + " append summary + call extend(view, s:Summary(resultset)) + + for par in resultset + if cur_file !=# par.file + let cur_file = par.file + call extend(view, s:Filename(par)) + else + call extend(view, s:Ellipsis()) + endif + + for line in par.lines + call extend(view, s:Line(line)) + + let line.vlnum = len(view) + + if line.matched() + let line.match.vlnum = len(view) + let line.match.vcol = line.match.col + ctrlsf#view#Indent() + endif + endfo + endfo + + return join(view, "\n") +endf + +" Reflect() +" +" Find resultset which is corresponding the given line. +" +" Parameters +" {vlnum} number of a line within rendered view +" +" Returns +" [file, line, match] if corresponding line contains one or more matches +" [file, line, {}] if corresponding line doesn't contains any match +" ['', {}, {}] if no corresponding line is found +" +func! ctrlsf#view#Reflect(vlnum) abort + let resultset = ctrlsf#db#ResultSet() + + " TODO: use binary search for better performance + let ret = ['', {}, {}] + for par in resultset + if a:vlnum < par.vlnum() + break + endif + + " if there is a corresponding line + if a:vlnum <= par.vlnum() + par.range() - 1 + " fetch file + let ret[0] = par.file + + " fetch line object + let line = par.lines[a:vlnum - par.vlnum()] + let ret[1] = line + + " fetch match object + if line.matched() + let ret[2] = line.match + endif + + break + endif + endfo + + call ctrlsf#log#Debug("Reflect: vlnum: %s, result: %s", a:vlnum, string(ret)) + return ret +endf + +" FindNextMatch() +" +" Find next match. Wrapping around or not depends on value of 'wrapscan'. +" +" Parameters +" {vlnum} the line number of search base +" {forward} true or false +" +" Returns +" [vlnum, vcol] line number and column number of next match +" +func! ctrlsf#view#FindNextMatch(vlnum, forward) abort + let regex = ctrlsf#pat#MatchPerLineRegex() + let flag = a:forward ? 'n' : 'nb' + return searchpos(regex, flag) +endf + +" s:DerenderParagraph() +" +func! s:DerenderParagraph(buffer, file) abort + let paragraph = { + \ 'file' : a:file, + \ 'lnum' : function("ctrlsf#class#paragraph#Lnum"), + \ 'vlnum' : function("ctrlsf#class#paragraph#Vlnum"), + \ 'range' : function("ctrlsf#class#paragraph#Range"), + \ 'lines' : [], + \ 'matches' : function("ctrlsf#class#paragraph#Matches"), + \ } + + let indent = ctrlsf#view#Indent() + + for line in a:buffer + call add(paragraph.lines, { + \ 'matched' : function("ctrlsf#class#line#Matched"), + \ 'match' : -1, + \ 'lnum' : -1, + \ 'vlnum' : -1, + \ 'content': strpart(line, indent), + \ }) + endfo + + return paragraph +endf + +" Derender() +" +" Return a pseudo-fileset which is derendered from {content}. +" +func! ctrlsf#view#Derender(content) abort + let lines = type(a:content) == 3 ? a:content : split(a:content, "\n") + + let fileset = [] + + let current_file = '' + let next_file = '' + + let i = 0 + while i < len(lines) + let buffer = [] + + while i < len(lines) + let line = lines[i] + let i += 1 + + if line ==# '....' || line ==# '' + break + elseif line !~ '\v^\d+[:-]' + " strip trailing colon + let next_file = substitute(line, ':$', '', '') + break + else + call add(buffer, line) + endif + endwh + + if len(buffer) > 0 + let paragraph = s:DerenderParagraph(buffer, current_file) + + " if derender failed, throw an exception + if empty(paragraph.file) + throw 'BrokenBufferException' + endif + + if len(fileset) > 0 && fileset[-1].file ==# paragraph.file + call add(fileset[-1].paragraphs, paragraph) + else + call add(fileset, { + \ 'file': paragraph.file, + \ 'paragraphs': [ paragraph ], + \ }) + endif + endif + + let current_file = next_file + endwh + + return fileset +endf diff --git a/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/win.vim b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/win.vim new file mode 100644 index 0000000000..19da1debc1 --- /dev/null +++ b/sources_non_forked/ctrlsf.vim/autoload/ctrlsf/win.vim @@ -0,0 +1,318 @@ +" ============================================================================ +" Description: An ack/ag powered code search and view tool. +" Author: Ye Ding +" Licence: Vim licence +" Version: 1.10 +" ============================================================================ + +" ctrlsf buffer's name +let s:MAIN_BUF_NAME = "__CtrlSF__" + +" window which brings up ctrlsf window +let s:caller_win = { + \ 'bufnr' : -1, + \ 'winnr' : -1, + \ } + +""""""""""""""""""""""""""""""""" +" Open & Close +""""""""""""""""""""""""""""""""" + +" OpenMainWindow() +" +func! ctrlsf#win#OpenMainWindow() abort + " backup current bufnr and winnr + let s:caller_win = { + \ 'bufnr' : bufnr('%'), + \ 'winnr' : winnr(), + \ } + + " try to focus an existing ctrlsf window, initialize a new one if failed + if ctrlsf#win#FocusMainWindow() != -1 + return + endif + + " backup width/height of other windows + " be sure doing this only when *opening new window* + call ctrlsf#win#BackupAllWinSize() + + if g:ctrlsf_winsize =~ '\d\{1,2}%' + if g:ctrlsf_position == "left" || g:ctrlsf_position == "right" + let winsize = &columns * str2nr(g:ctrlsf_winsize) / 100 + else + let winsize = &lines * str2nr(g:ctrlsf_winsize) / 100 + endif + elseif g:ctrlsf_winsize =~ '\d\+' + let winsize = str2nr(g:ctrlsf_winsize) + else + if g:ctrlsf_position == "left" || g:ctrlsf_position == "right" + let winsize = &columns / 2 + else + let winsize = &lines / 2 + endif + endif + + let openpos = { + \ 'top' : 'topleft', 'left' : 'topleft vertical', + \ 'bottom' : 'botright', 'right' : 'botright vertical'} + \[g:ctrlsf_position] . ' ' + exec 'silent keepalt ' . openpos . winsize . 'split ' . '__CtrlSF__' + + call s:InitMainWindow() + + " resize other windows + wincmd = +endf + +" Draw() +" +func! ctrlsf#win#Draw() abort + let content = ctrlsf#view#Render() + silent! undojoin | keepjumps call ctrlsf#buf#WriteString(content) +endf + +" CloseMainWindow() +" +func! ctrlsf#win#CloseMainWindow() abort + if ctrlsf#win#FocusMainWindow() == -1 + return + endif + + " Surely we are in CtrlSF window + close + + " restore width/height of other windows + call ctrlsf#win#RestoreAllWinSize() + + call ctrlsf#win#FocusCallerWindow() +endf + +" InitMainWindow() +func! s:InitMainWindow() abort + setl filetype=ctrlsf + setl noreadonly + setl buftype=acwrite + setl bufhidden=hide + setl noswapfile + setl nobuflisted + setl nolist + setl nonumber + setl nowrap + setl winfixwidth + setl winfixheight + setl textwidth=0 + setl nospell + setl nofoldenable + + call ctrlsf#hl#HighlightMatch('ctrlsfMatch') + + " map + let act_func_ref = { + \ "open" : "ctrlsf#JumpTo('o')", + \ "openb" : "ctrlsf#JumpTo('O')", + \ "tab" : "ctrlsf#JumpTo('t')", + \ "tabb" : "ctrlsf#JumpTo('T')", + \ "prevw" : "ctrlsf#JumpTo('p')", + \ "quit" : "ctrlsf#Quit()", + \ "next" : "ctrlsf#NextMatch(1)", + \ "prev" : "ctrlsf#NextMatch(0)", + \ } + + for act in keys(act_func_ref) + if !empty(g:ctrlsf_mapping[act]) + exec "nnoremap " . g:ctrlsf_mapping[act] + \ . " :call " . act_func_ref[act] . "" + endif + endfo + + " autocmd + augroup ctrlsf + au! + au BufWriteCmd call ctrlsf#Save() + au BufHidden,BufUnload call ctrlsf#buf#UndoAllChanges() + augroup END +endf + + +""""""""""""""""""""""""""""""""" +" Window Navigation +""""""""""""""""""""""""""""""""" + +" FindWindow() +" +func! ctrlsf#win#FindWindow(buf_name) abort + return bufwinnr(a:buf_name) +endf + +" FocusWindow() +" +" Parameters +" {exp} buffer name OR window number +" +func! ctrlsf#win#FocusWindow(exp) abort + if type(a:exp) == 0 + let winnr = a:exp + else + let winnr = ctrlsf#win#FindWindow(a:exp) + endif + + if winnr < 0 + return -1 + endif + + exec winnr . 'wincmd w' + return winnr +endf + +" FindMainWindow() +" +func! ctrlsf#win#FindMainWindow() abort + return ctrlsf#win#FindWindow(s:MAIN_BUF_NAME) +endf + +" FocusMainWindow() +" +func! ctrlsf#win#FocusMainWindow() abort + return ctrlsf#win#FocusWindow(s:MAIN_BUF_NAME) +endf + +" FindCallerWindow() +" +func! ctrlsf#win#FindCallerWindow() abort + let ctrlsf_winnr = ctrlsf#win#FindMainWindow() + if ctrlsf_winnr > 0 && ctrlsf_winnr <= s:caller_win.winnr + return s:caller_win.winnr + 1 + else + return s:caller_win.winnr + endif +endf + +" FocusCallerWindow() +" +func! ctrlsf#win#FocusCallerWindow() abort + let caller_winnr = ctrlsf#win#FindCallerWindow() + if ctrlsf#win#FocusWindow(caller_winnr) == -1 + wincmd p + endif +endf + +" FindTargetWindow() +" +func! ctrlsf#win#FindTargetWindow(file) abort + let target_winnr = bufwinnr(a:file) + + " case: there is a window containing the target file + if target_winnr > 0 + return target_winnr + endif + + " case: previous window where ctrlsf was triggered + let target_winnr = s:caller_win.winnr + + let ctrlsf_winnr = ctrlsf#win#FindMainWindow() + if ctrlsf_winnr > 0 && ctrlsf_winnr <= target_winnr + let target_winnr += 1 + endif + + let preview_winnr = ctrlsf#preview#FindPreviewWindow() + if preview_winnr > 0 && preview_winnr <= target_winnr + let target_winnr += 1 + endif + + if winbufnr(target_winnr) == s:caller_win.bufnr + \ && empty(getwinvar(target_winnr, '&buftype')) + return target_winnr + endif + + " case: pick up the first window containing regular file + let nr = 1 + while nr <= winnr('$') + if empty(getwinvar(nr, '&buftype')) + return nr + endif + let nr += 1 + endwh + + " case: can't find any valid window, tell front to open a new window + return 0 +endf + +""""""""""""""""""""""""""""""""" +" Cursor +""""""""""""""""""""""""""""""""" +" MoveCursor() +" +" Redraw, let {wlnum} be the top of window and place cursor at {lnum}, {col}. +" +" {wlnum} number of the top line in window +" {lnum} line number of cursor +" {col} column number of cursor +" +func! ctrlsf#win#MoveCursor(wlnum, lnum, col) abort + " Move cursor to specific position, and window stops at {wlnum} line + exec 'keepjumps normal ' . a:wlnum . "z\r" + call cursor(a:lnum, a:col) + + " Open fold + normal zv +endf + +" MoveCentralCursor() +" +func! ctrlsf#win#MoveCentralCursor(lnum, col) abort + " Move cursor to specific position + exec 'keepjumps normal ' . a:lnum . 'z.' + call cursor(a:lnum, a:col) + + " Open fold + normal zv +endf + +""""""""""""""""""""""""""""""""" +" Backup & Restore Window Size +""""""""""""""""""""""""""""""""" +" BackupAllWinSize() +" +" Purpose of BackupAllWinSize() and RestoreAllWinSize() is to restore +" width/height of fixed sized windows such like NERDTree's. As a result, we only +" backup width/height of fixed window's to keep least side effects. +" +func! ctrlsf#win#BackupAllWinSize() + let nr = 1 + while winbufnr(nr) != -1 + if getwinvar(nr, '&winfixwidth') || getwinvar(nr, '&winfixheight') + if type(getwinvar(nr, 'ctrlsf_winwidth_bak')) != 3 + call setwinvar(nr, 'ctrlsf_winwidth_bak', []) + endif + call add(getwinvar(nr, 'ctrlsf_winwidth_bak'), winwidth(nr)) + + if type(getwinvar(nr, 'ctrlsf_winheight_bak')) != 3 + call setwinvar(nr, 'ctrlsf_winheight_bak', []) + endif + call add(getwinvar(nr, 'ctrlsf_winheight_bak'), winheight(nr)) + endif + let nr += 1 + endwh +endf + +" RestoreAllWinSize() +" +func! ctrlsf#win#RestoreAllWinSize() + let nr = 1 + while winbufnr(nr) != -1 + if getwinvar(nr, '&winfixwidth') || getwinvar(nr, '&winfixheight') + exec nr . 'wincmd w' + + let width_stack = getwinvar(nr, 'ctrlsf_winwidth_bak') + if type(width_stack) == 3 && !empty(width_stack) + exec "vertical resize " . remove(width_stack, -1) + endif + + let height_stack = getwinvar(nr, 'ctrlsf_winheight_bak') + if type(height_stack) == 3 && !empty(height_stack) + exec "resize " . remove(height_stack, -1) + endif + endif + let nr += 1 + endwh +endf diff --git a/sources_non_forked/ctrlsf.vim/description.txt b/sources_non_forked/ctrlsf.vim/description.txt new file mode 100644 index 0000000000..b6ea30e878 --- /dev/null +++ b/sources_non_forked/ctrlsf.vim/description.txt @@ -0,0 +1,36 @@ +detailed description: + +An ack/ag powered code search and view tool, like ack.vim or `:vimgrep` but together with more context, and let you edit in-place with powerful edit mode. + + +Project repository: https://github.com/dyng/ctrlsf.vim + +(Please view above github link for comprehensive demo.) + + +Features: + +* Search and display result in a user friendly view with customizable context. + +* Edit mode which is incredible useful when you are doing refactoring. (Inspired by vim-ags) + +* Preview mode for fast exploring. + +* Various options for more detailed search, view and edit. + +------------------------------------------------------------------------------- + +install details: + +1. Good old way: + +Extract the archive to ~/.vim on Linux/MacOSX or $HOME\vimfiles on Windows. +Run :helptags ~/.vim/doc or :helptags $HOME\vimfiles\doc + +2. Modern way: + +Use package manager like pathogen, vundle or neobundle. + +Take vundle for example: + + Bundle 'dyng/ctrlsf.vim' diff --git a/sources_non_forked/ctrlsf.vim/doc/ctrlsf.txt b/sources_non_forked/ctrlsf.vim/doc/ctrlsf.txt new file mode 100644 index 0000000000..346d46a24a --- /dev/null +++ b/sources_non_forked/ctrlsf.vim/doc/ctrlsf.txt @@ -0,0 +1,417 @@ +*ctrlsf.txt* A code search and view tool. *CtrlSF* *'ctrlsf'* + +Author: Ye Ding +Licence: Vim licence, see |license| +Version: 1.10 + + + .-') _ _ .-') .-') + ( OO) ) ( \( -O ) ( OO ). + .-----./ '._ ,------. ,--. (_)---\_) ,------. + ' .--./|'--...__)| /`. ' | |.-') / _ | ('-| _.---' + | |('-.'--. .--'| / | | | | OO )\ :` `. (OO|(_\ + /_) |OO ) | | | |_.' | | |`-' | '..`''.)/ | '--. + || |`-'| | | | . '.'(| '---.'.-._) \\_)| .--' +(_' '--'\ | | | |\ \ | | \ / \| |_) + `-----' `--' `--' '--' `------' `-----' `--' + + +================================================================================ +Contents *ctrlsf-contents* + + 1. Intro ........................... |ctrlsf-intro| + 2. Usage ........................... |ctrlsf-usage| + 2.1 Quick Start ................ |ctrlsf-quickstart| + 2.2 Edit Mode .................. |ctrlsf-edit-mode| + 2.3 Examples ................... |ctrlsf-examples| + 3. Commands ........................ |ctrlsf-commands| + 4. Key Maps ........................ |ctrlsf-keymaps| + 5. Arguments ....................... |ctrlsf-arguments| + 6. Options ......................... |ctrlsf-options| + 7. About ........................... |ctrlsf-about| + +================================================================================ +1. Intro *ctrlsf-intro* + +CtrlSF is a tool for project-wide code search and view. It uses ack/ag as its +backend, parses the search result and displays the result in a user-friendly +format. It is developed as an alternative for ack.vim and ag.vim, and as its +name implies, it is inspired by 'Find in Files...' command in Sublime Text 2, +whose shortcut is 'Ctrl+Shift+F'. + +An example of CtrlSF search result is like this: +> + autoload/ctrlsf.vim: + 60- func! s:Init() + 61- if !exists('g:ctrlsf_open_left') + 62- let g:ctrlsf_open_left = 1 + 63: endif + 64- + 65- if !exists('g:ctrlsf_ackprg') + 66- let g:ctrlsf_ackprg = s:DetectAckprg() +< + +================================================================================ +2. Usage *ctrlsf-usage* + +-------------------------------------------------------------------------------- +2.1 Quick Start *ctrlsf-quickstart* + +A typical workflow using CtrlSF is like this: + + 1. Run |:CtrlSF| to invoke a search. In most cases you may just want to search + a literal string, it's as easy like this +> + :CtrlSF {string} +< + Then CtrlSF will split a new window to show you result. + + 2. Use and other keys to navigate through result, also there + are two handy maps and that can move forward to next match or + backward to previous match. + + 3. Press if you want to open corresponding file of line under + cursor. + + 4. Or you may need more context, press

to open that file in an individual + preview window. + + 5. Or press to quit. + + 6. |:CtrlSFOpen| can reopen CtrlSF window when you have closed CtrlSF window. + It is free because it won't invoke a same but new search. A useful command + |:CtrlSFToggle| is also available. + +-------------------------------------------------------------------------------- +2.2 Edit Mode *ctrlsf-edit-mode* + +CtrlSF has an edit mode, in which you can modify result buffer and immediately +apply those changes to files on disk. The following steps show how to use edit +mode: + + 1. Search some word to bring up CtrlSF. + + 2. Edit as you like in result buffer, and when your change is done, save it + by |:w|. + + 3. CtrlSF will ask you for confirmation about how many files will be + affected, and if you are sure, input |'y'| or just press |Enter|. + + 4. All changes then are saved to files. You can find result buffer is also + updated to the latest version of files. + + 5. If you change your mind later, you can always undo it by pressing + |u| and saving result buffer again. + +-------------------------------------------------------------------------------- +2.3 Examples *ctrlsf-examples* + + 1. Search in a specific sub-directory +> + :CtrlSF {pattern} /path/to/dir +< + 2. Search case-insensitivly +> + :CtrlSF -I {pattern} +< + 3. Search with regular expression +> + :CtrlSF -R {regex} +< + 4. Show result with specific context setting +> + :CtrlSF -A 3 -B 1 {pattern} +< + 5. Search in files of specific type +> + :CtrlSF --filetype cpp {pattern} +< +================================================================================ +3. Commands *ctrlsf-commands* + +:CtrlSF [arguments] {pattern} [path] ... *:CtrlSF* + + Search {pattern}. Default is search by literal. Show result in a new CtrlSF + window if there is no existing one, otherwise reuse that one. + + [arguments] are all valid CtrlSF arguments, see |ctrlsf-arguments| for what + they are. + + [path] is one or more directories/files where CtrlSF will search. If nothing + is given, the default directory is used, which is specified by + |g:ctrlsf_default_root|. + +:CtrlSFOpen *:CtrlSFOpen* + + If CtrlSF window is closed (by or |:CtrlSFClose|), reopen it. If the + window is already on display, then focus it. + +:CtrlSFUpdate *:CtrlSFUpdate* + + Update CtrlSF result by invoking a new search with same arguments and pattern + of last one. + +:CtrlSFClose *:CtrlSFClose* + + Close an existing CtrlSF window. If there is no active CtrlSF window, do + nothing. + +:CtrlSFClearHL *:CtrlSFClearHL* + + If you have turned on |g:ctrlsf_selected_line_hl|, use this command to clear + highlighting on the selected line. + +:CtrlSFToggle *:CtrlSFToggle* + + Open the CtrlSF window if it is closed, or vice versa. + +================================================================================ +4. Key Maps *ctrlsf-keymaps* + + Maps to launch CtrlSF: + + CtrlSFPrompt Input 'CtrlSF' in command line and waiting, just a + handy shortcut. + + CtrlSFVwordPath Input current visual selected word in command line + and waiting for any other user input. + + CtrlSFVwordExec Similar to above, but execute it immediately. + + CtrlSFCwordPath Input word in the cursor in command line and + waiting. + + CtrlSFCwordExec Similar to above, but execute it immediately. + + CtrlSFPwordPath Input last search pattern in command line and + waiting. + + CtrlSFPwordExec Similar to above, but execute it immediately. + + Maps by default in CtrlSF window: + + Open file which contains the line under cursor. + +

Open a preview window to view file. + + Like , but always leave CtrlSF window open. + + Like , but focus CtrlSF window instead of opened new tab. + + Quit CtrlSF. Also close preview window if any. + + Move cursor to next match. + + Move cursor to previous match. + + Maps by default in preview window: + + Quit preview mode. + +================================================================================ +5. Arguments *ctrlsf-arguments* + +'-after', '-A' *ctrlsf_args_A* *ctrlsf_args_after* + +Defines how many lines after the matching line will be printed. '-A' is an +alias for '-after'. +> + :CtrlSF -A 10 foo +< +'-before', '-B' *ctrlsf_args_B* *ctrlsf_args_before* + +Defines how many lines before the matching line will be printed. '-B' is an +alias for '-before'. +> + :CtrlSF -B 5 foo +< +'-context', '-C' *ctrlsf_args_C* *ctrlsf_args_context* + +Defines how many lines around the matching line will be printed. '-C' is an +alias for '-context'. +> + :CtrlSF -C 0 foo +< +'-filetype' *ctrlsf_args_filetype* + +Defines which type of files should the search be restricted to. view +`ack --help=typs` for all available types. +> + :CtrlSF -filetype vim foo +< +'-ignorecase', '-I' *ctrlsf_args_I* *ctrlsf_args_ignorecase* + +Make this search be case-insensitive. +> + :CtrlSF -I foo +< +'-literal', '-L' *ctrlsf_args_L* *ctrlsf_args_literal* + +Use pattern as literal string. +> + :CtrlSF -L foo.* +< +'-matchcase', '-S' *ctrlsf_args_S* *ctrlsf_args_matchcase* + +Make this search be case-sensitive. +> + :CtrlSF -S Foo +< +'-regex', '-R' *ctrlsf_args_R* *ctrlsf_args_regex* + +Use pattern as regular expression. +> + :CtrlSF -R foo.* +< +'-smartcase' *ctrlsf_args_smartcase* + +Make this search be smart-cased. +> + :CtrlSF -smartcase Foo +< +================================================================================ +6. Options *ctrlsf-options* + +g:ctrlsf_ackprg *'g:ctrlsf_ackprg'* +Default: auto +'g:ctrlsf_ackprg' defines the path of ack/ag which CtrlSF will use as its +backend. If nothing is given, CtrlSF will try 'ag' first and fallback to +'ack' if 'ag' is not available. You can also explicitly set it by +> + let g:ctrlsf_ackprg = '/usr/local/bin/ag' +< +g:ctrlsf_auto_close *'g:ctrlsf_auto_close'* +Default: 1 +'g:ctrlsf_auto_close' defines how CtrlSF handle itself after you have opened +a file from CtrlSF window. By default CtrlSF will close itself but you can +prevent this behavior by setting this option to 0 +> + let g:ctrlsf_auto_close = 0 +< +g:ctrlsf_case_sensitive *'g:ctrlsf_case_sensitive'* +Default: 'smart' +Defines the default case-sensitivity in search. Possible values are 'yes', +'no' and 'smart'. 'yes' and 'no' works exactly as its meaning. 'smart' means +smart-case, which is as same as it is in Vim. +> + let g:ctrlsf_case_sensitive = 'no' +< +g:ctrlsf_confirm_save *'g:ctrlsf_confirm_save'* +Default: 1 +Confirm before saving your changes to file. If you are tired of typing 'yes', +you can turn off this confirmation by +> + let g:ctrlsf_confirm_save = 0 +< +g:ctrlsf_context *'g:ctrlsf_context'* +Default: '-C 3' +Defines how many lines around the matching line will be printed. Use same format +as its counterpart in Ag/Ack. +> + let g:ctrlsf_context = '-B 5 -A 3' +< +g:ctrlsf_debug_mode *'g:ctrlsf_debug_mode'* +Default: 0 +Verbose informations will be printed if you turn this option on. It's useful +when something does not work as you expected. +> + let g:ctrlsf_debug_mode = 1 +< +g:ctrlsf_default_root *'g:ctrlsf_default_root'* +Default: 'cwd' +Defines how CtrlSF works if no explicit search path is given. Possible value +is 'cwd' and 'project'. With 'cwd', CtrlSF uses current working directory as +its search root. With 'project', CtrlSF will try to find project root of +current file and use it. A project root is a directory which VCS folder is +placed in, currently CtrlSF can recogonize .git, .hg, .svn, .bzr, _darcs. +> + let g:ctrlsf_default_root = 'project' +< +g:ctrlsf_indent *'g:ctrlsf_indent'* +Default: 4 +Defines how many spaces are places between line number and line content. You +can set a sane small value for more compact view. +> + let g:ctrlsf_indent = 2 +< +g:ctrlsf_mapping *'g:ctrlsf_mapping'* +Defines keys for mapping in result window. Sometimes you may find default +mapping of CtrlSF conflict with keys you have been used to sometimes, especially +in editing. Then you can change default mapping by setting this option. A +subset of available methods is valid, those unspecified methods will use default +keys. You can also disable a method by mapping it to an empty string. + +Default: +> + { + "open" : "", + "openb" : "O", + "tab" : "t", + "tabb" : "T", + "prevw" : "p", + "quit" : "q", + "next" : "", + "prev" : "", + "pquit" : "q", + } +< +Example: +> + let g:ctrlsf_mapping = { + \ "next": "n", + \ "prev": "N", + \ "openb": "", + \ } +< +g:ctrlsf_position *'g:ctrlsf_position'* +Default: 'left' +By default CtrlSF window will be opened at left. You can also specify for it to +be opened 'above', 'right', or 'below'. E.g.: +> + let g:ctrlsf_position = 'below' +< +g:ctrlsf_regex_pattern *'g:ctrlsf_regex_pattern'* +Default: 0 +Default case-sensitivity used in search. Default value 0 means CtrlSF search +pattern literally, if you want CtrlSF use regular expression by default (like +Ack/Ag), you can set it to 1. +> + let g:ctrlsf_regex_pattern = 1 +< +g:ctrlsf_selected_line_hl *'g:ctrlsf_selected_line_hl'* +Default: 'p' +Highlight matching line in the target file. It is useful especially in preview +mode. The value of this option is a flag-map including following valid +flags: +> + 'o' : highlight matching line in the target file after file is opened. + 'p' : highlight matching line in preview window. +< +If you want to enable this feature both in preview window and actual file, you +can set it as +> + let g:ctrlsf_selected_line_hl = 'op' +< +g:ctrlsf_winsize *'g:ctrlsf_width'* +Default: 'auto' +Size of CtrlSF window. This is its width if the window opens vertically (to the +left or right), or height if it opens horizontally (above or below). It accepts +string as its value and there are 3 types of argument: +> + 'auto' : half of current vim window size. + 'xx%' : xx percent of current vim window size. + 'xx' : absolute size in characters. +< +Example: +> + let g:ctrlsf_winsize = '30%' +< +================================================================================ +7. About *ctrlsf-about* + +CtrlSF was initially written by Ye Ding and released +under the Vim licence, see |licence|. The original author have learned a lot of +things from reading source of Tagbar, thanks to Jan Larres the author of Tagbar! + +================================================================================ + vim: tw=78 ts=8 sw=4 sts=4 et ft=help diff --git a/sources_non_forked/ctrlsf.vim/plugin/ctrlsf.vim b/sources_non_forked/ctrlsf.vim/plugin/ctrlsf.vim new file mode 100644 index 0000000000..4db446b5a2 --- /dev/null +++ b/sources_non_forked/ctrlsf.vim/plugin/ctrlsf.vim @@ -0,0 +1,205 @@ +" ============================================================================ +" Description: An ack/ag powered code search and view tool. +" Author: Ye Ding +" Licence: Vim licence +" Version: 1.10 +" ============================================================================ + +" Loading Guard {{{1 +if exists('g:ctrlsf_loaded') && !get(g:, 'ctrlsf_debug_mode', 0) + finish +endif +let g:ctrlsf_loaded = 1 +" }}} + +" Utils {{{1 +" s:VisualSelection() {{{ +" Thanks to xolox! +" http://stackoverflow.com/questions/1533565/how-to-get-visually-selected-text-in-vimscript +func! s:VisualSelection() abort + " Why is this not a built-in Vim script function?! + let [lnum1, col1] = getpos("'<")[1:2] + let [lnum2, col2] = getpos("'>")[1:2] + let lines = getline(lnum1, lnum2) + let lines[-1] = lines[-1][: col2 - (&selection == 'inclusive' ? 1 : 2)] + let lines[0] = lines[0][col1 - 1:] + return join(lines, "\n") +endf +" }}} + +" g:CtrlSFGetVisualSelection() {{{2 +func! g:CtrlSFGetVisualSelection() + let selection = s:VisualSelection() + + " A conditional process is needed because string("'") will return '''' + " but our option parser can't parse it properly + " + " Isn't the else clause unnecessary? Yes, but I prefer plain text :) + if selection =~# "'" + return '"' . escape(selection, ' \"') . '"' + elseif selection =~# '[ \"]' + return string(selection) + else + return selection + endif +endf +" }}} + +" s:SearchCwordCmd() {{{2 +func! s:SearchCwordCmd(to_exec) + let cmd = ":\CtrlSF " . expand('') + let cmd .= a:to_exec ? "\r" : " " + return cmd +endf +" }}} + +" s:SearchVwordCmd() {{{2 +" Within evaluation of a expression typed visual map, we can not get +" current visual selection normally, so I need to workaround it. +func! s:SearchVwordCmd(to_exec) + let keys = '":\CtrlSF " . g:CtrlSFGetVisualSelection()' + let keys .= a:to_exec ? '."\r"' : '." "' + let cmd = ":\call feedkeys(" . keys . ", 'n')\r" + return cmd +endf +" }}} + +" s:SearchPwordCmd() {{{2 +func! s:SearchPwordCmd(to_exec) + let cmd = ":\CtrlSF " . @/ + let cmd .= a:to_exec ? "\r" : " " + return cmd +endf +" }}} +" }}} + +" Options {{{1 +" g:ctrlsf_ackprg {{{2 +if !exists('g:ctrlsf_ackprg') + let g:ctrlsf_ackprg = ctrlsf#backend#Detect() +endif +" }}} + +" g:ctrlsf_auto_close {{{2 +if !exists('g:ctrlsf_auto_close') + let g:ctrlsf_auto_close = 1 +endif +" }}} + +" g:ctrlsf_case_sensitive {{{2 +if !exists('g:ctrlsf_case_sensitive') + let g:ctrlsf_case_sensitive = 'smart' +endif +" }}} + +" g:ctrlsf_confirm_save {{{2 +if !exists('g:ctrlsf_confirm_save') + let g:ctrlsf_confirm_save = 1 +endif +" }}} + +" g:ctrlsf_context {{{2 +if !exists('g:ctrlsf_context') + let g:ctrlsf_context = '-C 3' +endif +" }}} + +" g:ctrlsf_debug_mode {{{2 +if !exists('g:ctrlsf_debug_mode') + let g:ctrlsf_debug_mode = 0 +endif +" }}} + +" g:ctrlsf_default_root {{{2 +if !exists('g:ctrlsf_default_root') + let g:ctrlsf_default_root = 'cwd' +endif +" }}} + +" g:ctrlsf_indent {{{2 +if !exists('g:ctrlsf_indent') + let g:ctrlsf_indent = 4 +endif +" }}} + +" g:ctrlsf_mapping {{{ +let s:default_mapping = { + \ "open" : "", + \ "openb" : "O", + \ "tab" : "t", + \ "tabb" : "T", + \ "prevw" : "p", + \ "quit" : "q", + \ "next" : "", + \ "prev" : "", + \ "pquit" : "q", + \ } + +if !exists('g:ctrlsf_mapping') + let g:ctrlsf_mapping = s:default_mapping +else + for key in keys(s:default_mapping) + let g:ctrlsf_mapping[key] = get(g:ctrlsf_mapping, key, + \ s:default_mapping[key]) + endfo +endif +" }}} + +" g:ctrlsf_position {{{2 +if !exists('g:ctrlsf_position') + " [left], right, top, bottom + if exists('g:ctrlsf_open_left') + if g:ctrlsf_open_left + let g:ctrlsf_position = 'left' + else + let g:ctrlsf_position = 'right' + endif + else + let g:ctrlsf_position = 'left' + endif +endif +" }}} + +" g:ctrlsf_regex_pattern {{{2 +if !exists('g:ctrlsf_regex_pattern') + let g:ctrlsf_regex_pattern = 0 +endif +" }}} + +" g:ctrlsf_selected_line_hl {{{2 +if !exists('g:ctrlsf_selected_line_hl') + let g:ctrlsf_selected_line_hl = 'p' +endif +" }}} + +" g:ctrlsf_winsize {{{2 +if !exists('g:ctrlsf_winsize') + if exists('g:ctrlsf_width') + let g:ctrlsf_winsize = g:ctrlsf_width + endif + let g:ctrlsf_winsize = 'auto' +endif +" }}} +" }}} + +" Commands {{{1 +com! -n=* -comp=customlist,ctrlsf#comp#Completion CtrlSF call ctrlsf#Search() +com! -n=0 CtrlSFOpen call ctrlsf#Open() +com! -n=0 CtrlSFUpdate call ctrlsf#Update() +com! -n=0 CtrlSFClose call ctrlsf#Quit() +com! -n=0 CtrlSFClearHL call ctrlsf#ClearSelectedLine() +com! -n=0 CtrlSFToggle call ctrlsf#Toggle() +" }}} + +" Maps {{{1 +nnoremap CtrlSFPrompt :CtrlSF +nnoremap CtrlSFCwordPath SearchCwordCmd(0) +nnoremap CtrlSFCwordExec SearchCwordCmd(1) +vnoremap CtrlSFVwordPath SearchVwordCmd(0) +vnoremap CtrlSFVwordExec SearchVwordCmd(1) +nnoremap CtrlSFPwordPath SearchPwordCmd(0) +nnoremap CtrlSFPwordExec SearchPwordCmd(1) +" }}} + +" modeline {{{1 +" vim: set foldmarker={{{,}}} foldlevel=0 foldmethod=marker spell: diff --git a/sources_non_forked/ctrlsf.vim/syntax/ctrlsf.vim b/sources_non_forked/ctrlsf.vim/syntax/ctrlsf.vim new file mode 100644 index 0000000000..5cb6633058 --- /dev/null +++ b/sources_non_forked/ctrlsf.vim/syntax/ctrlsf.vim @@ -0,0 +1,24 @@ +" ============================================================================ +" Description: An ack/ag powered code search and view tool. +" Author: Ye Ding +" Licence: Vim licence +" Version: 1.10 +" ============================================================================ + +if exists('b:current_syntax') + finish +endif + +syntax case match +syntax match ctrlsfFilename /^.*\ze:$/ +syntax match ctrlsfLnumMatch /^\d\+:/ +syntax match ctrlsfLnumUnmatch /^\d\+-/ +syntax match ctrlsfCuttingLine /^\.\+$/ + +hi def link ctrlsfFilename Title +hi def link ctrlsfMatch MatchParen +hi def link ctrlsfLnumMatch SignColumn +hi def link ctrlsfLnumUnmatch LineNr +hi def link ctrlsfSelectedLine Visual + +let b:current_syntax = 'ctrlsf' diff --git a/sources_non_forked/goyo.vim/autoload/goyo.vim b/sources_non_forked/goyo.vim/autoload/goyo.vim index b790e8930b..9d3d1eb569 100644 --- a/sources_non_forked/goyo.vim/autoload/goyo.vim +++ b/sources_non_forked/goyo.vim/autoload/goyo.vim @@ -24,6 +24,10 @@ let s:cpo_save = &cpo set cpo&vim +function! s:const(val, min, max) + return min([max([a:val, a:min]), a:max]) +endfunction + function! s:get_color(group, attr) return synIDattr(synIDtrans(hlID(a:group)), a:attr) endfunction @@ -78,28 +82,27 @@ function! s:setup_pad(bufnr, vert, size, repel) execute winnr('#') . 'wincmd w' endfunction -function! s:hmargin() - let nwidth = max([len(string(line('$'))) + 1, &numberwidth]) - let width = t:goyo_width + (&number ? nwidth : 0) - return (&columns - width) -endfunction - function! s:resize_pads() - let t:goyo_width = max([2, t:goyo_width]) - let t:goyo_margin_top = min([max([2, t:goyo_margin_top]), &lines / 2 - 1]) - let t:goyo_margin_bottom = min([max([2, t:goyo_margin_bottom]), &lines / 2 - 1]) - - let hmargin = s:hmargin() - augroup goyop autocmd! augroup END - call s:setup_pad(t:goyo_pads.t, 0, t:goyo_margin_top - 1, 'j') - call s:setup_pad(t:goyo_pads.b, 0, t:goyo_margin_bottom - 2, 'k') - call s:setup_pad(t:goyo_pads.l, 1, hmargin / 2 - 1, 'l') - call s:setup_pad(t:goyo_pads.r, 1, hmargin / 2 - 1, 'h') - let t:goyo_width = winwidth(0) + let t:goyo_dim.width = s:const(t:goyo_dim.width, 2, &columns) + let t:goyo_dim.height = s:const(t:goyo_dim.height, 2, &lines) + + let vmargin = max([0, (&lines - t:goyo_dim.height) / 2 - 1]) + let yoff = s:const(t:goyo_dim.yoff, - vmargin, vmargin) + let top = vmargin + yoff + let bot = vmargin - yoff - 1 + call s:setup_pad(t:goyo_pads.t, 0, top, 'j') + call s:setup_pad(t:goyo_pads.b, 0, bot, 'k') + + let nwidth = max([len(string(line('$'))) + 1, &numberwidth]) + let width = t:goyo_dim.width + (&number ? nwidth : 0) + let hmargin = max([0, (&columns - width) / 2 - 1]) + let xoff = s:const(t:goyo_dim.xoff, - hmargin, hmargin) + call s:setup_pad(t:goyo_pads.l, 1, hmargin + xoff, 'l') + call s:setup_pad(t:goyo_pads.r, 1, hmargin - xoff, 'h') endfunction function! s:tranquilize() @@ -145,11 +148,11 @@ endfunction function! s:maps_resize() let commands = { - \ '=': ':let [t:goyo_width, t:goyo_margin_top, t:goyo_margin_bottom] = t:goyo_initial_dim call resize_pads()', - \ '>': ':let t:goyo_width = winwidth(0) + 2 * v:count1 call resize_pads()', - \ '<': ':let t:goyo_width = winwidth(0) - 2 * v:count1 call resize_pads()', - \ '+': ':let t:goyo_margin_top -= v:count1 let t:goyo_margin_bottom -= v:count1 call resize_pads()', - \ '-': ':let t:goyo_margin_top += v:count1 let t:goyo_margin_bottom += v:count1 call resize_pads()' + \ '=': ':let t:goyo_dim = parse_arg(t:goyo_dim_expr) call resize_pads()', + \ '>': ':let t:goyo_dim.width = winwidth(0) + 2 * v:count1 call resize_pads()', + \ '<': ':let t:goyo_dim.width = winwidth(0) - 2 * v:count1 call resize_pads()', + \ '+': ':let t:goyo_dim.height += 2 * v:count1 call resize_pads()', + \ '-': ':let t:goyo_dim.height -= 2 * v:count1 call resize_pads()' \ } let mapped = filter(keys(commands), "empty(maparg(\"\\".v:val, 'n'))") for c in mapped @@ -158,7 +161,12 @@ function! s:maps_resize() return mapped endfunction -function! s:goyo_on(width) +function! s:goyo_on(dim) + let dim = s:parse_arg(a:dim) + if empty(dim) + return + endif + let s:orig_tab = tabpagenr() let settings = \ { 'laststatus': &laststatus, @@ -177,10 +185,8 @@ function! s:goyo_on(width) tab split let t:goyo_master = winbufnr(0) - let t:goyo_width = a:width - let t:goyo_margin_top = get(g:, 'goyo_margin_top', 4) - let t:goyo_margin_bottom = get(g:, 'goyo_margin_bottom', 4) - let t:goyo_initial_dim = [t:goyo_width, t:goyo_margin_top, t:goyo_margin_bottom] + let t:goyo_dim = dim + let t:goyo_dim_expr = a:dim let t:goyo_pads = {} let t:goyo_revert = settings let t:goyo_maps = extend(s:maps_nop(), s:maps_resize()) @@ -360,19 +366,60 @@ function! s:goyo_off() silent! doautocmd User GoyoLeave endfunction -function! goyo#execute(bang, ...) - let width = a:0 > 0 ? a:1 : get(g:, 'goyo_width', 80) +function! s:relsz(expr, limit) + if a:expr !~ '%$' + return str2nr(a:expr) + endif + return a:limit * str2nr(a:expr[:-2]) / 100 +endfunction + +function! s:parse_arg(arg) + if exists('g:goyo_height') || !exists('g:goyo_margin_top') && !exists('g:goyo_margin_bottom') + let height = s:relsz(get(g:, 'goyo_height', '85%'), &lines) + let yoff = 0 + else + let top = max([0, s:relsz(get(g:, 'goyo_margin_top', 4), &lines)]) + let bot = max([0, s:relsz(get(g:, 'goyo_margin_bottom', 4), &lines)]) + let height = &lines - top - bot + let yoff = top - bot + endif + + let dim = { 'width': s:relsz(get(g:, 'goyo_width', 80), &columns), + \ 'height': height, + \ 'xoff': 0, + \ 'yoff': yoff } + if empty(a:arg) + return dim + endif + let parts = matchlist(a:arg, '^\s*\([0-9]\+%\?\)\?\([+-][0-9]\+%\?\)\?\%(x\([0-9]\+%\?\)\?\([+-][0-9]\+%\?\)\?\)\?\s*$') + if empty(parts) + echohl WarningMsg + echo 'Invalid dimension expression: '.a:arg + echohl None + return {} + endif + if !empty(parts[1]) | let dim.width = s:relsz(parts[1], &columns) | endif + if !empty(parts[2]) | let dim.xoff = s:relsz(parts[2], &columns) | endif + if !empty(parts[3]) | let dim.height = s:relsz(parts[3], &lines) | endif + if !empty(parts[4]) | let dim.yoff = s:relsz(parts[4], &lines) | endif + return dim +endfunction +function! goyo#execute(bang, dim) if a:bang if exists('#goyo') call s:goyo_off() endif else if exists('#goyo') == 0 - call s:goyo_on(width) - elseif a:0 > 0 - let t:goyo_width = width - call s:resize_pads() + call s:goyo_on(a:dim) + elseif !empty(a:dim) + let dim = s:parse_arg(a:dim) + if !empty(dim) + let t:goyo_dim = dim + let t:goyo_dim_expr = a:dim + call s:resize_pads() + endif else call s:goyo_off() end diff --git a/sources_non_forked/goyo.vim/plugin/goyo.vim b/sources_non_forked/goyo.vim/plugin/goyo.vim index 76e9ad3670..af4793a1f4 100644 --- a/sources_non_forked/goyo.vim/plugin/goyo.vim +++ b/sources_non_forked/goyo.vim/plugin/goyo.vim @@ -21,4 +21,4 @@ " OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION " WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -command! -nargs=? -bar -bang Goyo call goyo#execute(0, ) +command! -nargs=? -bar -bang Goyo call goyo#execute(0, ) diff --git a/sources_non_forked/nerdcommenter/.gitignore b/sources_non_forked/nerdcommenter/.gitignore new file mode 100644 index 0000000000..3698c0ef70 --- /dev/null +++ b/sources_non_forked/nerdcommenter/.gitignore @@ -0,0 +1,3 @@ +*~ +*.swp +tags diff --git a/sources_non_forked/nerdcommenter/README.md b/sources_non_forked/nerdcommenter/README.md new file mode 100644 index 0000000000..54f37cf49c --- /dev/null +++ b/sources_non_forked/nerdcommenter/README.md @@ -0,0 +1,91 @@ +# Installation + +_\*For simplicity, let's use **[VIM_ROOT]** which will mean ~/.vim (\*nix) or ~/vimfiles (Windows)_ + +The NERD Commenter requires Vim 7 or higher is comprised of 2 files: + + plugin/NERD_commenter.vim + doc/NERD_commenter.txt + +### Classic Install + +1. Extract the plugin files into your **[VIM_ROOT]**/plugin and **[VIM_ROOT]**/doc folders respectively. +2. Finish the install by updating your help files. Run: + +

:helptags [VIM_ROOT]/doc
+ +See **|add-local-help|** for more details. + +### Pathogen Install +1. Navigate to your **[VIM_ROOT]/bundle** directory in your local Vim setup +2. git clone https://github.com/scrooloose/nerdcommenter.git + +### Post Install +After the **'Classic'** or **'Pathogen'** install, make sure that you have filetype plugins enabled, as the script makes use of +**|'commentstring'|** where possible (which is usually set in a filetype plugin). +See **|filetype-plugin-on|** for details, but basically, stick this in your vimrc: + + filetype plugin on + +# Usage + +The following key mappings are provided by default (there is also a menu +provided that contains menu items corresponding to all the below mappings): + +Most of the following mappings are for normal/visual mode only. The |NERDComInsertComment| mapping is for insert mode only. + +**[count]\cc |NERDComComment|** +Comment out the current line or text selected in visual mode. + + +**[count]\cn |NERDComNestedComment|** +Same as \cc but forces nesting. + + +**[count]\c |NERDComToggleComment|** +Toggles the comment state of the selected line(s). If the topmost selected +line is commented, all selected lines are uncommented and vice versa. + + +**[count]\cm |NERDComMinimalComment|** +Comments the given lines using only one set of multipart delimiters. + + +**[count]\ci |NERDComInvertComment|** +Toggles the comment state of the selected line(s) individually. + + +**[count]\cs |NERDComSexyComment|** +Comments out the selected lines ``sexily'' + + +**[count]\cy |NERDComYankComment|** +Same as \cc except that the commented line(s) are yanked first. + + +**\c$ |NERDComEOLComment|** +Comments the current line from the cursor to the end of line. + + +**\cA |NERDComAppendComment|** +Adds comment delimiters to the end of line and goes into insert mode between +them. + + +**|NERDComInsertComment|** +Adds comment delimiters at the current cursor position and inserts between. +Disabled by default. + + +**\ca |NERDComAltDelim|** +Switches to the alternative set of delimiters. + + +**[count]\cl** +**[count]\cb |NERDComAlignedComment|** +Same as |NERDComComment| except that the delimiters are aligned down the +left side (\cl) or both sides (\cb). + + +**[count]\cu |NERDComUncommentLine|** +Uncomments the selected line(s). diff --git a/sources_non_forked/nerdcommenter/Rakefile b/sources_non_forked/nerdcommenter/Rakefile new file mode 100644 index 0000000000..c7bf9e6493 --- /dev/null +++ b/sources_non_forked/nerdcommenter/Rakefile @@ -0,0 +1,76 @@ +# written by travis jeffery +# contributions by scrooloose + +require 'rake' +require 'find' +require 'pathname' + +IGNORE = [/\.gitignore$/, /Rakefile$/] + +files = `git ls-files`.split("\n") +files.reject! { |f| IGNORE.any? { |re| f.match(re) } } + +desc 'Zip up the project files' +task :zip do + zip_name = File.basename(File.dirname(__FILE__)) + zip_name.gsub!(/ /, '_') + zip_name = "#{zip_name}.zip" + + if File.exist?(zip_name) + abort("Zip file #{zip_name} already exists. Remove it first.") + end + + puts "Creating zip file: #{zip_name}" + system("zip #{zip_name} #{files.join(" ")}") +end + +desc 'Install plugin and documentation' +task :install do + vimfiles = if ENV['VIMFILES'] + ENV['VIMFILES'] + elsif RUBY_PLATFORM =~ /(win|w)32$/ + File.expand_path("~/vimfiles") + else + File.expand_path("~/.vim") + end + files.each do |file| + target_file = File.join(vimfiles, file) + FileUtils.mkdir_p File.dirname(target_file) + FileUtils.cp file, target_file + + puts "Installed #{file} to #{target_file}" + end + +end + +desc 'Pulls from origin' +task :pull do + puts "Updating local repo..." + system("cd " << Dir.new(File.dirname(__FILE__)).path << " && git pull") +end + +desc 'Calls pull task and then install task' +task :update => ['pull', 'install'] do + puts "Update of vim script complete." +end + +desc 'Uninstall plugin and documentation' +task :uninstall do + vimfiles = if ENV['VIMFILES'] + ENV['VIMFILES'] + elsif RUBY_PLATFORM =~ /(win|w)32$/ + File.expand_path("~/vimfiles") + else + File.expand_path("~/.vim") + end + files.each do |file| + target_file = File.join(vimfiles, file) + FileUtils.rm target_file + + puts "Uninstalled #{target_file}" + end + +end + +task :default => ['update'] + diff --git a/sources_non_forked/nerdcommenter/doc/NERD_commenter.txt b/sources_non_forked/nerdcommenter/doc/NERD_commenter.txt new file mode 100644 index 0000000000..151ea290ca --- /dev/null +++ b/sources_non_forked/nerdcommenter/doc/NERD_commenter.txt @@ -0,0 +1,1009 @@ +*NERD_commenter.txt* Plugin for commenting code + + + NERD COMMENTER REFERENCE MANUAL~ + + + + + +============================================================================== +CONTENTS *NERDCommenterContents* + + 1.Intro...................................|NERDCommenter| + 2.Installation............................|NERDComInstallation| + 3.Functionality provided..................|NERDComFunctionality| + 3.1 Functionality Summary.............|NERDComFunctionalitySummary| + 3.2 Functionality Details.............|NERDComFunctionalityDetails| + 3.2.1 Comment map.................|NERDComComment| + 3.2.2 Nested comment map..........|NERDComNestedComment| + 3.2.3 Toggle comment map..........|NERDComToggleComment| + 3.2.4 Minimal comment map.........|NERDComMinimalComment| + 3.2.5 Invert comment map..........|NERDComInvertComment| + 3.2.6 Sexy comment map............|NERDComSexyComment| + 3.2.7 Yank comment map............|NERDComYankComment| + 3.2.8 Comment to EOL map..........|NERDComEOLComment| + 3.2.9 Append com to line map......|NERDComAppendComment| + 3.2.10 Insert comment map.........|NERDComInsertComment| + 3.2.11 Use alternate delims map...|NERDComAltDelim| + 3.2.12 Comment aligned maps.......|NERDComAlignedComment| + 3.2.13 Uncomment line map.........|NERDComUncommentLine| + 3.4 Sexy Comments.....................|NERDComSexyComments| + 3.5 The NERDComment function..........|NERDComNERDComment| + 4.Options.................................|NERDComOptions| + 4.1 Options summary...................|NERDComOptionsSummary| + 4.2 Options details...................|NERDComOptionsDetails| + 4.3 Default delimiter Options.........|NERDComDefaultDelims| + 5. Customising key mappings...............|NERDComMappings| + 6. Issues with the script.................|NERDComIssues| + 6.1 Delimiter detection heuristics....|NERDComHeuristics| + 6.2 Nesting issues....................|NERDComNesting| + 7.About.. ............................|NERDComAbout| + 8.Changelog...............................|NERDComChangelog| + 9.Credits.................................|NERDComCredits| + 10.License................................|NERDComLicense| + +============================================================================== +1. Intro *NERDCommenter* + +The NERD commenter provides many different commenting operations and styles +which are invoked via key mappings and a menu. These operations are available +for most filetypes. + +There are also options that allow to tweak the commenting engine to your +taste. + +============================================================================== +2. Installation *NERDComInstallation* + +The NERD Commenter requires Vim 7 or higher. + +Extract the plugin files in your ~/.vim (*nix) or ~/vimfiles (Windows). You +should have 2 files: > + plugin/NERD_commenter.vim + doc/NERD_commenter.txt +< +Next, to finish installing the help file run: > + :helptags ~/.vim/doc +< +See |add-local-help| for more details. + +Make sure that you have filetype plugins enabled, as the script makes use of +|'commentstring'| where possible (which is usually set in a filetype plugin). +See |filetype-plugin-on| for details, but basically, stick this in your vimrc > + filetype plugin on +< + +============================================================================== +3. Functionality provided *NERDComFunctionality* + +------------------------------------------------------------------------------ +3.1 Functionality summary *NERDComFunctionalitySummary* + +The following key mappings are provided by default (there is also a menu +with items corresponding to all the mappings below): + +[count]||cc |NERDComComment| +Comment out the current line or text selected in visual mode. + + +[count]||cn |NERDComNestedComment| +Same as ||cc but forces nesting. + + +[count]||c |NERDComToggleComment| +Toggles the comment state of the selected line(s). If the topmost selected +line is commented, all selected lines are uncommented and vice versa. + + +[count]||cm |NERDComMinimalComment| +Comments the given lines using only one set of multipart delimiters. + + +[count]||ci |NERDComInvertComment| +Toggles the comment state of the selected line(s) individually. + + +[count]||cs |NERDComSexyComment| +Comments out the selected lines ``sexily'' + + +[count]||cy |NERDComYankComment| +Same as ||cc except that the commented line(s) are yanked first. + + +||c$ |NERDComEOLComment| +Comments the current line from the cursor to the end of line. + + +||cA |NERDComAppendComment| +Adds comment delimiters to the end of line and goes into insert mode between +them. + + +|NERDComInsertComment| +Adds comment delimiters at the current cursor position and inserts between. +Disabled by default. + + +||ca |NERDComAltDelim| +Switches to the alternative set of delimiters. + + +[count]||cl +[count]||cb |NERDComAlignedComment| +Same as |NERDComComment| except that the delimiters are aligned down the +left side (||cl) or both sides (||cb). + + +[count]||cu |NERDComUncommentLine| +Uncomments the selected line(s). + + +With the optional repeat.vim plugin (vimscript #2136), the mappings can also +be repeated via |.| + +------------------------------------------------------------------------------ +3.2 Functionality details *NERDComFunctionalityDetails* + +------------------------------------------------------------------------------ +3.2.1 Comment map *NERDComComment* + +Default mapping: [count]||cc +Mapped to: NERDCommenterComment +Applicable modes: normal visual visual-line visual-block. + + +Comments out the current line. If multiple lines are selected in visual-line +mode, they are all commented out. If some text is selected in visual or +visual-block mode then the script will try to comment out the exact text that +is selected using multi-part delimiters if they are available. + +If a [count] is given in normal mode, the mapping works as though that many +lines were selected in visual-line mode. + +------------------------------------------------------------------------------ +3.2.2 Nested comment map *NERDComNestedComment* + +Default mapping: [count]||cn +Mapped to: NERDCommenterNested +Applicable modes: normal visual visual-line visual-block. + +Performs nested commenting. Works the same as ||cc except that if a line +is already commented then it will be commented again. + +If |'NERDUsePlaceHolders'| is set then the previous comment delimiters will +be replaced by place-holder delimiters if needed. Otherwise the nested +comment will only be added if the current commenting delimiters have no right +delimiter (to avoid syntax errors) + +If a [count] is given in normal mode, the mapping works as though that many +lines were selected in visual-line mode. + +Related options: +|'NERDDefaultNesting'| + +------------------------------------------------------------------------------ +3.2.3 Toggle comment map *NERDComToggleComment* + +Default mapping: [count]||c +Mapped to: NERDCommenterToggle +Applicable modes: normal visual-line. + +Toggles commenting of the lines selected. The behaviour of this mapping +depends on whether the first line selected is commented or not. If so, all +selected lines are uncommented and vice versa. + +With this mapping, a line is only considered to be commented if it starts with +a left delimiter. + +If a [count] is given in normal mode, the mapping works as though that many +lines were selected in visual-line mode. + +------------------------------------------------------------------------------ +3.2.4 Minimal comment map *NERDComMinimalComment* + +Default mapping: [count]||cm +Mapped to: NERDCommenterMinimal +Applicable modes: normal visual-line. + +Comments the selected lines using one set of multipart delimiters if possible. + +For example: if you are programming in c and you select 5 lines and press +||cm then a '/*' will be placed at the start of the top line and a '*/' +will be placed at the end of the last line. + +Sets of multipart comment delimiters that are between the top and bottom +selected lines are replaced with place holders (see |'NERDLPlace'|) if +|'NERDUsePlaceHolders'| is set for the current filetype. If it is not, then +the comment will be aborted if place holders are required to prevent illegal +syntax. + +If a [count] is given in normal mode, the mapping works as though that many +lines were selected in visual-line mode. + +------------------------------------------------------------------------------ +3.2.5 Invert comment map *NERDComInvertComment* + +Default mapping: ||ci +Mapped to: NERDCommenterInvert +Applicable modes: normal visual-line. + +Inverts the commented state of each selected line. If the a selected line is +commented then it is uncommented and vice versa. Each line is examined and +commented/uncommented individually. + +With this mapping, a line is only considered to be commented if it starts with +a left delimiter. + +If a [count] is given in normal mode, the mapping works as though that many +lines were selected in visual-line mode. + +------------------------------------------------------------------------------ +3.2.6 Sexy comment map *NERDComSexyComment* + +Default mapping: [count]||cs +Mapped to: NERDCommenterSexy +Applicable modes: normal, visual-line. + +Comments the selected line(s) ``sexily''... see |NERDComSexyComments| for +a description of what sexy comments are. Can only be done on filetypes for +which there is at least one set of multipart comment delimiters specified. + +Sexy comments cannot be nested and lines inside a sexy comment cannot be +commented again. + +If a [count] is given in normal mode, the mapping works as though that many +lines were selected in visual-line mode. + +Related options: +|'NERDCompactSexyComs'| + +------------------------------------------------------------------------------ +3.2.7 Yank comment map *NERDComYankComment* + +Default mapping: [count]||cy +Mapped to: NERDCommenterYank +Applicable modes: normal visual visual-line visual-block. + +Same as ||cc except that it yanks the line(s) that are commented first. + +------------------------------------------------------------------------------ +3.2.8 Comment to EOL map *NERDComEOLComment* + +Default mapping: ||c$ +Mapped to: NERDCommenterToEOL +Applicable modes: normal. + +Comments the current line from the current cursor position up to the end of +the line. + +------------------------------------------------------------------------------ +3.2.9 Append com to line map *NERDComAppendComment* + +Default mapping: ||cA +Mapped to: NERDCommenterAppend +Applicable modes: normal. + +Appends comment delimiters to the end of the current line and goes +to insert mode between the new delimiters. + +------------------------------------------------------------------------------ +3.2.10 Insert comment map *NERDComInsertComment* + +Default mapping: disabled by default. +Map it to: NERDCommenterInsert +Applicable modes: insert. + +Adds comment delimiters at the current cursor position and inserts +between them. + +NOTE: prior to version 2.1.17 this was mapped to ctrl-c. To restore this +mapping add > + imap NERDCommenterInsert +< +to your vimrc. + +------------------------------------------------------------------------------ +3.2.11 Use alternate delims map *NERDComAltDelim* + +Default mapping: ||ca +Mapped to: NERDCommenterAltDelims +Applicable modes: normal. + +Changes to the alternative commenting style if one is available. For example, +if the user is editing a c++ file using // comments and they hit ||ca +then they will be switched over to /**/ comments. + +See also |NERDComDefaultDelims| + +------------------------------------------------------------------------------ +3.2.12 Comment aligned maps *NERDComAlignedComment* + +Default mappings: [count]||cl [count]||cb +Mapped to: NERDCommenterAlignLeft + NERDCommenterAlignBoth +Applicable modes: normal visual-line. + +Same as ||cc except that the comment delimiters are aligned on the left +side or both sides respectively. These comments are always nested if the +line(s) are already commented. + +If a [count] is given in normal mode, the mapping works as though that many +lines were selected in visual-line mode. + +------------------------------------------------------------------------------ +3.2.13 Uncomment line map *NERDComUncommentLine* + +Default mapping: [count]||cu +Mapped to: NERDCommenterUncomment +Applicable modes: normal visual visual-line visual-block. + +Uncomments the current line. If multiple lines are selected in +visual mode then they are all uncommented. + +When uncommenting, if the line contains multiple sets of delimiters then the +``outtermost'' pair of delimiters will be removed. + +The script uses a set of heurisics to distinguish ``real'' delimiters from +``fake'' ones when uncommenting. See |NERDComIssues| for details. + +If a [count] is given in normal mode, the mapping works as though that many +lines were selected in visual-line mode. + +Related options: +|'NERDRemoveAltComs'| +|'NERDRemoveExtraSpaces'| + +------------------------------------------------------------------------------ +3.3 Sexy Comments *NERDComSexyComments* +These are comments that use one set of multipart comment delimiters as well as +one other marker symbol. For example: > + /* + * This is a c style sexy comment + * So there! + */ + + /* This is a c style sexy comment + * So there! + * But this one is ``compact'' style */ +< +Here the multipart delimiters are /* and */ and the marker is *. + +------------------------------------------------------------------------------ +3.4 The NERDComment function *NERDComNERDComment* + +All of the NERD commenter mappings and menu items invoke a single function +which delegates the commenting work to other functions. This function is +public and has the prototype: > + function! NERDComment(mode, type) +< +The arguments to this function are simple: + - mode: a character indicating the mode in which the comment is requested: + 'n' for Normal mode, 'x' for Visual mode + - type: is used to specify what type of commenting operation is to be + performed, and it can be one of the following: "sexy", "invert", + "minimal", "toggle", "alignLeft", "alignBoth", "comment", "nested", + "toEOL", "append", "insert", "uncomment", "yank" + +For example, if you typed > + :call NERDComment(1, 'sexy') +< +then the script would do a sexy comment on the last visual selection. + + +============================================================================== +4. Options *NERDComOptions* + +------------------------------------------------------------------------------ +4.1 Options summary *NERDComOptionsSummary* + +|'loaded_nerd_comments'| Turns off the script. +|'NERDAllowAnyVisualDelims'| Allows multipart alternative delims to + be used when commenting in + visual/visual-block mode. +|'NERDBlockComIgnoreEmpty'| Forces right delims to be placed when + doing visual-block comments. +|'NERDCommentWholeLinesInVMode'| Changes behaviour of visual comments. +|'NERDCreateDefaultMappings'| Turn the default mappings on/off. +|'NERDCustomDelimiters'| Add or override delimiters for any + filetypes. +|'NERDDefaultNesting'| Tells the script to use nested comments + by default. +|'NERDMenuMode'| Specifies how the NERD commenter menu + will appear (if at all). +|'NERDLPlace'| Specifies what to use as the left + delimiter placeholder when nesting + comments. +|'NERDUsePlaceHolders'| Specifies which filetypes may use + placeholders when nesting comments. +|'NERDRemoveAltComs'| Tells the script whether to remove + alternative comment delimiters when + uncommenting. +|'NERDRemoveExtraSpaces'| Tells the script to always remove the + extra spaces when uncommenting + (regardless of whether NERDSpaceDelims + is set) +|'NERDRPlace'| Specifies what to use as the right + delimiter placeholder when nesting + comments. +|'NERDSpaceDelims'| Specifies whether to add extra spaces + around delimiters when commenting, and + whether to remove them when + uncommenting. +|'NERDCompactSexyComs'| Specifies whether to use the compact + style sexy comments. + +------------------------------------------------------------------------------ +4.3 Options details *NERDComOptionsDetails* + +To enable any of the below options you should put the given line in your +~/.vimrc + + *'loaded_nerd_comments'* +If this script is driving you insane you can turn it off by setting this +option > + let loaded_nerd_comments=1 +< +------------------------------------------------------------------------------ + *'NERDAllowAnyVisualDelims'* +Values: 0 or 1. +Default: 1. + +If set to 1 then, when doing a visual or visual-block comment (but not a +visual-line comment), the script will choose the right delimiters to use for +the comment. This means either using the current delimiters if they are +multipart or using the alternative delimiters if THEY are multipart. For +example if we are editing the following java code: > + float foo = 1221; + float bar = 324; + System.out.println(foo * bar); +< +If we are using // comments and select the "foo" and "bar" in visual-block +mode, as shown left below (where '|'s are used to represent the visual-block +boundary), and comment it then the script will use the alternative delims as +shown on the right: > + + float |foo| = 1221; float /*foo*/ = 1221; + float |bar| = 324; float /*bar*/ = 324; + System.out.println(foo * bar); System.out.println(foo * bar); +< +------------------------------------------------------------------------------ + *'NERDBlockComIgnoreEmpty'* +Values: 0 or 1. +Default: 1. + +This option affects visual-block mode commenting. If this option is turned +on, lines that begin outside the right boundary of the selection block will be +ignored. + +For example, if you are commenting this chunk of c code in visual-block mode +(where the '|'s are used to represent the visual-block boundary) > + #include + #include + #include + |int| main(){ + | | printf("SUCK THIS\n"); + | | while(1){ + | | fork(); + | | } + |} | +< +If NERDBlockComIgnoreEmpty=0 then this code will become: > + #include + #include + #include + /*int*/ main(){ + /* */ printf("SUCK THIS\n"); + /* */ while(1){ + /* */ fork(); + /* */ } + /*} */ +< +Otherwise, the code block would become: > + #include + #include + #include + /*int*/ main(){ + printf("SUCK THIS\n"); + while(1){ + fork(); + } + /*} */ +< +------------------------------------------------------------------------------ + *'NERDCommentWholeLinesInVMode'* +Values: 0, 1 or 2. +Default: 0. + +By default the script tries to comment out exactly what is selected in visual +mode (v). For example if you select and comment the following c code (using | +to represent the visual boundary): > + in|t foo = 3; + int bar =| 9; + int baz = foo + bar; +< +This will result in: > + in/*t foo = 3;*/ + /*int bar =*/ 9; + int baz = foo + bar; +< +But some people prefer it if the whole lines are commented like: > + /*int foo = 3;*/ + /*int bar = 9;*/ + int baz = foo + bar; +< +If you prefer the second option then stick this line in your vimrc: > + let NERDCommentWholeLinesInVMode=1 +< + +If the filetype you are editing only has no multipart delimiters (for example +a shell script) and you hadnt set this option then the above would become > + in#t foo = 3; + #int bar = 9; +< +(where # is the comment delimiter) as this is the closest the script can +come to commenting out exactly what was selected. If you prefer for whole +lines to be commented out when there is no multipart delimiters but the EXACT +text that was selected to be commented out if there IS multipart delimiters +then stick the following line in your vimrc: > + let NERDCommentWholeLinesInVMode=2 +< + +Note that this option does not affect the behaviour of commenting in +|visual-block| mode. + +------------------------------------------------------------------------------ + *'NERDCreateDefaultMappings'* +Values: 0 or 1. +Default: 1. + +If set to 0, none of the default mappings will be created. + +See also |NERDComMappings|. + +------------------------------------------------------------------------------ + *'NERDCustomDelimiters'* +Values: A map (format specified below). +Default: {} + +Use this option if you have new filetypes you want the script to handle, or if +you want to override the default delimiters of a filetype. + +Example: > + let g:NERDCustomDelimiters = { + \ 'ruby': { 'left': '#', 'leftAlt': 'FOO', 'rightAlt': 'BAR' }, + \ 'grondle': { 'left': '{{', 'right': '}}' } + \ } +< + +Here we override the delimiter settings for ruby and add FOO/BAR as alternative +delimiters. We also add {{ and }} as delimiters for a new filetype called +'grondle'. + +------------------------------------------------------------------------------ + *'NERDRemoveAltComs'* +Values: 0 or 1. +Default: 1. + +When uncommenting a line (for a filetype with an alternative commenting style) +this option tells the script whether to look for, and remove, comment +delimiters of the alternative style. + +For example, if you are editing a c++ file using // style comments and you go +||cu on this line: > + /* This is a c++ comment baby! */ +< +It will not be uncommented if the NERDRemoveAltComs is set to 0. + +------------------------------------------------------------------------------ + *'NERDRemoveExtraSpaces'* +Values: 0 or 1. +Default: 0. + +By default, the NERD commenter will remove spaces around comment delimiters if +either: +1. |'NERDSpaceDelims'| is set to 1. +2. NERDRemoveExtraSpaces is set to 1. + +This means that if we have the following lines in a c code file: > + /* int foo = 5; */ + /* int bar = 10; */ + int baz = foo + bar +< +If either of the above conditions hold then if these lines are uncommented +they will become: > + int foo = 5; + int bar = 10; + int baz = foo + bar +< +Otherwise they would become: > + int foo = 5; + int bar = 10; + int baz = foo + bar +< + +------------------------------------------------------------------------------ + *'NERDLPlace'* + *'NERDRPlace'* +Values: arbitrary string. +Default: + NERDLPlace: "[>" + NERDRPlace: "<]" + +These options are used to control the strings used as place-holder delimiters. +Place holder delimiters are used when performing nested commenting when the +filetype supports commenting styles with both left and right delimiters. +To set these options use lines like: > + let NERDLPlace="FOO" + let NERDRPlace="BAR" +< +Following the above example, if we have line of c code: > + /* int horse */ +< +and we comment it with ||cn it will be changed to: > + /*FOO int horse BAR*/ +< +When we uncomment this line it will go back to what it was. + +------------------------------------------------------------------------------ + *'NERDMenuMode'* +Values: 0, 1, 2, 3. +Default: 3 + +This option can take 4 values: + "0": Turns the menu off. + "1": Turns the 'comment' menu on with no menu shortcut. + "2": Turns the 'comment' menu on with -c as the shortcut. + "3": Turns the 'Plugin -> comment' menu on with -c as the shortcut. + +------------------------------------------------------------------------------ + *'NERDUsePlaceHolders'* +Values: 0 or 1. +Default 1. + +This option is used to specify whether place-holder delimiters should be used +when creating a nested comment. + +------------------------------------------------------------------------------ + *'NERDSpaceDelims'* +Values: 0 or 1. +Default 0. + +Some people prefer a space after the left delimiter and before the right +delimiter like this: > + /* int foo=2; */ +< +as opposed to this: > + /*int foo=2;*/ +< +If you want spaces to be added then set NERDSpaceDelims to 1 in your vimrc. + +See also |'NERDRemoveExtraSpaces'|. + +------------------------------------------------------------------------------ + *'NERDCompactSexyComs'* +Values: 0 or 1. +Default 0. + +Some people may want their sexy comments to be like this: > + /* Hi There! + * This is a sexy comment + * in c */ +< +As opposed to like this: > + /* + * Hi There! + * This is a sexy comment + * in c + */ +< +If this option is set to 1 then the top style will be used. + +------------------------------------------------------------------------------ + *'NERDDefaultNesting'* +Values: 0 or 1. +Default 1. + +When this option is set to 1, comments are nested automatically. That is, if +you hit ||cc on a line that is already commented it will be commented +again. + +------------------------------------------------------------------------------ +3.3 Default delimiter customisation *NERDComDefaultDelims* + +If you want the NERD commenter to use the alternative delimiters for a +specific filetype by default then put a line of this form into your vimrc: > + let NERD__alt_style=1 +< +Example: java uses // style comments by default, but you want it to default to +/* */ style comments instead. You would put this line in your vimrc: > + let NERD_java_alt_style=1 +< + +See |NERDComAltDelim| for switching commenting styles at runtime. + +============================================================================== +5. Key mapping customisation *NERDComMappings* + +To change a mapping just map another key combo to the internal mapping. +For example, to remap the |NERDComComment| mapping to ",omg" you would put +this line in your vimrc: > + map ,omg NERDCommenterComment +< +This will stop the corresponding default mappings from being created. + +See the help for the mapping in question to see which mapping to +map to. + +See also |'NERDCreateDefaultMappings'|. + +============================================================================== +6. Issues with the script *NERDComIssues* + + +------------------------------------------------------------------------------ +6.1 Delimiter detection heuristics *NERDComHeuristics* + +Heuristics are used to distinguish the real comment delimiters + +Because we have comment mappings that place delimiters in the middle of lines, +removing comment delimiters is a bit tricky. This is because if comment +delimiters appear in a line doesnt mean they really ARE delimiters. For +example, Java uses // comments but the line > + System.out.println("//"); +< +clearly contains no real comment delimiters. + +To distinguish between ``real'' comment delimiters and ``fake'' ones we use a +set of heuristics. For example, one such heuristic states that any comment +delimiter that has an odd number of non-escaped " characters both preceding +and following it on the line is not a comment because it is probably part of a +string. These heuristics, while usually pretty accurate, will not work for all +cases. + +------------------------------------------------------------------------------ +6.2 Nesting issues *NERDComNesting* + +If we have some line of code like this: > + /*int foo */ = /*5 + 9;*/ +< +This will not be uncommented legally. The NERD commenter will remove the +"outter most" delimiters so the line will become: > + int foo */ = /*5 + 9; +< +which almost certainly will not be what you want. Nested sets of comments will +uncomment fine though. Eg: > + /*int/* foo =*/ 5 + 9;*/ +< +will become: > + int/* foo =*/ 5 + 9; +< +(Note that in the above examples I have deliberately not used place holders +for simplicity) + +============================================================================== +7. About *NERDComAbout* + +The author of the NERD commenter is Martyzillatron --- the half robot, half +dinosaur bastard son of Megatron and Godzilla. He enjoys destroying +metropolises and eating tourist busses. + +Drop him a line at martin_grenfell at msn.com. He would love to hear from you. +its a lonely life being the worlds premier terror machine. How would you feel +if your face looked like a toaster and a t-rex put together? :( + +The latest stable versions can be found at + http://www.vim.org/scripts/script.php?script_id=1218 + +The latest dev versions are on github + http://github.com/scrooloose/nerdcommenter + +============================================================================== +8. Changelog *NERDComChangelog* + +2.3.0 + - remove all filetypes which have a &commentstring in the standard vim + runtime for vim > 7.0 unless the script stores an alternate set of + delimiters + - make the script complain if the user doesnt have filetype plugins enabled + - use || instead of comma to start the default mappings + - fix a couple of bugs with sexy comments - thanks to Tim Smart + - lots of refactoring + +2.2.2 + - remove the NERDShutup option and the message is suppresses, this makes + the plugin silently rely on &commentstring for unknown filetypes. + - add support for dhcpd, limits, ntp, resolv, rgb, sysctl, udevconf and + udevrules. Thanks to Thilo Six. + - match filetypes case insensitively + - add support for mp (metapost), thanks to Andrey Skvortsov. + - add support for htmlcheetah, thanks to Simon Hengel. + - add support for javacc, thanks to Matt Tolton. + - make <%# %> the default delims for eruby, thanks to tpope. + - add support for javascript.jquery, thanks to Ivan Devat. + - add support for cucumber and pdf. Fix sass and railslog delims, + thanks to tpope + +2.2.1 + - add support for newlisp and clojure, thanks to Matthew Lee Hinman. + - fix automake comments, thanks to Elias Pipping + - make haml comments default to -# with / as the alternative delimiter, + thanks to tpope + - add support for actionscript and processing thanks to Edwin Benavides + - add support for ps1 (powershell), thanks to Jason Mills + - add support for hostsaccess, thanks to Thomas Rowe + - add support for CVScommit + - add support for asciidoc, git and gitrebase. Thanks to Simon Ruderich. + - use # for gitcommit comments, thanks to Simon Ruderich. + - add support for mako and genshi, thanks to Keitheis. + - add support for conkyrc, thanks to David + - add support for SVNannotate, thanks to Miguel Jaque Barbero. + - add support for sieve, thanks to Stefan Walk + - add support for objj, thanks to Adam Thorsen. + +2.2.0 + - rewrote the mappings system to be more "standard". + - removed all the mapping options. Now, mappings to mappings are + used + - see :help NERDComMappings, and :help NERDCreateDefaultMappings for + more info + - remove "prepend comments" and "right aligned comments". + - add support for applescript, calbire, man, SVNcommit, potwiki, txt2tags and SVNinfo. + Thanks to nicothakis, timberke, sgronblo, mntnoe, Bernhard Grotz, John + O'Shea, François and Giacomo Mariani respectively. + - bugfix for haskell delimiters. Thanks to mntnoe. +2.1.18 + - add support for llvm. Thanks to nicothakis. + - add support for xquery. Thanks to Phillip Kovalev. +2.1.17 + - fixed haskell delimiters (hackily). Thanks to Elias Pipping. + - add support for mailcap. Thanks to Pascal Brueckner. + - add support for stata. Thanks to Jerónimo Carballo. + - applied a patch from ewfalor to fix an error in the help file with the + NERDMapleader doc + - disable the insert mode ctrl-c mapping by default, see :help + NERDComInsertComment if you wish to restore it + +============================================================================== +9. Credits *NERDComCredits* + +Thanks to the follow people for suggestions and patches: + +Nick Brettell +Matthew Hawkins +Mathieu Clabaut +Greg Searle +Nguyen +Litchi +Jorge Scandaliaris +Shufeng Zheng +Martin Stubenschrott +Markus Erlmann +Brent Rice +Richard Willis +Igor Prischepoff +Harry +David Bourgeois +Eike Von Seggern +Torsten Blix +Alexander Bosecke +Stefano Zacchiroli +Norick Chen +Joseph Barker +Gary Church +Tim Carey-Smith +Markus Klinik +Anders +Seth Mason +James Hales +Heptite +Cheng Fang +Yongwei Wu +David Miani +Jeremy Hinegardner +Marco +Ingo Karkat +Zhang Shuhan +tpope +Ben Schmidt +David Fishburn +Erik Falor +JaGoTerr +Elias Pipping +mntnoe +Mark S. + + +Thanks to the following people for sending me new filetypes to support: + +The hackers The filetypes~ +Sam R verilog +Jonathan Derque context, plaintext and mail +Vigil fetchmail +Michael Brunner kconfig +Antono Vasiljev netdict +Melissa Reid omlet +Ilia N Ternovich quickfix +John O'Shea RTF, SVNcommitlog and vcscommit, SVNCommit +Anders occam +Mark Woodward csv +fREW gentoo-package-mask, + gentoo-package-keywords, + gentoo-package-use, and vo_base +Alexey verilog_systemverilog, systemverilog +Lizendir fstab +Michael Böhler autoit, autohotkey and docbk +Aaron Small cmake +Ramiro htmldjango and django +Stefano Zacchiroli debcontrol, debchangelog, mkd +Alex Tarkovsky ebuild and eclass +Jorge Rodrigues gams +Rainer Müller Objective C +Jason Mills Groovy, ps1 +Normandie Azucena vera +Florian Apolloner ldif +David Fishburn lookupfile +Niels Aan de Brugh rst +Don Hatlestad ahk +Christophe Benz Desktop and xsd +Eyolf Østrem lilypond, bbx and lytex +Ingo Karkat dosbatch +Nicolas Weber markdown, objcpp +tinoucas gentoo-conf-d +Greg Weber D, haml +Bruce Sherrod velocity +timberke cobol, calibre +Aaron Schaefer factor +Mr X asterisk, mplayerconf +Kuchma Michael plsql +Brett Warneke spectre +Pipp lhaskell +Renald Buter scala +Vladimir Lomov asymptote +Marco mrxvtrc, aap +nicothakis SVNAnnotate, CVSAnnotate, SVKAnnotate, + SVNdiff, gitAnnotate, gitdiff, dtrace + llvm, applescript +Chen Xing Wikipedia +Jacobo Diaz dakota, patran +Li Jin gentoo-env-d, gentoo-init-d, + gentoo-make-conf, grub, modconf, sudoers +SpookeyPeanut rib +Greg Jandl pyrex/cython +Christophe Benz services, gitcommit +A Pontus vimperator +Stromnov slice, bzr +Martin Kustermann pamconf +Indriði Einarsson mason +Chris map +Krzysztof A. Adamski group +Pascal Brueckner mailcap +Jerónimo Carballo stata +Phillip Kovalev xquery +Bernhard Grotz potwiki +sgronblo man +François txt2tags +Giacomo Mariani SVNinfo +Matthew Lee Hinman newlisp, clojure +Elias Pipping automake +Edwin Benavides actionscript, processing +Thomas Rowe hostsaccess +Simon Ruderich asciidoc, git, gitcommit, gitrebase +Keitheis mako, genshi +David conkyrc +Miguel Jaque Barbero SVNannotate +Stefan Walk sieve +Adam Thorsen objj +Thilo Six dhcpd, limits, ntp, resolv, rgb, sysctl, + udevconf, udevrules +Andrey Skvortsov mp +Simon Hengel htmlcheetah +Matt Tolton javacc +Ivan Devat javascript.jquery +tpope cucumber,pdf +============================================================================== +10. License *NERDComLicense* + +The NERD commenter is released under the wtfpl. +See http://sam.zoy.org/wtfpl/COPYING. diff --git a/sources_non_forked/nerdcommenter/plugin/NERD_commenter.vim b/sources_non_forked/nerdcommenter/plugin/NERD_commenter.vim new file mode 100644 index 0000000000..816a4d2b6b --- /dev/null +++ b/sources_non_forked/nerdcommenter/plugin/NERD_commenter.vim @@ -0,0 +1,2774 @@ +" ============================================================================ +" File: NERD_commenter.vim +" Description: vim global plugin that provides easy code commenting +" Maintainer: Martin Grenfell +" Version: 2.3.0 +" Last Change: Wed Dec 14 08:00 AM 2011 EST +" License: This program is free software. It comes without any warranty, +" to the extent permitted by applicable law. You can redistribute +" it and/or modify it under the terms of the Do What The Fuck You +" Want To Public License, Version 2, as published by Sam Hocevar. +" See http://sam.zoy.org/wtfpl/COPYING for more details. +" +" ============================================================================ + +" Section: script init stuff {{{1 +if exists("loaded_nerd_comments") + finish +endif +if v:version < 700 + echoerr "NERDCommenter: this plugin requires vim >= 7. DOWNLOAD IT! You'll thank me later!" + finish +endif +let loaded_nerd_comments = 1 + +" Function: s:InitVariable() function {{{2 +" This function is used to initialise a given variable to a given value. The +" variable is only initialised if it does not exist prior +" +" Args: +" -var: the name of the var to be initialised +" -value: the value to initialise var to +" +" Returns: +" 1 if the var is set, 0 otherwise +function s:InitVariable(var, value) + if !exists(a:var) + execute 'let ' . a:var . ' = ' . "'" . a:value . "'" + return 1 + endif + return 0 +endfunction + +" Section: space string init{{{2 +" When putting spaces after the left delim and before the right we use +" s:spaceStr for the space char. This way we can make it add anything after +" the left and before the right by modifying this variable +let s:spaceStr = ' ' +let s:lenSpaceStr = strlen(s:spaceStr) + +" Section: variable initialization {{{2 +call s:InitVariable("g:NERDAllowAnyVisualDelims", 1) +call s:InitVariable("g:NERDBlockComIgnoreEmpty", 0) +call s:InitVariable("g:NERDCommentWholeLinesInVMode", 0) +call s:InitVariable("g:NERDCompactSexyComs", 0) +call s:InitVariable("g:NERDCreateDefaultMappings", 1) +call s:InitVariable("g:NERDDefaultNesting", 1) +call s:InitVariable("g:NERDMenuMode", 3) +call s:InitVariable("g:NERDLPlace", "[>") +call s:InitVariable("g:NERDUsePlaceHolders", 1) +call s:InitVariable("g:NERDRemoveAltComs", 1) +call s:InitVariable("g:NERDRemoveExtraSpaces", 0) +call s:InitVariable("g:NERDRPlace", "<]") +call s:InitVariable("g:NERDSpaceDelims", 0) + +let s:NERDFileNameEscape="[]#*$%'\" ?`!&();<>\\" + +let s:delimiterMap = { + \ 'aap': { 'left': '#' }, + \ 'abc': { 'left': '%' }, + \ 'acedb': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'actionscript': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'ada': { 'left': '--', 'leftAlt': '-- ' }, + \ 'ahdl': { 'left': '--' }, + \ 'ahk': { 'left': ';', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'amiga': { 'left': ';' }, + \ 'aml': { 'left': '/*' }, + \ 'ampl': { 'left': '#' }, + \ 'apache': { 'left': '#' }, + \ 'apachestyle': { 'left': '#' }, + \ 'asciidoc': { 'left': '//' }, + \ 'applescript': { 'left': '--', 'leftAlt': '(*', 'rightAlt': '*)' }, + \ 'armasm': { 'left': ';' }, + \ 'asm68k': { 'left': ';' }, + \ 'asm': { 'left': ';', 'leftAlt': '#' }, + \ 'asn': { 'left': '--' }, + \ 'aspvbs': { 'left': '''', 'leftAlt': '' }, + \ 'asterisk': { 'left': ';' }, + \ 'asy': { 'left': '//' }, + \ 'atlas': { 'left': 'C', 'right': '$' }, + \ 'autohotkey': { 'left': ';' }, + \ 'autoit': { 'left': ';' }, + \ 'ave': { 'left': "'" }, + \ 'awk': { 'left': '#' }, + \ 'basic': { 'left': "'", 'leftAlt': 'REM ' }, + \ 'bbx': { 'left': '%' }, + \ 'bc': { 'left': '#' }, + \ 'bib': { 'left': '%' }, + \ 'bindzone': { 'left': ';' }, + \ 'bst': { 'left': '%' }, + \ 'btm': { 'left': '::' }, + \ 'cabal': { 'left': '--' }, + \ 'caos': { 'left': '*' }, + \ 'calibre': { 'left': '//' }, + \ 'catalog': { 'left': '--', 'right': '--' }, + \ 'c': { 'left': '/*','right': '*/', 'leftAlt': '//' }, + \ 'cf': { 'left': '' }, + \ 'cfg': { 'left': '#' }, + \ 'cg': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'ch': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'cl': { 'left': '#' }, + \ 'clean': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'clipper': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'clojure': { 'left': ';' }, + \ 'cmake': { 'left': '#' }, + \ 'coffee': { 'left': '#' }, + \ 'conkyrc': { 'left': '#' }, + \ 'context': { 'left': '%', 'leftAlt': '--' }, + \ 'cpp': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'cuda': { 'left': '/*','right': '*/', 'leftAlt': '//' }, + \ 'crontab': { 'left': '#' }, + \ 'cs': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'csp': { 'left': '--' }, + \ 'cterm': { 'left': '*' }, + \ 'cucumber': { 'left': '#' }, + \ 'cvs': { 'left': 'CVS:' }, + \ 'd': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'dcl': { 'left': '$!' }, + \ 'dakota': { 'left': '#' }, + \ 'debcontrol': { 'left': '#' }, + \ 'debsources': { 'left': '#' }, + \ 'def': { 'left': ';' }, + \ 'desktop': { 'left': '#' }, + \ 'dhcpd': { 'left': '#' }, + \ 'diff': { 'left': '#' }, + \ 'django': { 'left': '', 'leftAlt': '{#', 'rightAlt': '#}' }, + \ 'docbk': { 'left': '' }, + \ 'dns': { 'left': ';' }, + \ 'dosbatch': { 'left': 'REM ', 'leftAlt': '::' }, + \ 'dosini': { 'left': ';' }, + \ 'dot': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'dracula': { 'left': ';' }, + \ 'dsl': { 'left': ';' }, + \ 'dtml': { 'left': '', 'right': '' }, + \ 'dylan': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'ebuild': { 'left': '#' }, + \ 'ecd': { 'left': '#' }, + \ 'eclass': { 'left': '#' }, + \ 'eiffel': { 'left': '--' }, + \ 'elf': { 'left': "'" }, + \ 'elmfilt': { 'left': '#' }, + \ 'erlang': { 'left': '%', 'leftAlt': '%%' }, + \ 'eruby': { 'left': '<%#', 'right': '%>', 'leftAlt': '' }, + \ 'expect': { 'left': '#' }, + \ 'exports': { 'left': '#' }, + \ 'fancy': { 'left': '#' }, + \ 'factor': { 'left': '! ', 'leftAlt': '!# ' }, + \ 'fgl': { 'left': '#' }, + \ 'focexec': { 'left': '-*' }, + \ 'form': { 'left': '*' }, + \ 'foxpro': { 'left': '*' }, + \ 'fsharp': { 'left': '(*', 'right': '*)', 'leftAlt': '//' }, + \ 'fstab': { 'left': '#' }, + \ 'fvwm': { 'left': '#' }, + \ 'fx': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'gams': { 'left': '*' }, + \ 'gdb': { 'left': '#' }, + \ 'gdmo': { 'left': '--' }, + \ 'geek': { 'left': 'GEEK_COMMENT:' }, + \ 'genshi': { 'left': '', 'leftAlt': '{#', 'rightAlt': '#}' }, + \ 'gentoo-conf-d': { 'left': '#' }, + \ 'gentoo-env-d': { 'left': '#' }, + \ 'gentoo-init-d': { 'left': '#' }, + \ 'gentoo-make-conf': { 'left': '#' }, + \ 'gentoo-package-keywords': { 'left': '#' }, + \ 'gentoo-package-mask': { 'left': '#' }, + \ 'gentoo-package-use': { 'left': '#' }, + \ 'gitcommit': { 'left': '#' }, + \ 'gitconfig': { 'left': ';' }, + \ 'gitrebase': { 'left': '#' }, + \ 'gnuplot': { 'left': '#' }, + \ 'go': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'groovy': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'gsp': { 'left': '<%--', 'right': '--%>', 'leftAlt': ''}, + \ 'gtkrc': { 'left': '#' }, + \ 'haskell': { 'left': '{-','right': '-}', 'leftAlt': '--' }, + \ 'hb': { 'left': '#' }, + \ 'h': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'haml': { 'left': '-#', 'leftAlt': '/' }, + \ 'haxe': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'hercules': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'hog': { 'left': '#' }, + \ 'hostsaccess': { 'left': '#' }, + \ 'htmlcheetah': { 'left': '##' }, + \ 'htmldjango': { 'left': '', 'leftAlt': '{#', 'rightAlt': '#}' }, + \ 'htmlos': { 'left': '#', 'right': '/#' }, + \ 'hxml': { 'left': '#' }, + \ 'ia64': { 'left': '#' }, + \ 'icon': { 'left': '#' }, + \ 'idlang': { 'left': ';' }, + \ 'idl': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'inform': { 'left': '!' }, + \ 'inittab': { 'left': '#' }, + \ 'ishd': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'iss': { 'left': ';' }, + \ 'ist': { 'left': '%' }, + \ 'jade': { 'left': '//-', 'leftAlt': '//' }, + \ 'java': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'javacc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'javascript': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'javascript.jquery': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'jess': { 'left': ';' }, + \ 'jgraph': { 'left': '(*', 'right': '*)' }, + \ 'jproperties': { 'left': '#' }, + \ 'jsp': { 'left': '<%--', 'right': '--%>' }, + \ 'kix': { 'left': ';' }, + \ 'kscript': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'lace': { 'left': '--' }, + \ 'ldif': { 'left': '#' }, + \ 'less': { 'left': '/*','right': '*/' }, + \ 'lhaskell': { 'left': '>{-','right': '-}', 'leftAlt': '>-- ' }, + \ 'lilo': { 'left': '#' }, + \ 'lilypond': { 'left': '%' }, + \ 'liquid': { 'left': '{% comment %}', 'right': '{% endcomment %}' }, + \ 'lisp': { 'left': ';', 'leftAlt': '#|', 'rightAlt': '|#' }, + \ 'llvm': { 'left': ';' }, + \ 'lotos': { 'left': '(*', 'right': '*)' }, + \ 'lout': { 'left': '#' }, + \ 'lprolog': { 'left': '%' }, + \ 'lscript': { 'left': "'" }, + \ 'lss': { 'left': '#' }, + \ 'lua': { 'left': '--', 'leftAlt': '--[[', 'rightAlt': ']]' }, + \ 'lynx': { 'left': '#' }, + \ 'lytex': { 'left': '%' }, + \ 'mail': { 'left': '> ' }, + \ 'mako': { 'left': '##' }, + \ 'man': { 'left': '."' }, + \ 'map': { 'left': '%' }, + \ 'maple': { 'left': '#' }, + \ 'markdown': { 'left': '' }, + \ 'masm': { 'left': ';' }, + \ 'mason': { 'left': '<% #', 'right': '%>' }, + \ 'master': { 'left': '$' }, + \ 'matlab': { 'left': '%' }, + \ 'mel': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'mib': { 'left': '--' }, + \ 'mirah': {'left': '#'}, + \ 'mkd': { 'left': '>' }, + \ 'mma': { 'left': '(*', 'right': '*)' }, + \ 'model': { 'left': '$', 'right': '$' }, + \ 'moduala.': { 'left': '(*', 'right': '*)' }, + \ 'modula2': { 'left': '(*', 'right': '*)' }, + \ 'modula3': { 'left': '(*', 'right': '*)' }, + \ 'monk': { 'left': ';' }, + \ 'mush': { 'left': '#' }, + \ 'mustache': { 'left': '{{!', 'right': '}}' }, + \ 'named': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'nasm': { 'left': ';' }, + \ 'nastran': { 'left': '$' }, + \ 'natural': { 'left': '/*' }, + \ 'ncf': { 'left': ';' }, + \ 'newlisp': { 'left': ';' }, + \ 'nginx': { 'left': '#' }, + \ 'nimrod': { 'left': '#' }, + \ 'nroff': { 'left': '\"' }, + \ 'nsis': { 'left': '#' }, + \ 'ntp': { 'left': '#' }, + \ 'objc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'objcpp': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'objj': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'ocaml': { 'left': '(*', 'right': '*)' }, + \ 'occam': { 'left': '--' }, + \ 'octave': { 'left': '%', 'leftAlt': '#' }, + \ 'omlet': { 'left': '(*', 'right': '*)' }, + \ 'omnimark': { 'left': ';' }, + \ 'ooc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'openroad': { 'left': '//' }, + \ 'opl': { 'left': "REM" }, + \ 'ora': { 'left': '#' }, + \ 'ox': { 'left': '//' }, + \ 'pascal': { 'left': '{','right': '}', 'leftAlt': '(*', 'rightAlt': '*)' }, + \ 'patran': { 'left': '$', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'pcap': { 'left': '#' }, + \ 'pccts': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'pdf': { 'left': '%' }, + \ 'perl': { 'left': '#' }, + \ 'pfmain': { 'left': '//' }, + \ 'php': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'pic': { 'left': ';' }, + \ 'pike': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'pilrc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'pine': { 'left': '#' }, + \ 'plm': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'plsql': { 'left': '-- ', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'po': { 'left': '#' }, + \ 'postscr': { 'left': '%' }, + \ 'pov': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'povini': { 'left': ';' }, + \ 'ppd': { 'left': '%' }, + \ 'ppwiz': { 'left': ';;' }, + \ 'processing': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'prolog': { 'left': '%', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'ps1': { 'left': '#' }, + \ 'psf': { 'left': '#' }, + \ 'ptcap': { 'left': '#' }, + \ 'puppet': { 'left': '#' }, + \ 'python': { 'left': '# ', 'leftAlt': '#' }, + \ 'radiance': { 'left': '#' }, + \ 'ratpoison': { 'left': '#' }, + \ 'r': { 'left': '#' }, + \ 'rc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'rebol': { 'left': ';' }, + \ 'registry': { 'left': ';' }, + \ 'remind': { 'left': '#' }, + \ 'resolv': { 'left': '#' }, + \ 'rgb': { 'left': '!' }, + \ 'rib': { 'left': '#' }, + \ 'robots': { 'left': '#' }, + \ 'rspec': { 'left': '#' }, + \ 'ruby': { 'left': '#' }, + \ 'sa': { 'left': '--' }, + \ 'samba': { 'left': ';', 'leftAlt': '#' }, + \ 'sass': { 'left': '//', 'leftAlt': '/*' }, + \ 'sather': { 'left': '--' }, + \ 'scala': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'scons': { 'left': '#' }, + \ 'scheme': { 'left': ';', 'leftAlt': '#|', 'rightAlt': '|#' }, + \ 'scilab': { 'left': '//' }, + \ 'scsh': { 'left': ';' }, + \ 'scss': { 'left': '/*', 'right': '*/', 'leftAlt': '//' }, + \ 'sed': { 'left': '#' }, + \ 'sgmldecl': { 'left': '--', 'right': '--' }, + \ 'sgmllnx': { 'left': '' }, + \ 'sh': { 'left': '#' }, + \ 'sicad': { 'left': '*' }, + \ 'simula': { 'left': '%', 'leftAlt': '--' }, + \ 'sinda': { 'left': '$' }, + \ 'skill': { 'left': ';' }, + \ 'slang': { 'left': '%' }, + \ 'slice': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'slim': { 'left': '/', 'leftAlt': '/!' }, + \ 'slrnrc': { 'left': '%' }, + \ 'sm': { 'left': '#' }, + \ 'smarty': { 'left': '{*', 'right': '*}' }, + \ 'smil': { 'left': '' }, + \ 'smith': { 'left': ';' }, + \ 'sml': { 'left': '(*', 'right': '*)' }, + \ 'snnsnet': { 'left': '#' }, + \ 'snnspat': { 'left': '#' }, + \ 'snnsres': { 'left': '#' }, + \ 'snobol4': { 'left': '*' }, + \ 'spec': { 'left': '#' }, + \ 'specman': { 'left': '//' }, + \ 'spectre': { 'left': '//', 'leftAlt': '*' }, + \ 'spice': { 'left': '$' }, + \ 'sql': { 'left': '-- ' }, + \ 'sqlforms': { 'left': '-- ' }, + \ 'sqlj': { 'left': '-- ' }, + \ 'sqr': { 'left': '!' }, + \ 'squid': { 'left': '#' }, + \ 'st': { 'left': '"' }, + \ 'stp': { 'left': '--' }, + \ 'supercollider': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'systemverilog': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'tads': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'tags': { 'left': ';' }, + \ 'tak': { 'left': '$' }, + \ 'tasm': { 'left': ';' }, + \ 'tcl': { 'left': '#' }, + \ 'texinfo': { 'left': "@c " }, + \ 'texmf': { 'left': '%' }, + \ 'tf': { 'left': ';' }, + \ 'tidy': { 'left': '#' }, + \ 'tli': { 'left': '#' }, + \ 'tmux': { 'left': '#' }, + \ 'trasys': { 'left': "$" }, + \ 'tsalt': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'tsscl': { 'left': '#' }, + \ 'tssgm': { 'left': "comment = '", 'right': "'" }, + \ 'txt2tags': { 'left': '%' }, + \ 'twig': { 'left': '{#', 'right': '#}' }, + \ 'uc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'uil': { 'left': '!' }, + \ 'vala': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'vb': { 'left': "'" }, + \ 'velocity': { 'left': "##", 'right': "", 'leftAlt': '#*', 'rightAlt': '*#' }, + \ 'vera': { 'left': '/*','right': '*/', 'leftAlt': '//' }, + \ 'verilog': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'verilog_systemverilog': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'vgrindefs': { 'left': '#' }, + \ 'vhdl': { 'left': '--' }, + \ 'vimperator': { 'left': '"' }, + \ 'virata': { 'left': '%' }, + \ 'vrml': { 'left': '#' }, + \ 'vsejcl': { 'left': '/*' }, + \ 'webmacro': { 'left': '##' }, + \ 'wget': { 'left': '#' }, + \ 'Wikipedia': { 'left': '' }, + \ 'winbatch': { 'left': ';' }, + \ 'wml': { 'left': '#' }, + \ 'wvdial': { 'left': ';' }, + \ 'xdefaults': { 'left': '!' }, + \ 'xkb': { 'left': '//' }, + \ 'xmath': { 'left': '#' }, + \ 'xpm2': { 'left': '!' }, + \ 'xquery': { 'left': '(:', 'right': ':)' }, + \ 'z8a': { 'left': ';' } + \ } + +let g:NERDDelimiterMap = s:delimiterMap + +if exists("g:NERDCustomDelimiters") + call extend(s:delimiterMap, g:NERDCustomDelimiters) +endif + +" Section: Comment mapping functions, autocommands and commands {{{1 +" ============================================================================ +" Section: Comment enabler autocommands {{{2 +" ============================================================================ + +augroup NERDCommenter + + "if the user enters a buffer or reads a buffer then we gotta set up + "the comment delimiters for that new filetype + autocmd BufEnter,BufRead * :call s:SetUpForNewFiletype(&filetype, 0) + + "if the filetype of a buffer changes, force the script to reset the + "delims for the buffer + autocmd Filetype * :call s:SetUpForNewFiletype(&filetype, 1) +augroup END + + +" Function: s:SetUpForNewFiletype(filetype) function {{{2 +" This function is responsible for setting up buffer scoped variables for the +" given filetype. +" +" Args: +" -filetype: the filetype to set delimiters for +" -forceReset: 1 if the delimiters should be reset if they have already be +" set for this buffer. +" +function s:SetUpForNewFiletype(filetype, forceReset) + let ft = a:filetype + + "for compound filetypes, if we dont know how to handle the full filetype + "then break it down and use the first part that we know how to handle + if ft =~ '\.' && !has_key(s:delimiterMap, ft) + let filetypes = split(a:filetype, '\.') + for i in filetypes + if has_key(s:delimiterMap, i) + let ft = i + break + endif + endfor + endif + + let b:NERDSexyComMarker = '' + + if has_key(s:delimiterMap, ft) + let b:NERDCommenterDelims = s:delimiterMap[ft] + for i in ['left', 'leftAlt', 'right', 'rightAlt'] + if !has_key(b:NERDCommenterDelims, i) + let b:NERDCommenterDelims[i] = '' + endif + endfor + else + let b:NERDCommenterDelims = s:CreateDelimMapFromCms() + endif + +endfunction + +function s:CreateDelimMapFromCms() + return { + \ 'left': substitute(&commentstring, '\([^ \t]*\)\s*%s.*', '\1', ''), + \ 'right': substitute(&commentstring, '.*%s\s*\(.*\)', '\1', 'g'), + \ 'leftAlt': '', + \ 'rightAlt': '' } +endfunction + +" Function: s:SwitchToAlternativeDelimiters(printMsgs) function {{{2 +" This function is used to swap the delimiters that are being used to the +" alternative delimiters for that filetype. For example, if a c++ file is +" being edited and // comments are being used, after this function is called +" /**/ comments will be used. +" +" Args: +" -printMsgs: if this is 1 then a message is echoed to the user telling them +" if this function changed the delimiters or not +function s:SwitchToAlternativeDelimiters(printMsgs) + "if both of the alternative delimiters are empty then there is no + "alternative comment style so bail out + if b:NERDCommenterDelims['leftAlt'] == '' && b:NERDCommenterDelims['rightAlt'] == '' + if a:printMsgs + call s:NerdEcho("Cannot use alternative delimiters, none are specified", 0) + endif + return 0 + endif + + "save the current delimiters + let tempLeft = s:Left() + let tempRight = s:Right() + + "swap current delimiters for alternative + let b:NERDCommenterDelims['left'] = b:NERDCommenterDelims['leftAlt'] + let b:NERDCommenterDelims['right'] = b:NERDCommenterDelims['rightAlt'] + + "set the previously current delimiters to be the new alternative ones + let b:NERDCommenterDelims['leftAlt'] = tempLeft + let b:NERDCommenterDelims['rightAlt'] = tempRight + + "tell the user what comment delimiters they are now using + if a:printMsgs + call s:NerdEcho("Now using " . s:Left() . " " . s:Right() . " to delimit comments", 1) + endif + + return 1 +endfunction + +" Section: Comment delimiter add/removal functions {{{1 +" ============================================================================ +" Function: s:AppendCommentToLine(){{{2 +" This function appends comment delimiters at the EOL and places the cursor in +" position to start typing the comment +function s:AppendCommentToLine() + let left = s:Left({'space': 1}) + let right = s:Right({'space': 1}) + + " get the len of the right delim + let lenRight = strlen(right) + + let isLineEmpty = strlen(getline(".")) == 0 + let insOrApp = (isLineEmpty==1 ? 'i' : 'A') + + "stick the delimiters down at the end of the line. We have to format the + "comment with spaces as appropriate + execute ":normal! " . insOrApp . (isLineEmpty ? '' : ' ') . left . right . " " + + " if there is a right delimiter then we gotta move the cursor left + " by the len of the right delimiter so we insert between the delimiters + if lenRight > 0 + let leftMoveAmount = lenRight + execute ":normal! " . leftMoveAmount . "h" + endif + startinsert +endfunction + +" Function: s:CommentBlock(top, bottom, lSide, rSide, forceNested ) {{{2 +" This function is used to comment out a region of code. This region is +" specified as a bounding box by arguments to the function. +" +" Args: +" -top: the line number for the top line of code in the region +" -bottom: the line number for the bottom line of code in the region +" -lSide: the column number for the left most column in the region +" -rSide: the column number for the right most column in the region +" -forceNested: a flag indicating whether comments should be nested +function s:CommentBlock(top, bottom, lSide, rSide, forceNested ) + " we need to create local copies of these arguments so we can modify them + let top = a:top + let bottom = a:bottom + let lSide = a:lSide + let rSide = a:rSide + + "if the top or bottom line starts with tabs we have to adjust the left and + "right boundaries so that they are set as though the tabs were spaces + let topline = getline(top) + let bottomline = getline(bottom) + if s:HasLeadingTabs(topline, bottomline) + + "find out how many tabs are in the top line and adjust the left + "boundary accordingly + let numTabs = s:NumberOfLeadingTabs(topline) + if lSide < numTabs + let lSide = &ts * lSide + else + let lSide = (lSide - numTabs) + (&ts * numTabs) + endif + + "find out how many tabs are in the bottom line and adjust the right + "boundary accordingly + let numTabs = s:NumberOfLeadingTabs(bottomline) + let rSide = (rSide - numTabs) + (&ts * numTabs) + endif + + "we must check that bottom IS actually below top, if it is not then we + "swap top and bottom. Similarly for left and right. + if bottom < top + let temp = top + let top = bottom + let bottom = top + endif + if rSide < lSide + let temp = lSide + let lSide = rSide + let rSide = temp + endif + + "if the current delimiters arent multipart then we will switch to the + "alternative delims (if THEY are) as the comment will be better and more + "accurate with multipart delims + let switchedDelims = 0 + if !s:Multipart() && g:NERDAllowAnyVisualDelims && s:AltMultipart() + let switchedDelims = 1 + call s:SwitchToAlternativeDelimiters(0) + endif + + "start the commenting from the top and keep commenting till we reach the + "bottom + let currentLine=top + while currentLine <= bottom + + "check if we are allowed to comment this line + if s:CanCommentLine(a:forceNested, currentLine) + + "convert the leading tabs into spaces + let theLine = getline(currentLine) + let lineHasLeadTabs = s:HasLeadingTabs(theLine) + if lineHasLeadTabs + let theLine = s:ConvertLeadingTabsToSpaces(theLine) + endif + + "dont comment lines that begin after the right boundary of the + "block unless the user has specified to do so + if theLine !~ '^ \{' . rSide . '\}' || !g:NERDBlockComIgnoreEmpty + + "attempt to place the cursor in on the left of the boundary box, + "then check if we were successful, if not then we cant comment this + "line + call setline(currentLine, theLine) + if s:CanPlaceCursor(currentLine, lSide) + + let leftSpaced = s:Left({'space': 1}) + let rightSpaced = s:Right({'space': 1}) + + "stick the left delimiter down + let theLine = strpart(theLine, 0, lSide-1) . leftSpaced . strpart(theLine, lSide-1) + + if s:Multipart() + "stick the right delimiter down + let theLine = strpart(theLine, 0, rSide+strlen(leftSpaced)) . rightSpaced . strpart(theLine, rSide+strlen(leftSpaced)) + + let firstLeftDelim = s:FindDelimiterIndex(s:Left(), theLine) + let lastRightDelim = s:LastIndexOfDelim(s:Right(), theLine) + + if firstLeftDelim != -1 && lastRightDelim != -1 + let searchStr = strpart(theLine, 0, lastRightDelim) + let searchStr = strpart(searchStr, firstLeftDelim+strlen(s:Left())) + + "replace the outter most delims in searchStr with + "place-holders + let theLineWithPlaceHolders = s:ReplaceDelims(s:Left(), s:Right(), g:NERDLPlace, g:NERDRPlace, searchStr) + + "add the right delimiter onto the line + let theLine = strpart(theLine, 0, firstLeftDelim+strlen(s:Left())) . theLineWithPlaceHolders . strpart(theLine, lastRightDelim) + endif + endif + endif + endif + + "restore tabs if needed + if lineHasLeadTabs + let theLine = s:ConvertLeadingSpacesToTabs(theLine) + endif + + call setline(currentLine, theLine) + endif + + let currentLine = currentLine + 1 + endwhile + + "if we switched delims then we gotta go back to what they were before + if switchedDelims == 1 + call s:SwitchToAlternativeDelimiters(0) + endif +endfunction + +" Function: s:CommentLines(forceNested, alignLeft, alignRight, firstLine, lastLine) {{{2 +" This function comments a range of lines. +" +" Args: +" -forceNested: a flag indicating whether the called is requesting the comment +" to be nested if need be +" -align: should be "left" or "both" or "none" +" -firstLine/lastLine: the top and bottom lines to comment +function s:CommentLines(forceNested, align, firstLine, lastLine) + " we need to get the left and right indexes of the leftmost char in the + " block of of lines and the right most char so that we can do alignment of + " the delimiters if the user has specified + let leftAlignIndx = s:LeftMostIndx(a:forceNested, 0, a:firstLine, a:lastLine) + let rightAlignIndx = s:RightMostIndx(a:forceNested, 0, a:firstLine, a:lastLine) + + " gotta add the length of the left delimiter onto the rightAlignIndx cos + " we'll be adding a left delim to the line + let rightAlignIndx = rightAlignIndx + strlen(s:Left({'space': 1})) + + " now we actually comment the lines. Do it line by line + let currentLine = a:firstLine + while currentLine <= a:lastLine + + " get the next line, check commentability and convert spaces to tabs + let theLine = getline(currentLine) + let lineHasLeadingTabs = s:HasLeadingTabs(theLine) + let theLine = s:ConvertLeadingTabsToSpaces(theLine) + if s:CanCommentLine(a:forceNested, currentLine) + "if the user has specified forceNesting then we check to see if we + "need to switch delimiters for place-holders + if a:forceNested && g:NERDUsePlaceHolders + let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine) + endif + + " find out if the line is commented using normal delims and/or + " alternate ones + let isCommented = s:IsCommented(s:Left(), s:Right(), theLine) || s:IsCommented(s:Left({'alt': 1}), s:Right({'alt': 1}), theLine) + + " check if we can comment this line + if !isCommented || g:NERDUsePlaceHolders || s:Multipart() + if a:align == "left" || a:align == "both" + let theLine = s:AddLeftDelimAligned(s:Left({'space': 1}), theLine, leftAlignIndx) + else + let theLine = s:AddLeftDelim(s:Left({'space': 1}), theLine) + endif + if a:align == "both" + let theLine = s:AddRightDelimAligned(s:Right({'space': 1}), theLine, rightAlignIndx) + else + let theLine = s:AddRightDelim(s:Right({'space': 1}), theLine) + endif + endif + endif + + " restore leading tabs if appropriate + if lineHasLeadingTabs + let theLine = s:ConvertLeadingSpacesToTabs(theLine) + endif + + " we are done with this line + call setline(currentLine, theLine) + let currentLine = currentLine + 1 + endwhile + +endfunction + +" Function: s:CommentLinesMinimal(firstLine, lastLine) {{{2 +" This function comments a range of lines in a minimal style. I +" +" Args: +" -firstLine/lastLine: the top and bottom lines to comment +function s:CommentLinesMinimal(firstLine, lastLine) + "check that minimal comments can be done on this filetype + if !s:HasMultipartDelims() + throw 'NERDCommenter.Delimiters exception: Minimal comments can only be used for filetypes that have multipart delimiters' + endif + + "if we need to use place holders for the comment, make sure they are + "enabled for this filetype + if !g:NERDUsePlaceHolders && s:DoesBlockHaveMultipartDelim(a:firstLine, a:lastLine) + throw 'NERDCommenter.Settings exception: Place holders are required but disabled.' + endif + + "get the left and right delims to smack on + let left = s:GetSexyComLeft(g:NERDSpaceDelims,0) + let right = s:GetSexyComRight(g:NERDSpaceDelims,0) + + "make sure all multipart delims on the lines are replaced with + "placeholders to prevent illegal syntax + let currentLine = a:firstLine + while(currentLine <= a:lastLine) + let theLine = getline(currentLine) + let theLine = s:ReplaceDelims(left, right, g:NERDLPlace, g:NERDRPlace, theLine) + call setline(currentLine, theLine) + let currentLine = currentLine + 1 + endwhile + + "add the delim to the top line + let theLine = getline(a:firstLine) + let lineHasLeadingTabs = s:HasLeadingTabs(theLine) + let theLine = s:ConvertLeadingTabsToSpaces(theLine) + let theLine = s:AddLeftDelim(left, theLine) + if lineHasLeadingTabs + let theLine = s:ConvertLeadingSpacesToTabs(theLine) + endif + call setline(a:firstLine, theLine) + + "add the delim to the bottom line + let theLine = getline(a:lastLine) + let lineHasLeadingTabs = s:HasLeadingTabs(theLine) + let theLine = s:ConvertLeadingTabsToSpaces(theLine) + let theLine = s:AddRightDelim(right, theLine) + if lineHasLeadingTabs + let theLine = s:ConvertLeadingSpacesToTabs(theLine) + endif + call setline(a:lastLine, theLine) +endfunction + +" Function: s:CommentLinesSexy(topline, bottomline) function {{{2 +" This function is used to comment lines in the 'Sexy' style. eg in c: +" /* +" * This is a sexy comment +" */ +" Args: +" -topline: the line num of the top line in the sexy comment +" -bottomline: the line num of the bottom line in the sexy comment +function s:CommentLinesSexy(topline, bottomline) + let left = s:GetSexyComLeft(0, 0) + let right = s:GetSexyComRight(0, 0) + + "check if we can do a sexy comment with the available delimiters + if left == -1 || right == -1 + throw 'NERDCommenter.Delimiters exception: cannot perform sexy comments with available delimiters.' + endif + + "make sure the lines arent already commented sexually + if !s:CanSexyCommentLines(a:topline, a:bottomline) + throw 'NERDCommenter.Nesting exception: cannot nest sexy comments' + endif + + + let sexyComMarker = s:GetSexyComMarker(0,0) + let sexyComMarkerSpaced = s:GetSexyComMarker(1,0) + + + " we jam the comment as far to the right as possible + let leftAlignIndx = s:LeftMostIndx(1, 1, a:topline, a:bottomline) + + "check if we should use the compact style i.e that the left/right + "delimiters should appear on the first and last lines of the code and not + "on separate lines above/below the first/last lines of code + if g:NERDCompactSexyComs + let spaceString = (g:NERDSpaceDelims ? s:spaceStr : '') + + "comment the top line + let theLine = getline(a:topline) + let lineHasTabs = s:HasLeadingTabs(theLine) + if lineHasTabs + let theLine = s:ConvertLeadingTabsToSpaces(theLine) + endif + let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine) + let theLine = s:AddLeftDelimAligned(left . spaceString, theLine, leftAlignIndx) + if lineHasTabs + let theLine = s:ConvertLeadingSpacesToTabs(theLine) + endif + call setline(a:topline, theLine) + + "comment the bottom line + if a:bottomline != a:topline + let theLine = getline(a:bottomline) + let lineHasTabs = s:HasLeadingTabs(theLine) + if lineHasTabs + let theLine = s:ConvertLeadingTabsToSpaces(theLine) + endif + let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine) + endif + let theLine = s:AddRightDelim(spaceString . right, theLine) + if lineHasTabs + let theLine = s:ConvertLeadingSpacesToTabs(theLine) + endif + call setline(a:bottomline, theLine) + else + + " add the left delimiter one line above the lines that are to be commented + call cursor(a:topline, 1) + execute 'normal! O' + let theLine = repeat(' ', leftAlignIndx) . left + + " Make sure tabs are respected + if !&expandtab + let theLine = s:ConvertLeadingSpacesToTabs(theLine) + endif + call setline(a:topline, theLine) + + " add the right delimiter after bottom line (we have to add 1 cos we moved + " the lines down when we added the left delim + call cursor(a:bottomline+1, 1) + execute 'normal! o' + let theLine = repeat(' ', leftAlignIndx) . repeat(' ', strlen(left)-strlen(sexyComMarker)) . right + + " Make sure tabs are respected + if !&expandtab + let theLine = s:ConvertLeadingSpacesToTabs(theLine) + endif + call setline(a:bottomline+2, theLine) + + endif + + " go thru each line adding the sexyComMarker marker to the start of each + " line in the appropriate place to align them with the comment delims + let currentLine = a:topline+1 + while currentLine <= a:bottomline + !g:NERDCompactSexyComs + " get the line and convert the tabs to spaces + let theLine = getline(currentLine) + let lineHasTabs = s:HasLeadingTabs(theLine) + if lineHasTabs + let theLine = s:ConvertLeadingTabsToSpaces(theLine) + endif + + let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine) + + " add the sexyComMarker + let theLine = repeat(' ', leftAlignIndx) . repeat(' ', strlen(left)-strlen(sexyComMarker)) . sexyComMarkerSpaced . strpart(theLine, leftAlignIndx) + + if lineHasTabs + let theLine = s:ConvertLeadingSpacesToTabs(theLine) + endif + + + " set the line and move onto the next one + call setline(currentLine, theLine) + let currentLine = currentLine + 1 + endwhile + +endfunction + +" Function: s:CommentLinesToggle(forceNested, firstLine, lastLine) {{{2 +" Applies "toggle" commenting to the given range of lines +" +" Args: +" -forceNested: a flag indicating whether the called is requesting the comment +" to be nested if need be +" -firstLine/lastLine: the top and bottom lines to comment +function s:CommentLinesToggle(forceNested, firstLine, lastLine) + let currentLine = a:firstLine + while currentLine <= a:lastLine + + " get the next line, check commentability and convert spaces to tabs + let theLine = getline(currentLine) + let lineHasLeadingTabs = s:HasLeadingTabs(theLine) + let theLine = s:ConvertLeadingTabsToSpaces(theLine) + if s:CanToggleCommentLine(a:forceNested, currentLine) + + "if the user has specified forceNesting then we check to see if we + "need to switch delimiters for place-holders + if g:NERDUsePlaceHolders + let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine) + endif + + let theLine = s:AddLeftDelim(s:Left({'space': 1}), theLine) + let theLine = s:AddRightDelim(s:Right({'space': 1}), theLine) + endif + + " restore leading tabs if appropriate + if lineHasLeadingTabs + let theLine = s:ConvertLeadingSpacesToTabs(theLine) + endif + + " we are done with this line + call setline(currentLine, theLine) + let currentLine = currentLine + 1 + endwhile + +endfunction + +" Function: s:CommentRegion(topline, topCol, bottomLine, bottomCol) function {{{2 +" This function comments chunks of text selected in visual mode. +" It will comment exactly the text that they have selected. +" Args: +" -topLine: the line num of the top line in the sexy comment +" -topCol: top left col for this comment +" -bottomline: the line num of the bottom line in the sexy comment +" -bottomCol: the bottom right col for this comment +" -forceNested: whether the caller wants comments to be nested if the +" line(s) are already commented +function s:CommentRegion(topLine, topCol, bottomLine, bottomCol, forceNested) + + "switch delims (if we can) if the current set isnt multipart + let switchedDelims = 0 + if !s:Multipart() && s:AltMultipart() && !g:NERDAllowAnyVisualDelims + let switchedDelims = 1 + call s:SwitchToAlternativeDelimiters(0) + endif + + "if there is only one line in the comment then just do it + if a:topLine == a:bottomLine + call s:CommentBlock(a:topLine, a:bottomLine, a:topCol, a:bottomCol, a:forceNested) + + "there are multiple lines in the comment + else + "comment the top line + call s:CommentBlock(a:topLine, a:topLine, a:topCol, strlen(getline(a:topLine)), a:forceNested) + + "comment out all the lines in the middle of the comment + let topOfRange = a:topLine+1 + let bottomOfRange = a:bottomLine-1 + if topOfRange <= bottomOfRange + call s:CommentLines(a:forceNested, "none", topOfRange, bottomOfRange) + endif + + "comment the bottom line + let bottom = getline(a:bottomLine) + let numLeadingSpacesTabs = strlen(substitute(bottom, '^\([ \t]*\).*$', '\1', '')) + call s:CommentBlock(a:bottomLine, a:bottomLine, numLeadingSpacesTabs+1, a:bottomCol, a:forceNested) + + endif + + "stick the cursor back on the char it was on before the comment + call cursor(a:topLine, a:topCol + strlen(s:Left()) + g:NERDSpaceDelims) + + "if we switched delims then we gotta go back to what they were before + if switchedDelims == 1 + call s:SwitchToAlternativeDelimiters(0) + endif + +endfunction + +" Function: s:InvertComment(firstLine, lastLine) function {{{2 +" Inverts the comments on the lines between and including the given line +" numbers i.e all commented lines are uncommented and vice versa +" Args: +" -firstLine: the top of the range of lines to be inverted +" -lastLine: the bottom of the range of lines to be inverted +function s:InvertComment(firstLine, lastLine) + + " go thru all lines in the given range + let currentLine = a:firstLine + while currentLine <= a:lastLine + let theLine = getline(currentLine) + + let sexyComBounds = s:FindBoundingLinesOfSexyCom(currentLine) + + " if the line is commented normally, uncomment it + if s:IsCommentedFromStartOfLine(s:Left(), theLine) || s:IsCommentedFromStartOfLine(s:Left({'alt': 1}), theLine) + call s:UncommentLines(currentLine, currentLine) + let currentLine = currentLine + 1 + + " check if the line is commented sexually + elseif !empty(sexyComBounds) + let numLinesBeforeSexyComRemoved = s:NumLinesInBuf() + call s:UncommentLinesSexy(sexyComBounds[0], sexyComBounds[1]) + + "move to the line after last line of the sexy comment + let numLinesAfterSexyComRemoved = s:NumLinesInBuf() + let currentLine = sexyComBounds[1] - (numLinesBeforeSexyComRemoved - numLinesAfterSexyComRemoved) + 1 + + " the line isnt commented + else + call s:CommentLinesToggle(1, currentLine, currentLine) + let currentLine = currentLine + 1 + endif + + endwhile +endfunction + +" Function: NERDComment(mode, type) function {{{2 +" This function is a Wrapper for the main commenting functions +" +" Args: +" -mode: a character indicating the mode in which the comment is requested: +" 'n' for Normal mode, 'x' for Visual mode +" -type: the type of commenting requested. Can be 'Sexy', 'Invert', +" 'Minimal', 'Toggle', 'AlignLeft', 'AlignBoth', 'Comment', +" 'Nested', 'ToEOL', 'Append', 'Insert', 'Uncomment', 'Yank' +function! NERDComment(mode, type) range + let isVisual = a:mode =~ '[vsx]' + " we want case sensitivity when commenting + let oldIgnoreCase = &ignorecase + set noignorecase + + if !exists("g:did_load_ftplugin") || g:did_load_ftplugin != 1 + call s:NerdEcho("filetype plugins should be enabled. See :help NERDComInstallation and :help :filetype-plugin-on", 0) + endif + + if isVisual + let firstLine = line("'<") + let lastLine = line("'>") + let firstCol = col("'<") + let lastCol = col("'>") - (&selection == 'exclusive' ? 1 : 0) + else + let firstLine = a:firstline + let lastLine = a:lastline + endif + + let countWasGiven = (!isVisual && firstLine != lastLine) + + let forceNested = (a:type ==? 'Nested' || g:NERDDefaultNesting) + + if a:type ==? 'Comment' || a:type ==? 'Nested' + if isVisual && visualmode() == "\" + call s:CommentBlock(firstLine, lastLine, firstCol, lastCol, forceNested) + elseif isVisual && visualmode() == "v" && (g:NERDCommentWholeLinesInVMode==0 || (g:NERDCommentWholeLinesInVMode==2 && s:HasMultipartDelims())) + call s:CommentRegion(firstLine, firstCol, lastLine, lastCol, forceNested) + else + call s:CommentLines(forceNested, "none", firstLine, lastLine) + endif + + elseif a:type ==? 'AlignLeft' || a:type ==? 'AlignBoth' + let align = "none" + if a:type ==? "AlignLeft" + let align = "left" + elseif a:type ==? "AlignBoth" + let align = "both" + endif + call s:CommentLines(forceNested, align, firstLine, lastLine) + + elseif a:type ==? 'Invert' + call s:InvertComment(firstLine, lastLine) + + elseif a:type ==? 'Sexy' + try + call s:CommentLinesSexy(firstLine, lastLine) + catch /NERDCommenter.Delimiters/ + call s:CommentLines(forceNested, "none", firstLine, lastLine) + catch /NERDCommenter.Nesting/ + call s:NerdEcho("Sexy comment aborted. Nested sexy cannot be nested", 0) + endtry + + elseif a:type ==? 'Toggle' + let theLine = getline(firstLine) + + if s:IsInSexyComment(firstLine) || s:IsCommentedFromStartOfLine(s:Left(), theLine) || s:IsCommentedFromStartOfLine(s:Left({'alt': 1}), theLine) + call s:UncommentLines(firstLine, lastLine) + else + call s:CommentLinesToggle(forceNested, firstLine, lastLine) + endif + + elseif a:type ==? 'Minimal' + try + call s:CommentLinesMinimal(firstLine, lastLine) + catch /NERDCommenter.Delimiters/ + call s:NerdEcho("Minimal comments can only be used for filetypes that have multipart delimiters.", 0) + catch /NERDCommenter.Settings/ + call s:NerdEcho("Place holders are required but disabled.", 0) + endtry + + elseif a:type ==? 'ToEOL' + call s:SaveScreenState() + call s:CommentBlock(firstLine, firstLine, col("."), col("$")-1, 1) + call s:RestoreScreenState() + + elseif a:type ==? 'Append' + call s:AppendCommentToLine() + + elseif a:type ==? 'Insert' + call s:PlaceDelimitersAndInsBetween() + + elseif a:type ==? 'Uncomment' + call s:UncommentLines(firstLine, lastLine) + + elseif a:type ==? 'Yank' + if isVisual + normal! gvy + elseif countWasGiven + execute firstLine .','. lastLine .'yank' + else + normal! yy + endif + execute firstLine .','. lastLine .'call NERDComment("'. a:mode .'", "Comment")' + endif + + let &ignorecase = oldIgnoreCase + + if isVisual + let nlines = lastLine - firstLine + silent! call repeat#set("V" . nlines . "jo" . "\NERDCommenter". a:type) + else + silent! call repeat#set("\NERDCommenter". a:type) + endif +endfunction + +" Function: s:PlaceDelimitersAndInsBetween() function {{{2 +" This is function is called to place comment delimiters down and place the +" cursor between them +function s:PlaceDelimitersAndInsBetween() + " get the left and right delimiters without any escape chars in them + let left = s:Left({'space': 1}) + let right = s:Right({'space': 1}) + + let theLine = getline(".") + let lineHasLeadTabs = s:HasLeadingTabs(theLine) || (theLine =~ '^ *$' && !&expandtab) + + "convert tabs to spaces and adjust the cursors column to take this into + "account + let untabbedCol = s:UntabbedCol(theLine, col(".")) + call setline(line("."), s:ConvertLeadingTabsToSpaces(theLine)) + call cursor(line("."), untabbedCol) + + " get the len of the right delim + let lenRight = strlen(right) + + let isDelimOnEOL = col(".") >= strlen(getline(".")) + + " if the cursor is in the first col then we gotta insert rather than + " append the comment delimiters here + let insOrApp = (col(".")==1 ? 'i' : 'a') + + " place the delimiters down. We do it differently depending on whether + " there is a left AND right delimiter + if lenRight > 0 + execute ":normal! " . insOrApp . left . right + execute ":normal! " . lenRight . "h" + else + execute ":normal! " . insOrApp . left + endif + silent! normal! l + + "if needed convert spaces back to tabs and adjust the cursors col + "accordingly + if lineHasLeadTabs + let tabbedCol = s:TabbedCol(getline("."), col(".")) + call setline(line("."), s:ConvertLeadingSpacesToTabs(getline("."))) + call cursor(line("."), tabbedCol) + endif + + if isDelimOnEOL && lenRight == 0 + startinsert! + else + startinsert + endif +endfunction + +" Function: s:RemoveDelimiters(left, right, line) {{{2 +" this function is called to remove the first left comment delimiter and the +" last right delimiter of the given line. +" +" The args left and right must be strings. If there is no right delimiter (as +" is the case for e.g vim file comments) them the arg right should be "" +" +" Args: +" -left: the left comment delimiter +" -right: the right comment delimiter +" -line: the line to remove the delimiters from +function s:RemoveDelimiters(left, right, line) + + let l:left = a:left + let l:right = a:right + let lenLeft = strlen(left) + let lenRight = strlen(right) + + let delimsSpaced = (g:NERDSpaceDelims || g:NERDRemoveExtraSpaces) + + let line = a:line + + "look for the left delimiter, if we find it, remove it. + let leftIndx = s:FindDelimiterIndex(a:left, line) + if leftIndx != -1 + let line = strpart(line, 0, leftIndx) . strpart(line, leftIndx+lenLeft) + + "if the user has specified that there is a space after the left delim + "then check for the space and remove it if it is there + if delimsSpaced && strpart(line, leftIndx, s:lenSpaceStr) == s:spaceStr + let line = strpart(line, 0, leftIndx) . strpart(line, leftIndx+s:lenSpaceStr) + endif + endif + + "look for the right delimiter, if we find it, remove it + let rightIndx = s:FindDelimiterIndex(a:right, line) + if rightIndx != -1 + let line = strpart(line, 0, rightIndx) . strpart(line, rightIndx+lenRight) + + "if the user has specified that there is a space before the right delim + "then check for the space and remove it if it is there + if delimsSpaced && strpart(line, rightIndx-s:lenSpaceStr, s:lenSpaceStr) == s:spaceStr && s:Multipart() + let line = strpart(line, 0, rightIndx-s:lenSpaceStr) . strpart(line, rightIndx) + endif + endif + + return line +endfunction + +" Function: s:UncommentLines(topLine, bottomLine) {{{2 +" This function uncomments the given lines +" +" Args: +" topLine: the top line of the visual selection to uncomment +" bottomLine: the bottom line of the visual selection to uncomment +function s:UncommentLines(topLine, bottomLine) + "make local copies of a:firstline and a:lastline and, if need be, swap + "them around if the top line is below the bottom + let l:firstline = a:topLine + let l:lastline = a:bottomLine + if firstline > lastline + let firstline = lastline + let lastline = a:topLine + endif + + "go thru each line uncommenting each line removing sexy comments + let currentLine = firstline + while currentLine <= lastline + + "check the current line to see if it is part of a sexy comment + let sexyComBounds = s:FindBoundingLinesOfSexyCom(currentLine) + if !empty(sexyComBounds) + + "we need to store the num lines in the buf before the comment is + "removed so we know how many lines were removed when the sexy com + "was removed + let numLinesBeforeSexyComRemoved = s:NumLinesInBuf() + + call s:UncommentLinesSexy(sexyComBounds[0], sexyComBounds[1]) + + "move to the line after last line of the sexy comment + let numLinesAfterSexyComRemoved = s:NumLinesInBuf() + let numLinesRemoved = numLinesBeforeSexyComRemoved - numLinesAfterSexyComRemoved + let currentLine = sexyComBounds[1] - numLinesRemoved + 1 + let lastline = lastline - numLinesRemoved + + "no sexy com was detected so uncomment the line as normal + else + call s:UncommentLinesNormal(currentLine, currentLine) + let currentLine = currentLine + 1 + endif + endwhile + +endfunction + +" Function: s:UncommentLinesSexy(topline, bottomline) {{{2 +" This function removes all the comment characters associated with the sexy +" comment spanning the given lines +" Args: +" -topline/bottomline: the top/bottom lines of the sexy comment +function s:UncommentLinesSexy(topline, bottomline) + let left = s:GetSexyComLeft(0,1) + let right = s:GetSexyComRight(0,1) + + + "check if it is even possible for sexy comments to exist with the + "available delimiters + if left == -1 || right == -1 + throw 'NERDCommenter.Delimiters exception: cannot uncomment sexy comments with available delimiters.' + endif + + let leftUnEsc = s:GetSexyComLeft(0,0) + let rightUnEsc = s:GetSexyComRight(0,0) + + let sexyComMarker = s:GetSexyComMarker(0, 1) + let sexyComMarkerUnEsc = s:GetSexyComMarker(0, 0) + + "the markerOffset is how far right we need to move the sexyComMarker to + "line it up with the end of the left delim + let markerOffset = strlen(leftUnEsc)-strlen(sexyComMarkerUnEsc) + + " go thru the intermediate lines of the sexy comment and remove the + " sexy comment markers (eg the '*'s on the start of line in a c sexy + " comment) + let currentLine = a:topline+1 + while currentLine < a:bottomline + let theLine = getline(currentLine) + + " remove the sexy comment marker from the line. We also remove the + " space after it if there is one and if appropriate options are set + let sexyComMarkerIndx = stridx(theLine, sexyComMarkerUnEsc) + if strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc), s:lenSpaceStr) == s:spaceStr && g:NERDSpaceDelims + let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc)+s:lenSpaceStr) + else + let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc)) + endif + + let theLine = s:SwapOutterPlaceHoldersForMultiPartDelims(theLine) + + let theLine = s:ConvertLeadingWhiteSpace(theLine) + + " move onto the next line + call setline(currentLine, theLine) + let currentLine = currentLine + 1 + endwhile + + " gotta make a copy of a:bottomline cos we modify the position of the + " last line it if we remove the topline + let bottomline = a:bottomline + + " get the first line so we can remove the left delim from it + let theLine = getline(a:topline) + + " if the first line contains only the left delim then just delete it + if theLine =~ '^[ \t]*' . left . '[ \t]*$' && !g:NERDCompactSexyComs + call cursor(a:topline, 1) + normal! dd + let bottomline = bottomline - 1 + + " topline contains more than just the left delim + else + + " remove the delim. If there is a space after it + " then remove this too if appropriate + let delimIndx = stridx(theLine, leftUnEsc) + if strpart(theLine, delimIndx+strlen(leftUnEsc), s:lenSpaceStr) == s:spaceStr && g:NERDSpaceDelims + let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(leftUnEsc)+s:lenSpaceStr) + else + let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(leftUnEsc)) + endif + let theLine = s:SwapOutterPlaceHoldersForMultiPartDelims(theLine) + call setline(a:topline, theLine) + endif + + " get the last line so we can remove the right delim + let theLine = getline(bottomline) + + " if the bottomline contains only the right delim then just delete it + if theLine =~ '^[ \t]*' . right . '[ \t]*$' + call cursor(bottomline, 1) + normal! dd + + " the last line contains more than the right delim + else + " remove the right delim. If there is a space after it and + " if the appropriate options are set then remove this too. + let delimIndx = s:LastIndexOfDelim(rightUnEsc, theLine) + if strpart(theLine, delimIndx+strlen(leftUnEsc), s:lenSpaceStr) == s:spaceStr && g:NERDSpaceDelims + let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(rightUnEsc)+s:lenSpaceStr) + else + let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(rightUnEsc)) + endif + + " if the last line also starts with a sexy comment marker then we + " remove this as well + if theLine =~ '^[ \t]*' . sexyComMarker + + " remove the sexyComMarker. If there is a space after it then + " remove that too + let sexyComMarkerIndx = stridx(theLine, sexyComMarkerUnEsc) + if strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc), s:lenSpaceStr) == s:spaceStr && g:NERDSpaceDelims + let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset ) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc)+s:lenSpaceStr) + else + let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset ) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc)) + endif + endif + + let theLine = s:SwapOutterPlaceHoldersForMultiPartDelims(theLine) + call setline(bottomline, theLine) + endif +endfunction + +" Function: s:UncommentLineNormal(line) {{{2 +" uncomments the given line and returns the result +" Args: +" -line: the line to uncomment +function s:UncommentLineNormal(line) + let line = a:line + + "get the positions of all delim types on the line + let indxLeft = s:FindDelimiterIndex(s:Left(), line) + let indxLeftAlt = s:FindDelimiterIndex(s:Left({'alt': 1}), line) + let indxRight = s:FindDelimiterIndex(s:Right(), line) + let indxRightAlt = s:FindDelimiterIndex(s:Right({'alt': 1}), line) + + "get the comment status on the line so we know how it is commented + let lineCommentStatus = s:IsCommentedOuttermost(s:Left(), s:Right(), s:Left({'alt': 1}), s:Right({'alt': 1}), line) + + "it is commented with s:Left() and s:Right() so remove these delims + if lineCommentStatus == 1 + let line = s:RemoveDelimiters(s:Left(), s:Right(), line) + + "it is commented with s:Left({'alt': 1}) and s:Right({'alt': 1}) so remove these delims + elseif lineCommentStatus == 2 && g:NERDRemoveAltComs + let line = s:RemoveDelimiters(s:Left({'alt': 1}), s:Right({'alt': 1}), line) + + "it is not properly commented with any delims so we check if it has + "any random left or right delims on it and remove the outtermost ones + else + "remove the outter most left comment delim + if indxLeft != -1 && (indxLeft < indxLeftAlt || indxLeftAlt == -1) + let line = s:RemoveDelimiters(s:Left(), '', line) + elseif indxLeftAlt != -1 && g:NERDRemoveAltComs + let line = s:RemoveDelimiters(s:Left({'alt': 1}), '', line) + endif + + "remove the outter most right comment delim + if indxRight != -1 && (indxRight < indxRightAlt || indxRightAlt == -1) + let line = s:RemoveDelimiters('', s:Right(), line) + elseif indxRightAlt != -1 && g:NERDRemoveAltComs + let line = s:RemoveDelimiters('', s:Right({'alt': 1}), line) + endif + endif + + + let indxLeftPlace = s:FindDelimiterIndex(g:NERDLPlace, line) + let indxRightPlace = s:FindDelimiterIndex(g:NERDRPlace, line) + + let right = s:Right() + let left = s:Left() + if !s:Multipart() + let right = s:Right({'alt': 1}) + let left = s:Left({'alt': 1}) + endif + + + "if there are place-holders on the line then we check to see if they are + "the outtermost delimiters on the line. If so then we replace them with + "real delimiters + if indxLeftPlace != -1 + if (indxLeftPlace < indxLeft || indxLeft==-1) && (indxLeftPlace < indxLeftAlt || indxLeftAlt==-1) + let line = s:ReplaceDelims(g:NERDLPlace, g:NERDRPlace, left, right, line) + endif + elseif indxRightPlace != -1 + if (indxRightPlace < indxLeft || indxLeft==-1) && (indxLeftPlace < indxLeftAlt || indxLeftAlt==-1) + let line = s:ReplaceDelims(g:NERDLPlace, g:NERDRPlace, left, right, line) + endif + + endif + + let line = s:ConvertLeadingWhiteSpace(line) + + return line +endfunction + +" Function: s:UncommentLinesNormal(topline, bottomline) {{{2 +" This function is called to uncomment lines that arent a sexy comment +" Args: +" -topline/bottomline: the top/bottom line numbers of the comment +function s:UncommentLinesNormal(topline, bottomline) + let currentLine = a:topline + while currentLine <= a:bottomline + let line = getline(currentLine) + call setline(currentLine, s:UncommentLineNormal(line)) + let currentLine = currentLine + 1 + endwhile +endfunction + + +" Section: Other helper functions {{{1 +" ============================================================================ + +" Function: s:AddLeftDelim(delim, theLine) {{{2 +" Args: +function s:AddLeftDelim(delim, theLine) + return substitute(a:theLine, '^\([ \t]*\)', '\1' . a:delim, '') +endfunction + +" Function: s:AddLeftDelimAligned(delim, theLine) {{{2 +" Args: +function s:AddLeftDelimAligned(delim, theLine, alignIndx) + + "if the line is not long enough then bung some extra spaces on the front + "so we can align the delim properly + let theLine = a:theLine + if strlen(theLine) < a:alignIndx + let theLine = repeat(' ', a:alignIndx - strlen(theLine)) + endif + + return strpart(theLine, 0, a:alignIndx) . a:delim . strpart(theLine, a:alignIndx) +endfunction + +" Function: s:AddRightDelim(delim, theLine) {{{2 +" Args: +function s:AddRightDelim(delim, theLine) + if a:delim == '' + return a:theLine + else + return substitute(a:theLine, '$', a:delim, '') + endif +endfunction + +" Function: s:AddRightDelimAligned(delim, theLine, alignIndx) {{{2 +" Args: +function s:AddRightDelimAligned(delim, theLine, alignIndx) + if a:delim == "" + return a:theLine + else + + " when we align the right delim we are just adding spaces + " so we get a string containing the needed spaces (it + " could be empty) + let extraSpaces = '' + let extraSpaces = repeat(' ', a:alignIndx-strlen(a:theLine)) + + " add the right delim + return substitute(a:theLine, '$', extraSpaces . a:delim, '') + endif +endfunction + +" Function: s:AltMultipart() {{{2 +" returns 1 if the alternative delims are multipart +function s:AltMultipart() + return b:NERDCommenterDelims['rightAlt'] != '' +endfunction + +" Function: s:CanCommentLine(forceNested, line) {{{2 +"This function is used to determine whether the given line can be commented. +"It returns 1 if it can be and 0 otherwise +" +" Args: +" -forceNested: a flag indicating whether the caller wants comments to be nested +" if the current line is already commented +" -lineNum: the line num of the line to check for commentability +function s:CanCommentLine(forceNested, lineNum) + let theLine = getline(a:lineNum) + + " make sure we don't comment lines that are just spaces or tabs or empty. + if theLine =~ "^[ \t]*$" + return 0 + endif + + "if the line is part of a sexy comment then just flag it... + if s:IsInSexyComment(a:lineNum) + return 0 + endif + + let isCommented = s:IsCommentedNormOrSexy(a:lineNum) + + "if the line isnt commented return true + if !isCommented + return 1 + endif + + "if the line is commented but nesting is allowed then return true + if a:forceNested && (!s:Multipart() || g:NERDUsePlaceHolders) + return 1 + endif + + return 0 +endfunction + +" Function: s:CanPlaceCursor(line, col) {{{2 +" returns 1 if the cursor can be placed exactly in the given position +function s:CanPlaceCursor(line, col) + let c = col(".") + let l = line(".") + call cursor(a:line, a:col) + let success = (line(".") == a:line && col(".") == a:col) + call cursor(l,c) + return success +endfunction + +" Function: s:CanSexyCommentLines(topline, bottomline) {{{2 +" Return: 1 if the given lines can be commented sexually, 0 otherwise +function s:CanSexyCommentLines(topline, bottomline) + " see if the selected regions have any sexy comments + let currentLine = a:topline + while(currentLine <= a:bottomline) + if s:IsInSexyComment(currentLine) + return 0 + endif + let currentLine = currentLine + 1 + endwhile + return 1 +endfunction +" Function: s:CanToggleCommentLine(forceNested, line) {{{2 +"This function is used to determine whether the given line can be toggle commented. +"It returns 1 if it can be and 0 otherwise +" +" Args: +" -lineNum: the line num of the line to check for commentability +function s:CanToggleCommentLine(forceNested, lineNum) + let theLine = getline(a:lineNum) + if (s:IsCommentedFromStartOfLine(s:Left(), theLine) || s:IsCommentedFromStartOfLine(s:Left({'alt': 1}), theLine)) && !a:forceNested + return 0 + endif + + " make sure we don't comment lines that are just spaces or tabs or empty. + if theLine =~ "^[ \t]*$" + return 0 + endif + + "if the line is part of a sexy comment then just flag it... + if s:IsInSexyComment(a:lineNum) + return 0 + endif + + return 1 +endfunction + +" Function: s:ConvertLeadingSpacesToTabs(line) {{{2 +" This function takes a line and converts all leading tabs on that line into +" spaces +" +" Args: +" -line: the line whose leading tabs will be converted +function s:ConvertLeadingSpacesToTabs(line) + let toReturn = a:line + while toReturn =~ '^\t*' . s:TabSpace() . '\(.*\)$' + let toReturn = substitute(toReturn, '^\(\t*\)' . s:TabSpace() . '\(.*\)$' , '\1\t\2' , "") + endwhile + + return toReturn +endfunction + + +" Function: s:ConvertLeadingTabsToSpaces(line) {{{2 +" This function takes a line and converts all leading spaces on that line into +" tabs +" +" Args: +" -line: the line whose leading spaces will be converted +function s:ConvertLeadingTabsToSpaces(line) + let toReturn = a:line + while toReturn =~ '^\( *\)\t' + let toReturn = substitute(toReturn, '^\( *\)\t', '\1' . s:TabSpace() , "") + endwhile + + return toReturn +endfunction + +" Function: s:ConvertLeadingWhiteSpace(line) {{{2 +" Converts the leading white space to tabs/spaces depending on &ts +" +" Args: +" -line: the line to convert +function s:ConvertLeadingWhiteSpace(line) + let toReturn = a:line + while toReturn =~ '^ *\t' + let toReturn = substitute(toReturn, '^ *\zs\t\ze', s:TabSpace(), "g") + endwhile + + if !&expandtab + let toReturn = s:ConvertLeadingSpacesToTabs(toReturn) + endif + + return toReturn +endfunction + + +" Function: s:CountNonESCedOccurances(str, searchstr, escChar) {{{2 +" This function counts the number of substrings contained in another string. +" These substrings are only counted if they are not escaped with escChar +" Args: +" -str: the string to look for searchstr in +" -searchstr: the substring to search for in str +" -escChar: the escape character which, when preceding an instance of +" searchstr, will cause it not to be counted +function s:CountNonESCedOccurances(str, searchstr, escChar) + "get the index of the first occurrence of searchstr + let indx = stridx(a:str, a:searchstr) + + "if there is an instance of searchstr in str process it + if indx != -1 + "get the remainder of str after this instance of searchstr is removed + let lensearchstr = strlen(a:searchstr) + let strLeft = strpart(a:str, indx+lensearchstr) + + "if this instance of searchstr is not escaped, add one to the count + "and recurse. If it is escaped, just recurse + if !s:IsEscaped(a:str, indx, a:escChar) + return 1 + s:CountNonESCedOccurances(strLeft, a:searchstr, a:escChar) + else + return s:CountNonESCedOccurances(strLeft, a:searchstr, a:escChar) + endif + endif +endfunction +" Function: s:DoesBlockHaveDelim(delim, top, bottom) {{{2 +" Returns 1 if the given block of lines has a delimiter (a:delim) in it +" Args: +" -delim: the comment delimiter to check the block for +" -top: the top line number of the block +" -bottom: the bottom line number of the block +function s:DoesBlockHaveDelim(delim, top, bottom) + let currentLine = a:top + while currentLine < a:bottom + let theline = getline(currentLine) + if s:FindDelimiterIndex(a:delim, theline) != -1 + return 1 + endif + let currentLine = currentLine + 1 + endwhile + return 0 +endfunction + +" Function: s:DoesBlockHaveMultipartDelim(top, bottom) {{{2 +" Returns 1 if the given block has a >= 1 multipart delimiter in it +" Args: +" -top: the top line number of the block +" -bottom: the bottom line number of the block +function s:DoesBlockHaveMultipartDelim(top, bottom) + if s:HasMultipartDelims() + if s:Multipart() + return s:DoesBlockHaveDelim(s:Left(), a:top, a:bottom) || s:DoesBlockHaveDelim(s:Right(), a:top, a:bottom) + else + return s:DoesBlockHaveDelim(s:Left({'alt': 1}), a:top, a:bottom) || s:DoesBlockHaveDelim(s:Right({'alt': 1}), a:top, a:bottom) + endif + endif + return 0 +endfunction + + +" Function: s:Esc(str) {{{2 +" Escapes all the tricky chars in the given string +function s:Esc(str) + let charsToEsc = '*/\."&$+' + return escape(a:str, charsToEsc) +endfunction + +" Function: s:FindDelimiterIndex(delimiter, line) {{{2 +" This function is used to get the string index of the input comment delimiter +" on the input line. If no valid comment delimiter is found in the line then +" -1 is returned +" Args: +" -delimiter: the delimiter we are looking to find the index of +" -line: the line we are looking for delimiter on +function s:FindDelimiterIndex(delimiter, line) + + "make sure the delimiter isnt empty otherwise we go into an infinite loop. + if a:delimiter == "" + return -1 + endif + + + let l:delimiter = a:delimiter + let lenDel = strlen(l:delimiter) + + "get the index of the first occurrence of the delimiter + let delIndx = stridx(a:line, l:delimiter) + + "keep looping thru the line till we either find a real comment delimiter + "or run off the EOL + while delIndx != -1 + + "if we are not off the EOL get the str before the possible delimiter + "in question and check if it really is a delimiter. If it is, return + "its position + if delIndx != -1 + if s:IsDelimValid(l:delimiter, delIndx, a:line) + return delIndx + endif + endif + + "we have not yet found a real comment delimiter so move past the + "current one we are lookin at + let restOfLine = strpart(a:line, delIndx + lenDel) + let distToNextDelim = stridx(restOfLine , l:delimiter) + + "if distToNextDelim is -1 then there is no more potential delimiters + "on the line so set delIndx to -1. Otherwise, move along the line by + "distToNextDelim + if distToNextDelim == -1 + let delIndx = -1 + else + let delIndx = delIndx + lenDel + distToNextDelim + endif + endwhile + + "there is no comment delimiter on this line + return -1 +endfunction + +" Function: s:FindBoundingLinesOfSexyCom(lineNum) {{{2 +" This function takes in a line number and tests whether this line number is +" the top/bottom/middle line of a sexy comment. If it is then the top/bottom +" lines of the sexy comment are returned +" Args: +" -lineNum: the line number that is to be tested whether it is the +" top/bottom/middle line of a sexy com +" Returns: +" A string that has the top/bottom lines of the sexy comment encoded in it. +" The format is 'topline,bottomline'. If a:lineNum turns out not to be the +" top/bottom/middle of a sexy comment then -1 is returned +function s:FindBoundingLinesOfSexyCom(lineNum) + + "find which delimiters to look for as the start/end delims of the comment + let left = '' + let right = '' + if s:Multipart() + let left = s:Left({'esc': 1}) + let right = s:Right({'esc': 1}) + elseif s:AltMultipart() + let left = s:Left({'alt': 1, 'esc': 1}) + let right = s:Right({'alt': 1, 'esc': 1}) + else + return [] + endif + + let sexyComMarker = s:GetSexyComMarker(0, 1) + + "initialise the top/bottom line numbers of the sexy comment to -1 + let top = -1 + let bottom = -1 + + let currentLine = a:lineNum + while top == -1 || bottom == -1 + let theLine = getline(currentLine) + + "check if the current line is the top of the sexy comment + if currentLine <= a:lineNum && theLine =~ '^[ \t]*' . left && theLine !~ '.*' . right && currentLine < s:NumLinesInBuf() + let top = currentLine + let currentLine = a:lineNum + + "check if the current line is the bottom of the sexy comment + elseif theLine =~ '^[ \t]*' . right && theLine !~ '.*' . left && currentLine > 1 + let bottom = currentLine + + "the right delimiter is on the same line as the last sexyComMarker + elseif theLine =~ '^[ \t]*' . sexyComMarker . '.*' . right + let bottom = currentLine + + "we have not found the top or bottom line so we assume currentLine is an + "intermediate line and look to prove otherwise + else + + "if the line doesnt start with a sexyComMarker then it is not a sexy + "comment + if theLine !~ '^[ \t]*' . sexyComMarker + return [] + endif + + endif + + "if top is -1 then we havent found the top yet so keep looking up + if top == -1 + let currentLine = currentLine - 1 + "if we have found the top line then go down looking for the bottom + else + let currentLine = currentLine + 1 + endif + + endwhile + + return [top, bottom] +endfunction + + +" Function: s:GetSexyComMarker() {{{2 +" Returns the sexy comment marker for the current filetype. +" +" C style sexy comments are assumed if possible. If not then the sexy comment +" marker is the last char of the delimiter pair that has both left and right +" delims and has the longest left delim +" +" Args: +" -space: specifies whether the marker is to have a space string after it +" (the space string will only be added if NERDSpaceDelims is set) +" -esc: specifies whether the tricky chars in the marker are to be ESCed +function s:GetSexyComMarker(space, esc) + let sexyComMarker = b:NERDSexyComMarker + + "if there is no hardcoded marker then we find one + if sexyComMarker == '' + + "if the filetype has c style comments then use standard c sexy + "comments + if s:HasCStyleComments() + let sexyComMarker = '*' + else + "find a comment marker by getting the longest available left delim + "(that has a corresponding right delim) and taking the last char + let lenLeft = strlen(s:Left()) + let lenLeftAlt = strlen(s:Left({'alt': 1})) + let left = '' + let right = '' + if s:Multipart() && lenLeft >= lenLeftAlt + let left = s:Left() + elseif s:AltMultipart() + let left = s:Left({'alt': 1}) + else + return -1 + endif + + "get the last char of left + let sexyComMarker = strpart(left, strlen(left)-1) + endif + endif + + if a:space && g:NERDSpaceDelims + let sexyComMarker = sexyComMarker . s:spaceStr + endif + + if a:esc + let sexyComMarker = s:Esc(sexyComMarker) + endif + + return sexyComMarker +endfunction + +" Function: s:GetSexyComLeft(space, esc) {{{2 +" Returns the left delimiter for sexy comments for this filetype or -1 if +" there is none. C style sexy comments are used if possible +" Args: +" -space: specifies if the delim has a space string on the end +" (the space string will only be added if NERDSpaceDelims is set) +" -esc: specifies whether the tricky chars in the string are ESCed +function s:GetSexyComLeft(space, esc) + let lenLeft = strlen(s:Left()) + let lenLeftAlt = strlen(s:Left({'alt': 1})) + let left = '' + + "assume c style sexy comments if possible + if s:HasCStyleComments() + let left = '/*' + else + "grab the longest left delim that has a right + if s:Multipart() && lenLeft >= lenLeftAlt + let left = s:Left() + elseif s:AltMultipart() + let left = s:Left({'alt': 1}) + else + return -1 + endif + endif + + if a:space && g:NERDSpaceDelims + let left = left . s:spaceStr + endif + + if a:esc + let left = s:Esc(left) + endif + + return left +endfunction + +" Function: s:GetSexyComRight(space, esc) {{{2 +" Returns the right delimiter for sexy comments for this filetype or -1 if +" there is none. C style sexy comments are used if possible. +" Args: +" -space: specifies if the delim has a space string on the start +" (the space string will only be added if NERDSpaceDelims +" is specified for the current filetype) +" -esc: specifies whether the tricky chars in the string are ESCed +function s:GetSexyComRight(space, esc) + let lenLeft = strlen(s:Left()) + let lenLeftAlt = strlen(s:Left({'alt': 1})) + let right = '' + + "assume c style sexy comments if possible + if s:HasCStyleComments() + let right = '*/' + else + "grab the right delim that pairs with the longest left delim + if s:Multipart() && lenLeft >= lenLeftAlt + let right = s:Right() + elseif s:AltMultipart() + let right = s:Right({'alt': 1}) + else + return -1 + endif + endif + + if a:space && g:NERDSpaceDelims + let right = s:spaceStr . right + endif + + if a:esc + let right = s:Esc(right) + endif + + return right +endfunction + +" Function: s:HasMultipartDelims() {{{2 +" Returns 1 iff the current filetype has at least one set of multipart delims +function s:HasMultipartDelims() + return s:Multipart() || s:AltMultipart() +endfunction + +" Function: s:HasLeadingTabs(...) {{{2 +" Returns 1 if any of the given strings have leading tabs +function s:HasLeadingTabs(...) + for s in a:000 + if s =~ '^\t.*' + return 1 + end + endfor + return 0 +endfunction +" Function: s:HasCStyleComments() {{{2 +" Returns 1 iff the current filetype has c style comment delimiters +function s:HasCStyleComments() + return (s:Left() == '/*' && s:Right() == '*/') || (s:Left({'alt': 1}) == '/*' && s:Right({'alt': 1}) == '*/') +endfunction + +" Function: s:IsCommentedNormOrSexy(lineNum) {{{2 +"This function is used to determine whether the given line is commented with +"either set of delimiters or if it is part of a sexy comment +" +" Args: +" -lineNum: the line number of the line to check +function s:IsCommentedNormOrSexy(lineNum) + let theLine = getline(a:lineNum) + + "if the line is commented normally return 1 + if s:IsCommented(s:Left(), s:Right(), theLine) || s:IsCommented(s:Left({'alt': 1}), s:Right({'alt': 1}), theLine) + return 1 + endif + + "if the line is part of a sexy comment return 1 + if s:IsInSexyComment(a:lineNum) + return 1 + endif + return 0 +endfunction + +" Function: s:IsCommented(left, right, line) {{{2 +"This function is used to determine whether the given line is commented with +"the given delimiters +" +" Args: +" -line: the line that to check if commented +" -left/right: the left and right delimiters to check for +function s:IsCommented(left, right, line) + "if the line isnt commented return true + if s:FindDelimiterIndex(a:left, a:line) != -1 && (s:FindDelimiterIndex(a:right, a:line) != -1 || !s:Multipart()) + return 1 + endif + return 0 +endfunction + +" Function: s:IsCommentedFromStartOfLine(left, line) {{{2 +"This function is used to determine whether the given line is commented with +"the given delimiters at the start of the line i.e the left delimiter is the +"first thing on the line (apart from spaces\tabs) +" +" Args: +" -line: the line that to check if commented +" -left: the left delimiter to check for +function s:IsCommentedFromStartOfLine(left, line) + let theLine = s:ConvertLeadingTabsToSpaces(a:line) + let numSpaces = strlen(substitute(theLine, '^\( *\).*$', '\1', '')) + let delimIndx = s:FindDelimiterIndex(a:left, theLine) + return delimIndx == numSpaces +endfunction + +" Function: s:IsCommentedOuttermost(left, right, leftAlt, rightAlt, line) {{{2 +" Finds the type of the outtermost delims on the line +" +" Args: +" -line: the line that to check if the outtermost comments on it are +" left/right +" -left/right: the left and right delimiters to check for +" -leftAlt/rightAlt: the left and right alternative delimiters to check for +" +" Returns: +" 0 if the line is not commented with either set of delims +" 1 if the line is commented with the left/right delim set +" 2 if the line is commented with the leftAlt/rightAlt delim set +function s:IsCommentedOuttermost(left, right, leftAlt, rightAlt, line) + "get the first positions of the left delims and the last positions of the + "right delims + let indxLeft = s:FindDelimiterIndex(a:left, a:line) + let indxLeftAlt = s:FindDelimiterIndex(a:leftAlt, a:line) + let indxRight = s:LastIndexOfDelim(a:right, a:line) + let indxRightAlt = s:LastIndexOfDelim(a:rightAlt, a:line) + + "check if the line has a left delim before a leftAlt delim + if (indxLeft <= indxLeftAlt || indxLeftAlt == -1) && indxLeft != -1 + "check if the line has a right delim after any rightAlt delim + if (indxRight > indxRightAlt && indxRight > indxLeft) || !s:Multipart() + return 1 + endif + + "check if the line has a leftAlt delim before a left delim + elseif (indxLeftAlt <= indxLeft || indxLeft == -1) && indxLeftAlt != -1 + "check if the line has a rightAlt delim after any right delim + if (indxRightAlt > indxRight && indxRightAlt > indxLeftAlt) || !s:AltMultipart() + return 2 + endif + else + return 0 + endif + + return 0 + +endfunction + + +" Function: s:IsDelimValid(delimiter, delIndx, line) {{{2 +" This function is responsible for determining whether a given instance of a +" comment delimiter is a real delimiter or not. For example, in java the +" // string is a comment delimiter but in the line: +" System.out.println("//"); +" it does not count as a comment delimiter. This function is responsible for +" distinguishing between such cases. It does so by applying a set of +" heuristics that are not fool proof but should work most of the time. +" +" Args: +" -delimiter: the delimiter we are validating +" -delIndx: the position of delimiter in line +" -line: the line that delimiter occurs in +" +" Returns: +" 0 if the given delimiter is not a real delimiter (as far as we can tell) , +" 1 otherwise +function s:IsDelimValid(delimiter, delIndx, line) + "get the delimiter without the escchars + let l:delimiter = a:delimiter + + "get the strings before and after the delimiter + let preComStr = strpart(a:line, 0, a:delIndx) + let postComStr = strpart(a:line, a:delIndx+strlen(delimiter)) + + "to check if the delimiter is real, make sure it isnt preceded by + "an odd number of quotes and followed by the same (which would indicate + "that it is part of a string and therefore is not a comment) + if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, '"', "\\")) && !s:IsNumEven(s:CountNonESCedOccurances(postComStr, '"', "\\")) + return 0 + endif + if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, "'", "\\")) && !s:IsNumEven(s:CountNonESCedOccurances(postComStr, "'", "\\")) + return 0 + endif + if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, "`", "\\")) && !s:IsNumEven(s:CountNonESCedOccurances(postComStr, "`", "\\")) + return 0 + endif + + + "if the comment delimiter is escaped, assume it isnt a real delimiter + if s:IsEscaped(a:line, a:delIndx, "\\") + return 0 + endif + + "vim comments are so fuckin stupid!! Why the hell do they have comment + "delimiters that are used elsewhere in the syntax?!?! We need to check + "some conditions especially for vim + if &filetype == "vim" + if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, '"', "\\")) + return 0 + endif + + "if the delimiter is on the very first char of the line or is the + "first non-tab/space char on the line then it is a valid comment delimiter + if a:delIndx == 0 || a:line =~ "^[ \t]\\{" . a:delIndx . "\\}\".*$" + return 1 + endif + + let numLeftParen =s:CountNonESCedOccurances(preComStr, "(", "\\") + let numRightParen =s:CountNonESCedOccurances(preComStr, ")", "\\") + + "if the quote is inside brackets then assume it isnt a comment + if numLeftParen > numRightParen + return 0 + endif + + "if the line has an even num of unescaped "'s then we can assume that + "any given " is not a comment delimiter + if s:IsNumEven(s:CountNonESCedOccurances(a:line, "\"", "\\")) + return 0 + endif + endif + + return 1 + +endfunction + +" Function: s:IsNumEven(num) {{{2 +" A small function the returns 1 if the input number is even and 0 otherwise +" Args: +" -num: the number to check +function s:IsNumEven(num) + return (a:num % 2) == 0 +endfunction + +" Function: s:IsEscaped(str, indx, escChar) {{{2 +" This function takes a string, an index into that string and an esc char and +" returns 1 if the char at the index is escaped (i.e if it is preceded by an +" odd number of esc chars) +" Args: +" -str: the string to check +" -indx: the index into str that we want to check +" -escChar: the escape char the char at indx may be ESCed with +function s:IsEscaped(str, indx, escChar) + "initialise numEscChars to 0 and look at the char before indx + let numEscChars = 0 + let curIndx = a:indx-1 + + "keep going back thru str until we either reach the start of the str or + "run out of esc chars + while curIndx >= 0 && strpart(a:str, curIndx, 1) == a:escChar + + "we have found another esc char so add one to the count and move left + "one char + let numEscChars = numEscChars + 1 + let curIndx = curIndx - 1 + + endwhile + + "if there is an odd num of esc chars directly before the char at indx then + "the char at indx is escaped + return !s:IsNumEven(numEscChars) +endfunction + +" Function: s:IsInSexyComment(line) {{{2 +" returns 1 if the given line number is part of a sexy comment +function s:IsInSexyComment(line) + return !empty(s:FindBoundingLinesOfSexyCom(a:line)) +endfunction + +" Function: s:IsSexyComment(topline, bottomline) {{{2 +" This function takes in 2 line numbers and returns 1 if the lines between and +" including the given line numbers are a sexy comment. It returns 0 otherwise. +" Args: +" -topline: the line that the possible sexy comment starts on +" -bottomline: the line that the possible sexy comment stops on +function s:IsSexyComment(topline, bottomline) + + "get the delim set that would be used for a sexy comment + let left = '' + let right = '' + if s:Multipart() + let left = s:Left() + let right = s:Right() + elseif s:AltMultipart() + let left = s:Left({'alt': 1}) + let right = s:Right({'alt': 1}) + else + return 0 + endif + + "swap the top and bottom line numbers around if need be + let topline = a:topline + let bottomline = a:bottomline + if bottomline < topline + topline = bottomline + bottomline = a:topline + endif + + "if there is < 2 lines in the comment it cannot be sexy + if (bottomline - topline) <= 0 + return 0 + endif + + "if the top line doesnt begin with a left delim then the comment isnt sexy + if getline(a:topline) !~ '^[ \t]*' . left + return 0 + endif + + "if there is a right delim on the top line then this isnt a sexy comment + if s:FindDelimiterIndex(right, getline(a:topline)) != -1 + return 0 + endif + + "if there is a left delim on the bottom line then this isnt a sexy comment + if s:FindDelimiterIndex(left, getline(a:bottomline)) != -1 + return 0 + endif + + "if the bottom line doesnt begin with a right delim then the comment isnt + "sexy + if getline(a:bottomline) !~ '^.*' . right . '$' + return 0 + endif + + let sexyComMarker = s:GetSexyComMarker(0, 1) + + "check each of the intermediate lines to make sure they start with a + "sexyComMarker + let currentLine = a:topline+1 + while currentLine < a:bottomline + let theLine = getline(currentLine) + + if theLine !~ '^[ \t]*' . sexyComMarker + return 0 + endif + + "if there is a right delim in an intermediate line then the block isnt + "a sexy comment + if s:FindDelimiterIndex(right, theLine) != -1 + return 0 + endif + + let currentLine = currentLine + 1 + endwhile + + "we have not found anything to suggest that this isnt a sexy comment so + return 1 + +endfunction + +" Function: s:LastIndexOfDelim(delim, str) {{{2 +" This function takes a string and a delimiter and returns the last index of +" that delimiter in string +" Args: +" -delim: the delimiter to look for +" -str: the string to look for delim in +function s:LastIndexOfDelim(delim, str) + let delim = a:delim + let lenDelim = strlen(delim) + + "set index to the first occurrence of delim. If there is no occurrence then + "bail + let indx = s:FindDelimiterIndex(delim, a:str) + if indx == -1 + return -1 + endif + + "keep moving to the next instance of delim in str till there is none left + while 1 + + "search for the next delim after the previous one + let searchStr = strpart(a:str, indx+lenDelim) + let indx2 = s:FindDelimiterIndex(delim, searchStr) + + "if we find a delim update indx to record the position of it, if we + "dont find another delim then indx is the last one so break out of + "this loop + if indx2 != -1 + let indx = indx + indx2 + lenDelim + else + break + endif + endwhile + + return indx + +endfunction + +" Function: s:Left(...) {{{2 +" returns left delimiter data +function s:Left(...) + let params = a:0 ? a:1 : {} + + let delim = has_key(params, 'alt') ? b:NERDCommenterDelims['leftAlt'] : b:NERDCommenterDelims['left'] + + if delim == '' + return '' + endif + + if has_key(params, 'space') && g:NERDSpaceDelims + let delim = delim . s:spaceStr + endif + + if has_key(params, 'esc') + let delim = s:Esc(delim) + endif + + return delim +endfunction + +" Function: s:LeftMostIndx(countCommentedLines, countEmptyLines, topline, bottomline) {{{2 +" This function takes in 2 line numbers and returns the index of the left most +" char (that is not a space or a tab) on all of these lines. +" Args: +" -countCommentedLines: 1 if lines that are commented are to be checked as +" well. 0 otherwise +" -countEmptyLines: 1 if empty lines are to be counted in the search +" -topline: the top line to be checked +" -bottomline: the bottom line to be checked +function s:LeftMostIndx(countCommentedLines, countEmptyLines, topline, bottomline) + + " declare the left most index as an extreme value + let leftMostIndx = 1000 + + " go thru the block line by line updating leftMostIndx + let currentLine = a:topline + while currentLine <= a:bottomline + + " get the next line and if it is allowed to be commented, or is not + " commented, check it + let theLine = getline(currentLine) + if a:countEmptyLines || theLine !~ '^[ \t]*$' + if a:countCommentedLines || (!s:IsCommented(s:Left(), s:Right(), theLine) && !s:IsCommented(s:Left({'alt': 1}), s:Right({'alt': 1}), theLine)) + " convert spaces to tabs and get the number of leading spaces for + " this line and update leftMostIndx if need be + let theLine = s:ConvertLeadingTabsToSpaces(theLine) + let leadSpaceOfLine = strlen( substitute(theLine, '\(^[ \t]*\).*$','\1','') ) + if leadSpaceOfLine < leftMostIndx + let leftMostIndx = leadSpaceOfLine + endif + endif + endif + + " move on to the next line + let currentLine = currentLine + 1 + endwhile + + if leftMostIndx == 1000 + return 0 + else + return leftMostIndx + endif +endfunction + +" Function: s:Multipart() {{{2 +" returns 1 if the current delims are multipart +function s:Multipart() + return s:Right() != '' +endfunction + +" Function: s:NerdEcho(msg, typeOfMsg) {{{2 +" Args: +" -msg: the message to echo +" -typeOfMsg: 0 = warning message +" 1 = normal message +function s:NerdEcho(msg, typeOfMsg) + if a:typeOfMsg == 0 + echohl WarningMsg + echom 'NERDCommenter:' . a:msg + echohl None + elseif a:typeOfMsg == 1 + echom 'NERDCommenter:' . a:msg + endif +endfunction + +" Function: s:NumberOfLeadingTabs(s) {{{2 +" returns the number of leading tabs in the given string +function s:NumberOfLeadingTabs(s) + return strlen(substitute(a:s, '^\(\t*\).*$', '\1', "")) +endfunction + +" Function: s:NumLinesInBuf() {{{2 +" Returns the number of lines in the current buffer +function s:NumLinesInBuf() + return line('$') +endfunction + +" Function: s:ReplaceDelims(toReplace1, toReplace2, replacor1, replacor2, str) {{{2 +" This function takes in a string, 2 delimiters in that string and 2 strings +" to replace these delimiters with. +" +" Args: +" -toReplace1: the first delimiter to replace +" -toReplace2: the second delimiter to replace +" -replacor1: the string to replace toReplace1 with +" -replacor2: the string to replace toReplace2 with +" -str: the string that the delimiters to be replaced are in +function s:ReplaceDelims(toReplace1, toReplace2, replacor1, replacor2, str) + let line = s:ReplaceLeftMostDelim(a:toReplace1, a:replacor1, a:str) + let line = s:ReplaceRightMostDelim(a:toReplace2, a:replacor2, line) + return line +endfunction + +" Function: s:ReplaceLeftMostDelim(toReplace, replacor, str) {{{2 +" This function takes a string and a delimiter and replaces the left most +" occurrence of this delimiter in the string with a given string +" +" Args: +" -toReplace: the delimiter in str that is to be replaced +" -replacor: the string to replace toReplace with +" -str: the string that contains toReplace +function s:ReplaceLeftMostDelim(toReplace, replacor, str) + let toReplace = a:toReplace + let replacor = a:replacor + "get the left most occurrence of toReplace + let indxToReplace = s:FindDelimiterIndex(toReplace, a:str) + + "if there IS an occurrence of toReplace in str then replace it and return + "the resulting string + if indxToReplace != -1 + let line = strpart(a:str, 0, indxToReplace) . replacor . strpart(a:str, indxToReplace+strlen(toReplace)) + return line + endif + + return a:str +endfunction + +" Function: s:ReplaceRightMostDelim(toReplace, replacor, str) {{{2 +" This function takes a string and a delimiter and replaces the right most +" occurrence of this delimiter in the string with a given string +" +" Args: +" -toReplace: the delimiter in str that is to be replaced +" -replacor: the string to replace toReplace with +" -str: the string that contains toReplace +" +function s:ReplaceRightMostDelim(toReplace, replacor, str) + let toReplace = a:toReplace + let replacor = a:replacor + let lenToReplace = strlen(toReplace) + + "get the index of the last delim in str + let indxToReplace = s:LastIndexOfDelim(toReplace, a:str) + + "if there IS a delimiter in str, replace it and return the result + let line = a:str + if indxToReplace != -1 + let line = strpart(a:str, 0, indxToReplace) . replacor . strpart(a:str, indxToReplace+strlen(toReplace)) + endif + return line +endfunction + +"FUNCTION: s:RestoreScreenState() {{{2 +" +"Sets the screen state back to what it was when s:SaveScreenState was last +"called. +" +function s:RestoreScreenState() + if !exists("t:NERDComOldTopLine") || !exists("t:NERDComOldPos") + throw 'NERDCommenter exception: cannot restore screen' + endif + + call cursor(t:NERDComOldTopLine, 0) + normal! zt + call setpos(".", t:NERDComOldPos) +endfunction + +" Function: s:Right(...) {{{2 +" returns right delimiter data +function s:Right(...) + let params = a:0 ? a:1 : {} + + let delim = has_key(params, 'alt') ? b:NERDCommenterDelims['rightAlt'] : b:NERDCommenterDelims['right'] + + if delim == '' + return '' + endif + + if has_key(params, 'space') && g:NERDSpaceDelims + let delim = s:spaceStr . delim + endif + + if has_key(params, 'esc') + let delim = s:Esc(delim) + endif + + return delim +endfunction + +" Function: s:RightMostIndx(countCommentedLines, countEmptyLines, topline, bottomline) {{{2 +" This function takes in 2 line numbers and returns the index of the right most +" char on all of these lines. +" Args: +" -countCommentedLines: 1 if lines that are commented are to be checked as +" well. 0 otherwise +" -countEmptyLines: 1 if empty lines are to be counted in the search +" -topline: the top line to be checked +" -bottomline: the bottom line to be checked +function s:RightMostIndx(countCommentedLines, countEmptyLines, topline, bottomline) + let rightMostIndx = -1 + + " go thru the block line by line updating rightMostIndx + let currentLine = a:topline + while currentLine <= a:bottomline + + " get the next line and see if it is commentable, otherwise it doesnt + " count + let theLine = getline(currentLine) + if a:countEmptyLines || theLine !~ '^[ \t]*$' + + if a:countCommentedLines || (!s:IsCommented(s:Left(), s:Right(), theLine) && !s:IsCommented(s:Left({'alt': 1}), s:Right({'alt': 1}), theLine)) + + " update rightMostIndx if need be + let theLine = s:ConvertLeadingTabsToSpaces(theLine) + let lineLen = strlen(theLine) + if lineLen > rightMostIndx + let rightMostIndx = lineLen + endif + endif + endif + + " move on to the next line + let currentLine = currentLine + 1 + endwhile + + return rightMostIndx +endfunction + +"FUNCTION: s:SaveScreenState() {{{2 +"Saves the current cursor position in the current buffer and the window +"scroll position +function s:SaveScreenState() + let t:NERDComOldPos = getpos(".") + let t:NERDComOldTopLine = line("w0") +endfunction + +" Function: s:SwapOutterMultiPartDelimsForPlaceHolders(line) {{{2 +" This function takes a line and swaps the outter most multi-part delims for +" place holders +" Args: +" -line: the line to swap the delims in +" +function s:SwapOutterMultiPartDelimsForPlaceHolders(line) + " find out if the line is commented using normal delims and/or + " alternate ones + let isCommented = s:IsCommented(s:Left(), s:Right(), a:line) + let isCommentedAlt = s:IsCommented(s:Left({'alt': 1}), s:Right({'alt': 1}), a:line) + + let line2 = a:line + + "if the line is commented and there is a right delimiter, replace + "the delims with place-holders + if isCommented && s:Multipart() + let line2 = s:ReplaceDelims(s:Left(), s:Right(), g:NERDLPlace, g:NERDRPlace, a:line) + + "similarly if the line is commented with the alternative + "delimiters + elseif isCommentedAlt && s:AltMultipart() + let line2 = s:ReplaceDelims(s:Left({'alt': 1}), s:Right({'alt': 1}), g:NERDLPlace, g:NERDRPlace, a:line) + endif + + return line2 +endfunction + +" Function: s:SwapOutterPlaceHoldersForMultiPartDelims(line) {{{2 +" This function takes a line and swaps the outtermost place holders for +" multi-part delims +" Args: +" -line: the line to swap the delims in +" +function s:SwapOutterPlaceHoldersForMultiPartDelims(line) + let left = '' + let right = '' + if s:Multipart() + let left = s:Left() + let right = s:Right() + elseif s:AltMultipart() + let left = s:Left({'alt': 1}) + let right = s:Right({'alt': 1}) + endif + + let line = s:ReplaceDelims(g:NERDLPlace, g:NERDRPlace, left, right, a:line) + return line +endfunction +" Function: s:TabbedCol(line, col) {{{2 +" Gets the col number for given line and existing col number. The new col +" number is the col number when all leading spaces are converted to tabs +" Args: +" -line:the line to get the rel col for +" -col: the abs col +function s:TabbedCol(line, col) + let lineTruncated = strpart(a:line, 0, a:col) + let lineSpacesToTabs = substitute(lineTruncated, s:TabSpace(), '\t', 'g') + return strlen(lineSpacesToTabs) +endfunction +"FUNCTION: s:TabSpace() {{{2 +"returns a string of spaces equal in length to &tabstop +function s:TabSpace() + let tabSpace = "" + let spacesPerTab = &tabstop + while spacesPerTab > 0 + let tabSpace = tabSpace . " " + let spacesPerTab = spacesPerTab - 1 + endwhile + return tabSpace +endfunction + +" Function: s:UnEsc(str, escChar) {{{2 +" This function removes all the escape chars from a string +" Args: +" -str: the string to remove esc chars from +" -escChar: the escape char to be removed +function s:UnEsc(str, escChar) + return substitute(a:str, a:escChar, "", "g") +endfunction + +" Function: s:UntabbedCol(line, col) {{{2 +" Takes a line and a col and returns the absolute column of col taking into +" account that a tab is worth 3 or 4 (or whatever) spaces. +" Args: +" -line:the line to get the abs col for +" -col: the col that doesnt take into account tabs +function s:UntabbedCol(line, col) + let lineTruncated = strpart(a:line, 0, a:col) + let lineTabsToSpaces = substitute(lineTruncated, '\t', s:TabSpace(), 'g') + return strlen(lineTabsToSpaces) +endfunction +" Section: Comment mapping and menu item setup {{{1 +" =========================================================================== + +" Create menu items for the specified modes. If a:combo is not empty, then +" also define mappings and show a:combo in the menu items. +function! s:CreateMaps(modes, target, desc, combo) + " Build up a map command like + " 'noremap NERDCommenterComment :call NERDComment("n", "Comment")' + let plug = 'NERDCommenter' . a:target + let plug_start = 'noremap ' . plug . ' :call NERDComment("' + let plug_end = '", "' . a:target . '")' + " Build up a menu command like + " 'menu comment.Comment\\cc NERDCommenterComment' + let menuRoot = get(['', 'comment', '&comment', '&Plugin.&comment'], + \ g:NERDMenuMode, '') + let menu_command = 'menu ' . menuRoot . '.' . escape(a:desc, ' ') + if strlen(a:combo) + let leader = exists('g:mapleader') ? g:mapleader : '\' + let menu_command .= '' . escape(leader, '\') . a:combo + endif + let menu_command .= ' ' . (strlen(a:combo) ? plug : a:target) + " Execute the commands built above for each requested mode. + for mode in (a:modes == '') ? [''] : split(a:modes, '\zs') + if strlen(a:combo) + execute mode . plug_start . mode . plug_end + if g:NERDCreateDefaultMappings && !hasmapto(plug, mode) + execute mode . 'map ' . a:combo . ' ' . plug + endif + endif + " Check if the user wants the menu to be displayed. + if g:NERDMenuMode != 0 + execute mode . menu_command + endif + endfor +endfunction +call s:CreateMaps('nx', 'Comment', 'Comment', 'cc') +call s:CreateMaps('nx', 'Toggle', 'Toggle', 'c') +call s:CreateMaps('nx', 'Minimal', 'Minimal', 'cm') +call s:CreateMaps('nx', 'Nested', 'Nested', 'cn') +call s:CreateMaps('n', 'ToEOL', 'To EOL', 'c$') +call s:CreateMaps('nx', 'Invert', 'Invert', 'ci') +call s:CreateMaps('nx', 'Sexy', 'Sexy', 'cs') +call s:CreateMaps('nx', 'Yank', 'Yank then comment', 'cy') +call s:CreateMaps('n', 'Append', 'Append', 'cA') +call s:CreateMaps('', ':', '-Sep-', '') +call s:CreateMaps('nx', 'AlignLeft', 'Left aligned', 'cl') +call s:CreateMaps('nx', 'AlignBoth', 'Left and right aligned', 'cb') +call s:CreateMaps('', ':', '-Sep2-', '') +call s:CreateMaps('nx', 'Uncomment', 'Uncomment', 'cu') +call s:CreateMaps('n', 'AltDelims', 'Switch Delimiters', 'ca') +call s:CreateMaps('i', 'Insert', 'Insert Comment Here', '') +call s:CreateMaps('', ':', '-Sep3-', '') +call s:CreateMaps('', ':help NERDCommenterContents', 'Help', '') + +inoremap NERDCommenterInsert :call NERDComment('i', "insert") + +" switch to/from alternative delimiters (does not use wrapper function) +nnoremap NERDCommenterAltDelims :call SwitchToAlternativeDelimiters(1) +" vim: set foldmethod=marker : diff --git a/sources_non_forked/nerdtree/README.markdown b/sources_non_forked/nerdtree/README.markdown index 4234b54f23..0317e62458 100644 --- a/sources_non_forked/nerdtree/README.markdown +++ b/sources_non_forked/nerdtree/README.markdown @@ -66,48 +66,42 @@ Then reload vim, run `:Helptags`, and check out `:help NERD_tree.txt`. Faq --- -__Q. Can I have the nerdtree on every tab automatically?__ +> Is there any support for `git` flags? -A. Nope. If this is something you want then chances are you aren't using tabs - and buffers as they were intended to be used. Read this - http://stackoverflow.com/questions/102384/using-vims-tabs-like-buffers +Yes, install [nerdtree-git-plugin](https://github.com/Xuyuanp/nerdtree-git-plugin). - If you are interested in this behaviour then consider [vim-nerdtree-tabs](https://github.com/jistr/vim-nerdtree-tabs) -__Q. How can I open a NERDTree automatically when vim starts up?__ +> Can I have the nerdtree on every tab automatically? -A. Stick this in your vimrc: `autocmd vimenter * NERDTree` +Nope. If this is something you want then chances are you aren't using tabs and +buffers as they were intended to be used. Read this +http://stackoverflow.com/questions/102384/using-vims-tabs-like-buffers -__Q. How can I open a NERDTree automatically when vim starts up if no files were specified?__ +If you are interested in this behaviour then consider [vim-nerdtree-tabs](https://github.com/jistr/vim-nerdtree-tabs) -A. Stick this in your vimrc +> How can I open a NERDTree automatically when vim starts up? - autocmd StdinReadPre * let s:std_in=1 - autocmd VimEnter * if argc() == 0 && !exists("s:std_in") | NERDTree | endif +Stick this in your vimrc: `autocmd vimenter * NERDTree` -__Q. How can I map a specific key or shortcut to open NERDTree?__ +> How can I open a NERDTree automatically when vim starts up if no files were specified? -A. Stick this in your vimrc to open NERDTree with `Ctrl+n` (you can set whatever key you want): +Stick this in your vimrc -`map :NERDTreeToggle` + autocmd StdinReadPre * let s:std_in=1 + autocmd VimEnter * if argc() == 0 && !exists("s:std_in") | NERDTree | endif -__Q. How can I close vim if the only window left open is a NERDTree?__ +> How can I map a specific key or shortcut to open NERDTree? -A. Stick this in your vimrc: +Stick this in your vimrc to open NERDTree with `Ctrl+n` (you can set whatever key you want): - `autocmd bufenter * if (winnr("$") == 1 && exists("b:NERDTreeType") && b:NERDTreeType == "primary") | q | endif` + map :NERDTreeToggle +> How can I close vim if the only window left open is a NERDTree? -Changelog ---------- +Stick this in your vimrc: -4.2.0 (2011-12-28) + autocmd bufenter * if (winnr("$") == 1 && exists("b:NERDTreeType") && b:NERDTreeType == "primary") | q | endif - * Add NERDTreeDirArrows option to make the UI use pretty arrow chars instead of the old +~| chars to define the tree structure (sickill) - * shift the syntax highlighting out into its own syntax file (gnap) * add some mac specific options to the filesystem menu - for macvim only (andersonfreitas) - * Add NERDTreeMinimalUI option to remove some non functional parts of the nerdtree ui (camthompson) - * tweak the behaviour of :NERDTreeFind - see :help :NERDTreeFind for the new behaviour (benjamingeiger) - * if no name is given to :Bookmark, make it default to the name of the target file/dir (minyoung) - * use 'file' completion when doing copying, create, and move operations (EvanDotPro) - * lots of misc bug fixes (paddyoloughlin, sdewald, camthompson, Vitaly Bogdanov, AndrewRadev, mathias, scottstvnsn, kml, wycats, me RAWR!) +> Can I have different highlighting for different file extensions? +See here: https://github.com/scrooloose/nerdtree/issues/433#issuecomment-92590696 diff --git a/sources_non_forked/nerdtree/autoload/nerdtree.vim b/sources_non_forked/nerdtree/autoload/nerdtree.vim index 539e7838bc..37d7d105b5 100644 --- a/sources_non_forked/nerdtree/autoload/nerdtree.vim +++ b/sources_non_forked/nerdtree/autoload/nerdtree.vim @@ -34,6 +34,17 @@ function! nerdtree#compareNodes(n1, n2) return a:n1.path.compareTo(a:n2.path) endfunction +"FUNCTION: nerdtree#compareNodesBySortKey(n1, n2) {{{2 +function! nerdtree#compareNodesBySortKey(n1, n2) + if a:n1.path.getSortKey() <# a:n2.path.getSortKey() + return -1 + elseif a:n1.path.getSortKey() ># a:n2.path.getSortKey() + return 1 + else + return 0 + endif +endfunction + " FUNCTION: nerdtree#deprecated(func, [msg]) {{{2 " Issue a deprecation warning for a:func. If a second arg is given, use this " as the deprecation message @@ -95,175 +106,9 @@ function! nerdtree#runningWindows() return has("win16") || has("win32") || has("win64") endfunction -"FUNCTION: nerdtree#treeMarkupReg(dir) {{{2 -function! nerdtree#treeMarkupReg() - if g:NERDTreeDirArrows - return '^\([▾▸] \| \+[▾▸] \| \+\)' - endif - - return '^[ `|]*[\-+~]' -endfunction - -"FUNCTION: nerdtree#treeUpDirLine(dir) {{{2 -function! nerdtree#treeUpDirLine() - return '.. (up a dir)' -endfunction - -"FUNCTION: nerdtree#treeWid(dir) {{{2 -function! nerdtree#treeWid() - return 2 -endfunction - " SECTION: View Functions {{{1 "============================================================ -"FUNCTION: nerdtree#closeTree() {{{2 -"Closes the primary NERD tree window for this tab -function! nerdtree#closeTree() - if !nerdtree#isTreeOpen() - throw "NERDTree.NoTreeFoundError: no NERDTree is open" - endif - - if winnr("$") != 1 - if winnr() == nerdtree#getTreeWinNum() - call nerdtree#exec("wincmd p") - let bufnr = bufnr("") - call nerdtree#exec("wincmd p") - else - let bufnr = bufnr("") - endif - - call nerdtree#exec(nerdtree#getTreeWinNum() . " wincmd w") - close - call nerdtree#exec(bufwinnr(bufnr) . " wincmd w") - else - close - endif -endfunction - -"FUNCTION: nerdtree#closeTreeIfOpen() {{{2 -"Closes the NERD tree window if it is open -function! nerdtree#closeTreeIfOpen() - if nerdtree#isTreeOpen() - call nerdtree#closeTree() - endif -endfunction - -"FUNCTION: nerdtree#closeTreeIfQuitOnOpen() {{{2 -"Closes the NERD tree window if the close on open option is set -function! nerdtree#closeTreeIfQuitOnOpen() - if g:NERDTreeQuitOnOpen && nerdtree#isTreeOpen() - call nerdtree#closeTree() - endif -endfunction - -"FUNCTION: nerdtree#dumpHelp {{{2 -"prints out the quick help -function! nerdtree#dumpHelp() - let old_h = @h - if b:treeShowHelp ==# 1 - let @h= "\" NERD tree (" . nerdtree#version() . ") quickhelp~\n" - let @h=@h."\" ============================\n" - let @h=@h."\" File node mappings~\n" - let @h=@h."\" ". (g:NERDTreeMouseMode ==# 3 ? "single" : "double") ."-click,\n" - let @h=@h."\" ,\n" - if b:NERDTreeType ==# "primary" - let @h=@h."\" ". g:NERDTreeMapActivateNode .": open in prev window\n" - else - let @h=@h."\" ". g:NERDTreeMapActivateNode .": open in current window\n" - endif - if b:NERDTreeType ==# "primary" - let @h=@h."\" ". g:NERDTreeMapPreview .": preview\n" - endif - let @h=@h."\" ". g:NERDTreeMapOpenInTab.": open in new tab\n" - let @h=@h."\" ". g:NERDTreeMapOpenInTabSilent .": open in new tab silently\n" - let @h=@h."\" middle-click,\n" - let @h=@h."\" ". g:NERDTreeMapOpenSplit .": open split\n" - let @h=@h."\" ". g:NERDTreeMapPreviewSplit .": preview split\n" - let @h=@h."\" ". g:NERDTreeMapOpenVSplit .": open vsplit\n" - let @h=@h."\" ". g:NERDTreeMapPreviewVSplit .": preview vsplit\n" - - let @h=@h."\"\n\" ----------------------------\n" - let @h=@h."\" Directory node mappings~\n" - let @h=@h."\" ". (g:NERDTreeMouseMode ==# 1 ? "double" : "single") ."-click,\n" - let @h=@h."\" ". g:NERDTreeMapActivateNode .": open & close node\n" - let @h=@h."\" ". g:NERDTreeMapOpenRecursively .": recursively open node\n" - let @h=@h."\" ". g:NERDTreeMapCloseDir .": close parent of node\n" - let @h=@h."\" ". g:NERDTreeMapCloseChildren .": close all child nodes of\n" - let @h=@h."\" current node recursively\n" - let @h=@h."\" middle-click,\n" - let @h=@h."\" ". g:NERDTreeMapOpenExpl.": explore selected dir\n" - - let @h=@h."\"\n\" ----------------------------\n" - let @h=@h."\" Bookmark table mappings~\n" - let @h=@h."\" double-click,\n" - let @h=@h."\" ". g:NERDTreeMapActivateNode .": open bookmark\n" - let @h=@h."\" ". g:NERDTreeMapOpenInTab.": open in new tab\n" - let @h=@h."\" ". g:NERDTreeMapOpenInTabSilent .": open in new tab silently\n" - let @h=@h."\" ". g:NERDTreeMapDeleteBookmark .": delete bookmark\n" - - let @h=@h."\"\n\" ----------------------------\n" - let @h=@h."\" Tree navigation mappings~\n" - let @h=@h."\" ". g:NERDTreeMapJumpRoot .": go to root\n" - let @h=@h."\" ". g:NERDTreeMapJumpParent .": go to parent\n" - let @h=@h."\" ". g:NERDTreeMapJumpFirstChild .": go to first child\n" - let @h=@h."\" ". g:NERDTreeMapJumpLastChild .": go to last child\n" - let @h=@h."\" ". g:NERDTreeMapJumpNextSibling .": go to next sibling\n" - let @h=@h."\" ". g:NERDTreeMapJumpPrevSibling .": go to prev sibling\n" - - let @h=@h."\"\n\" ----------------------------\n" - let @h=@h."\" Filesystem mappings~\n" - let @h=@h."\" ". g:NERDTreeMapChangeRoot .": change tree root to the\n" - let @h=@h."\" selected dir\n" - let @h=@h."\" ". g:NERDTreeMapUpdir .": move tree root up a dir\n" - let @h=@h."\" ". g:NERDTreeMapUpdirKeepOpen .": move tree root up a dir\n" - let @h=@h."\" but leave old root open\n" - let @h=@h."\" ". g:NERDTreeMapRefresh .": refresh cursor dir\n" - let @h=@h."\" ". g:NERDTreeMapRefreshRoot .": refresh current root\n" - let @h=@h."\" ". g:NERDTreeMapMenu .": Show menu\n" - let @h=@h."\" ". g:NERDTreeMapChdir .":change the CWD to the\n" - let @h=@h."\" selected dir\n" - let @h=@h."\" ". g:NERDTreeMapCWD .":change tree root to CWD\n" - - let @h=@h."\"\n\" ----------------------------\n" - let @h=@h."\" Tree filtering mappings~\n" - let @h=@h."\" ". g:NERDTreeMapToggleHidden .": hidden files (" . (b:NERDTreeShowHidden ? "on" : "off") . ")\n" - let @h=@h."\" ". g:NERDTreeMapToggleFilters .": file filters (" . (b:NERDTreeIgnoreEnabled ? "on" : "off") . ")\n" - let @h=@h."\" ". g:NERDTreeMapToggleFiles .": files (" . (b:NERDTreeShowFiles ? "on" : "off") . ")\n" - let @h=@h."\" ". g:NERDTreeMapToggleBookmarks .": bookmarks (" . (b:NERDTreeShowBookmarks ? "on" : "off") . ")\n" - - "add quickhelp entries for each custom key map - let @h=@h."\"\n\" ----------------------------\n" - let @h=@h."\" Custom mappings~\n" - for i in g:NERDTreeKeyMap.All() - if !empty(i.quickhelpText) - let @h=@h."\" ". i.key .": ". i.quickhelpText ."\n" - endif - endfor - - let @h=@h."\"\n\" ----------------------------\n" - let @h=@h."\" Other mappings~\n" - let @h=@h."\" ". g:NERDTreeMapQuit .": Close the NERDTree window\n" - let @h=@h."\" ". g:NERDTreeMapToggleZoom .": Zoom (maximize-minimize)\n" - let @h=@h."\" the NERDTree window\n" - let @h=@h."\" ". g:NERDTreeMapHelp .": toggle help\n" - let @h=@h."\"\n\" ----------------------------\n" - let @h=@h."\" Bookmark commands~\n" - let @h=@h."\" :Bookmark []\n" - let @h=@h."\" :BookmarkToRoot \n" - let @h=@h."\" :RevealBookmark \n" - let @h=@h."\" :OpenBookmark \n" - let @h=@h."\" :ClearBookmarks []\n" - let @h=@h."\" :ClearAllBookmarks\n" - silent! put h - elseif g:NERDTreeMinimalUI == 0 - let @h="\" Press ". g:NERDTreeMapHelp ." for help\n" - silent! put h - endif - - let @h = old_h -endfunction - "FUNCTION: nerdtree#echo {{{2 "A wrapper for :echo. Appends 'NERDTree:' on the front of all messages " @@ -294,114 +139,9 @@ function! nerdtree#echoWarning(msg) echohl normal endfunction -"FUNCTION: nerdtree#getTreeWinNum() {{{2 -"gets the nerd tree window number for this tab -function! nerdtree#getTreeWinNum() - if exists("t:NERDTreeBufName") - return bufwinnr(t:NERDTreeBufName) - else - return -1 - endif -endfunction - -"FUNCTION: nerdtree#isTreeOpen() {{{2 -function! nerdtree#isTreeOpen() - return nerdtree#getTreeWinNum() != -1 -endfunction - -"FUNCTION: nerdtree#putCursorOnBookmarkTable(){{{2 -"Places the cursor at the top of the bookmarks table -function! nerdtree#putCursorOnBookmarkTable() - if !b:NERDTreeShowBookmarks - throw "NERDTree.IllegalOperationError: cant find bookmark table, bookmarks arent active" - endif - - if g:NERDTreeMinimalUI - return cursor(1, 2) - endif - - let rootNodeLine = b:NERDTree.ui.getRootLineNum() - - let line = 1 - while getline(line) !~# '^>-\+Bookmarks-\+$' - let line = line + 1 - if line >= rootNodeLine - throw "NERDTree.BookmarkTableNotFoundError: didnt find the bookmarks table" - endif - endwhile - call cursor(line, 2) -endfunction - -"FUNCTION: nerdtree#putCursorInTreeWin(){{{2 -"Places the cursor in the nerd tree window -function! nerdtree#putCursorInTreeWin() - if !nerdtree#isTreeOpen() - throw "NERDTree.InvalidOperationError: cant put cursor in NERD tree window, no window exists" - endif - - call nerdtree#exec(nerdtree#getTreeWinNum() . "wincmd w") -endfunction - -"FUNCTION: nerdtree#renderBookmarks {{{2 -function! nerdtree#renderBookmarks() - - if g:NERDTreeMinimalUI == 0 - call setline(line(".")+1, ">----------Bookmarks----------") - call cursor(line(".")+1, col(".")) - endif - - for i in g:NERDTreeBookmark.Bookmarks() - call setline(line(".")+1, i.str()) - call cursor(line(".")+1, col(".")) - endfor - - call setline(line(".")+1, '') - call cursor(line(".")+1, col(".")) -endfunction - "FUNCTION: nerdtree#renderView {{{2 function! nerdtree#renderView() call b:NERDTree.render() endfunction -" -"FUNCTION: nerdtree#stripMarkupFromLine(line, removeLeadingSpaces){{{2 -"returns the given line with all the tree parts stripped off -" -"Args: -"line: the subject line -"removeLeadingSpaces: 1 if leading spaces are to be removed (leading spaces = -"any spaces before the actual text of the node) -function! nerdtree#stripMarkupFromLine(line, removeLeadingSpaces) - let line = a:line - "remove the tree parts and the leading space - let line = substitute (line, nerdtree#treeMarkupReg(),"","") - - "strip off any read only flag - let line = substitute (line, ' \[RO\]', "","") - - "strip off any bookmark flags - let line = substitute (line, ' {[^}]*}', "","") - - "strip off any executable flags - let line = substitute (line, '*\ze\($\| \)', "","") - - "strip off any generic flags - let line = substitute (line, '\[[^]]*\]', "","") - - let wasdir = 0 - if line =~# '/$' - let wasdir = 1 - endif - let line = substitute (line,' -> .*',"","") " remove link to - if wasdir ==# 1 - let line = substitute (line, '/\?$', '/', "") - endif - - if a:removeLeadingSpaces - let line = substitute (line, '^ *', '', '') - endif - - return line -endfunction " vim: set sw=4 sts=4 et fdm=marker: diff --git a/sources_non_forked/nerdtree/autoload/nerdtree/ui_glue.vim b/sources_non_forked/nerdtree/autoload/nerdtree/ui_glue.vim index 8607389d23..1f922df163 100644 --- a/sources_non_forked/nerdtree/autoload/nerdtree/ui_glue.vim +++ b/sources_non_forked/nerdtree/autoload/nerdtree/ui_glue.vim @@ -85,7 +85,7 @@ endfunction "FUNCTION: s:activateAll() {{{1 "handle the user activating the updir line function! s:activateAll() - if getline(".") ==# nerdtree#treeUpDirLine() + if getline(".") ==# g:NERDTreeUI.UpDirLine() return nerdtree#ui_glue#upDir(0) endif endfunction @@ -93,13 +93,13 @@ endfunction "FUNCTION: s:activateDirNode() {{{1 "handle the user activating a tree node function! s:activateDirNode(node) - call a:node.activate({'reuse': 1}) + call a:node.activate() endfunction "FUNCTION: s:activateFileNode() {{{1 "handle the user activating a tree node function! s:activateFileNode(node) - call a:node.activate({'reuse': 1, 'where': 'p'}) + call a:node.activate({'reuse': 'all', 'where': 'p'}) endfunction "FUNCTION: s:activateBookmark() {{{1 @@ -212,7 +212,7 @@ function! s:closeTreeWindow() exec "buffer " . b:NERDTreePreviousBuf else if winnr("$") > 1 - call nerdtree#closeTree() + call g:NERDTree.Close() else call nerdtree#echo("Cannot close last window") endif @@ -275,20 +275,20 @@ function! s:findAndRevealPath() endif else if !p.isUnder(g:NERDTreeFileNode.GetRootForTab().path) - if !nerdtree#isTreeOpen() + if !g:NERDTree.IsOpen() call g:NERDTreeCreator.TogglePrimary('') else - call nerdtree#putCursorInTreeWin() + call g:NERDTree.CursorToTreeWin() endif let b:NERDTreeShowHidden = g:NERDTreeShowHidden call s:chRoot(g:NERDTreeDirNode.New(p.getParent())) else - if !nerdtree#isTreeOpen() + if !g:NERDTree.IsOpen() call g:NERDTreeCreator.TogglePrimary("") endif endif endif - call nerdtree#putCursorInTreeWin() + call g:NERDTree.CursorToTreeWin() call b:NERDTreeRoot.reveal(p) if p.isUnixHiddenFile() @@ -312,7 +312,7 @@ function! s:handleLeftClick() endfor if currentNode.path.isDirectory - if startToCur =~# nerdtree#treeMarkupReg() && startToCur =~# '[+~▾▸] \?$' + if startToCur =~# g:NERDTreeUI.MarkupReg() && startToCur =~# '[+~▾▸] \?$' call currentNode.activate() return endif @@ -320,11 +320,11 @@ function! s:handleLeftClick() if (g:NERDTreeMouseMode ==# 2 && currentNode.path.isDirectory) || g:NERDTreeMouseMode ==# 3 let char = strpart(startToCur, strlen(startToCur)-1, 1) - if char !~# nerdtree#treeMarkupReg() + if char !~# g:NERDTreeUI.MarkupReg() if currentNode.path.isDirectory call currentNode.activate() else - call currentNode.activate({'reuse': 1, 'where': 'p'}) + call currentNode.activate({'reuse': 'all', 'where': 'p'}) endif return endif @@ -547,7 +547,7 @@ endfunction function! nerdtree#ui_glue#setupCommands() command! -n=? -complete=dir -bar NERDTree :call g:NERDTreeCreator.CreatePrimary('') command! -n=? -complete=dir -bar NERDTreeToggle :call g:NERDTreeCreator.TogglePrimary('') - command! -n=0 -bar NERDTreeClose :call nerdtree#closeTreeIfOpen() + command! -n=0 -bar NERDTreeClose :call g:NERDTree.Close() command! -n=1 -complete=customlist,nerdtree#completeBookmarks -bar NERDTreeFromBookmark call g:NERDTreeCreator.CreatePrimary('') command! -n=0 -bar NERDTreeMirror call g:NERDTreeCreator.CreateMirror() command! -n=0 -bar NERDTreeFind call s:findAndRevealPath() diff --git a/sources_non_forked/nerdtree/doc/NERD_tree.txt b/sources_non_forked/nerdtree/doc/NERD_tree.txt index 5d5b3f6f7c..cfc8ed9b58 100644 --- a/sources_non_forked/nerdtree/doc/NERD_tree.txt +++ b/sources_non_forked/nerdtree/doc/NERD_tree.txt @@ -34,6 +34,8 @@ CONTENTS *NERDTree-contents* 4.The NERD tree API.......................|NERDTreeAPI| 4.1.Key map API.......................|NERDTreeKeymapAPI| 4.2.Menu API..........................|NERDTreeMenuAPI| + 4.3.Menu API..........................|NERDTreeAddPathFilter()| + 4.4.Path Listener API.................|NERDTreePathListenerAPI| 5.About...................................|NERDTreeAbout| 6.Changelog...............................|NERDTreeChangelog| 7.Credits.................................|NERDTreeCredits| @@ -131,7 +133,7 @@ The following features and functionality are provided by the NERD tree: :NERDTreeFind *:NERDTreeFind* Find the current file in the tree. - If not tree exists and the current file is under vim's CWD, then init a + If no tree exists and the current file is under vim's CWD, then init a tree at the CWD and reveal the file. Otherwise init a tree in the current file's directory. @@ -1173,6 +1175,44 @@ Where selecting "a (s)ub menu" will lead to a second menu: > When any of the 3 concrete menu items are selected the function "SomeFunction" will be called. +------------------------------------------------------------------------------ +4.3 NERDTreeAddPathFilter(callback) *NERDTreeAddPathFilter()* + +Path filters are essentially a more powerful version of |NERDTreeIgnore|. +If the simple regex matching in |NERDTreeIgnore| is not enough then use +|NERDTreeAddPathFilter()| to add a callback function that paths will be +checked against when the decision to ignore them is made. Example > + + call NERDTreeAddPathFilter('MyFilter') + + function! MyFilter(params) + "params is a dict containing keys: 'nerdtree' and 'path' which are + "g:NERDTree and g:NERDTreePath objects + + "return 1 to ignore params['path'] or 0 otherwise + endfunction +< +------------------------------------------------------------------------------ +4.4 Path Listener API *NERDTreePathListenerAPI* + +Use this API if you want to run a callback for events on Path objects. E.G > + + call g:NERDTreePathNotifier.AddListener("init", "MyListener") + + ".... + + function! MyListener(event) + "This function will be called whenever a Path object is created. + + "a:event is an object that contains a bunch of relevant info - + "including the path in question. See lib/event.vim for details. + endfunction +< +Current events supported: + init ~ + refresh ~ + refreshFlags ~ + ------------------------------------------------------------------------------ NERDTreeRender() *NERDTreeRender()* Re-renders the NERD tree buffer. Useful if you change the state of the @@ -1203,6 +1243,8 @@ Next - add 'scope' argument to the key map API - add NERDTreeCustomIgnoreFilter hook - needs doc - add magic [[dir]] and [[file]] flags to NERDTreeIgnore + - add support for custom path filters. See :help NERDTreeAddPathFilter() + - add path listener API. See :help NERDTreePathListenerAPI. 4.2.0 - Add NERDTreeDirArrows option to make the UI use pretty arrow chars diff --git a/sources_non_forked/nerdtree/lib/nerdtree/bookmark.vim b/sources_non_forked/nerdtree/lib/nerdtree/bookmark.vim index 6de9be4c36..8a94b25674 100644 --- a/sources_non_forked/nerdtree/lib/nerdtree/bookmark.vim +++ b/sources_non_forked/nerdtree/lib/nerdtree/bookmark.vim @@ -253,7 +253,7 @@ endfunction " FUNCTION: Bookmark.str() {{{1 " Get the string that should be rendered in the view for this bookmark function! s:Bookmark.str() - let pathStrMaxLen = winwidth(nerdtree#getTreeWinNum()) - 4 - len(self.name) + let pathStrMaxLen = winwidth(g:NERDTree.GetWinNum()) - 4 - len(self.name) if &nu let pathStrMaxLen = pathStrMaxLen - &numberwidth endif diff --git a/sources_non_forked/nerdtree/lib/nerdtree/creator.vim b/sources_non_forked/nerdtree/lib/nerdtree/creator.vim index 86f951ae37..2d6a5c2ea6 100644 --- a/sources_non_forked/nerdtree/lib/nerdtree/creator.vim +++ b/sources_non_forked/nerdtree/lib/nerdtree/creator.vim @@ -42,6 +42,11 @@ endfunction "name: the name of a bookmark or a directory function! s:Creator.createPrimary(name) let path = self._pathForString(a:name) + + "abort if exception was thrown (bookmark/dir doesn't exist) + if empty(path) + return + endif "if instructed to, then change the vim CWD to the dir the NERDTree is "inited in @@ -50,8 +55,8 @@ function! s:Creator.createPrimary(name) endif if g:NERDTree.ExistsForTab() - if nerdtree#isTreeOpen() - call nerdtree#closeTree() + if g:NERDTree.IsOpen() + call g:NERDTree.Close() endif unlet t:NERDTreeBufName endif @@ -163,8 +168,8 @@ function! s:Creator.createMirror() return endif - if g:NERDTree.ExistsForTab() && nerdtree#isTreeOpen() - call nerdtree#closeTree() + if g:NERDTree.ExistsForTab() && g:NERDTree.IsOpen() + call g:NERDTree.Close() endif let t:NERDTreeBufName = bufferName @@ -328,14 +333,14 @@ endfunction "initialized. function! s:Creator.togglePrimary(dir) if g:NERDTree.ExistsForTab() - if !nerdtree#isTreeOpen() + if !g:NERDTree.IsOpen() call self._createTreeWin() if !&hidden call b:NERDTree.render() endif call b:NERDTree.ui.restoreScreenState() else - call nerdtree#closeTree() + call g:NERDTree.Close() endif else call self.createPrimary(a:dir) diff --git a/sources_non_forked/nerdtree/lib/nerdtree/nerdtree.vim b/sources_non_forked/nerdtree/lib/nerdtree/nerdtree.vim index a41490b757..55f3dd75cf 100644 --- a/sources_non_forked/nerdtree/lib/nerdtree/nerdtree.vim +++ b/sources_non_forked/nerdtree/lib/nerdtree/nerdtree.vim @@ -3,6 +3,73 @@ let s:NERDTree = {} let g:NERDTree = s:NERDTree +"FUNCTION: s:NERDTree.AddPathFilter() {{{1 +function! s:NERDTree.AddPathFilter(callback) + call add(s:NERDTree.PathFilters(), a:callback) +endfunction + +"FUNCTION: s:NERDTree.Close() {{{1 +"Closes the primary NERD tree window for this tab +function! s:NERDTree.Close() + if !s:NERDTree.IsOpen() + return + endif + + if winnr("$") != 1 + if winnr() == s:NERDTree.GetWinNum() + call nerdtree#exec("wincmd p") + let bufnr = bufnr("") + call nerdtree#exec("wincmd p") + else + let bufnr = bufnr("") + endif + + call nerdtree#exec(s:NERDTree.GetWinNum() . " wincmd w") + close + call nerdtree#exec(bufwinnr(bufnr) . " wincmd w") + else + close + endif +endfunction + +"FUNCTION: s:NERDTree.CloseIfQuitOnOpen() {{{1 +"Closes the NERD tree window if the close on open option is set +function! s:NERDTree.CloseIfQuitOnOpen() + if g:NERDTreeQuitOnOpen && s:NERDTree.IsOpen() + call s:NERDTree.Close() + endif +endfunction + +"FUNCTION: s:NERDTree.CursorToBookmarkTable(){{{1 +"Places the cursor at the top of the bookmarks table +function! s:NERDTree.CursorToBookmarkTable() + if !b:NERDTreeShowBookmarks + throw "NERDTree.IllegalOperationError: cant find bookmark table, bookmarks arent active" + endif + + if g:NERDTreeMinimalUI + return cursor(1, 2) + endif + + let rootNodeLine = b:NERDTree.ui.getRootLineNum() + + let line = 1 + while getline(line) !~# '^>-\+Bookmarks-\+$' + let line = line + 1 + if line >= rootNodeLine + throw "NERDTree.BookmarkTableNotFoundError: didnt find the bookmarks table" + endif + endwhile + call cursor(line, 2) +endfunction + +"FUNCTION: s:NERDTree.CursorToTreeWin(){{{1 +"Places the cursor in the nerd tree window +function! s:NERDTree.CursorToTreeWin() + call g:NERDTree.MustBeOpen() + call nerdtree#exec(g:NERDTree.GetWinNum() . "wincmd w") +endfunction + " Function: s:NERDTree.ExistsForBuffer() {{{1 " Returns 1 if a nerd tree root exists in the current buffer function! s:NERDTree.ExistsForBuf() @@ -23,6 +90,29 @@ function! s:NERDTree.ForCurrentBuf() endif endfunction +"FUNCTION: s:NERDTree.GetWinNum() {{{1 +"gets the nerd tree window number for this tab +function! s:NERDTree.GetWinNum() + if exists("t:NERDTreeBufName") + return bufwinnr(t:NERDTreeBufName) + else + return -1 + endif +endfunction + +"FUNCTION: s:NERDTree.IsOpen() {{{1 +function! s:NERDTree.IsOpen() + return s:NERDTree.GetWinNum() != -1 +endfunction + +"FUNCTION: s:NERDTree.MustBeOpen() {{{1 +function! s:NERDTree.MustBeOpen() + if !s:NERDTree.IsOpen() + throw "NERDTree.TreeNotOpen" + endif +endfunction + +"FUNCTION: s:NERDTree.New() {{{1 function! s:NERDTree.New(path) let newObj = copy(self) let newObj.ui = g:NERDTreeUI.New(newObj) @@ -31,9 +121,17 @@ function! s:NERDTree.New(path) return newObj endfunction +"FUNCTION: s:NERDTree.PathFilters() {{{1 +function! s:NERDTree.PathFilters() + if !exists('s:NERDTree._PathFilters') + let s:NERDTree._PathFilters = [] + endif + return s:NERDTree._PathFilters +endfunction + + "FUNCTION: s:NERDTree.render() {{{1 "A convenience function - since this is called often function! s:NERDTree.render() call self.ui.render() endfunction - diff --git a/sources_non_forked/nerdtree/lib/nerdtree/opener.vim b/sources_non_forked/nerdtree/lib/nerdtree/opener.vim index 845e55c49f..3a6b39248c 100644 --- a/sources_non_forked/nerdtree/lib/nerdtree/opener.vim +++ b/sources_non_forked/nerdtree/lib/nerdtree/opener.vim @@ -40,7 +40,7 @@ function! s:Opener._checkToCloseTree(newtab) endif if (a:newtab && self._where == 't') || !a:newtab - call nerdtree#closeTreeIfQuitOnOpen() + call g:NERDTree.CloseIfQuitOnOpen() endif endfunction @@ -131,7 +131,8 @@ endfunction " 'where': Specifies whether the node should be opened in new split/tab or in " the previous window. Can be either 'v' or 'h' or 't' (for open in " new tab) -" 'reuse': if a window is displaying the file then jump the cursor there +" 'reuse': if a window is displaying the file then jump the cursor there. Can +" 'all', 'currenttab' or empty to not reuse. " 'keepopen': dont close the tree window " 'stay': open the file, but keep the cursor in the tree win function! s:Opener.New(path, opts) @@ -139,7 +140,13 @@ function! s:Opener.New(path, opts) let newObj._path = a:path let newObj._stay = nerdtree#has_opt(a:opts, 'stay') - let newObj._reuse = nerdtree#has_opt(a:opts, 'reuse') + + if has_key(a:opts, 'reuse') + let newObj._reuse = a:opts['reuse'] + else + let newObj._reuse = '' + endif + let newObj._keepopen = nerdtree#has_opt(a:opts, 'keepopen') let newObj._where = has_key(a:opts, 'where') ? a:opts['where'] : '' let newObj._treetype = b:NERDTreeType @@ -189,7 +196,7 @@ function! s:Opener._newSplit() try exec(splitMode." sp ") catch /^Vim\%((\a\+)\)\=:E37/ - call nerdtree#putCursorInTreeWin() + call g:NERDTree.CursorToTreeWin() throw "NERDTree.FileAlreadyOpenAndModifiedError: ". self._path.str() ." is already open and modified." catch /^Vim\%((\a\+)\)\=:/ "do nothing @@ -219,7 +226,7 @@ function! s:Opener._newVSplit() vnew "resize the nerd tree back to the original size - call nerdtree#putCursorInTreeWin() + call g:NERDTree.CursorToTreeWin() exec("silent vertical resize ". winwidth) call nerdtree#exec('wincmd p') endfunction @@ -235,7 +242,7 @@ endfunction "FUNCTION: Opener._openFile() {{{1 function! s:Opener._openFile() - if self._reuse && self._reuseWindow() + if self._reuseWindow() return endif @@ -288,7 +295,7 @@ function! s:Opener._previousWindow() call nerdtree#exec('wincmd p') endif catch /^Vim\%((\a\+)\)\=:E37/ - call nerdtree#putCursorInTreeWin() + call g:NERDTree.CursorToTreeWin() throw "NERDTree.FileAlreadyOpenAndModifiedError: ". self._path.str() ." is already open and modified." catch /^Vim\%((\a\+)\)\=:/ echo v:exception @@ -307,23 +314,32 @@ endfunction " "return 1 if we were successful function! s:Opener._reuseWindow() + if empty(self._reuse) + return 0 + endif + "check the current tab for the window let winnr = bufwinnr('^' . self._path.str() . '$') if winnr != -1 call nerdtree#exec(winnr . "wincmd w") call self._checkToCloseTree(0) return 1 - else - "check other tabs - let tabnr = self._path.tabnr() - if tabnr - call self._checkToCloseTree(1) - call nerdtree#exec('normal! ' . tabnr . 'gt') - let winnr = bufwinnr('^' . self._path.str() . '$') - call nerdtree#exec(winnr . "wincmd w") - return 1 - endif endif + + if self._reuse == 'currenttab' + return 0 + endif + + "check other tabs + let tabnr = self._path.tabnr() + if tabnr + call self._checkToCloseTree(1) + call nerdtree#exec('normal! ' . tabnr . 'gt') + let winnr = bufwinnr('^' . self._path.str() . '$') + call nerdtree#exec(winnr . "wincmd w") + return 1 + endif + return 0 endfunction diff --git a/sources_non_forked/nerdtree/lib/nerdtree/path.vim b/sources_non_forked/nerdtree/lib/nerdtree/path.vim index dbecb027e7..2af07ddbaf 100644 --- a/sources_non_forked/nerdtree/lib/nerdtree/path.vim +++ b/sources_non_forked/nerdtree/lib/nerdtree/path.vim @@ -1,6 +1,12 @@ "we need to use this number many times for sorting... so we calculate it only "once here let s:NERDTreeSortStarIndex = index(g:NERDTreeSortOrder, '*') +" used in formating sortKey, e.g. '%04d' +if exists("log10") + let s:sortKeyFormat = "%0" . float2nr(ceil(log10(len(g:NERDTreeSortOrder)))) . "d" +else + let s:sortKeyFormat = "%04d" +endif "CLASS: Path "============================================================ @@ -361,6 +367,24 @@ function! s:Path.getSortOrderIndex() return s:NERDTreeSortStarIndex endfunction +"FUNCTION: Path.getSortKey() {{{1 +"returns a string used in compare function for sorting +function! s:Path.getSortKey() + if !exists("self._sortKey") + let path = self.getLastPathComponent(1) + if !g:NERDTreeSortHiddenFirst + let path = substitute(path, '^[._]', '', '') + endif + if !g:NERDTreeCaseSensitiveSort + let path = tolower(path) + endif + let self._sortKey = printf(s:sortKeyFormat, self.getSortOrderIndex()) . path + endif + + return self._sortKey +endfunction + + "FUNCTION: Path.isUnixHiddenFile() {{{1 "check for unix hidden files function! s:Path.isUnixHiddenFile() @@ -392,6 +416,12 @@ function! s:Path.ignore() return 1 endif endfor + + for callback in g:NERDTree.PathFilters() + if {callback}({'path': self, 'nerdtree': b:NERDTree}) + return 1 + endif + endfor endif "dont show hidden files unless instructed to @@ -403,10 +433,6 @@ function! s:Path.ignore() return 1 endif - if exists("*NERDTreeCustomIgnoreFilter") && NERDTreeCustomIgnoreFilter(self) - return 1 - endif - return 0 endfunction @@ -611,7 +637,7 @@ function! s:Path.str(...) if has_key(self, '_strFor' . format) exec 'let toReturn = self._strFor' . format . '()' else - raise 'NERDTree.UnknownFormatError: unknown format "'. format .'"' + throw 'NERDTree.UnknownFormatError: unknown format "'. format .'"' endif else let toReturn = self._str() diff --git a/sources_non_forked/nerdtree/lib/nerdtree/tree_dir_node.vim b/sources_non_forked/nerdtree/lib/nerdtree/tree_dir_node.vim index a24c270467..765982dfc0 100644 --- a/sources_non_forked/nerdtree/lib/nerdtree/tree_dir_node.vim +++ b/sources_non_forked/nerdtree/lib/nerdtree/tree_dir_node.vim @@ -246,8 +246,12 @@ function! s:TreeDirNode._initChildren(silent) "filter out the .. and . directories "Note: we must match .. AND ../ cos sometimes the globpath returns "../ for path with strange chars (eg $) - if i !~# '\/\.\.\/\?$' && i !~# '\/\.\/\?$' - +" if i !~# '\/\.\.\/\?$' && i !~# '\/\.\/\?$' +" + " Regular expression is too expensive. Use simply string comparison + " instead + if i[len(i)-3:2] != ".." && i[len(i)-2:2] != ".." && + \ i[len(i)-2:1] != "." && i[len(i)-1] != "." "put the next file in a new node and attach it try let path = g:NERDTreePath.New(i) @@ -405,8 +409,12 @@ function! s:TreeDirNode.refresh() "filter out the .. and . directories "Note: we must match .. AND ../ cos sometimes the globpath returns "../ for path with strange chars (eg $) - if i !~# '\/\.\.\/\?$' && i !~# '\/\.\/\?$' + "if i !~# '\/\.\.\/\?$' && i !~# '\/\.\/\?$' + " Regular expression is too expensive. Use simply string comparison + " instead + if i[len(i)-3:2] != ".." && i[len(i)-2:2] != ".." && + \ i[len(i)-2:1] != "." && i[len(i)-1] != "." try "create a new path and see if it exists in this nodes children let path = g:NERDTreePath.New(i) @@ -504,7 +512,7 @@ endfunction "directory priority. " function! s:TreeDirNode.sortChildren() - let CompareFunc = function("nerdtree#compareNodes") + let CompareFunc = function("nerdtree#compareNodesBySortKey") call sort(self.children, CompareFunc) endfunction diff --git a/sources_non_forked/nerdtree/lib/nerdtree/ui.vim b/sources_non_forked/nerdtree/lib/nerdtree/ui.vim index ed93d80c17..22e450c889 100644 --- a/sources_non_forked/nerdtree/lib/nerdtree/ui.vim +++ b/sources_non_forked/nerdtree/lib/nerdtree/ui.vim @@ -3,11 +3,6 @@ let s:UI = {} let g:NERDTreeUI = s:UI - -function! s:UI.lolcats() - echomsg "lolcats" -endfunction - "FUNCTION: s:UI.centerView() {{{2 "centers the nerd tree window around the cursor (provided the nerd tree "options permit) @@ -15,13 +10,121 @@ function! s:UI.centerView() if g:NERDTreeAutoCenter let current_line = winline() let lines_to_top = current_line - let lines_to_bottom = winheight(nerdtree#getTreeWinNum()) - current_line + let lines_to_bottom = winheight(g:NERDTree.GetWinNum()) - current_line if lines_to_top < g:NERDTreeAutoCenterThreshold || lines_to_bottom < g:NERDTreeAutoCenterThreshold normal! zz endif endif endfunction +"FUNCTION: s:UI._dumpHelp {{{1 +"prints out the quick help +function! s:UI._dumpHelp() + let old_h = @h + if b:treeShowHelp ==# 1 + let @h= "\" NERD tree (" . nerdtree#version() . ") quickhelp~\n" + let @h=@h."\" ============================\n" + let @h=@h."\" File node mappings~\n" + let @h=@h."\" ". (g:NERDTreeMouseMode ==# 3 ? "single" : "double") ."-click,\n" + let @h=@h."\" ,\n" + if b:NERDTreeType ==# "primary" + let @h=@h."\" ". g:NERDTreeMapActivateNode .": open in prev window\n" + else + let @h=@h."\" ". g:NERDTreeMapActivateNode .": open in current window\n" + endif + if b:NERDTreeType ==# "primary" + let @h=@h."\" ". g:NERDTreeMapPreview .": preview\n" + endif + let @h=@h."\" ". g:NERDTreeMapOpenInTab.": open in new tab\n" + let @h=@h."\" ". g:NERDTreeMapOpenInTabSilent .": open in new tab silently\n" + let @h=@h."\" middle-click,\n" + let @h=@h."\" ". g:NERDTreeMapOpenSplit .": open split\n" + let @h=@h."\" ". g:NERDTreeMapPreviewSplit .": preview split\n" + let @h=@h."\" ". g:NERDTreeMapOpenVSplit .": open vsplit\n" + let @h=@h."\" ". g:NERDTreeMapPreviewVSplit .": preview vsplit\n" + + let @h=@h."\"\n\" ----------------------------\n" + let @h=@h."\" Directory node mappings~\n" + let @h=@h."\" ". (g:NERDTreeMouseMode ==# 1 ? "double" : "single") ."-click,\n" + let @h=@h."\" ". g:NERDTreeMapActivateNode .": open & close node\n" + let @h=@h."\" ". g:NERDTreeMapOpenRecursively .": recursively open node\n" + let @h=@h."\" ". g:NERDTreeMapCloseDir .": close parent of node\n" + let @h=@h."\" ". g:NERDTreeMapCloseChildren .": close all child nodes of\n" + let @h=@h."\" current node recursively\n" + let @h=@h."\" middle-click,\n" + let @h=@h."\" ". g:NERDTreeMapOpenExpl.": explore selected dir\n" + + let @h=@h."\"\n\" ----------------------------\n" + let @h=@h."\" Bookmark table mappings~\n" + let @h=@h."\" double-click,\n" + let @h=@h."\" ". g:NERDTreeMapActivateNode .": open bookmark\n" + let @h=@h."\" ". g:NERDTreeMapOpenInTab.": open in new tab\n" + let @h=@h."\" ". g:NERDTreeMapOpenInTabSilent .": open in new tab silently\n" + let @h=@h."\" ". g:NERDTreeMapDeleteBookmark .": delete bookmark\n" + + let @h=@h."\"\n\" ----------------------------\n" + let @h=@h."\" Tree navigation mappings~\n" + let @h=@h."\" ". g:NERDTreeMapJumpRoot .": go to root\n" + let @h=@h."\" ". g:NERDTreeMapJumpParent .": go to parent\n" + let @h=@h."\" ". g:NERDTreeMapJumpFirstChild .": go to first child\n" + let @h=@h."\" ". g:NERDTreeMapJumpLastChild .": go to last child\n" + let @h=@h."\" ". g:NERDTreeMapJumpNextSibling .": go to next sibling\n" + let @h=@h."\" ". g:NERDTreeMapJumpPrevSibling .": go to prev sibling\n" + + let @h=@h."\"\n\" ----------------------------\n" + let @h=@h."\" Filesystem mappings~\n" + let @h=@h."\" ". g:NERDTreeMapChangeRoot .": change tree root to the\n" + let @h=@h."\" selected dir\n" + let @h=@h."\" ". g:NERDTreeMapUpdir .": move tree root up a dir\n" + let @h=@h."\" ". g:NERDTreeMapUpdirKeepOpen .": move tree root up a dir\n" + let @h=@h."\" but leave old root open\n" + let @h=@h."\" ". g:NERDTreeMapRefresh .": refresh cursor dir\n" + let @h=@h."\" ". g:NERDTreeMapRefreshRoot .": refresh current root\n" + let @h=@h."\" ". g:NERDTreeMapMenu .": Show menu\n" + let @h=@h."\" ". g:NERDTreeMapChdir .":change the CWD to the\n" + let @h=@h."\" selected dir\n" + let @h=@h."\" ". g:NERDTreeMapCWD .":change tree root to CWD\n" + + let @h=@h."\"\n\" ----------------------------\n" + let @h=@h."\" Tree filtering mappings~\n" + let @h=@h."\" ". g:NERDTreeMapToggleHidden .": hidden files (" . (b:NERDTreeShowHidden ? "on" : "off") . ")\n" + let @h=@h."\" ". g:NERDTreeMapToggleFilters .": file filters (" . (b:NERDTreeIgnoreEnabled ? "on" : "off") . ")\n" + let @h=@h."\" ". g:NERDTreeMapToggleFiles .": files (" . (b:NERDTreeShowFiles ? "on" : "off") . ")\n" + let @h=@h."\" ". g:NERDTreeMapToggleBookmarks .": bookmarks (" . (b:NERDTreeShowBookmarks ? "on" : "off") . ")\n" + + "add quickhelp entries for each custom key map + let @h=@h."\"\n\" ----------------------------\n" + let @h=@h."\" Custom mappings~\n" + for i in g:NERDTreeKeyMap.All() + if !empty(i.quickhelpText) + let @h=@h."\" ". i.key .": ". i.quickhelpText ."\n" + endif + endfor + + let @h=@h."\"\n\" ----------------------------\n" + let @h=@h."\" Other mappings~\n" + let @h=@h."\" ". g:NERDTreeMapQuit .": Close the NERDTree window\n" + let @h=@h."\" ". g:NERDTreeMapToggleZoom .": Zoom (maximize-minimize)\n" + let @h=@h."\" the NERDTree window\n" + let @h=@h."\" ". g:NERDTreeMapHelp .": toggle help\n" + let @h=@h."\"\n\" ----------------------------\n" + let @h=@h."\" Bookmark commands~\n" + let @h=@h."\" :Bookmark []\n" + let @h=@h."\" :BookmarkToRoot \n" + let @h=@h."\" :RevealBookmark \n" + let @h=@h."\" :OpenBookmark \n" + let @h=@h."\" :ClearBookmarks []\n" + let @h=@h."\" :ClearAllBookmarks\n" + silent! put h + elseif g:NERDTreeMinimalUI == 0 + let @h="\" Press ". g:NERDTreeMapHelp ." for help\n" + silent! put h + endif + + let @h = old_h +endfunction + + "FUNCTION: s:UI.new(nerdtree) {{{1 function! s:UI.New(nerdtree) let newObj = copy(self) @@ -56,14 +159,14 @@ function! s:UI.getPath(ln) endif endif - if line ==# nerdtree#treeUpDirLine() + if line ==# s:UI.UpDirLine() return b:NERDTreeRoot.path.getParent() endif let indent = self._indentLevelFor(line) "remove the tree parts and the leading space - let curFile = nerdtree#stripMarkupFromLine(line, 0) + let curFile = self._stripMarkup(line, 0) let wasdir = 0 if curFile =~# '/$' @@ -76,7 +179,7 @@ function! s:UI.getPath(ln) while lnum > 0 let lnum = lnum - 1 let curLine = getline(lnum) - let curLineStripped = nerdtree#stripMarkupFromLine(curLine, 1) + let curLineStripped = self._stripMarkup(curLine, 1) "have we reached the top of the tree? if lnum == rootLine @@ -127,7 +230,7 @@ function! s:UI.getLineNum(file_node) let indent = self._indentLevelFor(curLine) if indent ==# curPathComponent - let curLine = nerdtree#stripMarkupFromLine(curLine, 1) + let curLine = self._stripMarkup(curLine, 1) let curPath = join(pathcomponents, '/') . '/' . curLine if stridx(fullpath, curPath, 0) ==# 0 @@ -146,7 +249,6 @@ function! s:UI.getLineNum(file_node) return -1 endfunction - "FUNCTION: s:UI.getRootLineNum(){{{1 "gets the line number of the root node function! s:UI.getRootLineNum() @@ -157,9 +259,9 @@ function! s:UI.getRootLineNum() return rootLine endfunction -"FUNCTION: s:UI._indentLevelFor(line) {{{2 +"FUNCTION: s:UI._indentLevelFor(line) {{{1 function! s:UI._indentLevelFor(line) - let level = match(a:line, '[^ \-+~▸▾`|]') / nerdtree#treeWid() + let level = match(a:line, '[^ \-+~▸▾`|]') / s:UI.IndentWid() " check if line includes arrows if match(a:line, '[▸▾]') > -1 " decrement level as arrow uses 3 ascii chars @@ -168,8 +270,38 @@ function! s:UI._indentLevelFor(line) return level endfunction +"FUNCTION: s:UI.IndentWid() {{{1 +function! s:UI.IndentWid() + return 2 +endfunction + +"FUNCTION: s:UI.MarkupReg() {{{1 +function! s:UI.MarkupReg() + if g:NERDTreeDirArrows + return '^\([▾▸] \| \+[▾▸] \| \+\)' + endif + + return '^[ `|]*[\-+~]' +endfunction + +"FUNCTION: s:UI._renderBookmarks {{{1 +function! s:UI._renderBookmarks() + + if g:NERDTreeMinimalUI == 0 + call setline(line(".")+1, ">----------Bookmarks----------") + call cursor(line(".")+1, col(".")) + endif + + for i in g:NERDTreeBookmark.Bookmarks() + call setline(line(".")+1, i.str()) + call cursor(line(".")+1, col(".")) + endfor + + call setline(line(".")+1, '') + call cursor(line(".")+1, col(".")) +endfunction -"FUNCTION: s:UI.restoreScreenState() {{{2 +"FUNCTION: s:UI.restoreScreenState() {{{1 " "Sets the screen state back to what it was when nerdtree#saveScreenState was last "called. @@ -189,23 +321,60 @@ function! s:UI.restoreScreenState() let &scrolloff=old_scrolloff endfunction -"FUNCTION: s:UI.saveScreenState() {{{2 +"FUNCTION: s:UI.saveScreenState() {{{1 "Saves the current cursor position in the current buffer and the window "scroll position function! s:UI.saveScreenState() let win = winnr() - try - call nerdtree#putCursorInTreeWin() - let self._screenState = {} - let self._screenState['oldPos'] = getpos(".") - let self._screenState['oldTopLine'] = line("w0") - let self._screenState['oldWindowSize']= winwidth("") - call nerdtree#exec(win . "wincmd w") - catch /^NERDTree.InvalidOperationError/ - endtry + call g:NERDTree.CursorToTreeWin() + let self._screenState = {} + let self._screenState['oldPos'] = getpos(".") + let self._screenState['oldTopLine'] = line("w0") + let self._screenState['oldWindowSize']= winwidth("") + call nerdtree#exec(win . "wincmd w") endfunction -"FUNCTION: s:UI.render() {{{2 +"FUNCTION: s:UI._stripMarkup(line, removeLeadingSpaces){{{1 +"returns the given line with all the tree parts stripped off +" +"Args: +"line: the subject line +"removeLeadingSpaces: 1 if leading spaces are to be removed (leading spaces = +"any spaces before the actual text of the node) +function! s:UI._stripMarkup(line, removeLeadingSpaces) + let line = a:line + "remove the tree parts and the leading space + let line = substitute (line, g:NERDTreeUI.MarkupReg(),"","") + + "strip off any read only flag + let line = substitute (line, ' \[RO\]', "","") + + "strip off any bookmark flags + let line = substitute (line, ' {[^}]*}', "","") + + "strip off any executable flags + let line = substitute (line, '*\ze\($\| \)', "","") + + "strip off any generic flags + let line = substitute (line, '\[[^]]*\]', "","") + + let wasdir = 0 + if line =~# '/$' + let wasdir = 1 + endif + let line = substitute (line,' -> .*',"","") " remove link to + if wasdir ==# 1 + let line = substitute (line, '/\?$', '/', "") + endif + + if a:removeLeadingSpaces + let line = substitute (line, '^ *', '', '') + endif + + return line +endfunction + +"FUNCTION: s:UI.render() {{{1 function! s:UI.render() setlocal modifiable @@ -218,7 +387,7 @@ function! s:UI.render() "delete all lines in the buffer (being careful not to clobber a register) silent 1,$delete _ - call nerdtree#dumpHelp() + call self._dumpHelp() "delete the blank line before the help and add one after it if g:NERDTreeMinimalUI == 0 @@ -227,12 +396,12 @@ function! s:UI.render() endif if b:NERDTreeShowBookmarks - call nerdtree#renderBookmarks() + call self._renderBookmarks() endif "add the 'up a dir' line if !g:NERDTreeMinimalUI - call setline(line(".")+1, nerdtree#treeUpDirLine()) + call setline(line(".")+1, s:UI.UpDirLine()) call cursor(line(".")+1, col(".")) endif @@ -295,7 +464,7 @@ function! s:UI.toggleShowBookmarks() let b:NERDTreeShowBookmarks = !b:NERDTreeShowBookmarks if b:NERDTreeShowBookmarks call b:NERDTree.render() - call nerdtree#putCursorOnBookmarkTable() + call g:NERDTree.CursorToBookmarkTable() else call b:NERDTree.ui.renderViewSavingPosition() endif @@ -330,3 +499,8 @@ function! s:UI.toggleZoom() let b:NERDTreeZoomed = 1 endif endfunction + +"FUNCTION: s:UI.UpDirLine() {{{1 +function! s:UI.UpDirLine() + return '.. (up a dir)' +endfunction diff --git a/sources_non_forked/nerdtree/plugin/NERD_tree.vim b/sources_non_forked/nerdtree/plugin/NERD_tree.vim index 28fd3ad1e2..966838c352 100644 --- a/sources_non_forked/nerdtree/plugin/NERD_tree.vim +++ b/sources_non_forked/nerdtree/plugin/NERD_tree.vim @@ -148,7 +148,7 @@ call nerdtree#ui_glue#setupCommands() "============================================================ augroup NERDTree "Save the cursor position whenever we close the nerd tree - exec "autocmd BufLeave ". g:NERDTreeCreator.BufNamePrefix() ."* call b:NERDTree.ui.saveScreenState()" + exec "autocmd BufLeave ". g:NERDTreeCreator.BufNamePrefix() ."* if g:NERDTree.IsOpen() | call b:NERDTree.ui.saveScreenState() | endif" "disallow insert mode in the NERDTree exec "autocmd BufEnter ". g:NERDTreeCreator.BufNamePrefix() ."* stopinsert" @@ -185,8 +185,8 @@ function! NERDTreeRender() endfunction function! NERDTreeFocus() - if nerdtree#isTreeOpen() - call nerdtree#putCursorInTreeWin() + if g:NERDTree.IsOpen() + call g:NERDTree.CursorToTreeWin() else call g:NERDTreeCreator.TogglePrimary("") endif @@ -196,6 +196,11 @@ function! NERDTreeCWD() call NERDTreeFocus() call nerdtree#ui_glue#chRootCwd() endfunction + +function! NERDTreeAddPathFilter(callback) + call g:NERDTree.AddPathFilter(a:callback) +endfunction + " SECTION: Post Source Actions {{{1 call nerdtree#postSourceActions() diff --git a/sources_non_forked/syntastic/README.markdown b/sources_non_forked/syntastic/README.markdown index 6c6fab4f4c..beaaeae139 100644 --- a/sources_non_forked/syntastic/README.markdown +++ b/sources_non_forked/syntastic/README.markdown @@ -53,21 +53,22 @@ are detected, the user is notified and is happy because they didn't have to compile their code or execute their script to find them. At the time of this writing, syntastic has checking plugins for ActionScript, -Ada, API Blueprint, AppleScript, AsciiDoc, ASM, BEMHTML, Bro, Bourne shell, -C, C++, C#, Cabal, Chef, CoffeeScript, Coco, Coq, CSS, Cucumber, CUDA, D, -Dart, DocBook, Dust, Elixir, Erlang, eRuby, Fortran, Gentoo metadata, GLSL, -Go, Haml, Haskell, Haxe, Handlebars, HSS, HTML, Java, JavaScript, JSON, JSX, -LESS, Lex, Limbo, LISP, LLVM intermediate language, Lua, Markdown, MATLAB, -NASM, Objective-C, Objective-C++, OCaml, Perl, Perl POD, PHP, gettext Portable +Ada, API Blueprint, AppleScript, AsciiDoc, ASM, BEMHTML, Bro, Bourne shell, C, +C++, C#, Cabal, Chef, CoffeeScript, Coco, Coq, CSS, Cucumber, CUDA, D, Dart, +DocBook, Dust, Elixir, Erlang, eRuby, Fortran, Gentoo metadata, GLSL, Go, Haml, +Haskell, Haxe, Handlebars, HSS, HTML, Java, JavaScript, JSON, JSX, LESS, Lex, +Limbo, LISP, LLVM intermediate language, Lua, Markdown, MATLAB, Mercury, NASM, +Nix, Objective-C, Objective-C++, OCaml, Perl, Perl POD, PHP, gettext Portable Object, OS X and iOS property lists, Puppet, Python, R, Racket, Relax NG, -reStructuredText, RPM spec, Ruby, SASS/SCSS, Scala, Slim, SML, Tcl, TeX, -Texinfo, Twig, TypeScript, Vala, Verilog, VHDL, VimL, xHtml, XML, XSLT, YACC, -YAML, z80, Zope page templates, and zsh. See the [wiki][3] for details about -the corresponding supported checkers. +reStructuredText, RPM spec, Ruby, SASS/SCSS, Scala, Slim, SML, Sphinx, SQL, +Stylus, Tcl, TeX, Texinfo, Twig, TypeScript, Vala, Verilog, VHDL, VimL, xHtml, +XML, XSLT, YACC, YAML, z80, Zope page templates, and zsh. See the [wiki][3] +for details about the corresponding supported checkers. A number of third-party Vim plugins also provide checkers for syntastic, for example: [omnisharp-vim][25], [rust.vim][12], [syntastic-extras][26], -[syntastic-more][27], and [vim-swift][24]. +[syntastic-more][27], [vim-crystal][29], [vim-eastwood][28], and +[vim-swift][24]. Below is a screenshot showing the methods that Syntastic uses to display syntax errors. Note that, in practise, you will only have a subset of these methods @@ -410,7 +411,7 @@ work around it: ```vim nnoremap :lclose:bdelete -cabbrev bd lclose\|bdelete +cabbrev bd =(getcmdtype()==#':' && getcmdpos()==1 ? 'lclose\|bdelete' : 'bd') ``` @@ -456,6 +457,8 @@ a look at [jedi-vim][7], [python-mode][8], or [YouCompleteMe][9]. [25]: https://github.com/OmniSharp/omnisharp-vim [26]: https://github.com/myint/syntastic-extras [27]: https://github.com/roktas/syntastic-more +[28]: https://github.com/venantius/vim-eastwood +[29]: https://github.com/rhysd/vim-crystal [key, prev, next] + dict.clear(self) + + def __setitem__(self, key, value): + if key not in self: + end = self.__end + curr = end[1] + curr[2] = end[1] = self.__map[key] = [key, curr, end] + dict.__setitem__(self, key, value) + + def __delitem__(self, key): + dict.__delitem__(self, key) + key, prev, next = self.__map.pop(key) + prev[2] = next + next[1] = prev + + def __iter__(self): + end = self.__end + curr = end[2] + while curr is not end: + yield curr[0] + curr = curr[2] + + def __reversed__(self): + end = self.__end + curr = end[1] + while curr is not end: + yield curr[0] + curr = curr[1] + + def popitem(self, last=True): + if not self: + raise KeyError('dictionary is empty') + if last: + key = reversed(self).next() + else: + key = iter(self).next() + value = self.pop(key) + return key, value + + def __reduce__(self): + items = [[k, self[k]] for k in self] + tmp = self.__map, self.__end + del self.__map, self.__end + inst_dict = vars(self).copy() + self.__map, self.__end = tmp + if inst_dict: + return (self.__class__, (items,), inst_dict) + return self.__class__, (items,) + + def keys(self): + return list(self) + + setdefault = DictMixin.setdefault + update = DictMixin.update + pop = DictMixin.pop + values = DictMixin.values + items = DictMixin.items + iterkeys = DictMixin.iterkeys + itervalues = DictMixin.itervalues + iteritems = DictMixin.iteritems + + def __repr__(self): + if not self: + return '%s()' % (self.__class__.__name__,) + return '%s(%r)' % (self.__class__.__name__, self.items()) + + def copy(self): + return self.__class__(self) + + @classmethod + def fromkeys(cls, iterable, value=None): + d = cls() + for key in iterable: + d[key] = value + return d + + def __eq__(self, other): + if isinstance(other, OrderedDict): + if len(self) != len(other): + return False + for p, q in zip(self.items(), other.items()): + if p != q: + return False + return True + return dict.__eq__(self, other) + + def __ne__(self, other): + return not self == other diff --git a/sources_non_forked/vim-wakatime/plugin/packages/wakatime/packages/pygments_py2/pygments/__init__.py b/sources_non_forked/vim-wakatime/plugin/packages/wakatime/packages/pygments_py2/pygments/__init__.py new file mode 100644 index 0000000000..872ad97619 --- /dev/null +++ b/sources_non_forked/vim-wakatime/plugin/packages/wakatime/packages/pygments_py2/pygments/__init__.py @@ -0,0 +1,91 @@ +# -*- coding: utf-8 -*- +""" + Pygments + ~~~~~~~~ + + Pygments is a syntax highlighting package written in Python. + + It is a generic syntax highlighter for general use in all kinds of software + such as forum systems, wikis or other applications that need to prettify + source code. Highlights are: + + * a wide range of common languages and markup formats is supported + * special attention is paid to details, increasing quality by a fair amount + * support for new languages and formats are added easily + * a number of output formats, presently HTML, LaTeX, RTF, SVG, all image + formats that PIL supports, and ANSI sequences + * it is usable as a command-line tool and as a library + * ... and it highlights even Brainfuck! + + The `Pygments tip`_ is installable with ``easy_install Pygments==dev``. + + .. _Pygments tip: + http://bitbucket.org/birkenfeld/pygments-main/get/tip.zip#egg=Pygments-dev + + :copyright: Copyright 2006-2014 by the Pygments team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +__version__ = '2.0.1' +__docformat__ = 'restructuredtext' + +__all__ = ['lex', 'format', 'highlight'] + + +import sys + +from pygments.util import StringIO, BytesIO + + +def lex(code, lexer): + """ + Lex ``code`` with ``lexer`` and return an iterable of tokens. + """ + try: + return lexer.get_tokens(code) + except TypeError as err: + if isinstance(err.args[0], str) and \ + 'unbound method get_tokens' in err.args[0]: + raise TypeError('lex() argument must be a lexer instance, ' + 'not a class') + raise + + +def format(tokens, formatter, outfile=None): + """ + Format a tokenlist ``tokens`` with the formatter ``formatter``. + + If ``outfile`` is given and a valid file object (an object + with a ``write`` method), the result will be written to it, otherwise + it is returned as a string. + """ + try: + if not outfile: + #print formatter, 'using', formatter.encoding + realoutfile = formatter.encoding and BytesIO() or StringIO() + formatter.format(tokens, realoutfile) + return realoutfile.getvalue() + else: + formatter.format(tokens, outfile) + except TypeError as err: + if isinstance(err.args[0], str) and \ + 'unbound method format' in err.args[0]: + raise TypeError('format() argument must be a formatter instance, ' + 'not a class') + raise + + +def highlight(code, lexer, formatter, outfile=None): + """ + Lex ``code`` with ``lexer`` and format it with the formatter ``formatter``. + + If ``outfile`` is given and a valid file object (an object + with a ``write`` method), the result will be written to it, otherwise + it is returned as a string. + """ + return format(lex(code, lexer), formatter, outfile) + + +if __name__ == '__main__': + from pygments.cmdline import main + sys.exit(main(sys.argv)) diff --git a/sources_non_forked/vim-wakatime/plugin/packages/wakatime/packages/pygments_py2/pygments/cmdline.py b/sources_non_forked/vim-wakatime/plugin/packages/wakatime/packages/pygments_py2/pygments/cmdline.py new file mode 100644 index 0000000000..b6c319cfaf --- /dev/null +++ b/sources_non_forked/vim-wakatime/plugin/packages/wakatime/packages/pygments_py2/pygments/cmdline.py @@ -0,0 +1,509 @@ +# -*- coding: utf-8 -*- +""" + pygments.cmdline + ~~~~~~~~~~~~~~~~ + + Command line interface. + + :copyright: Copyright 2006-2014 by the Pygments team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +from __future__ import print_function + +import sys +import getopt +from textwrap import dedent + +from pygments import __version__, highlight +from pygments.util import ClassNotFound, OptionError, docstring_headline, \ + guess_decode, guess_decode_from_terminal, terminal_encoding +from pygments.lexers import get_all_lexers, get_lexer_by_name, guess_lexer, \ + get_lexer_for_filename, find_lexer_class, TextLexer +from pygments.formatters.latex import LatexEmbeddedLexer, LatexFormatter +from pygments.formatters import get_all_formatters, get_formatter_by_name, \ + get_formatter_for_filename, find_formatter_class, \ + TerminalFormatter # pylint:disable-msg=E0611 +from pygments.filters import get_all_filters, find_filter_class +from pygments.styles import get_all_styles, get_style_by_name + + +USAGE = """\ +Usage: %s [-l | -g] [-F [:]] [-f ] + [-O ] [-P ] [-s] [-o ] [] + + %s -S + + +

%(title)s

+ +''' + +DOC_HEADER_EXTERNALCSS = '''\ + + + + + %(title)s + + + + +

%(title)s

+ +''' + +DOC_FOOTER = '''\ + + +''' + + +class HtmlFormatter(Formatter): + r""" + Format tokens as HTML 4 ```` tags within a ``
`` tag, wrapped
+    in a ``
`` tag. The ``
``'s CSS class can be set by the `cssclass` + option. + + If the `linenos` option is set to ``"table"``, the ``
`` is
+    additionally wrapped inside a ```` which has one row and two
+    cells: one containing the line numbers and one containing the code.
+    Example:
+
+    .. sourcecode:: html
+
+        
+
+ + +
+
1
+            2
+
+
def foo(bar):
+              pass
+            
+
+ + (whitespace added to improve clarity). + + Wrapping can be disabled using the `nowrap` option. + + A list of lines can be specified using the `hl_lines` option to make these + lines highlighted (as of Pygments 0.11). + + With the `full` option, a complete HTML 4 document is output, including + the style definitions inside a `` + + +

%(title)s

+ +''' + +DOC_HEADER_EXTERNALCSS = '''\ + + + + + %(title)s + + + + +

%(title)s

+ +''' + +DOC_FOOTER = '''\ + + +''' + + +class HtmlFormatter(Formatter): + r""" + Format tokens as HTML 4 ```` tags within a ``
`` tag, wrapped
+    in a ``
`` tag. The ``
``'s CSS class can be set by the `cssclass` + option. + + If the `linenos` option is set to ``"table"``, the ``
`` is
+    additionally wrapped inside a ```` which has one row and two
+    cells: one containing the line numbers and one containing the code.
+    Example:
+
+    .. sourcecode:: html
+
+        
+
+ + +
+
1
+            2
+
+
def foo(bar):
+              pass
+            
+
+ + (whitespace added to improve clarity). + + Wrapping can be disabled using the `nowrap` option. + + A list of lines can be specified using the `hl_lines` option to make these + lines highlighted (as of Pygments 0.11). + + With the `full` option, a complete HTML 4 document is output, including + the style definitions inside a ``