├── .github ├── FUNDING.yml └── workflows │ ├── reviewdog.yml │ └── vint.yml ├── .gitignore ├── .vintrc.yaml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── autoload └── nerdcommenter.vim ├── doc └── nerdcommenter.txt └── plugin └── nerdcommenter.vim /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [alerque, scrooloose] 2 | -------------------------------------------------------------------------------- /.github/workflows/reviewdog.yml: -------------------------------------------------------------------------------- 1 | name: Reviewdog 2 | on: [pull_request] 3 | jobs: 4 | vint: 5 | strategy: 6 | fail-fast: false 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Checkout 10 | uses: actions/checkout@v2 11 | - name: Lint Vimscript in PR changes 12 | uses: reviewdog/action-vint@v1 13 | with: 14 | github_token: ${{ secrets.github_token }} 15 | reporter: github-pr-review 16 | level: info 17 | -------------------------------------------------------------------------------- /.github/workflows/vint.yml: -------------------------------------------------------------------------------- 1 | name: Vint 2 | on: [push] 3 | jobs: 4 | vint: 5 | strategy: 6 | fail-fast: false 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Checkout 10 | uses: actions/checkout@v2 11 | - name: Set up Python 12 | uses: actions/setup-python@v2 13 | - name: Setup dependencies 14 | run: pip install vim-vint 15 | - name: Lint Vimscript 16 | run: vint . 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.swp 3 | tags 4 | DEBUG 5 | -------------------------------------------------------------------------------- /.vintrc.yaml: -------------------------------------------------------------------------------- 1 | cmdargs: 2 | severity: style_problem 3 | color: true 4 | env: 5 | neovim: false 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ### 2.7.0 4 | 5 | * Support for many more filetypes 6 | * Sort out race condition when using utility functions directly 7 | * Fixup undo support when commenting results in cursor moves 8 | * Refactor comment insertion code 9 | 10 | ### 2.6.0 11 | 12 | * Refactor code to run as autoload plugin 13 | * Add lots of community contributed file types 14 | * Fix several languages with idiosyncrasies 15 | * Improve interoperability with other vim settings 16 | * Improve handling of ranges 17 | * Improve help documentation 18 | * Cleanup and fix vimscript issues 19 | 20 | ### 2.5.2 21 | 22 | * Minor update to include new file types contributed by the community over the last few months. 23 | * Also adds a customization option to the sexy comment style. 24 | 25 | ### 2.5.1 26 | 27 | * Minor update release that adds a few new contributed filetypes and normalizes the code format a little bit. 28 | 29 | ### 2.5.0 30 | 31 | * Add lots of new contributed file types, cleanup some odds and ends. 32 | * Bump "release" for the sake of plugin managers still not tracking master. 33 | 34 | ### 2.4.0 35 | 36 | * Bump release number for the benefit of plugin managers that update to tags 37 | 38 | ### 2.3.0 39 | 40 | * remove all filetypes which have a &commentstring in the standard vim runtime 41 | for vim > 7.0 unless the script stores an alternate set of delimiters 42 | * make the script complain if the user doesn't have filetype plugins enabled 43 | * use || instead of comma to start the default mappings 44 | * fix a couple of bugs with sexy comments - thanks to Tim Smart 45 | * lots of refactoring 46 | 47 | ### 2.2.2 48 | 49 | * remove the NERDShutup option and the message is suppresses, this makes the plugin silently rely on &commentstring for unknown filetypes. 50 | * add support for dhcpd, limits, ntp, resolv, rgb, sysctl, udevconf and udevrules. Thanks to Thilo Six. 51 | * match filetypes case insensitively 52 | * add support for mp (metapost), thanks to Andrey Skvortsov. 53 | * add support for htmlcheetah, thanks to Simon Hengel. 54 | * add support for javacc, thanks to Matt Tolton. 55 | * make <%# %> the default delims for eruby, thanks to tpope. 56 | * add support for javascript.jquery, thanks to Ivan Devat. 57 | * add support for cucumber and pdf. Fix sass and railslog delims, thanks to tpope 58 | 59 | ### 2.2.1 60 | 61 | * add support for newlisp and clojure, thanks to Matthew Lee Hinman. 62 | * fix automake comments, thanks to Elias Pipping 63 | * make haml comments default to -# with / as the alternative delimiter, thanks to tpope 64 | * add support for actionscript and processing thanks to Edwin Benavides 65 | * add support for ps1 (powershell), thanks to Jason Mills 66 | * add support for hostsaccess, thanks to Thomas Rowe 67 | * add support for CVScommit 68 | * add support for asciidoc, git and gitrebase. Thanks to Simon Ruderich. 69 | * use # for gitcommit comments, thanks to Simon Ruderich. 70 | * add support for mako and genshi, thanks to Keitheis. 71 | * add support for conkyrc, thanks to David 72 | * add support for SVNannotate, thanks to Miguel Jaque Barbero. 73 | * add support for sieve, thanks to Stefan Walk 74 | * add support for objj, thanks to Adam Thorsen. 75 | 76 | ### 2.2.0 77 | 78 | * rewrote the mappings system to be more "standard". 79 | * removed all the mapping options. Now, mappings to mappings are used 80 | * see :help NERDComMappings, and :help NERDCreateDefaultMappings for more info 81 | * remove "prepend comments" and "right aligned comments". 82 | * 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. 83 | * bugfix for haskell delimiters. Thanks to mntnoe. 84 | 85 | ### 2.1.18 86 | 87 | * add support for llvm. Thanks to nicothakis. 88 | * add support for xquery. Thanks to Phillip Kovalev. 89 | 90 | ### 2.1.17 91 | 92 | * fixed haskell delimiters (hackily). Thanks to Elias Pipping. 93 | * add support for mailcap. Thanks to Pascal Brueckner. 94 | * add support for stata. Thanks to Jerónimo Carballo. 95 | * applied a patch from ewfalor to fix an error in the help file with the NERDMapleader doc 96 | * disable the insert mode ctrl-c mapping by default, see :help NERDCommenterInsert if you wish to restore it 97 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NERD Commenter 2 | 3 | [![Vint](https://github.com/preservim/nerdcommenter/workflows/Vint/badge.svg)](https://github.com/preservim/nerdcommenter/actions?workflow=Vint) 4 | 5 | Comment functions so powerful—no comment necessary. 6 | 7 | ## Installation 8 | 9 | ### Via Plugin Manager (Recommended) 10 | 11 |
12 | Vim Plug 13 | 14 | #### [Vim-Plug](https://github.com/junegunn/vim-plug) 15 | 16 | 1. Add `Plug 'preservim/nerdcommenter'` to your vimrc file. 17 | 2. Reload your vimrc or restart 18 | 3. Run `:PlugInstall` 19 | 20 |
21 | 22 |
23 | Vundle 24 | 25 | #### [Vundle](https://github.com/VundleVim/Vundle.vim) or similar 26 | 27 | 1. Add `Plugin 'preservim/nerdcommenter'` to your vimrc file. 28 | 2. Reload your vimrc or restart 29 | 3. Run `:BundleInstall` 30 | 31 |
32 | 33 |
34 | NeoBundle 35 | 36 | #### [NeoBundle](https://github.com/Shougo/neobundle.vim) 37 | 38 | 1. Add `NeoBundle 'preservim/nerdcommenter'` to your vimrc file. 39 | 2. Reload your vimrc or restart 40 | 3. Run `:NeoUpdate` 41 | 42 |
43 | 44 |
45 | Pathogen 46 | 47 | #### [Pathogen](https://github.com/tpope/vim-pathogen) 48 | 49 | ```sh 50 | cd ~/.vim/bundle 51 | git clone https://github.com/preservim/nerdcommenter.git 52 | ``` 53 |
54 | 55 |
56 | Vim 8+ Packages 57 | 58 | git clone https://github.com/preservim/nerdcommenter.git ~/.vim/pack/vendor/start/nerdcommenter 59 |
60 | 61 | ### Manual Installation 62 | 63 |
64 | Unix 65 | 66 | #### Unix 67 | 68 | (For Neovim, change `~/.vim/` to `~/.config/nvim/`.) 69 | 70 | ```sh 71 | curl -fLo ~/.vim/plugin/nerdcommenter.vim --create-dirs \ 72 | https://raw.githubusercontent.com/preservim/nerdcommenter/master/plugin/nerdcommenter.vim 73 | curl -fLo ~/.vim/doc/nerdcommenter.txt --create-dirs \ 74 | https://raw.githubusercontent.com/preservim/nerdcommenter/master/doc/nerdcommenter.txt 75 | curl -fLo ~/.vim/autoload/nerdcommenter.vim --create-dirs \ 76 | https://raw.githubusercontent.com/preservim/nerdcommenter/master/autoload/nerdcommenter.vim 77 | ``` 78 |
79 | 80 |
81 | Windows 82 | #### Windows (PowerShell) 83 | 84 | ```powershell 85 | md ~\vimfiles\plugin 86 | md ~\vimfiles\doc 87 | $pluguri = 'https://raw.githubusercontent.com/preservim/nerdcommenter/master/plugin/nerdcommenter.vim' 88 | $docsuri = 'https://raw.githubusercontent.com/preservim/nerdcommenter/master/doc/nerdcommenter.txt' 89 | (New-Object Net.WebClient).DownloadFile($pluguri, $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath("~\vimfiles\plugin\nerdcommenter.vim")) 90 | (New-Object Net.WebClient).DownloadFile($docsuri, $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath("~\vimfiles\doc\nerdcommenter.txt")) 91 | ``` 92 |
93 | 94 | ### Post Installation 95 | 96 | Make sure that you have filetype plugins enabled, as the plugin makes use of **|commentstring|** where possible (which is usually set in a filetype plugin). See **|filetype-plugin-on|** for details, but the short version is make sure this line appears in your vimrc: 97 | 98 | ```sh 99 | filetype plugin on 100 | ``` 101 | 102 | ## Usage 103 | 104 | ### Documentation 105 | 106 | Please see the vim help system for full documentation of all options: `:help nerdcommenter` 107 | 108 | ### Settings 109 | 110 | Several settings can be added to your vimrc to change the default behavior. Some examples: 111 | 112 | ```vim 113 | " Create default mappings 114 | let g:NERDCreateDefaultMappings = 1 115 | 116 | " Add spaces after comment delimiters by default 117 | let g:NERDSpaceDelims = 1 118 | 119 | " Use compact syntax for prettified multi-line comments 120 | let g:NERDCompactSexyComs = 1 121 | 122 | " Align line-wise comment delimiters flush left instead of following code indentation 123 | let g:NERDDefaultAlign = 'left' 124 | 125 | " Set a language to use its alternate delimiters by default 126 | let g:NERDAltDelims_java = 1 127 | 128 | " Add your own custom formats or override the defaults 129 | let g:NERDCustomDelimiters = { 'c': { 'left': '/**','right': '*/' } } 130 | 131 | " Allow commenting and inverting empty lines (useful when commenting a region) 132 | let g:NERDCommentEmptyLines = 1 133 | 134 | " Enable trimming of trailing whitespace when uncommenting 135 | let g:NERDTrimTrailingWhitespace = 1 136 | 137 | " Enable NERDCommenterToggle to check all selected lines is commented or not 138 | let g:NERDToggleCheckAllLines = 1 139 | ``` 140 | 141 | ### Default mappings 142 | 143 | > **Note:** You can turn off settings default mappings to provide your own from scratch (look at the [Settings list](#settings) above) 144 | 145 | The following key mappings are provided by default (there is also a menu provided that contains menu items corresponding to all the below mappings): 146 | 147 | Most of the following mappings are for normal/visual mode only. The **|NERDCommenterInsert|** mapping is for insert mode only. 148 | 149 | * `[count]cc` **|NERDCommenterComment|** 150 | 151 | Comment out the current line or text selected in visual mode. 152 | 153 | * `[count]cn` **|NERDCommenterNested|** 154 | 155 | Same as cc but forces nesting. 156 | 157 | * `[count]c` **|NERDCommenterToggle|** 158 | 159 | Toggles the comment state of the selected line(s). If the topmost selected line is commented, all selected lines are uncommented and vice versa. 160 | 161 | * `[count]cm` **|NERDCommenterMinimal|** 162 | 163 | Comments the given lines using only one set of multipart delimiters. 164 | 165 | * `[count]ci` **|NERDCommenterInvert|** 166 | 167 | Toggles the comment state of the selected line(s) individually. 168 | 169 | * `[count]cs` **|NERDCommenterSexy|** 170 | 171 | Comments out the selected lines with a pretty block formatted layout. 172 | 173 | * `[count]cy` **|NERDCommenterYank|** 174 | 175 | Same as cc except that the commented line(s) are yanked first. 176 | 177 | * `c$` **|NERDCommenterToEOL|** 178 | 179 | Comments the current line from the cursor to the end of line. 180 | 181 | * `cA` **|NERDCommenterAppend|** 182 | 183 | Adds comment delimiters to the end of line and goes into insert mode between them. 184 | 185 | * **|NERDCommenterInsert|** 186 | 187 | Adds comment delimiters at the current cursor position and inserts between. Disabled by default. 188 | 189 | * `ca` **|NERDCommenterAltDelims|** 190 | 191 | Switches to the alternative set of delimiters. 192 | 193 | * `[count]cl` **|NERDCommenterAlignLeft** 194 | `[count]cb` **|NERDCommenterAlignBoth** 195 | 196 | Same as **|NERDCommenterComment|** except that the delimiters are aligned down the left side (`cl`) or both sides (`cb`). 197 | 198 | * `[count]cu` **|NERDCommenterUncomment|** 199 | 200 | Uncomments the selected line(s). 201 | 202 | ## Motions 203 | 204 | While the plugin does not directly support motions, you can leverage its support for selections to do something very similar. For example, to add motions to toggle comments on the paragraph text object you could use: 205 | ```vim 206 | nnoremap c} V}:call nerdcommenter#Comment('x', 'toggle') 207 | nnoremap c{ V{:call nerdcommenter#Comment('x', 'toggle') 208 | ``` 209 | 210 | ## Contributions 211 | 212 | This plugin was originally written in 2007 by [Martin Grenfell (@scrooloose)](https://github.com/scrooloose/). Lots of features and many of the supported filetypes have come from [community contributors](https://github.com/preservim/nerdcommenter/graphs/contributors). Since 2016 it has been maintained primarily by [Caleb Maclennan (@alerque)](https://github.com/alerque). Additional file type support, bug fixes, and new feature contributons are all welcome, please send them as Pull Requests on Github. If you can't contribute yourself please also feel free to open issues to report problems or request features. 213 | -------------------------------------------------------------------------------- /autoload/nerdcommenter.vim: -------------------------------------------------------------------------------- 1 | " Section: space string init 2 | " When putting spaces after the left delimiter and before the right we use 3 | " s:spaceStr for the space char. This way we can make it add anything after 4 | " the left and before the right by modifying this variable 5 | let s:spaceStr = ' ' 6 | let s:lenSpaceStr = strlen(s:spaceStr) 7 | 8 | let s:NERDFileNameEscape="[]#*$%'\" ?`!&();<>\\" 9 | 10 | let s:delimiterMap = { 11 | \ 'aap': { 'left': '#' }, 12 | \ 'abc': { 'left': '%' }, 13 | \ 'acedb': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 14 | \ 'actionscript': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 15 | \ 'ada': { 'left': '--', 'leftAlt': '-- ' }, 16 | \ 'ahdl': { 'left': '--' }, 17 | \ 'ahk': { 'left': ';', 'leftAlt': '/*', 'rightAlt': '*/' }, 18 | \ 'alloy': { 'left': '/*', 'right': '*/', 'leftAlt': '//' }, 19 | \ 'amiga': { 'left': ';' }, 20 | \ 'aml': { 'left': '/*' }, 21 | \ 'ampl': { 'left': '#' }, 22 | \ 'ansible': { 'left': '#' }, 23 | \ 'apache': { 'left': '#' }, 24 | \ 'apachestyle': { 'left': '#' }, 25 | \ 'apdl': { 'left': '!' }, 26 | \ 'applescript': { 'left': '--', 'leftAlt': '(*', 'rightAlt': '*)' }, 27 | \ 'aptconf': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 28 | \ 'armasm': { 'left': ';' }, 29 | \ 'asciidoc': { 'left': '//' }, 30 | \ 'asm': { 'left': ';', 'leftAlt': '#' }, 31 | \ 'asm68k': { 'left': ';' }, 32 | \ 'asn': { 'left': '--' }, 33 | \ 'asp': { 'left': '%', 'leftAlt': '%*', 'rightAlt': '*%' }, 34 | \ 'aspvbs': { 'left': '''', 'leftAlt': '' }, 35 | \ 'asterisk': { 'left': ';' }, 36 | \ 'asy': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 37 | \ 'atlas': { 'left': 'C', 'right': '$' }, 38 | \ 'ats': { 'left': '//', 'leftAlt': '(*', 'rightAlt': '*)' }, 39 | \ 'augeas': { 'left': '(*', 'right': '*)' }, 40 | \ 'autohotkey': { 'left': ';', 'leftAlt': '/*', 'rightAlt': '*/' }, 41 | \ 'autoit': { 'left': ';' }, 42 | \ 'ave': { 'left': "'" }, 43 | \ 'awk': { 'left': '#' }, 44 | \ 'basic': { 'left': "'", 'leftAlt': 'REM ' }, 45 | \ 'bbx': { 'left': '%' }, 46 | \ 'bc': { 'left': '#' }, 47 | \ 'bib': { 'left': '//' }, 48 | \ 'bindzone': { 'left': ';' }, 49 | \ 'bind-named': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 50 | \ 'blade': { 'left': '{{--', 'right': '--}}' }, 51 | \ 'bst': { 'left': '%' }, 52 | \ 'btm': { 'left': '::' }, 53 | \ 'c': { 'left': '/*', 'right': '*/', 'leftAlt': '//' }, 54 | \ 'cabal': { 'left': '--' }, 55 | \ 'cairo': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 56 | \ 'calibre': { 'left': '//' }, 57 | \ 'caos': { 'left': '*' }, 58 | \ 'catalog': { 'left': '--', 'right': '--' }, 59 | \ 'cel': { 'left': '//' }, 60 | \ 'cf': { 'left': '' }, 61 | \ 'cfg': { 'left': '#' }, 62 | \ 'cg': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 63 | \ 'ch': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 64 | \ 'cl': { 'left': '#' }, 65 | \ 'clean': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 66 | \ 'clipper': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 67 | \ 'clojure': { 'left': ';' }, 68 | \ 'cmake': { 'left': '#' }, 69 | \ 'cocci': { 'left': '//' }, 70 | \ 'coffee': { 'left': '#', 'leftAlt': '###', 'rightAlt': '###' }, 71 | \ 'conkyrc': { 'left': '#' }, 72 | \ 'context': { 'left': '%', 'leftAlt': '--' }, 73 | \ 'coq': { 'left': '(*', 'right': '*)' }, 74 | \ 'cpp': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 75 | \ 'crontab': { 'left': '#' }, 76 | \ 'cs': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 77 | \ 'csp': { 'left': '--' }, 78 | \ 'cterm': { 'left': '*' }, 79 | \ 'cucumber': { 'left': '#' }, 80 | \ 'cuda': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 81 | \ 'cvs': { 'left': 'CVS:' }, 82 | \ 'cypher': { 'left': '//' }, 83 | \ 'cython': { 'left': '# ', 'leftAlt': '#' }, 84 | \ 'd': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 85 | \ 'dakota': { 'left': '#' }, 86 | \ 'dart': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 87 | \ 'dcl': { 'left': '$!' }, 88 | \ 'debcontrol': { 'left': '#' }, 89 | \ 'debsources': { 'left': '#' }, 90 | \ 'def': { 'left': ';' }, 91 | \ 'desktop': { 'left': '#' }, 92 | \ 'dhcpd': { 'left': '#' }, 93 | \ 'diff': { 'left': '#' }, 94 | \ 'dts': { 'left': '/*', 'right': '*/', 'leftAlt': '//' }, 95 | \ 'django': { 'left': '{% comment %}', 'right': '{% endcomment %}', 'leftAlt': '{#', 'rightAlt': '#}' }, 96 | \ 'dns': { 'left': ';' }, 97 | \ 'docbk': { 'left': '' }, 98 | \ 'dockerfile': { 'left': '#' }, 99 | \ 'dosbatch': { 'left': 'REM ', 'nested': 1, 'leftAlt': 'REM ', 'nestedAlt': 1 }, 100 | \ 'dosini': { 'left': ';' }, 101 | \ 'dot': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 102 | \ 'dracula': { 'left': ';' }, 103 | \ 'dsl': { 'left': ';' }, 104 | \ 'dtml': { 'left': '', 'right': '' }, 105 | \ 'dylan': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 106 | \ 'ebuild': { 'left': '#' }, 107 | \ 'ecd': { 'left': '#' }, 108 | \ 'eclass': { 'left': '#' }, 109 | \ 'eiffel': { 'left': '--' }, 110 | \ 'elf': { 'left': "'" }, 111 | \ 'elixir': { 'left': '#' }, 112 | \ 'elm': { 'left': '--', 'leftAlt': '{--', 'rightAlt': '--}' }, 113 | \ 'elmfilt': { 'left': '#' }, 114 | \ 'ember-script': { 'left': '#' }, 115 | \ 'emblem': { 'left': '/' }, 116 | \ 'erlang': { 'left': '%', 'leftAlt': '%%' }, 117 | \ 'eruby': { 'left': '<%#', 'right': '%>', 'leftAlt': '' }, 118 | \ 'esmtprc': { 'left': '#' }, 119 | \ 'exim': { 'left': '#' }, 120 | \ 'expect': { 'left': '#' }, 121 | \ 'exports': { 'left': '#' }, 122 | \ 'factor': { 'left': '! ', 'leftAlt': '!# ' }, 123 | \ 'fancy': { 'left': '#' }, 124 | \ 'fasm': { 'left': ';' }, 125 | \ 'faust': { 'left': '//' }, 126 | \ 'fgl': { 'left': '#' }, 127 | \ 'fluent': { 'left': '#', 'leftAlt': '##' }, 128 | \ 'focexec': { 'left': '-*' }, 129 | \ 'form': { 'left': '*' }, 130 | \ 'fortran': { 'left': '!' }, 131 | \ 'foxpro': { 'left': '*' }, 132 | \ 'fsharp': { 'left': '(*', 'right': '*)', 'leftAlt': '//' }, 133 | \ 'fstab': { 'left': '#' }, 134 | \ 'fvwm': { 'left': '#' }, 135 | \ 'fx': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 136 | \ 'gams': { 'left': '*' }, 137 | \ 'gdb': { 'left': '#' }, 138 | \ 'gdmo': { 'left': '--' }, 139 | \ 'gdscript3': { 'left': '# ', 'leftAlt': '#' }, 140 | \ 'geek': { 'left': 'GEEK_COMMENT:' }, 141 | \ 'genshi': { 'left': '', 'leftAlt': '{#', 'rightAlt': '#}' }, 142 | \ 'gentoo-conf-d': { 'left': '#' }, 143 | \ 'gentoo-env-d': { 'left': '#' }, 144 | \ 'gentoo-init-d': { 'left': '#' }, 145 | \ 'gentoo-make-conf': { 'left': '#' }, 146 | \ 'gentoo-package-keywords': { 'left': '#' }, 147 | \ 'gentoo-package-mask': { 'left': '#' }, 148 | \ 'gentoo-package-use': { 'left': '#' }, 149 | \ 'gitcommit': { 'left': '#' }, 150 | \ 'gitconfig': { 'left': ';' }, 151 | \ 'gitignore': { 'left': '#' }, 152 | \ 'gitrebase': { 'left': '#' }, 153 | \ 'glsl': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 154 | \ 'gnuplot': { 'left': '#' }, 155 | \ 'go': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 156 | \ 'groff': { 'left': '\#' }, 157 | \ 'groovy': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 158 | \ 'gsp': { 'left': '<%--', 'right': '--%>', 'leftAlt': '' }, 159 | \ 'gtkrc': { 'left': '#' }, 160 | \ 'h': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 161 | \ 'haml': { 'left': '-#', 'leftAlt': '/' }, 162 | \ 'handlebars': { 'left': '{{!-- ', 'right': ' --}}' }, 163 | \ 'haskell': { 'left': '--', 'nested': 0, 'leftAlt': '{-', 'rightAlt': '-}', 'nestedAlt': 1 }, 164 | \ 'haxe': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 165 | \ 'hb': { 'left': '#' }, 166 | \ 'hbs': { 'left': '{{!-- ', 'right': ' --}}' }, 167 | \ 'hcl': { 'left': '#', 'leftAlt': '/*', 'rightAlt': '*/' }, 168 | \ 'hercules': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 169 | \ 'hive': { 'left': '-- ' }, 170 | \ 'hocon': { 'left': '//', 'leftAlt': '#' }, 171 | \ 'hog': { 'left': '#' }, 172 | \ 'hostsaccess': { 'left': '#' }, 173 | \ 'htmlcheetah': { 'left': '##' }, 174 | \ 'htmldjango': { 'left': '{% comment %}', 'right': '{% endcomment %}', 'leftAlt': '{#', 'rightAlt': '#}' }, 175 | \ 'htmlos': { 'left': '#', 'right': '/#' }, 176 | \ 'hxml': { 'left': '#' }, 177 | \ 'hyphy': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 178 | \ 'ia64': { 'left': '#' }, 179 | \ 'icon': { 'left': '#' }, 180 | \ 'idl': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 181 | \ 'idlang': { 'left': ';' }, 182 | \ 'idris': { 'leftAlt': '--', 'left': '{-', 'right': '-}' }, 183 | \ 'incar': { 'left': '!' }, 184 | \ 'inform': { 'left': '!' }, 185 | \ 'inittab': { 'left': '#' }, 186 | \ 'ishd': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 187 | \ 'iss': { 'left': ';' }, 188 | \ 'ist': { 'left': '%' }, 189 | \ 'jade': { 'left': '//-', 'leftAlt': '//' }, 190 | \ 'java': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 191 | \ 'javacc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 192 | \ 'javascript': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 193 | \ 'javascriptreact': { 'left': '//', 'leftAlt': '{/*', 'rightAlt': '*/}' }, 194 | \ 'javascript.jquery': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 195 | \ 'jess': { 'left': ';' }, 196 | \ 'jgraph': { 'left': '(*', 'right': '*)' }, 197 | \ 'jinja': { 'left': '{#', 'right': '#}', 'leftAlt': '' }, 198 | \ 'jproperties': { 'left': '#' }, 199 | \ 'jq': { 'left': '#' }, 200 | \ 'json5': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 201 | \ 'jsonc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 202 | \ 'jsonnet': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 203 | \ 'jsp': { 'left': '<%--', 'right': '--%>' }, 204 | \ 'julia': { 'left': '# ', 'leftAlt': '#=', 'rightAlt': '=#' }, 205 | \ 'just' : { 'left': '#' }, 206 | \ 'kivy': { 'left': '#' }, 207 | \ 'kix': { 'left': ';' }, 208 | \ 'kscript': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 209 | \ 'lace': { 'left': '--' }, 210 | \ 'laravel': { 'left': '{{--', 'right': '--}}' }, 211 | \ 'ldif': { 'left': '#' }, 212 | \ 'lean': { 'left': '--', 'leftAlt': '/-', 'rightAlt': '-/' }, 213 | \ 'ledger': { 'left': '#', 'leftAlt': ';' }, 214 | \ 'less': { 'left': '/*', 'right': '*/' }, 215 | \ 'lhaskell': { 'left': '>{-', 'right': '-}', 'leftAlt': '>-- ' }, 216 | \ 'lilo': { 'left': '#' }, 217 | \ 'lilypond': { 'left': '%' }, 218 | \ 'liquid': { 'left': '{% comment %}', 'right': '{% endcomment %}' }, 219 | \ 'lisp': { 'left': ';', 'nested': 1, 'leftAlt': '#|', 'rightAlt': '|#', 'nestedAlt': 1 }, 220 | \ 'llvm': { 'left': ';' }, 221 | \ 'lotos': { 'left': '(*', 'right': '*)' }, 222 | \ 'lout': { 'left': '#' }, 223 | \ 'lpc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 224 | \ 'lprolog': { 'left': '%' }, 225 | \ 'lscript': { 'left': "'" }, 226 | \ 'lss': { 'left': '#' }, 227 | \ 'lua': { 'left': '--', 'leftAlt': '--[[', 'rightAlt': ']]' }, 228 | \ 'lynx': { 'left': '#' }, 229 | \ 'lytex': { 'left': '%' }, 230 | \ 'm4': { 'left': 'dnl ' }, 231 | \ 'mail': { 'left': '> ' }, 232 | \ 'mako': { 'left': '##' }, 233 | \ 'man': { 'left': '."' }, 234 | \ 'mandoc': { 'left': '.\\"' }, 235 | \ 'map': { 'left': '%' }, 236 | \ 'maple': { 'left': '#' }, 237 | \ 'markdown': { 'left': '' }, 238 | \ 'masm': { 'left': ';' }, 239 | \ 'mason': { 'left': '<% #', 'right': '%>' }, 240 | \ 'master': { 'left': '$' }, 241 | \ 'matlab': { 'left': '%', 'leftAlt': '%{', 'rightAlt': '%}' }, 242 | \ 'mel': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 243 | \ 'meson': { 'left': '#' }, 244 | \ 'mib': { 'left': '--' }, 245 | \ 'minizinc': { 'left': '% ', 'leftAlt': '/*', 'rightAlt': '*/' }, 246 | \ 'mips': { 'left': '#' }, 247 | \ 'mirah': {'left': '#' }, 248 | \ 'mkd': { 'left': '' }, 249 | \ 'mma': { 'left': '(*', 'right': '*)' }, 250 | \ 'model': { 'left': '$', 'right': '$' }, 251 | \ 'modula2': { 'left': '(*', 'right': '*)' }, 252 | \ 'modula3': { 'left': '(*', 'right': '*)' }, 253 | \ 'molpro': { 'left': '!' }, 254 | \ 'monk': { 'left': ';' }, 255 | \ 'mush': { 'left': '#' }, 256 | \ 'mustache': { 'left': '{{!', 'right': '}}' }, 257 | \ 'nagios': { 'left': ';' }, 258 | \ 'named': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 259 | \ 'nasm': { 'left': ';' }, 260 | \ 'nastran': { 'left': '$' }, 261 | \ 'natural': { 'left': '/*' }, 262 | \ 'ncf': { 'left': ';' }, 263 | \ 'newlisp': { 'left': ';' }, 264 | \ 'nginx': { 'left': '#' }, 265 | \ 'nimrod': { 'left': '#' }, 266 | \ 'nix': { 'left': '#' }, 267 | \ 'nroff': { 'left': '\"' }, 268 | \ 'nsis': { 'left': '#' }, 269 | \ 'ntp': { 'left': '#' }, 270 | \ 'objc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 271 | \ 'objcpp': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 272 | \ 'objj': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 273 | \ 'ocaml': { 'left': '(*', 'right': '*)', 'nested': 1 }, 274 | \ 'occam': { 'left': '--' }, 275 | \ 'octave': { 'left': '%', 'leftAlt': '#' }, 276 | \ 'omlet': { 'left': '(*', 'right': '*)' }, 277 | \ 'omnimark': { 'left': ';' }, 278 | \ 'ooc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 279 | \ 'openroad': { 'left': '//' }, 280 | \ 'opl': { 'left': 'REM' }, 281 | \ 'ora': { 'left': '#' }, 282 | \ 'ox': { 'left': '//' }, 283 | \ 'paludis-use-conf': { 'left': '#' }, 284 | \ 'pandoc': { 'left': '' }, 285 | \ 'pamenv': { 'left': '#' }, 286 | \ 'pascal': { 'left': '{', 'right': '}', 'leftAlt': '(*', 'rightAlt': '*)' }, 287 | \ 'patran': { 'left': '$', 'leftAlt': '/*', 'rightAlt': '*/' }, 288 | \ 'pcap': { 'left': '#' }, 289 | \ 'pccts': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 290 | \ 'pdf': { 'left': '%' }, 291 | \ 'perl': { 'left': '#' }, 292 | \ 'pfmain': { 'left': '//' }, 293 | \ 'php': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 294 | \ 'pic': { 'left': ';' }, 295 | \ 'pike': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 296 | \ 'pilrc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 297 | \ 'pine': { 'left': '#' }, 298 | \ 'plm': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 299 | \ 'plsql': { 'left': '-- ', 'leftAlt': '/*', 'rightAlt': '*/' }, 300 | \ 'po': { 'left': '#' }, 301 | \ 'poscar': { 'left': '!' }, 302 | \ 'postscr': { 'left': '%' }, 303 | \ 'pov': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 304 | \ 'povini': { 'left': ';' }, 305 | \ 'ppd': { 'left': '%' }, 306 | \ 'ppwiz': { 'left': ';;' }, 307 | \ 'praat': { 'left': '#' }, 308 | \ 'privoxy': { 'left': '#' }, 309 | \ 'processing': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 310 | \ 'prolog': { 'left': '%', 'leftAlt': '/*', 'rightAlt': '*/' }, 311 | \ 'proto': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 312 | \ 'ps1': { 'left': '#' }, 313 | \ 'psf': { 'left': '#' }, 314 | \ 'ptcap': { 'left': '#' }, 315 | \ 'pug': { 'left': '//-', 'leftAlt': '//' }, 316 | \ 'puppet': { 'left': '#' }, 317 | \ 'pyrex': { 'left': '# ', 'leftAlt': '#' }, 318 | \ 'python': { 'left': '# ', 'leftAlt': '#' }, 319 | \ 'r': { 'left': '#', 'leftAlt': '#''' }, 320 | \ 'racket': { 'left': ';', 'nested': 1, 'leftAlt': '#|', 'rightAlt': '|#', 'nestedAlt': 1 }, 321 | \ 'radiance': { 'left': '#' }, 322 | \ 'ratpoison': { 'left': '#' }, 323 | \ 'rc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 324 | \ 'rebol': { 'left': ';' }, 325 | \ 'registry': { 'left': ';' }, 326 | \ 'rego': { 'left': '#' }, 327 | \ 'remind': { 'left': '#' }, 328 | \ 'renpy': { 'left': '# ' }, 329 | \ 'resolv': { 'left': '#' }, 330 | \ 'rgb': { 'left': '!' }, 331 | \ 'rib': { 'left': '#' }, 332 | \ 'rmd': { 'left': '', 'leftAlt': '#' }, 333 | \ 'robot': { 'left': '#' }, 334 | \ 'robots': { 'left': '#' }, 335 | \ 'rspec': { 'left': '#' }, 336 | \ 'ruby': { 'left': '#' }, 337 | \ 'rust': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 338 | \ 'sa': { 'left': '--' }, 339 | \ 'samba': { 'left': ';', 'leftAlt': '#' }, 340 | \ 'sass': { 'left': '//', 'leftAlt': '/*' }, 341 | \ 'sather': { 'left': '--' }, 342 | \ 'scala': { 'left': '//', 'nested': 1, 'leftAlt': '/*', 'rightAlt': '*/', 'nestedAlt': 1 }, 343 | \ 'scheme': { 'left': ';', 'nested': 1, 'leftAlt': '#|', 'rightAlt': '|#', 'nestedAlt': 1 }, 344 | \ 'scilab': { 'left': '//' }, 345 | \ 'scilla': { 'left': '(*', 'right': '*)', 'nested': 1 }, 346 | \ 'scons': { 'left': '#' }, 347 | \ 'scsh': { 'left': ';' }, 348 | \ 'scss': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 349 | \ 'sdc': { 'left': '#' }, 350 | \ 'sed': { 'left': '#' }, 351 | \ 'sentinel': { 'left': '#', 'leftAlt': '/*', 'rightAlt': '*/' }, 352 | \ 'sgmldecl': { 'left': '--', 'right': '--' }, 353 | \ 'sgmllnx': { 'left': '' }, 354 | \ 'sh': { 'left': '#' }, 355 | \ 'shader_test': { 'left': '#' }, 356 | \ 'sicad': { 'left': '*' }, 357 | \ 'sile': { 'left': '%', 'leftAlt': '--' }, 358 | \ 'simula': { 'left': '%', 'leftAlt': '--' }, 359 | \ 'sinda': { 'left': '$' }, 360 | \ 'skill': { 'left': ';' }, 361 | \ 'slang': { 'left': '%' }, 362 | \ 'slice': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 363 | \ 'slim': { 'left': '/', 'leftAlt': '/!' }, 364 | \ 'slrnrc': { 'left': '%' }, 365 | \ 'sls': { 'left': '#' }, 366 | \ 'sm': { 'left': '#' }, 367 | \ 'smarty': { 'left': '{*', 'right': '*}' }, 368 | \ 'smil': { 'left': '' }, 369 | \ 'smith': { 'left': ';' }, 370 | \ 'sml': { 'left': '(*', 'right': '*)', 'nested': 1 }, 371 | \ 'snakemake': { 'left': '#' }, 372 | \ 'snippets': { 'left': '#' }, 373 | \ 'snnsnet': { 'left': '#' }, 374 | \ 'snnspat': { 'left': '#' }, 375 | \ 'snnsres': { 'left': '#' }, 376 | \ 'snobol4': { 'left': '*' }, 377 | \ 'spec': { 'left': '#' }, 378 | \ 'specman': { 'left': '//' }, 379 | \ 'spectre': { 'left': '//', 'leftAlt': '*' }, 380 | \ 'spice': { 'left': '$' }, 381 | \ 'spin': { 'left': '''', 'leftAlt': '{', 'rightAlt': '}' }, 382 | \ 'sql': { 'left': '-- ', 'leftAlt': '/*', 'rightAlt': '*/' }, 383 | \ 'sqlforms': { 'left': '-- ' }, 384 | \ 'sqlj': { 'left': '-- ' }, 385 | \ 'sqr': { 'left': '!' }, 386 | \ 'squid': { 'left': '#' }, 387 | \ 'ss': { 'left': ';', 'leftAlt': '#|', 'rightAlt': '|#' }, 388 | \ 'sshconfig': { 'left': '#' }, 389 | \ 'sshdconfig': { 'left': '#' }, 390 | \ 'st': { 'left': '"' }, 391 | \ 'stan': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 392 | \ 'stp': { 'left': '/*', 'right': '*/', 'leftAlt': '//' }, 393 | \ 'supercollider': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 394 | \ 'svelte': { 'left': '' }, 395 | \ 'swift': { 'left': '/*', 'right': '*/', 'leftAlt': '//' }, 396 | \ 'systemverilog': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 397 | \ 'tads': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 398 | \ 'tags': { 'left': ';' }, 399 | \ 'tak': { 'left': '$' }, 400 | \ 'tasm': { 'left': ';' }, 401 | \ 'tcl': { 'left': '#' }, 402 | \ 'teak': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 403 | \ 'terraform': { 'left': '#', 'leftAlt': '/*', 'rightAlt': '*/' }, 404 | \ 'tex': { 'left': '%' }, 405 | \ 'texinfo': { 'left': '@c ' }, 406 | \ 'texmf': { 'left': '%' }, 407 | \ 'tf': { 'left': '#' }, 408 | \ 'tidy': { 'left': '#' }, 409 | \ 'tjp': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 410 | \ 'tla': { 'left': '\\*', 'leftAlt': '(*', 'rightAlt': '*)' }, 411 | \ 'tli': { 'left': '#' }, 412 | \ 'tmux': { 'left': '#' }, 413 | \ 'toml': { 'left': '#' }, 414 | \ 'trasys': { 'left': '$' }, 415 | \ 'troff': { 'left': '.\\"' }, 416 | \ 'tsalt': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 417 | \ 'tsscl': { 'left': '#' }, 418 | \ 'tssgm': { 'left': "comment = '", 'right': "'" }, 419 | \ 'ttl': { 'left': '#' }, 420 | \ 'tup': { 'left': '#' }, 421 | \ 'twig': { 'left': '{#', 'right': '#}' }, 422 | \ 'txt2tags': { 'left': '%' }, 423 | \ 'typescript': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 424 | \ 'typescriptreact': { 'left': '//', 'leftAlt': '{/*', 'rightAlt': '*/}' }, 425 | \ 'typst': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 426 | \ 'uc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 427 | \ 'uc4': { 'left': '!' }, 428 | \ 'uil': { 'left': '!' }, 429 | \ 'upstart': { 'left': '#' }, 430 | \ 'vala': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 431 | \ 'vasp': { 'left': '!' }, 432 | \ 'vb': { 'left': "'" }, 433 | \ 'vcl': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 434 | \ 'velocity': { 'left': '##', 'right': '', 'leftAlt': '#*', 'rightAlt': '*#' }, 435 | \ 'vera': { 'left': '/*', 'right': '*/', 'leftAlt': '//' }, 436 | \ 'verilog': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 437 | \ 'verilog_systemverilog': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, 438 | \ 'vgrindefs': { 'left': '#' }, 439 | \ 'vhdl': { 'left': '--' }, 440 | \ 'vimperator': { 'left': '"' }, 441 | \ 'virata': { 'left': '%' }, 442 | \ 'vrml': { 'left': '#' }, 443 | \ 'vsejcl': { 'left': '/*' }, 444 | \ 'webmacro': { 'left': '##' }, 445 | \ 'wget': { 'left': '#' }, 446 | \ 'wikipedia': { 'left': '' }, 447 | \ 'winbatch': { 'left': ';' }, 448 | \ 'wml': { 'left': '#' }, 449 | \ 'wvdial': { 'left': ';' }, 450 | \ 'xdefaults': { 'left': '!' }, 451 | \ 'xkb': { 'left': '//' }, 452 | \ 'xmath': { 'left': '#' }, 453 | \ 'xpm2': { 'left': '!' }, 454 | \ 'xquery': { 'left': '(:', 'right': ':)' }, 455 | \ 'yaml': { 'left': '#' }, 456 | \ 'z8a': { 'left': ';' }, 457 | \ 'zig': { 'left': '//' } 458 | \ } 459 | 460 | let g:NERDDelimiterMap = s:delimiterMap 461 | let nerdcommenter#delimiterMap = s:delimiterMap 462 | 463 | if exists('g:NERDCustomDelimiters') 464 | call extend(s:delimiterMap, g:NERDCustomDelimiters) 465 | endif 466 | 467 | " Section: Comment mapping functions, autocommands and commands 468 | " ============================================================================ 469 | 470 | " Function: nerdcommenter#SetUp() function 471 | " This function is responsible for setting up buffer scoped variables for the 472 | " current buffer. 473 | function! nerdcommenter#SetUp() abort 474 | let filetype = &filetype 475 | 476 | "for compound filetypes, if we don't know how to handle the full filetype 477 | "then break it down and use the first part that we know how to handle 478 | if filetype =~# '\.' && !has_key(s:delimiterMap, filetype) 479 | let filetypes = split(filetype, '\.') 480 | for i in filetypes 481 | if has_key(s:delimiterMap, i) 482 | let filetype = i 483 | break 484 | endif 485 | endfor 486 | endif 487 | 488 | let b:NERDSexyComMarker = '' 489 | 490 | if has_key(s:delimiterMap, filetype) 491 | let b:NERDCommenterDelims = copy(s:delimiterMap[filetype]) 492 | for i in ['left', 'leftAlt', 'right', 'rightAlt'] 493 | if !has_key(b:NERDCommenterDelims, i) 494 | let b:NERDCommenterDelims[i] = '' 495 | endif 496 | endfor 497 | for i in ['nested', 'nestedAlt'] 498 | if !has_key(b:NERDCommenterDelims, i) 499 | let b:NERDCommenterDelims[i] = 0 500 | endif 501 | endfor 502 | " if g:NERD__alt_style is defined, use the alternate style 503 | let b:NERDCommenterFirstInit = getbufvar(bufnr('%'),'NERDCommenterFirstInit') 504 | if exists('g:NERDAltDelims_'.filetype) && eval('g:NERDAltDelims_'.filetype) && !b:NERDCommenterFirstInit 505 | let b:NERDCommenterFirstInit = 1 506 | call nerdcommenter#SwitchToAlternativeDelimiters(0) 507 | endif 508 | else 509 | let b:NERDCommenterDelims = s:CreateDelimMapFromCms() 510 | endif 511 | 512 | endfunction 513 | 514 | function! s:CreateDelimMapFromCms() abort 515 | if &filetype ==# '' && exists('g:NERDDefaultDelims') 516 | let delims = g:NERDDefaultDelims 517 | for i in ['left', 'leftAlt', 'right', 'rightAlt'] 518 | if !has_key(delims, i) 519 | let delims[i] = '' 520 | endif 521 | endfor 522 | return delims 523 | endif 524 | return { 525 | \ 'left': matchstr(&commentstring, '^\S*\ze\s*%s'), 526 | \ 'right': matchstr(&commentstring, '%s\s*\zs.*$'), 527 | \ 'nested': 0, 528 | \ 'leftAlt': '', 529 | \ 'rightAlt': '', 530 | \ 'nestedAlt': 0} 531 | endfunction 532 | 533 | " Function: nerdcommenter#SwitchToAlternativeDelimiters(printMsgs) function 534 | " This function is used to swap the delimiters that are being used to the 535 | " alternative delimiters for that filetype. For example, if a c++ file is 536 | " being edited and // comments are being used, after this function is called 537 | " /**/ comments will be used. 538 | " 539 | " Args: 540 | " -printMsgs: if this is 1 then a message is echoed to the user telling them 541 | " if this function changed the delimiters or not 542 | " function nerdcommenter#SwitchToAlternativeDelimiters(printMsgs) 543 | function! nerdcommenter#SwitchToAlternativeDelimiters(printMsgs) abort 544 | if exists('*NERDCommenter_before') 545 | exe 'call NERDCommenter_before()' 546 | endif 547 | call nerdcommenter#SetUp() 548 | "if both of the alternative delimiters are empty then there is no 549 | "alternative comment style so bail out 550 | if b:NERDCommenterDelims['leftAlt'] ==# '' && b:NERDCommenterDelims['rightAlt'] ==# '' 551 | if a:printMsgs 552 | call s:NerdEcho('Cannot use alternative delimiters, none are specified', 0) 553 | endif 554 | return 0 555 | endif 556 | 557 | "save the current delimiters 558 | let tempLeft = s:Left() 559 | let tempRight = s:Right() 560 | let tempNested = s:Nested() 561 | 562 | "swap current delimiters for alternative 563 | let b:NERDCommenterDelims['left'] = b:NERDCommenterDelims['leftAlt'] 564 | let b:NERDCommenterDelims['right'] = b:NERDCommenterDelims['rightAlt'] 565 | "set information on whether these are nested 566 | let b:NERDCommenterDelims['nested'] = b:NERDCommenterDelims['nestedAlt'] 567 | 568 | "set the previously current delimiters to be the new alternative ones 569 | let b:NERDCommenterDelims['leftAlt'] = tempLeft 570 | let b:NERDCommenterDelims['rightAlt'] = tempRight 571 | let b:NERDCommenterDelims['nestedAlt'] = tempNested 572 | 573 | "tell the user what comment delimiters they are now using 574 | if a:printMsgs 575 | call s:NerdEcho('Now using ' . s:Left() . ' ' . s:Right() . ' to delimit comments', 1) 576 | endif 577 | 578 | if exists('*NERDCommenter_after') 579 | exe 'call NERDCommenter_after()' 580 | endif 581 | 582 | return 1 583 | endfunction 584 | 585 | " Section: Comment delimiter add/removal functions 586 | " ============================================================================ 587 | " Function: s:AppendCommentToLine() 588 | " This function appends comment delimiters at the EOL and places the cursor in 589 | " position to start typing the comment 590 | function! s:AppendCommentToLine() abort 591 | let left = s:Left({'space': 1}) 592 | let right = s:Right({'space': 1}) 593 | 594 | " get the length of the right delimiter 595 | let lenRight = strlen(right) 596 | 597 | let isLineEmpty = strlen(getline('.')) ==# 0 598 | let insOrApp = (isLineEmpty==#1 ? 'i' : 'A') 599 | 600 | "stick the delimiters down at the end of the line. We have to format the 601 | "comment with spaces as appropriate 602 | execute ':normal! ' . insOrApp . (isLineEmpty ? '' : ' ') . left . right 603 | 604 | " if there is a right delimiter then we gotta move the cursor left 605 | " by the length of the right delimiter so we insert between the delimiters 606 | if lenRight > 0 607 | let leftMoveAmount = lenRight - 1 608 | execute ':normal! ' . leftMoveAmount . 'h' 609 | startinsert 610 | else 611 | startinsert! 612 | endif 613 | endfunction 614 | 615 | " Function: s:CommentBlock(top, bottom, lSide, rSide, forceNested ) 616 | " This function is used to comment out a region of code. This region is 617 | " specified as a bounding box by arguments to the function. 618 | " 619 | " Args: 620 | " -top: the line number for the top line of code in the region 621 | " -bottom: the line number for the bottom line of code in the region 622 | " -lSide: the column number for the left most column in the region 623 | " -rSide: the column number for the right most column in the region 624 | " -forceNested: a flag indicating whether comments should be nested 625 | function! s:CommentBlock(top, bottom, lSide, rSide, forceNested) abort 626 | " we need to create local copies of these arguments so we can modify them 627 | let top = a:top 628 | let bottom = a:bottom 629 | let lSide = a:lSide 630 | let rSide = a:rSide 631 | 632 | "if the top or bottom line starts with tabs we have to adjust the left and 633 | "right boundaries so that they are set as though the tabs were spaces 634 | let topline = getline(top) 635 | let bottomline = getline(bottom) 636 | if s:HasLeadingTabs(topline, bottomline) 637 | 638 | "find out how many tabs are in the top line and adjust the left 639 | "boundary accordingly 640 | let numTabs = s:NumberOfLeadingTabs(topline) 641 | if lSide < numTabs 642 | let lSide = &tabstop * lSide 643 | else 644 | let lSide = (lSide - numTabs) + (&tabstop * numTabs) 645 | endif 646 | 647 | "find out how many tabs are in the bottom line and adjust the right 648 | "boundary accordingly 649 | let numTabs = s:NumberOfLeadingTabs(bottomline) 650 | let rSide = (rSide - numTabs) + (&tabstop * numTabs) 651 | endif 652 | 653 | "we must check that bottom IS actually below top, if it is not then we 654 | "swap top and bottom. Similarly for left and right. 655 | if bottom < top 656 | let temp = top 657 | let top = bottom 658 | let bottom = top 659 | endif 660 | if rSide < lSide 661 | let temp = lSide 662 | let lSide = rSide 663 | let rSide = temp 664 | endif 665 | 666 | "if the current delimiters aren't multipart then we will switch to the 667 | "alternative delimiters (if THEY are) as the comment will be better and more 668 | "accurate with multipart delimiters 669 | let switchedDelims = 0 670 | if !s:Multipart() && g:NERDAllowAnyVisualDelims && s:AltMultipart() 671 | let switchedDelims = 1 672 | call nerdcommenter#SwitchToAlternativeDelimiters(0) 673 | endif 674 | 675 | "start the commenting from the top and keep commenting till we reach the 676 | "bottom 677 | let currentLine=top 678 | while currentLine <= bottom 679 | 680 | "check if we are allowed to comment this line 681 | if s:CanCommentLine(a:forceNested, currentLine) 682 | 683 | "convert the leading tabs into spaces 684 | let theLine = getline(currentLine) 685 | let lineHasLeadTabs = s:HasLeadingTabs(theLine) 686 | if lineHasLeadTabs 687 | let theLine = s:ConvertLeadingTabsToSpaces(theLine) 688 | endif 689 | 690 | "don't comment lines that begin after the right boundary of the 691 | "block unless the user has specified to do so 692 | if theLine !~# '^ \{' . rSide . '\}' || !g:NERDBlockComIgnoreEmpty 693 | 694 | "attempt to place the cursor in on the left of the boundary box, 695 | "then check if we were successful, if not then we cant comment this 696 | "line 697 | call setline(currentLine, theLine) 698 | if s:CanPlaceCursor(currentLine, lSide) 699 | 700 | let leftSpaced = s:Left({'space': 1}) 701 | let rightSpaced = s:Right({'space': 1}) 702 | 703 | "stick the left delimiter down 704 | let theLine = strpart(theLine, 0, lSide-1) . leftSpaced . strpart(theLine, lSide-1) 705 | 706 | if s:Multipart() 707 | "stick the right delimiter down 708 | "byte idx of the char next to the last char = (byte idx of last char + 1) + (last char byte len) - 1 709 | let rIndex = (rSide+strlen(leftSpaced)) + strlen(strcharpart(strpart(theLine, rSide+strlen(leftSpaced)-1), 0, 1)) - 1 710 | let theLine = strpart(theLine, 0, rIndex) . rightSpaced . strpart(theLine, rIndex) 711 | 712 | let firstLeftDelim = s:FindDelimiterIndex(s:Left(), theLine) 713 | let lastRightDelim = s:LastIndexOfDelim(s:Right(), theLine) 714 | 715 | if firstLeftDelim !=# -1 && lastRightDelim !=# -1 716 | let searchStr = strpart(theLine, 0, lastRightDelim) 717 | let searchStr = strpart(searchStr, firstLeftDelim+strlen(s:Left())) 718 | 719 | "replace the outer most delimiters in searchStr with 720 | "place-holders 721 | let theLineWithPlaceHolders = s:ReplaceDelims(s:Left(), s:Right(), g:NERDLPlace, g:NERDRPlace, searchStr) 722 | 723 | "add the right delimiter onto the line 724 | let theLine = strpart(theLine, 0, firstLeftDelim+strlen(s:Left())) . theLineWithPlaceHolders . strpart(theLine, lastRightDelim) 725 | endif 726 | endif 727 | endif 728 | endif 729 | 730 | "restore tabs if needed 731 | if lineHasLeadTabs 732 | let theLine = s:ConvertLeadingSpacesToTabs(theLine) 733 | endif 734 | 735 | if g:NERDTrimTrailingWhitespace ==# 1 736 | let theLine = s:TrimTrailingWhitespace(theLine) 737 | endif 738 | 739 | call setline(currentLine, theLine) 740 | endif 741 | 742 | let currentLine = currentLine + 1 743 | endwhile 744 | 745 | "if we switched delimiterss then we gotta go back to what they were before 746 | if switchedDelims ==# 1 747 | call nerdcommenter#SwitchToAlternativeDelimiters(0) 748 | endif 749 | endfunction 750 | 751 | " Function: s:CommentLines(forceNested, alignLeft, alignRight, firstLine, lastLine) 752 | " This function comments a range of lines. 753 | " 754 | " Args: 755 | " -forceNested: a flag indicating whether the called is requesting the comment 756 | " to be nested if need be 757 | " -align: should be "left", "start", "both" or "none" 758 | " -firstLine/lastLine: the top and bottom lines to comment 759 | function! s:CommentLines(forceNested, align, firstLine, lastLine) abort 760 | " we need to get the left and right indexes of the leftmost char in the 761 | " block of of lines and the right most char so that we can do alignment of 762 | " the delimiters if the user has specified 763 | let leftAlignIndx = a:align ==# 'start' ? 0 : s:LeftMostIndx(a:forceNested, 0, a:firstLine, a:lastLine) 764 | let rightAlignIndx = s:RightMostIndx(a:forceNested, 0, a:firstLine, a:lastLine) 765 | 766 | " gotta add the length of the left delimiter onto the rightAlignIndx cos 767 | " we'll be adding a left delimiter to the line 768 | let rightAlignIndx = rightAlignIndx + strlen(s:Left({'space': 1})) 769 | 770 | " now we actually comment the lines. Do it line by line 771 | let currentLine = a:firstLine 772 | while currentLine <= a:lastLine 773 | 774 | " get the next line, check commentability and convert spaces to tabs 775 | let theLine = getline(currentLine) 776 | let lineHasLeadingTabs = s:HasLeadingTabs(theLine) 777 | let theLine = s:ConvertLeadingTabsToSpaces(theLine) 778 | if s:CanCommentLine(a:forceNested, currentLine) 779 | "if the user has specified forceNesting then we check to see if we 780 | "need to switch delimiters for place-holders 781 | if a:forceNested && g:NERDUsePlaceHolders && !s:Nested() 782 | let theLine = s:SwapOuterMultiPartDelimsForPlaceHolders(theLine) 783 | endif 784 | 785 | " find out if the line is commented using normal delimiters and/or 786 | " alternate ones 787 | let isCommented = s:IsCommented(s:Left(), s:Right(), theLine) || s:IsCommented(s:Left({'alt': 1}), s:Right({'alt': 1}), theLine) 788 | 789 | " check if we can comment this line 790 | if !isCommented || g:NERDUsePlaceHolders || s:Multipart() 791 | if a:align ==# 'left' || a:align ==# 'start' || a:align ==# 'both' 792 | let theLine = s:AddLeftDelimAligned(s:Left({'space': 1}), theLine, leftAlignIndx) 793 | else 794 | let theLine = s:AddLeftDelim(s:Left({'space': 1}), theLine) 795 | endif 796 | if a:align ==# 'both' 797 | let theLine = s:AddRightDelimAligned(s:Right({'space': 1}), theLine, rightAlignIndx) 798 | else 799 | let theLine = s:AddRightDelim(s:Right({'space': 1}), theLine) 800 | endif 801 | endif 802 | endif 803 | 804 | " restore leading tabs if appropriate 805 | if lineHasLeadingTabs 806 | let theLine = s:ConvertLeadingSpacesToTabs(theLine) 807 | endif 808 | 809 | if g:NERDTrimTrailingWhitespace ==# 1 810 | let theLine = s:TrimTrailingWhitespace(theLine) 811 | endif 812 | 813 | " we are done with this line 814 | call setline(currentLine, theLine) 815 | let currentLine = currentLine + 1 816 | endwhile 817 | 818 | endfunction 819 | 820 | " Function: s:CommentLinesMinimal(firstLine, lastLine) 821 | " This function comments a range of lines in a minimal style. I 822 | " 823 | " Args: 824 | " -firstLine/lastLine: the top and bottom lines to comment 825 | function! s:CommentLinesMinimal(firstLine, lastLine) abort 826 | "check that minimal comments can be done on this filetype 827 | if !s:HasMultipartDelims() 828 | throw 'NERDCommenter.Delimiters exception: Minimal comments can only be used for filetypes that have multipart delimiters' 829 | endif 830 | 831 | let sexyNested = s:SexyNested() 832 | 833 | "if we need to use place holders for the comment, make sure they are 834 | "enabled for this filetype, or the delimiterss allow nesting 835 | if !g:NERDUsePlaceHolders && !sexyNested && s:DoesBlockHaveMultipartDelim(a:firstLine, a:lastLine) 836 | throw 'NERDCommenter.Settings exception: Place holders are required but disabled.' 837 | endif 838 | 839 | "get the left and right delimiters to smack on 840 | let left = s:GetSexyComLeft(g:NERDSpaceDelims,0) 841 | let right = s:GetSexyComRight(g:NERDSpaceDelims,0) 842 | 843 | "make sure all multipart delimiters on the lines are replaced with 844 | "placeholders to prevent illegal syntax 845 | if !sexyNested 846 | let currentLine = a:firstLine 847 | while(currentLine <= a:lastLine) 848 | let theLine = getline(currentLine) 849 | let theLine = s:ReplaceDelims(left, right, g:NERDLPlace, g:NERDRPlace, theLine) 850 | call setline(currentLine, theLine) 851 | let currentLine = currentLine + 1 852 | endwhile 853 | endif 854 | 855 | "add the delimiter to the top line 856 | let theLine = getline(a:firstLine) 857 | let lineHasLeadingTabs = s:HasLeadingTabs(theLine) 858 | let theLine = s:ConvertLeadingTabsToSpaces(theLine) 859 | let theLine = s:AddLeftDelim(left, theLine) 860 | if lineHasLeadingTabs 861 | let theLine = s:ConvertLeadingSpacesToTabs(theLine) 862 | endif 863 | call setline(a:firstLine, theLine) 864 | 865 | "add the delimiter to the bottom line 866 | let theLine = getline(a:lastLine) 867 | let lineHasLeadingTabs = s:HasLeadingTabs(theLine) 868 | let theLine = s:ConvertLeadingTabsToSpaces(theLine) 869 | let theLine = s:AddRightDelim(right, theLine) 870 | if lineHasLeadingTabs 871 | let theLine = s:ConvertLeadingSpacesToTabs(theLine) 872 | endif 873 | 874 | if g:NERDTrimTrailingWhitespace ==# 1 875 | let theLine = s:TrimTrailingWhitespace(theLine) 876 | endif 877 | 878 | call setline(a:lastLine, theLine) 879 | endfunction 880 | 881 | " Function: s:CommentLinesSexy(topline, bottomline) function 882 | " This function is used to comment lines in the 'Sexy' style. E.g., in c: 883 | " /* 884 | " * This is a sexy comment 885 | " */ 886 | " Args: 887 | " -topline: the line number of the top line in the sexy comment 888 | " -bottomline: the line number of the bottom line in the sexy comment 889 | function! s:CommentLinesSexy(topline, bottomline) abort 890 | let left = s:GetSexyComLeft(0, 0) 891 | let right = s:GetSexyComRight(0, 0) 892 | 893 | "check if we can do a sexy comment with the available delimiters 894 | if left ==# -1 || right ==# -1 895 | throw 'NERDCommenter.Delimiters exception: cannot perform sexy comments with available delimiters.' 896 | endif 897 | 898 | "make sure the lines aren't already commented sexually or we can nest 899 | if !s:CanSexyCommentLines(a:topline, a:bottomline) 900 | throw 'NERDCommenter.Nesting exception: cannot nest sexy comments' 901 | endif 902 | 903 | 904 | let sexyComMarker = s:GetSexyComMarker(0,0) 905 | let sexyComMarkerSpaced = s:GetSexyComMarker(1,0) 906 | 907 | 908 | " we jam the comment as far to the right as possible 909 | let leftAlignIndx = s:LeftMostIndx(1, 1, a:topline, a:bottomline) 910 | 911 | "check if we should use the compact style i.e that the left/right 912 | "delimiters should appear on the first and last lines of the code and not 913 | "on separate lines above/below the first/last lines of code 914 | if g:NERDCompactSexyComs 915 | let spaceString = (g:NERDSpaceDelims ? s:spaceStr : '') 916 | 917 | "comment the top line 918 | let theLine = getline(a:topline) 919 | let lineHasTabs = s:HasLeadingTabs(theLine) 920 | if lineHasTabs 921 | let theLine = s:ConvertLeadingTabsToSpaces(theLine) 922 | endif 923 | if !s:SexyNested() 924 | let theLine = s:SwapOuterMultiPartDelimsForPlaceHolders(theLine) 925 | endif 926 | let theLine = s:AddLeftDelimAligned(left . spaceString, theLine, leftAlignIndx) 927 | if lineHasTabs 928 | let theLine = s:ConvertLeadingSpacesToTabs(theLine) 929 | endif 930 | call setline(a:topline, theLine) 931 | 932 | "comment the bottom line 933 | if a:bottomline !=# a:topline 934 | let theLine = getline(a:bottomline) 935 | let lineHasTabs = s:HasLeadingTabs(theLine) 936 | if lineHasTabs 937 | let theLine = s:ConvertLeadingTabsToSpaces(theLine) 938 | endif 939 | if !s:SexyNested() 940 | let theLine = s:SwapOuterMultiPartDelimsForPlaceHolders(theLine) 941 | endif 942 | endif 943 | let theLine = s:AddRightDelim(spaceString . right, theLine) 944 | if lineHasTabs 945 | let theLine = s:ConvertLeadingSpacesToTabs(theLine) 946 | endif 947 | call setline(a:bottomline, theLine) 948 | else 949 | 950 | " add the left delimiter one line above the lines that are to be commented 951 | call cursor(a:topline, 1) 952 | execute 'normal! O' 953 | let theLine = repeat(' ', leftAlignIndx) . left 954 | 955 | " Make sure tabs are respected 956 | if !&expandtab 957 | let theLine = s:ConvertLeadingSpacesToTabs(theLine) 958 | endif 959 | call setline(a:topline, theLine) 960 | 961 | " add the right delimiter after bottom line (we have to add 1 cos we moved 962 | " the lines down when we added the left delimiter 963 | call cursor(a:bottomline+1, 1) 964 | execute 'normal! o' 965 | if g:NERDDisableTabsInBlockComm 966 | let theLine = repeat(' ', leftAlignIndx) . right 967 | else 968 | let theLine = repeat(' ', leftAlignIndx) . repeat(' ', strlen(left)-strlen(sexyComMarker)) . right 969 | endif 970 | 971 | " Make sure tabs are respected 972 | if !&expandtab 973 | let theLine = s:ConvertLeadingSpacesToTabs(theLine) 974 | endif 975 | call setline(a:bottomline+2, theLine) 976 | 977 | endif 978 | 979 | " go thru each line adding the sexyComMarker marker to the start of each 980 | " line in the appropriate place to align them with the comment delimiters 981 | let currentLine = a:topline+1 982 | while currentLine <= a:bottomline + !g:NERDCompactSexyComs 983 | " get the line and convert the tabs to spaces 984 | let theLine = getline(currentLine) 985 | let lineHasTabs = s:HasLeadingTabs(theLine) 986 | if lineHasTabs 987 | let theLine = s:ConvertLeadingTabsToSpaces(theLine) 988 | endif 989 | 990 | if !s:SexyNested() 991 | let theLine = s:SwapOuterMultiPartDelimsForPlaceHolders(theLine) 992 | endif 993 | 994 | " add the sexyComMarker 995 | if g:NERDDisableTabsInBlockComm 996 | let theLine = repeat(' ', leftAlignIndx) . sexyComMarkerSpaced . strpart(theLine, leftAlignIndx) 997 | else 998 | let theLine = repeat(' ', leftAlignIndx) . repeat(' ', strlen(left)-strlen(sexyComMarker)) . sexyComMarkerSpaced . strpart(theLine, leftAlignIndx) 999 | endif 1000 | 1001 | if lineHasTabs 1002 | let theLine = s:ConvertLeadingSpacesToTabs(theLine) 1003 | endif 1004 | 1005 | if g:NERDTrimTrailingWhitespace ==# 1 1006 | let theLine = s:TrimTrailingWhitespace(theLine) 1007 | endif 1008 | 1009 | " set the line and move onto the next one 1010 | call setline(currentLine, theLine) 1011 | let currentLine = currentLine + 1 1012 | endwhile 1013 | 1014 | endfunction 1015 | 1016 | " Function: s:CommentLinesToggle(forceNested, firstLine, lastLine) 1017 | " Applies "toggle" commenting to the given range of lines 1018 | " 1019 | " Args: 1020 | " -forceNested: a flag indicating whether the called is requesting the comment 1021 | " to be nested if need be 1022 | " -firstLine/lastLine: the top and bottom lines to comment 1023 | function! s:CommentLinesToggle(forceNested, firstLine, lastLine) abort 1024 | let currentLine = a:firstLine 1025 | 1026 | let align = g:NERDDefaultAlign 1027 | let leftAlignIndx = align ==# 'start' ? 0 : s:LeftMostIndx(a:forceNested, 0, a:firstLine, a:lastLine) 1028 | let rightAlignIndx = s:RightMostIndx(a:forceNested, 0, a:firstLine, a:lastLine) 1029 | let rightAlignIndx = rightAlignIndx + strlen(s:Left({'space': 1})) 1030 | 1031 | while currentLine <= a:lastLine 1032 | 1033 | " get the next line, check commentability and convert spaces to tabs 1034 | let theLine = getline(currentLine) 1035 | let lineHasLeadingTabs = s:HasLeadingTabs(theLine) 1036 | let theLine = s:ConvertLeadingTabsToSpaces(theLine) 1037 | if s:CanToggleCommentLine(a:forceNested, currentLine) 1038 | 1039 | "if the user has specified forceNesting then we check to see if we 1040 | "need to switch delimiters for place-holders 1041 | if g:NERDUsePlaceHolders && !s:Nested() 1042 | let theLine = s:SwapOuterMultiPartDelimsForPlaceHolders(theLine) 1043 | endif 1044 | 1045 | if align ==# 'left' || align ==# 'start' || align ==# 'both' 1046 | let theLine = s:AddLeftDelimAligned(s:Left({'space': 1}), theLine, leftAlignIndx) 1047 | else 1048 | let theLine = s:AddLeftDelim(s:Left({'space': 1}), theLine) 1049 | endif 1050 | if align ==# 'both' 1051 | let theLine = s:AddRightDelimAligned(s:Right({'space': 1}), theLine, rightAlignIndx) 1052 | else 1053 | let theLine = s:AddRightDelim(s:Right({'space': 1}), theLine) 1054 | endif 1055 | endif 1056 | 1057 | " restore leading tabs if appropriate 1058 | if lineHasLeadingTabs 1059 | let theLine = s:ConvertLeadingSpacesToTabs(theLine) 1060 | endif 1061 | 1062 | if g:NERDTrimTrailingWhitespace ==# 1 1063 | let theLine = s:TrimTrailingWhitespace(theLine) 1064 | endif 1065 | 1066 | " we are done with this line 1067 | call setline(currentLine, theLine) 1068 | let currentLine = currentLine + 1 1069 | endwhile 1070 | 1071 | endfunction 1072 | 1073 | " Function: s:CommentRegion(topline, topCol, bottomLine, bottomCol) function 1074 | " This function comments chunks of text selected in visual mode. 1075 | " It will comment exactly the text that they have selected. 1076 | " Args: 1077 | " -topLine: the line number of the top line in the sexy comment 1078 | " -topCol: top left column for this comment 1079 | " -bottomline: the line number of the bottom line in the sexy comment 1080 | " -bottomCol: the bottom right column for this comment 1081 | " -forceNested: whether the caller wants comments to be nested if the 1082 | " line(s) are already commented 1083 | function! s:CommentRegion(topLine, topCol, bottomLine, bottomCol, forceNested) abort 1084 | 1085 | "switch delimiters (if we can) if the current set isn't multipart 1086 | let switchedDelims = 0 1087 | if !s:Multipart() && s:AltMultipart() && g:NERDAllowAnyVisualDelims 1088 | let switchedDelims = 1 1089 | call nerdcommenter#SwitchToAlternativeDelimiters(0) 1090 | endif 1091 | 1092 | "if there is only one line in the comment then just do it 1093 | if a:topLine ==# a:bottomLine 1094 | call s:CommentBlock(a:topLine, a:bottomLine, a:topCol, a:bottomCol, a:forceNested) 1095 | 1096 | "there are multiple lines in the comment 1097 | else 1098 | "comment the top line 1099 | call s:CommentBlock(a:topLine, a:topLine, a:topCol, strlen(getline(a:topLine)), a:forceNested) 1100 | 1101 | "comment out all the lines in the middle of the comment 1102 | let topOfRange = a:topLine+1 1103 | let bottomOfRange = a:bottomLine-1 1104 | if topOfRange <= bottomOfRange 1105 | call s:CommentLines(a:forceNested, g:NERDDefaultAlign, topOfRange, bottomOfRange) 1106 | endif 1107 | 1108 | "comment the bottom line 1109 | let bottom = getline(a:bottomLine) 1110 | let numLeadingSpacesTabs = strlen(matchstr(bottom, '^\s*')) 1111 | call s:CommentBlock(a:bottomLine, a:bottomLine, numLeadingSpacesTabs+1, a:bottomCol, a:forceNested) 1112 | 1113 | endif 1114 | 1115 | "stick the cursor back on the char it was on before the comment 1116 | call cursor(a:topLine, a:topCol + strlen(s:Left()) + g:NERDSpaceDelims) 1117 | 1118 | "if we switched delimiters then we gotta go back to what they were before 1119 | if switchedDelims ==# 1 1120 | call nerdcommenter#SwitchToAlternativeDelimiters(0) 1121 | endif 1122 | 1123 | endfunction 1124 | 1125 | " Function: s:InvertComment(firstLine, lastLine) function 1126 | " Inverts the comments on the lines between and including the given line 1127 | " numbers i.e all commented lines are uncommented and vice versa 1128 | " Args: 1129 | " -firstLine: the top of the range of lines to be inverted 1130 | " -lastLine: the bottom of the range of lines to be inverted 1131 | function! s:InvertComment(firstLine, lastLine) abort 1132 | 1133 | " go thru all lines in the given range 1134 | let currentLine = a:firstLine 1135 | while currentLine <= a:lastLine 1136 | let theLine = getline(currentLine) 1137 | 1138 | let sexyComBounds = s:FindBoundingLinesOfSexyCom(currentLine) 1139 | 1140 | " if the line is commented normally, uncomment it 1141 | if s:IsCommentedFromStartOfLine(s:Left(), theLine) || s:IsCommentedFromStartOfLine(s:Left({'alt': 1}), theLine) 1142 | call s:UncommentLines(currentLine, currentLine) 1143 | let currentLine = currentLine + 1 1144 | 1145 | " check if the line is commented sexually 1146 | elseif !empty(sexyComBounds) 1147 | let numLinesBeforeSexyComRemoved = s:NumLinesInBuf() 1148 | call s:UncommentLinesSexy(sexyComBounds[0], sexyComBounds[1]) 1149 | 1150 | "move to the line after last line of the sexy comment 1151 | let numLinesAfterSexyComRemoved = s:NumLinesInBuf() 1152 | let currentLine = sexyComBounds[1] - (numLinesBeforeSexyComRemoved - numLinesAfterSexyComRemoved) + 1 1153 | 1154 | " the line isn't commented 1155 | else 1156 | call s:CommentLinesToggle(1, currentLine, currentLine) 1157 | let currentLine = currentLine + 1 1158 | endif 1159 | 1160 | endwhile 1161 | endfunction 1162 | 1163 | " Function: nerdcommenter#IsLineCommented(lineNo) 1164 | " Check if the line is a comment 1165 | " Note this function checks if the line is **completely** a comment 1166 | " Args: 1167 | " -lineNo: the line number of the line to check 1168 | " Return: Number, 1 if the line is a comment, 0 else 1169 | function! nerdcommenter#IsLineCommented(lineNo) abort 1170 | call nerdcommenter#SetUp() 1171 | let theLine = getline(a:lineNo) 1172 | return s:IsInSexyComment(a:lineNo) || s:IsCommentedFromStartOfLine(s:Left(), theLine) || s:IsCommentedFromStartOfLine(s:Left({'alt': 1}), theLine) 1173 | endfunction 1174 | 1175 | " Function: nerdcommenter#Comment(mode, type) function 1176 | " This function is a Wrapper for the main commenting functions 1177 | " 1178 | " Args: 1179 | " -mode: a character indicating the mode in which the comment is requested: 1180 | " 'n' for Normal mode, 'x' for Visual mode 1181 | " -type: the type of commenting requested. Can be 'Sexy', 'Invert', 1182 | " 'Minimal', 'Toggle', 'AlignLeft', 'AlignBoth', 'Comment', 1183 | " 'Nested', 'ToEOL', 'Append', 'Insert', 'Uncomment', 'Yank' 1184 | function! nerdcommenter#Comment(mode, type) range abort 1185 | if exists('*NERDCommenter_before') 1186 | exe 'call NERDCommenter_before()' 1187 | endif 1188 | call nerdcommenter#SetUp() 1189 | 1190 | let isVisual = a:mode =~# '[vsx]' 1191 | 1192 | if !exists('g:did_load_ftplugin') || g:did_load_ftplugin !=# 1 1193 | call s:NerdEcho('filetype plugins should be enabled. See :help NERDComInstallation and :help :filetype-plugin-on', 0) 1194 | endif 1195 | 1196 | if isVisual 1197 | let firstLine = line("'<") 1198 | let lastLine = line("'>") 1199 | let firstCol = col("'<") 1200 | let lastCol = col("'>") - (&selection ==# 'exclusive' ? 1 : 0) 1201 | else 1202 | let firstLine = a:firstline 1203 | let lastLine = a:lastline 1204 | endif 1205 | " 1206 | " Save options we need to change so we can recover them later 1207 | let state = s:SetupStateBeforeLineComment(firstLine, lastLine) 1208 | 1209 | let countWasGiven = (!isVisual && firstLine !=# lastLine) 1210 | 1211 | let forceNested = (a:type ==? 'Nested' || g:NERDDefaultNesting) 1212 | 1213 | if a:type ==? 'Comment' || a:type ==? 'Nested' 1214 | if isVisual && visualmode() ==# "\" 1215 | call s:CommentBlock(firstLine, lastLine, firstCol, lastCol, forceNested) 1216 | elseif isVisual && visualmode() ==# 'v' && (g:NERDCommentWholeLinesInVMode==#0 || (g:NERDCommentWholeLinesInVMode==#2 && s:HasMultipartDelims())) 1217 | call s:CommentRegion(firstLine, firstCol, lastLine, lastCol, forceNested) 1218 | else 1219 | call s:CommentLines(forceNested, g:NERDDefaultAlign, firstLine, lastLine) 1220 | endif 1221 | 1222 | elseif a:type ==? 'AlignLeft' || a:type ==? 'AlignBoth' 1223 | let align = 'none' 1224 | if a:type ==? 'AlignLeft' 1225 | let align = 'left' 1226 | elseif a:type ==? 'AlignBoth' 1227 | let align = 'both' 1228 | endif 1229 | call s:CommentLines(forceNested, align, firstLine, lastLine) 1230 | 1231 | elseif a:type ==? 'Invert' 1232 | call s:InvertComment(firstLine, lastLine) 1233 | 1234 | elseif a:type ==? 'Sexy' 1235 | try 1236 | call s:CommentLinesSexy(firstLine, lastLine) 1237 | catch /NERDCommenter.Delimiters/ 1238 | call s:CommentLines(forceNested, g:NERDDefaultAlign, firstLine, lastLine) 1239 | catch /NERDCommenter.Nesting/ 1240 | call s:NerdEcho('Sexy comment aborted. Nested sexy cannot be nested', 0) 1241 | endtry 1242 | 1243 | elseif a:type ==? 'Toggle' 1244 | if g:NERDToggleCheckAllLines ==# 0 1245 | let theLine = getline(firstLine) 1246 | if s:IsInSexyComment(firstLine) || s:IsCommentedFromStartOfLine(s:Left(), theLine) || s:IsCommentedFromStartOfLine(s:Left({'alt': 1}), theLine) 1247 | call s:UncommentLines(firstLine, lastLine) 1248 | else 1249 | call s:CommentLinesToggle(forceNested, firstLine, lastLine) 1250 | endif 1251 | else 1252 | let l:commentAllLines = 0 1253 | for i in range(firstLine, lastLine) 1254 | let theLine = getline(i) 1255 | " if have one line no comment(not include blank/whitespace-only lines), then comment all lines 1256 | if theLine =~# '\S\+' && !s:IsInSexyComment(firstLine) && !s:IsCommentedFromStartOfLine(s:Left(), theLine) && !s:IsCommentedFromStartOfLine(s:Left({'alt': 1}), theLine) 1257 | let l:commentAllLines = 1 1258 | break 1259 | else 1260 | endif 1261 | endfor 1262 | if l:commentAllLines ==# 1 1263 | call s:CommentLinesToggle(forceNested, firstLine, lastLine) 1264 | else 1265 | call s:UncommentLines(firstLine, lastLine) 1266 | endif 1267 | endif 1268 | 1269 | elseif a:type ==? 'Minimal' 1270 | try 1271 | call s:CommentLinesMinimal(firstLine, lastLine) 1272 | catch /NERDCommenter.Delimiters/ 1273 | call s:NerdEcho('Minimal comments can only be used for filetypes that have multipart delimiters.', 0) 1274 | catch /NERDCommenter.Settings/ 1275 | call s:NerdEcho('Place holders are required but disabled.', 0) 1276 | endtry 1277 | 1278 | elseif a:type ==? 'ToEOL' 1279 | let view = winsaveview() 1280 | call s:CommentBlock(firstLine, firstLine, col('.'), col('$')-1, 1) 1281 | call winrestview(view) 1282 | 1283 | elseif a:type ==? 'Append' 1284 | call s:AppendCommentToLine() 1285 | 1286 | elseif a:type ==? 'Insert' 1287 | call s:PlaceDelimitersAndInsBetween() 1288 | 1289 | elseif a:type ==? 'Uncomment' 1290 | call s:UncommentLines(firstLine, lastLine) 1291 | 1292 | elseif a:type ==? 'Yank' 1293 | if isVisual 1294 | normal! gvy 1295 | elseif countWasGiven 1296 | execute firstLine .','. lastLine .'yank' 1297 | else 1298 | normal! yy 1299 | endif 1300 | execute firstLine .','. lastLine .'call nerdcommenter#Comment("'. a:mode .'", "Comment")' 1301 | endif 1302 | 1303 | call s:RecoverStateAfterLineComment(state) 1304 | 1305 | if isVisual 1306 | let nlines = lastLine - firstLine 1307 | silent! call repeat#set('V' . nlines . 'jo' . "\NERDCommenter". a:type) 1308 | else 1309 | silent! call repeat#set("\NERDCommenter". a:type) 1310 | endif 1311 | 1312 | if exists('*NERDCommenter_after') 1313 | exe 'call NERDCommenter_after()' 1314 | endif 1315 | 1316 | endfunction 1317 | 1318 | " Function: nerdcommenter#IsCharCommented(line, col) abort 1319 | " Check if the character at [line, col] is inside a comment 1320 | " Note the Comment delimeter it self is considered as part of the comment 1321 | " 1322 | " Args: 1323 | " -line the line number of the character 1324 | " -col the column number of the character 1325 | " Return: Number, 1 if the character is inside a comment, 0 if is not 1326 | function! nerdcommenter#IsCharCommented(line, col) abort 1327 | call nerdcommenter#SetUp() 1328 | " Function: s:searchfor(str, line, col, direction, [maxline]) 1329 | " search str in the buffer, including the character at [line, col] 1330 | " Args: 1331 | " -str: the string for search 1332 | " -line: the line number where search begins 1333 | " -col: the column number where search begins 1334 | " -direction: 0 if forward, and 1 if backward 1335 | " -maxline: the max lines the search would look up 1336 | " 1 if search only one line 1337 | " if not given, search until reaches the begining or end of file 1338 | " Return: List, in the format of [line, col], where line and col is the 1339 | " position of first found result; If str cannot be found, returns 1340 | " [0, 0] 1341 | function! s:searchfor(str, line, col, direction, ...) abort 1342 | let l:curlinenr = a:line 1343 | let l:maxline = (a:0 > 0) ? a:1 : (a:direction ? a:line : line('$') - a:line + 1) 1344 | while abs(curlinenr - a:line) < maxline 1345 | let linestr = getline(curlinenr) 1346 | if curlinenr == a:line 1347 | if !a:direction 1348 | let l:partstr = strpart(linestr, a:col - strlen(a:str)) 1349 | else 1350 | let l:partstr = strpart(linestr, 0, a:col + strlen(a:str) - 1) 1351 | endif 1352 | else 1353 | let l:partstr = linestr 1354 | endif 1355 | if !a:direction 1356 | " forward 1357 | let idx = stridx(partstr, a:str) 1358 | if idx != -1 1359 | if curlinenr == a:line 1360 | let idx += a:col - strlen(a:str) 1361 | else 1362 | endif 1363 | return [curlinenr, idx + 1] 1364 | endif 1365 | else 1366 | " backward 1367 | let idx = strridx(partstr, a:str) 1368 | if idx != -1 1369 | return [curlinenr, idx + 1] 1370 | endif 1371 | endif 1372 | let curlinenr += a:direction ? -1 : 1 1373 | endwhile 1374 | return [0, 0] 1375 | endfunction 1376 | " Function: s:checkwith(left, right, line, col) abort 1377 | " check if the char at [line, col] is commented using [left, right] pair 1378 | " Args: 1379 | " -left: the string begins a comment 1380 | " -right: the string ends a comment 1381 | " -line: the line position of the character 1382 | " -col: the column position of the character 1383 | " Return: Number, 1 if is in a comment, 0 else 1384 | function! s:checkwith(left, right, line, col) abort 1385 | let linecommented = 0 1386 | let blockcommented = 0 1387 | if a:right ==# '' 1388 | let leftpos = s:searchfor(a:left, a:line, a:col, 1, 1) 1389 | if leftpos == [0, 0] 1390 | if !linecommented | let linecommented = 0 | endif 1391 | else 1392 | if !linecommented | let linecommented = 1 | endif 1393 | endif 1394 | else 1395 | let leftpos = s:searchfor(a:left, a:line, a:col, 1) 1396 | if leftpos == [0, 0] 1397 | if !blockcommented | let blockcommented = 0 | endif 1398 | else 1399 | " call s:searchfor(a:right, a:line, a:col, 0) 1400 | let rightpos = s:searchfor(a:right, leftpos[0], leftpos[1] + strlen(a:right) + 1, 0) 1401 | if rightpos != [0, 0] 1402 | if rightpos[0] < a:line 1403 | if !blockcommented | let blockcommented = 0 | endif 1404 | elseif rightpos[0] == a:line 1405 | if !blockcommented 1406 | let blockcommented = (rightpos[1] + strlen(a:right) > a:col) ? 1 : 0 1407 | endif 1408 | else " rightpos > a:line 1409 | if !blockcommented | let blockcommented = 1 | endif 1410 | endif 1411 | else 1412 | if !blockcommented | let blockcommented = 1 | endif 1413 | endif 1414 | endif 1415 | endif 1416 | return linecommented || blockcommented 1417 | endfunction 1418 | return s:checkwith( 1419 | \ b:NERDCommenterDelims['left'], 1420 | \ b:NERDCommenterDelims['right'], 1421 | \ a:line, 1422 | \ a:col) || 1423 | \ s:checkwith( 1424 | \ b:NERDCommenterDelims['leftAlt'], 1425 | \ b:NERDCommenterDelims['rightAlt'], 1426 | \ a:line, 1427 | \ a:col) 1428 | endfunction 1429 | 1430 | " Function: s:PlaceDelimitersAndInsBetween() function 1431 | " This is function is called to place comment delimiters down and place the 1432 | " cursor between them 1433 | function! s:PlaceDelimitersAndInsBetween() abort 1434 | " get the left and right delimiters without any escape chars in them 1435 | let left = s:Left({'space': 1}) 1436 | let right = s:Right({'space': 1}) 1437 | 1438 | " 0. Entered insert normal mode using (:h i_CTRL-\_CTRL-O) to 1439 | " maintain the cursor position (from NERDCommenterInsert). 1440 | " 1. Enter insert mode without changing the cursor position. 1441 | " If the cursor is on EOL (right of the last char), use 'a'. 1442 | " Otherwise, use 'i'. 1443 | let insert = col('.') > strlen(getline('.')) ? 'a' : 'i' 1444 | " 2. Insert comment delimiters. 1445 | " 3. Move the cursor to the left of the closing delimiter, without 1446 | " breaking undo sequence. 1447 | " 4. Enter insert normal mode again without changing the cursor position. 1448 | " This ensures that returning to the insert mode after finishing the 1449 | " script execution does not move the cursor. 1450 | " ( 1 ) ( 2 ) ( 3 ) ( 4 ) 1451 | execute 'normal!' insert . left . right . repeat("\U\", strchars(right)) . "\\" 1452 | endfunction 1453 | 1454 | " Function: s:RemoveDelimiters(left, right, line) 1455 | " this function is called to remove the first left comment delimiter and the 1456 | " last right delimiter of the given line. 1457 | " 1458 | " The arguments left and right must be strings. If there is no right delimiter (as 1459 | " is the case for e.g vim file comments) them the argument right should be '' 1460 | " 1461 | " Args: 1462 | " -left: the left comment delimiter 1463 | " -right: the right comment delimiter 1464 | " -line: the line to remove the delimiters from 1465 | function! s:RemoveDelimiters(left, right, line) abort 1466 | 1467 | let l:left = a:left 1468 | let l:right = a:right 1469 | let lenLeft = strlen(left) 1470 | let lenRight = strlen(right) 1471 | 1472 | let delimsSpaced = (g:NERDSpaceDelims || g:NERDRemoveExtraSpaces) 1473 | 1474 | let line = a:line 1475 | 1476 | "look for the left delimiter, if we find it, remove it. 1477 | let leftIndx = s:FindDelimiterIndex(a:left, line) 1478 | if leftIndx !=# -1 1479 | let line = strpart(line, 0, leftIndx) . strpart(line, leftIndx+lenLeft) 1480 | 1481 | "if the user has specified that there is a space after the left delimiter 1482 | "then check for the space and remove it if it is there 1483 | if delimsSpaced && strpart(line, leftIndx, s:lenSpaceStr) ==# s:spaceStr 1484 | let line = strpart(line, 0, leftIndx) . strpart(line, leftIndx+s:lenSpaceStr) 1485 | endif 1486 | endif 1487 | 1488 | "look for the right delimiter, if we find it, remove it 1489 | let rightIndx = s:LastIndexOfDelim(a:right, line) 1490 | if rightIndx !=# -1 1491 | let line = strpart(line, 0, rightIndx) . strpart(line, rightIndx+lenRight) 1492 | 1493 | "if the user has specified that there is a space before the right delimiter 1494 | "then check for the space and remove it if it is there 1495 | if delimsSpaced && strpart(line, rightIndx-s:lenSpaceStr, s:lenSpaceStr) ==# s:spaceStr && (s:Multipart() || s:AltMultipart()) 1496 | let line = strpart(line, 0, rightIndx-s:lenSpaceStr) . strpart(line, rightIndx) 1497 | endif 1498 | endif 1499 | 1500 | return line 1501 | endfunction 1502 | 1503 | " Function: s:SetupStateBeforeLineComment(topLine, bottomLine) 1504 | " Changes ignorecase and foldmethod options before commenting lines and saves 1505 | " their original values in a dict, which is returned as a result 1506 | " 1507 | " Args: 1508 | " topLine: the top line of the visual selection to uncomment 1509 | " bottomLine: the bottom line of the visual selection to uncomment 1510 | " 1511 | " Return: a dict with the state prior to configuration changes 1512 | " 1513 | function! s:SetupStateBeforeLineComment(topLine, bottomLine) abort 1514 | let state = {'foldmethod' : &foldmethod, 1515 | \'ignorecase' : &ignorecase} 1516 | 1517 | " Vim's foldmethods are evaluated every time we use 'setline', which can 1518 | " make commenting wide ranges of lines VERY slow. We'll change it to 1519 | " manual, do the commenting stuff and recover it later. To avoid slowing 1520 | " down commenting few lines, we avoid doing this for ranges smaller than 1521 | " 10 lines 1522 | if a:bottomLine - a:topLine >= 10 && &foldmethod !=# 'manual' 1523 | set foldmethod=manual 1524 | endif 1525 | 1526 | " we want case sensitivity when commenting 1527 | set noignorecase 1528 | 1529 | return state 1530 | endfunction 1531 | 1532 | " Function: s:RecoverStateAfterLineComment(state) 1533 | " Receives the state returned by s:SetupStateBeforeLineComment and restores 1534 | " the state accordingly 1535 | " 1536 | " Args: 1537 | " state: the top line of the visual selection to uncomment 1538 | " bottomLine: the bottom line of the visual selection to uncomment 1539 | function! s:RecoverStateAfterLineComment(state) abort 1540 | if a:state['foldmethod'] !=# &foldmethod 1541 | let &foldmethod = a:state['foldmethod'] 1542 | endif 1543 | if a:state['ignorecase'] !=# &ignorecase 1544 | let &ignorecase = a:state['ignorecase'] 1545 | endif 1546 | endfunction 1547 | 1548 | " Function: s:TrimTrailingWhitespace(line) 1549 | " This function removes all the trailing whitespace 1550 | " Args: 1551 | " -line: the target line 1552 | function! s:TrimTrailingWhitespace(line) abort 1553 | let toReturn = substitute(a:line, '\s\+$', '', 'g') 1554 | return toReturn 1555 | endfunction 1556 | 1557 | " Function: s:UncommentLines(topLine, bottomLine) 1558 | " This function uncomments the given lines 1559 | " 1560 | " Args: 1561 | " topLine: the top line of the visual selection to uncomment 1562 | " bottomLine: the bottom line of the visual selection to uncomment 1563 | function! s:UncommentLines(topLine, bottomLine) abort 1564 | "make local copies of a:firstline and a:lastline and, if need be, swap 1565 | "them around if the top line is below the bottom 1566 | let l:firstline = a:topLine 1567 | let l:lastline = a:bottomLine 1568 | if firstline > lastline 1569 | let firstline = lastline 1570 | let lastline = a:topLine 1571 | endif 1572 | 1573 | "go thru each line uncommenting each line removing sexy comments 1574 | let currentLine = firstline 1575 | while currentLine <= lastline 1576 | 1577 | "check the current line to see if it is part of a sexy comment 1578 | let sexyComBounds = s:FindBoundingLinesOfSexyCom(currentLine) 1579 | if !empty(sexyComBounds) 1580 | 1581 | "we need to store the number of lines in the buffer before the comment is 1582 | "removed so we know how many lines were removed when the sexy comment 1583 | "was removed 1584 | let numLinesBeforeSexyComRemoved = s:NumLinesInBuf() 1585 | 1586 | call s:UncommentLinesSexy(sexyComBounds[0], sexyComBounds[1]) 1587 | 1588 | "move to the line after last line of the sexy comment 1589 | let numLinesAfterSexyComRemoved = s:NumLinesInBuf() 1590 | let numLinesRemoved = numLinesBeforeSexyComRemoved - numLinesAfterSexyComRemoved 1591 | let currentLine = sexyComBounds[1] - numLinesRemoved + 1 1592 | let lastline = lastline - numLinesRemoved 1593 | 1594 | "no sexy com was detected so uncomment the line as normal 1595 | else 1596 | call s:UncommentLinesNormal(currentLine, currentLine) 1597 | let currentLine = currentLine + 1 1598 | endif 1599 | endwhile 1600 | 1601 | endfunction 1602 | 1603 | " Function: s:UncommentLinesSexy(topline, bottomline) 1604 | " This function removes all the comment characters associated with the sexy 1605 | " comment spanning the given lines 1606 | " Args: 1607 | " -topline/bottomline: the top/bottom lines of the sexy comment 1608 | function! s:UncommentLinesSexy(topline, bottomline) abort 1609 | let left = s:GetSexyComLeft(0,1) 1610 | let right = s:GetSexyComRight(0,1) 1611 | 1612 | 1613 | "check if it is even possible for sexy comments to exist with the 1614 | "available delimiters 1615 | if left ==# -1 || right ==# -1 1616 | throw 'NERDCommenter.Delimiters exception: cannot uncomment sexy comments with available delimiters.' 1617 | endif 1618 | 1619 | let leftUnEsc = s:GetSexyComLeft(0,0) 1620 | let rightUnEsc = s:GetSexyComRight(0,0) 1621 | 1622 | let sexyComMarker = s:GetSexyComMarker(0, 1) 1623 | let sexyComMarkerUnEsc = s:GetSexyComMarker(0, 0) 1624 | 1625 | "the markerOffset is how far right we need to move the sexyComMarker to 1626 | "line it up with the end of the left delimiter 1627 | let markerOffset = strlen(leftUnEsc)-strlen(sexyComMarkerUnEsc) 1628 | 1629 | " go thru the intermediate lines of the sexy comment and remove the 1630 | " sexy comment markers (e.g., the '*'s on the start of line in a c sexy 1631 | " comment) 1632 | let currentLine = a:topline+1 1633 | while currentLine < a:bottomline 1634 | let theLine = getline(currentLine) 1635 | 1636 | " remove the sexy comment marker from the line. We also remove the 1637 | " space after it if there is one and if appropriate options are set 1638 | let sexyComMarkerIndx = stridx(theLine, sexyComMarkerUnEsc) 1639 | if strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc), s:lenSpaceStr) ==# s:spaceStr && g:NERDSpaceDelims 1640 | let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc)+s:lenSpaceStr) 1641 | else 1642 | let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc)) 1643 | endif 1644 | 1645 | let theLine = s:SwapOuterPlaceHoldersForMultiPartDelims(theLine) 1646 | 1647 | let theLine = s:ConvertLeadingWhiteSpace(theLine) 1648 | 1649 | if g:NERDTrimTrailingWhitespace ==# 1 1650 | let theLine = s:TrimTrailingWhitespace(theLine) 1651 | endif 1652 | 1653 | " move onto the next line 1654 | call setline(currentLine, theLine) 1655 | let currentLine = currentLine + 1 1656 | endwhile 1657 | 1658 | " gotta make a copy of a:bottomline cos we modify the position of the 1659 | " last line it if we remove the topline 1660 | let bottomline = a:bottomline 1661 | 1662 | " get the first line so we can remove the left delimiter from it 1663 | let theLine = getline(a:topline) 1664 | 1665 | " if the first line contains only the left delimiter then just delete it 1666 | if theLine =~# '^\s*' . left . '\s*$' && !g:NERDCompactSexyComs 1667 | call cursor(a:topline, 1) 1668 | normal! dd 1669 | let bottomline = bottomline - 1 1670 | 1671 | " topline contains more than just the left delimiter 1672 | else 1673 | 1674 | " remove the delimiter. If there is a space after it 1675 | " then remove this too if appropriate 1676 | let delimIndx = stridx(theLine, leftUnEsc) 1677 | if strpart(theLine, delimIndx+strlen(leftUnEsc), s:lenSpaceStr) ==# s:spaceStr && g:NERDSpaceDelims 1678 | let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(leftUnEsc)+s:lenSpaceStr) 1679 | else 1680 | let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(leftUnEsc)) 1681 | endif 1682 | let theLine = s:SwapOuterPlaceHoldersForMultiPartDelims(theLine) 1683 | call setline(a:topline, theLine) 1684 | endif 1685 | 1686 | " get the last line so we can remove the right delimiter 1687 | let theLine = getline(bottomline) 1688 | 1689 | " if the bottomline contains only the right delimiter then just delete it 1690 | if theLine =~# '^\s*' . right . '\s*$' 1691 | call cursor(bottomline, 1) 1692 | normal! dd 1693 | 1694 | " the last line contains more than the right delimiter 1695 | else 1696 | " remove the right delimiter. If there is a space after it and 1697 | " if the appropriate options are set then remove this too. 1698 | let delimIndx = s:LastIndexOfDelim(rightUnEsc, theLine) 1699 | if strpart(theLine, delimIndx+strlen(leftUnEsc), s:lenSpaceStr) ==# s:spaceStr && g:NERDSpaceDelims 1700 | let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(rightUnEsc)+s:lenSpaceStr) 1701 | else 1702 | let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(rightUnEsc)) 1703 | endif 1704 | 1705 | " if the last line also starts with a sexy comment marker then we 1706 | " remove this as well 1707 | if theLine =~# '^\s*' . sexyComMarker 1708 | 1709 | " remove the sexyComMarker. If there is a space after it then 1710 | " remove that too 1711 | let sexyComMarkerIndx = stridx(theLine, sexyComMarkerUnEsc) 1712 | if strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc), s:lenSpaceStr) ==# s:spaceStr && g:NERDSpaceDelims 1713 | let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset ) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc)+s:lenSpaceStr) 1714 | else 1715 | let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset ) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc)) 1716 | endif 1717 | endif 1718 | 1719 | let theLine = s:SwapOuterPlaceHoldersForMultiPartDelims(theLine) 1720 | call setline(bottomline, theLine) 1721 | endif 1722 | 1723 | " remove trailing whitespaces for first and last line 1724 | if g:NERDTrimTrailingWhitespace ==# 1 1725 | let theLine = getline(a:bottomline) 1726 | let theLine = s:TrimTrailingWhitespace(theLine) 1727 | call setline(a:bottomline, theLine) 1728 | let theLine = getline(a:topline) 1729 | let theLine = s:TrimTrailingWhitespace(theLine) 1730 | call setline(a:topline, theLine) 1731 | endif 1732 | endfunction 1733 | 1734 | " Function: s:UncommentLineNormal(line) 1735 | " uncomments the given line and returns the result 1736 | " Args: 1737 | " -line: the line to uncomment 1738 | function! s:UncommentLineNormal(line) abort 1739 | let line = a:line 1740 | 1741 | "get the positions of all delimiter types on the line 1742 | let indxLeft = s:FindDelimiterIndex(s:Left(), line) 1743 | let indxLeftAlt = s:FindDelimiterIndex(s:Left({'alt': 1}), line) 1744 | let indxRight = s:LastIndexOfDelim(s:Right(), line) 1745 | let indxRightAlt = s:LastIndexOfDelim(s:Right({'alt': 1}), line) 1746 | 1747 | "get the comment status on the line so we know how it is commented 1748 | let lineCommentStatus = s:IsCommentedOutermost(s:Left(), s:Right(), s:Left({'alt': 1}), s:Right({'alt': 1}), line) 1749 | 1750 | "it is commented with s:Left() and s:Right() so remove these delimiters 1751 | if lineCommentStatus ==# 1 1752 | let line = s:RemoveDelimiters(s:Left(), s:Right(), line) 1753 | 1754 | "it is commented with s:Left({'alt': 1}) and s:Right({'alt': 1}) so remove these delimiters 1755 | elseif lineCommentStatus ==# 2 && g:NERDRemoveAltComs 1756 | let line = s:RemoveDelimiters(s:Left({'alt': 1}), s:Right({'alt': 1}), line) 1757 | 1758 | "it is not properly commented with any delimiters so we check if it has 1759 | "any random left or right delimiters on it and remove the outermost ones 1760 | else 1761 | "remove the outer most left comment delimiter 1762 | if indxLeft !=# -1 && (indxLeft < indxLeftAlt || indxLeftAlt ==# -1) 1763 | let line = s:RemoveDelimiters(s:Left(), '', line) 1764 | elseif indxLeftAlt !=# -1 && g:NERDRemoveAltComs 1765 | let line = s:RemoveDelimiters(s:Left({'alt': 1}), '', line) 1766 | endif 1767 | 1768 | "remove the outer most right comment delimiter 1769 | if indxRight !=# -1 && (indxRight < indxRightAlt || indxRightAlt ==# -1) 1770 | let line = s:RemoveDelimiters('', s:Right(), line) 1771 | elseif indxRightAlt !=# -1 && g:NERDRemoveAltComs 1772 | let line = s:RemoveDelimiters('', s:Right({'alt': 1}), line) 1773 | endif 1774 | endif 1775 | 1776 | 1777 | let indxLeft = s:FindDelimiterIndex(s:Left(), line) 1778 | let indxLeftAlt = s:FindDelimiterIndex(s:Left({'alt': 1}), line) 1779 | let indxLeftPlace = s:FindDelimiterIndex(g:NERDLPlace, line) 1780 | let indxRightPlace = s:FindDelimiterIndex(g:NERDRPlace, line) 1781 | 1782 | let right = s:Right() 1783 | let left = s:Left() 1784 | if !s:Multipart() 1785 | let right = s:Right({'alt': 1}) 1786 | let left = s:Left({'alt': 1}) 1787 | endif 1788 | 1789 | 1790 | "if there are place-holders on the line then we check to see if they are 1791 | "the outermost delimiters on the line. If so then we replace them with 1792 | "real delimiters 1793 | if indxLeftPlace !=# -1 1794 | if (indxLeftPlace < indxLeft || indxLeft==-1) && (indxLeftPlace < indxLeftAlt || indxLeftAlt==-1) 1795 | let line = s:ReplaceDelims(g:NERDLPlace, g:NERDRPlace, left, right, line) 1796 | endif 1797 | elseif indxRightPlace !=# -1 1798 | if (indxRightPlace < indxLeft || indxLeft==-1) && (indxLeftPlace < indxLeftAlt || indxLeftAlt==-1) 1799 | let line = s:ReplaceDelims(g:NERDLPlace, g:NERDRPlace, left, right, line) 1800 | endif 1801 | 1802 | endif 1803 | 1804 | let line = s:ConvertLeadingWhiteSpace(line) 1805 | 1806 | if g:NERDTrimTrailingWhitespace ==# 1 1807 | let line = s:TrimTrailingWhitespace(line) 1808 | endif 1809 | 1810 | return line 1811 | endfunction 1812 | 1813 | " Function: s:UncommentLinesNormal(topline, bottomline) 1814 | " This function is called to uncomment lines that aren't a sexy comment 1815 | " Args: 1816 | " -topline/bottomline: the top/bottom line numbers of the comment 1817 | function! s:UncommentLinesNormal(topline, bottomline) abort 1818 | let currentLine = a:topline 1819 | while currentLine <= a:bottomline 1820 | let line = getline(currentLine) 1821 | call setline(currentLine, s:UncommentLineNormal(line)) 1822 | let currentLine = currentLine + 1 1823 | endwhile 1824 | endfunction 1825 | 1826 | 1827 | " Section: Other helper functions 1828 | " ============================================================================ 1829 | 1830 | " Function: s:AddLeftDelim(delim, theLine) 1831 | " Args: 1832 | function! s:AddLeftDelim(delim, theLine) abort 1833 | return substitute(a:theLine, '^\(\s*\)', '\1' . a:delim, '') 1834 | endfunction 1835 | 1836 | " Function: s:AddLeftDelimAligned(delim, theLine) 1837 | " Args: 1838 | function! s:AddLeftDelimAligned(delim, theLine, alignIndx) abort 1839 | 1840 | "if the line is not long enough then bung some extra spaces on the front 1841 | "so we can align the delimiter properly 1842 | let theLine = a:theLine 1843 | if strlen(theLine) < a:alignIndx 1844 | let theLine = repeat(' ', a:alignIndx - strlen(theLine)) 1845 | endif 1846 | 1847 | return strpart(theLine, 0, a:alignIndx) . a:delim . strpart(theLine, a:alignIndx) 1848 | endfunction 1849 | 1850 | " Function: s:AddRightDelim(delim, theLine) 1851 | " Args: 1852 | function! s:AddRightDelim(delim, theLine) abort 1853 | if a:delim ==# '' 1854 | return a:theLine 1855 | else 1856 | return substitute(a:theLine, '$', a:delim, '') 1857 | endif 1858 | endfunction 1859 | 1860 | " Function: s:AddRightDelimAligned(delim, theLine, alignIndx) 1861 | " Args: 1862 | function! s:AddRightDelimAligned(delim, theLine, alignIndx) abort 1863 | if a:delim ==# '' 1864 | return a:theLine 1865 | else 1866 | 1867 | " when we align the right delimiter we are just adding spaces 1868 | " so we get a string containing the needed spaces (it 1869 | " could be empty) 1870 | let extraSpaces = '' 1871 | let extraSpaces = repeat(' ', a:alignIndx-strlen(a:theLine)) 1872 | 1873 | " add the right delimiter 1874 | return substitute(a:theLine, '$', extraSpaces . a:delim, '') 1875 | endif 1876 | endfunction 1877 | 1878 | " Function: s:AltMultipart() 1879 | " returns 1 if the alternative delimiters are multipart 1880 | function! s:AltMultipart() abort 1881 | return b:NERDCommenterDelims['rightAlt'] !=# '' 1882 | endfunction 1883 | 1884 | " Function: s:AltNested() 1885 | " returns 1 if the alternate multipart (if any) delimiters allow nesting 1886 | function! s:AltNested() abort 1887 | return b:NERDCommenterDelims['nestedAlt'] 1888 | endfunction 1889 | 1890 | " Function: s:CanCommentLine(forceNested, line) 1891 | "This function is used to determine whether the given line can be commented. 1892 | "It returns 1 if it can be and 0 otherwise 1893 | " 1894 | " Args: 1895 | " -forceNested: a flag indicating whether the caller wants comments to be nested 1896 | " if the current line is already commented 1897 | " -lineNum: the line number of the line to check for commentability 1898 | function! s:CanCommentLine(forceNested, lineNum) abort 1899 | let theLine = getline(a:lineNum) 1900 | 1901 | " make sure we don't comment lines that are just spaces or tabs or empty, 1902 | " unless configured otherwise 1903 | if g:NERDCommentEmptyLines ==# 0 && theLine =~# '^\s*$' 1904 | return 0 1905 | endif 1906 | 1907 | "if the line is part of a sexy comment then just flag it... 1908 | if s:IsInSexyComment(a:lineNum) 1909 | return 0 1910 | endif 1911 | 1912 | let isCommented = s:IsCommentedNormOrSexy(a:lineNum) 1913 | 1914 | "if the line isn't commented return true 1915 | if !isCommented 1916 | return 1 1917 | endif 1918 | 1919 | "if the line is commented but nesting is allowed then return true 1920 | if s:Nested() || (a:forceNested && (!s:Multipart() || g:NERDUsePlaceHolders)) 1921 | return 1 1922 | endif 1923 | 1924 | return 0 1925 | endfunction 1926 | 1927 | " Function: s:CanPlaceCursor(line, col) 1928 | " returns 1 if the cursor can be placed exactly in the given position 1929 | function! s:CanPlaceCursor(line, col) abort 1930 | let c = col('.') 1931 | let l = line('.') 1932 | call cursor(a:line, a:col) 1933 | let success = (line('.') ==# a:line && col('.') ==# a:col) 1934 | call cursor(l,c) 1935 | return success 1936 | endfunction 1937 | 1938 | " Function: s:CanSexyCommentLines(topline, bottomline) 1939 | " Return: 1 if the given lines can be commented sexually, 0 otherwise 1940 | function! s:CanSexyCommentLines(topline, bottomline) abort 1941 | " see if the selected regions have any sexy comments 1942 | " however, if the language allows nested comments, 1943 | " we allow nested sexy comments 1944 | if s:SexyNested() 1945 | return 1 1946 | endif 1947 | let currentLine = a:topline 1948 | while(currentLine <= a:bottomline) 1949 | if s:IsInSexyComment(currentLine) 1950 | return 0 1951 | endif 1952 | let currentLine = currentLine + 1 1953 | endwhile 1954 | return 1 1955 | endfunction 1956 | " Function: s:CanToggleCommentLine(forceNested, line) 1957 | "This function is used to determine whether the given line can be toggle commented. 1958 | "It returns 1 if it can be and 0 otherwise 1959 | " 1960 | " Args: 1961 | " -lineNum: the line number of the line to check for commentability 1962 | function! s:CanToggleCommentLine(forceNested, lineNum) abort 1963 | let theLine = getline(a:lineNum) 1964 | if (s:IsCommentedFromStartOfLine(s:Left(), theLine) || s:IsCommentedFromStartOfLine(s:Left({'alt': 1}), theLine)) && !a:forceNested 1965 | return 0 1966 | endif 1967 | 1968 | " make sure we don't comment lines that are just spaces or tabs or empty, 1969 | " unless configured otherwise 1970 | if g:NERDCommentEmptyLines ==# 0 && theLine =~# '^\s*$' 1971 | return 0 1972 | endif 1973 | 1974 | "if the line is part of a sexy comment then just flag it... 1975 | if s:IsInSexyComment(a:lineNum) 1976 | return 0 1977 | endif 1978 | 1979 | return 1 1980 | endfunction 1981 | 1982 | " Function: s:ConvertLeadingSpacesToTabs(line) 1983 | " This function takes a line and converts all leading tabs on that line into 1984 | " spaces 1985 | " 1986 | " Args: 1987 | " -line: the line whose leading tabs will be converted 1988 | function! s:ConvertLeadingSpacesToTabs(line) abort 1989 | let toReturn = a:line 1990 | while toReturn =~# '^\t*' . s:TabSpace() . '\(.*\)$' 1991 | let toReturn = substitute(toReturn, '^\(\t*\)' . s:TabSpace() . '\(.*\)$' , '\1\t\2' , '') 1992 | endwhile 1993 | 1994 | return toReturn 1995 | endfunction 1996 | 1997 | 1998 | " Function: s:ConvertLeadingTabsToSpaces(line) 1999 | " This function takes a line and converts all leading spaces on that line into 2000 | " tabs 2001 | " 2002 | " Args: 2003 | " -line: the line whose leading spaces will be converted 2004 | function! s:ConvertLeadingTabsToSpaces(line) abort 2005 | let toReturn = a:line 2006 | while toReturn =~# '^\( *\)\t' 2007 | let toReturn = substitute(toReturn, '^\( *\)\t', '\1' . s:TabSpace() , '') 2008 | endwhile 2009 | 2010 | return toReturn 2011 | endfunction 2012 | 2013 | " Function: s:ConvertLeadingWhiteSpace(line) 2014 | " Converts the leading white space to tabs/spaces depending on &tabstop 2015 | " 2016 | " Args: 2017 | " -line: the line to convert 2018 | function! s:ConvertLeadingWhiteSpace(line) abort 2019 | let toReturn = a:line 2020 | while toReturn =~# '^ *\t' 2021 | let toReturn = substitute(toReturn, '^ *\zs\t\ze', s:TabSpace(), 'g') 2022 | endwhile 2023 | 2024 | if !&expandtab 2025 | let toReturn = s:ConvertLeadingSpacesToTabs(toReturn) 2026 | endif 2027 | 2028 | return toReturn 2029 | endfunction 2030 | 2031 | 2032 | " Function: s:CountNonESCedOccurances(str, searchstr, escChar) 2033 | " This function counts the number of substrings contained in another string. 2034 | " These substrings are only counted if they are not escaped with escChar 2035 | " Args: 2036 | " -str: the string to look for searchstr in 2037 | " -searchstr: the substring to search for in str 2038 | " -escChar: the escape character which, when preceding an instance of 2039 | " searchstr, will cause it not to be counted 2040 | function! s:CountNonESCedOccurances(str, searchstr, escChar) abort 2041 | "get the index of the first occurrence of searchstr 2042 | let indx = stridx(a:str, a:searchstr) 2043 | 2044 | "if there is an instance of searchstr in str process it 2045 | if indx !=# -1 2046 | "get the remainder of str after this instance of searchstr is removed 2047 | let lensearchstr = strlen(a:searchstr) 2048 | let strLeft = strpart(a:str, indx+lensearchstr) 2049 | 2050 | "if this instance of searchstr is not escaped, add one to the count 2051 | "and recurse. If it is escaped, just recurse 2052 | if !s:IsEscaped(a:str, indx, a:escChar) 2053 | return 1 + s:CountNonESCedOccurances(strLeft, a:searchstr, a:escChar) 2054 | else 2055 | return s:CountNonESCedOccurances(strLeft, a:searchstr, a:escChar) 2056 | endif 2057 | endif 2058 | endfunction 2059 | " Function: s:DoesBlockHaveDelim(delim, top, bottom) 2060 | " Returns 1 if the given block of lines has a delimiter (a:delim) in it 2061 | " Args: 2062 | " -delim: the comment delimiter to check the block for 2063 | " -top: the top line number of the block 2064 | " -bottom: the bottom line number of the block 2065 | function! s:DoesBlockHaveDelim(delim, top, bottom) abort 2066 | let currentLine = a:top 2067 | while currentLine < a:bottom 2068 | let theline = getline(currentLine) 2069 | if s:FindDelimiterIndex(a:delim, theline) !=# -1 2070 | return 1 2071 | endif 2072 | let currentLine = currentLine + 1 2073 | endwhile 2074 | return 0 2075 | endfunction 2076 | 2077 | " Function: s:DoesBlockHaveMultipartDelim(top, bottom) 2078 | " Returns 1 if the given block has a >= 1 multipart delimiter in it 2079 | " Args: 2080 | " -top: the top line number of the block 2081 | " -bottom: the bottom line number of the block 2082 | function! s:DoesBlockHaveMultipartDelim(top, bottom) abort 2083 | if s:HasMultipartDelims() 2084 | if s:Multipart() 2085 | return s:DoesBlockHaveDelim(s:Left(), a:top, a:bottom) || s:DoesBlockHaveDelim(s:Right(), a:top, a:bottom) 2086 | else 2087 | return s:DoesBlockHaveDelim(s:Left({'alt': 1}), a:top, a:bottom) || s:DoesBlockHaveDelim(s:Right({'alt': 1}), a:top, a:bottom) 2088 | endif 2089 | endif 2090 | return 0 2091 | endfunction 2092 | 2093 | 2094 | " Function: s:Esc(str) 2095 | " Escapes all the tricky chars in the given string 2096 | function! s:Esc(str) abort 2097 | let charsToEsc = '*/\."&$+[]' 2098 | return escape(a:str, charsToEsc) 2099 | endfunction 2100 | 2101 | " Function: s:FindDelimiterIndex(delimiter, line) 2102 | " This function is used to get the string index of the input comment delimiter 2103 | " on the input line. If no valid comment delimiter is found in the line then 2104 | " -1 is returned 2105 | " Args: 2106 | " -delimiter: the delimiter we are looking to find the index of 2107 | " -line: the line we are looking for delimiter on 2108 | function! s:FindDelimiterIndex(delimiter, line) abort 2109 | 2110 | "make sure the delimiter isn't empty otherwise we go into an infinite loop. 2111 | if a:delimiter ==# '' 2112 | return -1 2113 | endif 2114 | 2115 | 2116 | let l:delimiter = a:delimiter 2117 | let lenDel = strlen(l:delimiter) 2118 | 2119 | "get the index of the first occurrence of the delimiter 2120 | let delIndx = stridx(a:line, l:delimiter) 2121 | 2122 | "keep looping thru the line till we either find a real comment delimiter 2123 | "or run off the EOL 2124 | while delIndx !=# -1 2125 | 2126 | "if we are not off the EOL get the str before the possible delimiter 2127 | "in question and check if it really is a delimiter. If it is, return 2128 | "its position 2129 | if delIndx !=# -1 2130 | if s:IsDelimValid(l:delimiter, delIndx, a:line) 2131 | return delIndx 2132 | endif 2133 | endif 2134 | 2135 | "we have not yet found a real comment delimiter so move past the 2136 | "current one we are looking at 2137 | let restOfLine = strpart(a:line, delIndx + lenDel) 2138 | let distToNextDelim = stridx(restOfLine , l:delimiter) 2139 | 2140 | "if distToNextDelim is -1 then there is no more potential delimiters 2141 | "on the line so set delIndx to -1. Otherwise, move along the line by 2142 | "distToNextDelim 2143 | if distToNextDelim ==# -1 2144 | let delIndx = -1 2145 | else 2146 | let delIndx = delIndx + lenDel + distToNextDelim 2147 | endif 2148 | endwhile 2149 | 2150 | "there is no comment delimiter on this line 2151 | return -1 2152 | endfunction 2153 | 2154 | " Function: s:FindBoundingLinesOfSexyCom(lineNum) 2155 | " This function takes in a line number and tests whether this line number is 2156 | " the top/bottom/middle line of a sexy comment. If it is then the top/bottom 2157 | " lines of the sexy comment are returned 2158 | " Args: 2159 | " -lineNum: the line number that is to be tested whether it is the 2160 | " top/bottom/middle line of a sexy com 2161 | " Returns: 2162 | " A string that has the top/bottom lines of the sexy comment encoded in it. 2163 | " The format is 'topline,bottomline'. If a:lineNum turns out not to be the 2164 | " top/bottom/middle of a sexy comment then -1 is returned 2165 | function! s:FindBoundingLinesOfSexyCom(lineNum) abort 2166 | 2167 | "find which delimiters to look for as the start/end delimiters of the comment 2168 | let left = '' 2169 | let right = '' 2170 | if s:Multipart() 2171 | let left = s:Left({'esc': 1}) 2172 | let right = s:Right({'esc': 1}) 2173 | elseif s:AltMultipart() 2174 | let left = s:Left({'alt': 1, 'esc': 1}) 2175 | let right = s:Right({'alt': 1, 'esc': 1}) 2176 | else 2177 | return [] 2178 | endif 2179 | 2180 | let sexyComMarker = s:GetSexyComMarker(0, 1) 2181 | 2182 | "initialise the top/bottom line numbers of the sexy comment to -1 2183 | let top = -1 2184 | let bottom = -1 2185 | 2186 | let currentLine = a:lineNum 2187 | while top ==# -1 || bottom ==# -1 2188 | let theLine = getline(currentLine) 2189 | 2190 | "check if the current line is the top of the sexy comment 2191 | if currentLine <= a:lineNum && theLine =~# '^\s*' . left && theLine !~# '.*' . right && currentLine < s:NumLinesInBuf() 2192 | let top = currentLine 2193 | let currentLine = a:lineNum 2194 | 2195 | "check if the current line is the bottom of the sexy comment 2196 | elseif theLine =~# '^\s*' . right && theLine !~# '.*' . left && currentLine > 1 2197 | let bottom = currentLine 2198 | 2199 | "the right delimiter is on the same line as the last sexyComMarker 2200 | elseif theLine =~# '^\s*' . sexyComMarker . '.*' . right 2201 | let bottom = currentLine 2202 | 2203 | "we have not found the top or bottom line so we assume currentLine is an 2204 | "intermediate line and look to prove otherwise 2205 | else 2206 | 2207 | "if the line doesn't start with a sexyComMarker then it is not a sexy 2208 | "comment 2209 | if theLine !~# '^\s*' . sexyComMarker 2210 | return [] 2211 | endif 2212 | 2213 | endif 2214 | 2215 | "if top is -1 then we haven't found the top yet so keep looking up 2216 | if top ==# -1 2217 | let currentLine = currentLine - 1 2218 | "if we have found the top line then go down looking for the bottom 2219 | else 2220 | let currentLine = currentLine + 1 2221 | endif 2222 | 2223 | endwhile 2224 | 2225 | return [top, bottom] 2226 | endfunction 2227 | 2228 | 2229 | " Function: s:GetSexyComMarker() 2230 | " Returns the sexy comment marker for the current filetype. 2231 | " 2232 | " C style sexy comments are assumed if possible. If not then the sexy comment 2233 | " marker is the last char of the delimiter pair that has both left and right 2234 | " delimiters and has the longest left delimiter 2235 | " 2236 | " Args: 2237 | " -space: specifies whether the marker is to have a space string after it 2238 | " (the space string will only be added if NERDSpaceDelims is set) 2239 | " -esc: specifies whether the tricky chars in the marker are to be ESCed 2240 | function! s:GetSexyComMarker(space, esc) abort 2241 | let sexyComMarker = b:NERDSexyComMarker 2242 | 2243 | "if there is no hardcoded marker then we find one 2244 | if sexyComMarker ==# '' 2245 | 2246 | "if the filetype has c style comments then use standard c sexy 2247 | "comments 2248 | if s:HasCStyleComments() 2249 | let sexyComMarker = '*' 2250 | else 2251 | "find a comment marker by getting the longest available left delimiter 2252 | "(that has a corresponding right delimiter) and taking the last char 2253 | let lenLeft = strlen(s:Left()) 2254 | let lenLeftAlt = strlen(s:Left({'alt': 1})) 2255 | let left = '' 2256 | let right = '' 2257 | if s:Multipart() && lenLeft >= lenLeftAlt 2258 | let left = s:Left() 2259 | elseif s:AltMultipart() 2260 | let left = s:Left({'alt': 1}) 2261 | else 2262 | return -1 2263 | endif 2264 | 2265 | "get the last char of left 2266 | let sexyComMarker = strpart(left, strlen(left)-1) 2267 | endif 2268 | endif 2269 | 2270 | if a:space && g:NERDSpaceDelims 2271 | let sexyComMarker = sexyComMarker . s:spaceStr 2272 | endif 2273 | 2274 | if a:esc 2275 | let sexyComMarker = s:Esc(sexyComMarker) 2276 | endif 2277 | 2278 | return sexyComMarker 2279 | endfunction 2280 | 2281 | " Function: s:SexyNested() 2282 | " Returns 1 if the sexy delimeters allow nesting 2283 | " TODO this is ugly copy&paste from the GetSexyComLeft/Right functions, 2284 | " these could all be cleaned up 2285 | function! s:SexyNested() abort 2286 | let lenLeft = strlen(s:Left()) 2287 | let lenLeftAlt = strlen(s:Left({'alt': 1})) 2288 | 2289 | "assume c style sexy comments if possible 2290 | if s:HasCStyleComments() 2291 | return (s:Left() ==# '/*' && s:Nested()) || (s:Left({'alt': 1}) ==# '/*' && s:AltNested()) 2292 | else 2293 | "grab the longest left delim that has a right 2294 | if s:Multipart() && lenLeft >= lenLeftAlt 2295 | return s:Nested() 2296 | elseif s:AltMultipart() 2297 | return s:AltNested() 2298 | else 2299 | return 0 2300 | endif 2301 | endif 2302 | endfunction 2303 | 2304 | " Function: s:GetSexyComLeft(space, esc) 2305 | " Returns the left delimiter for sexy comments for this filetype or -1 if 2306 | " there is none. C style sexy comments are used if possible 2307 | " Args: 2308 | " -space: specifies if the delimiter has a space string on the end 2309 | " (the space string will only be added if NERDSpaceDelims is set) 2310 | " -esc: specifies whether the tricky chars in the string are ESCed 2311 | function! s:GetSexyComLeft(space, esc) abort 2312 | let lenLeft = strlen(s:Left()) 2313 | let lenLeftAlt = strlen(s:Left({'alt': 1})) 2314 | let left = '' 2315 | 2316 | "assume c style sexy comments if possible 2317 | if s:HasCStyleComments() 2318 | let left = '/*' 2319 | else 2320 | "grab the longest left delimiter that has a right 2321 | if s:Multipart() && lenLeft >= lenLeftAlt 2322 | let left = s:Left() 2323 | elseif s:AltMultipart() 2324 | let left = s:Left({'alt': 1}) 2325 | else 2326 | return -1 2327 | endif 2328 | endif 2329 | 2330 | if a:space && g:NERDSpaceDelims 2331 | let left = left . s:spaceStr 2332 | endif 2333 | 2334 | if a:esc 2335 | let left = s:Esc(left) 2336 | endif 2337 | 2338 | return left 2339 | endfunction 2340 | 2341 | " Function: s:GetSexyComRight(space, esc) 2342 | " Returns the right delimiter for sexy comments for this filetype or -1 if 2343 | " there is none. C style sexy comments are used if possible. 2344 | " Args: 2345 | " -space: specifies if the delimiter has a space string on the start 2346 | " (the space string will only be added if NERDSpaceDelims 2347 | " is specified for the current filetype) 2348 | " -esc: specifies whether the tricky chars in the string are ESCed 2349 | function! s:GetSexyComRight(space, esc) abort 2350 | let lenLeft = strlen(s:Left()) 2351 | let lenLeftAlt = strlen(s:Left({'alt': 1})) 2352 | let right = '' 2353 | 2354 | "assume c style sexy comments if possible 2355 | if s:HasCStyleComments() 2356 | let right = '*/' 2357 | else 2358 | "grab the right delimiter that pairs with the longest left delimiter 2359 | if s:Multipart() && lenLeft >= lenLeftAlt 2360 | let right = s:Right() 2361 | elseif s:AltMultipart() 2362 | let right = s:Right({'alt': 1}) 2363 | else 2364 | return -1 2365 | endif 2366 | endif 2367 | 2368 | if a:space && g:NERDSpaceDelims 2369 | let right = s:spaceStr . right 2370 | endif 2371 | 2372 | if a:esc 2373 | let right = s:Esc(right) 2374 | endif 2375 | 2376 | return right 2377 | endfunction 2378 | 2379 | " Function: s:HasMultipartDelims() 2380 | " Returns 1 if the current filetype has at least one set of multipart delimiters 2381 | function! s:HasMultipartDelims() abort 2382 | return s:Multipart() || s:AltMultipart() 2383 | endfunction 2384 | 2385 | " Function: s:HasLeadingTabs(...) 2386 | " Returns 1 if any of the given strings have leading tabs 2387 | function! s:HasLeadingTabs(...) abort 2388 | for s in a:000 2389 | if s =~# '^\t.*' 2390 | return 1 2391 | end 2392 | endfor 2393 | return 0 2394 | endfunction 2395 | " Function: s:HasCStyleComments() 2396 | " Returns 1 if the current filetype has c style comment delimiters 2397 | function! s:HasCStyleComments() abort 2398 | return (s:Left() ==# '/*' && s:Right() ==# '*/') || (s:Left({'alt': 1}) ==# '/*' && s:Right({'alt': 1}) ==# '*/') 2399 | endfunction 2400 | 2401 | " Function: s:IsCommentedNormOrSexy(lineNum) 2402 | "This function is used to determine whether the given line is commented with 2403 | "either set of delimiters or if it is part of a sexy comment 2404 | " 2405 | " Args: 2406 | " -lineNum: the line number of the line to check 2407 | function! s:IsCommentedNormOrSexy(lineNum) abort 2408 | let theLine = getline(a:lineNum) 2409 | 2410 | "if the line is commented normally return 1 2411 | if s:IsCommented(s:Left(), s:Right(), theLine) || s:IsCommented(s:Left({'alt': 1}), s:Right({'alt': 1}), theLine) 2412 | return 1 2413 | endif 2414 | 2415 | "if the line is part of a sexy comment return 1 2416 | if s:IsInSexyComment(a:lineNum) 2417 | return 1 2418 | endif 2419 | return 0 2420 | endfunction 2421 | 2422 | " Function: s:IsCommented(left, right, line) 2423 | "This function is used to determine whether the given line is commented with 2424 | "the given delimiters 2425 | " 2426 | " Args: 2427 | " -line: the line that to check if commented 2428 | " -left/right: the left and right delimiters to check for 2429 | function! s:IsCommented(left, right, line) abort 2430 | "if the line isn't commented return true 2431 | if s:FindDelimiterIndex(a:left, a:line) !=# -1 && (s:LastIndexOfDelim(a:right, a:line) !=# -1 || !s:Multipart()) 2432 | return 1 2433 | endif 2434 | return 0 2435 | endfunction 2436 | 2437 | " Function: s:IsCommentedFromStartOfLine(left, line) 2438 | "This function is used to determine whether the given line is commented with 2439 | "the given delimiters at the start of the line i.e the left delimiter is the 2440 | "first thing on the line (apart from spaces\tabs) 2441 | " 2442 | " Args: 2443 | " -line: the line that to check if commented 2444 | " -left: the left delimiter to check for 2445 | function! s:IsCommentedFromStartOfLine(left, line) abort 2446 | let theLine = s:ConvertLeadingTabsToSpaces(a:line) 2447 | let numSpaces = strlen(matchstr(theLine, '^ *')) 2448 | let delimIndx = s:FindDelimiterIndex(a:left, theLine) 2449 | return delimIndx ==# numSpaces 2450 | endfunction 2451 | 2452 | " Function: s:IsCommentedOutermost(left, right, leftAlt, rightAlt, line) 2453 | " Finds the type of the outermost delimiters on the line 2454 | " 2455 | " Args: 2456 | " -line: the line that to check if the outermost comments on it are 2457 | " left/right 2458 | " -left/right: the left and right delimiters to check for 2459 | " -leftAlt/rightAlt: the left and right alternative delimiters to check for 2460 | " 2461 | " Returns: 2462 | " 0 if the line is not commented with either set of delimiters 2463 | " 1 if the line is commented with the left/right delimiter set 2464 | " 2 if the line is commented with the leftAlt/rightAlt delim set 2465 | function! s:IsCommentedOutermost(left, right, leftAlt, rightAlt, line) abort 2466 | "get the first positions of the left delimiters and the last positions of the 2467 | "right delimiters 2468 | let indxLeft = s:FindDelimiterIndex(a:left, a:line) 2469 | let indxLeftAlt = s:FindDelimiterIndex(a:leftAlt, a:line) 2470 | let indxRight = s:LastIndexOfDelim(a:right, a:line) 2471 | let indxRightAlt = s:LastIndexOfDelim(a:rightAlt, a:line) 2472 | 2473 | "check if the line has a left delimiter before a leftAlt delimiter 2474 | if (indxLeft <= indxLeftAlt || indxLeftAlt ==# -1) && indxLeft !=# -1 2475 | "check if the line has a right delimiter after any rightAlt delimiter 2476 | if (indxRight > indxRightAlt && indxRight > indxLeft) || !s:Multipart() 2477 | return 1 2478 | endif 2479 | 2480 | "check if the line has a leftAlt delimiter before a left delimiter 2481 | elseif (indxLeftAlt <= indxLeft || indxLeft ==# -1) && indxLeftAlt !=# -1 2482 | "check if the line has a rightAlt delimiter after any right delimiter 2483 | if (indxRightAlt > indxRight && indxRightAlt > indxLeftAlt) || !s:AltMultipart() 2484 | return 2 2485 | endif 2486 | else 2487 | return 0 2488 | endif 2489 | 2490 | return 0 2491 | 2492 | endfunction 2493 | 2494 | 2495 | " Function: s:IsDelimValid(delimiter, delIndx, line) 2496 | " This function is responsible for determining whether a given instance of a 2497 | " comment delimiter is a real delimiter or not. For example, in java the 2498 | " // string is a comment delimiter but in the line: 2499 | " System.out.println("//"); 2500 | " it does not count as a comment delimiter. This function is responsible for 2501 | " distinguishing between such cases. It does so by applying a set of 2502 | " heuristics that are not fool proof but should work most of the time. 2503 | " 2504 | " Args: 2505 | " -delimiter: the delimiter we are validating 2506 | " -delIndx: the position of delimiter in line 2507 | " -line: the line that delimiter occurs in 2508 | " 2509 | " Returns: 2510 | " 0 if the given delimiter is not a real delimiter (as far as we can tell) , 2511 | " 1 otherwise 2512 | function! s:IsDelimValid(delimiter, delIndx, line) abort 2513 | "get the delimiter without the escchars 2514 | let l:delimiter = a:delimiter 2515 | 2516 | "get the strings before and after the delimiter 2517 | let preComStr = strpart(a:line, 0, a:delIndx) 2518 | let postComStr = strpart(a:line, a:delIndx+strlen(delimiter)) 2519 | 2520 | "to check if the delimiter is real, make sure it isn't preceded by 2521 | "an odd number of quotes and followed by the same (which would indicate 2522 | "that it is part of a string and therefore is not a comment) 2523 | if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, '"', "\\")) && !s:IsNumEven(s:CountNonESCedOccurances(postComStr, '"', '\\')) 2524 | return 0 2525 | endif 2526 | if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, "'", '\\')) && !s:IsNumEven(s:CountNonESCedOccurances(postComStr, "'", '\\')) 2527 | return 0 2528 | endif 2529 | if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, '`', '\\')) && !s:IsNumEven(s:CountNonESCedOccurances(postComStr, '`', '\\')) 2530 | return 0 2531 | endif 2532 | 2533 | 2534 | "if the comment delimiter is escaped, assume it isn't a real delimiter 2535 | if s:IsEscaped(a:line, a:delIndx, "\\") 2536 | return 0 2537 | endif 2538 | 2539 | "vim comments are so fucking stupid!! Why the hell do they have comment 2540 | "delimiters that are used elsewhere in the syntax?!?! We need to check 2541 | "some conditions especially for vim. 2542 | "Also check &commentstring because it may be overwritten for embedded lua. 2543 | if &filetype ==# 'vim' && &commentstring[0] ==# '"' 2544 | if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, '"', "\\")) 2545 | return 0 2546 | endif 2547 | 2548 | " if the delimiter is the first non-whitespace character, it is valid 2549 | if a:line =~# '^\s*"' 2550 | return 1 2551 | endif 2552 | 2553 | let numLeftParen =s:CountNonESCedOccurances(preComStr, '(', '\\') 2554 | let numRightParen =s:CountNonESCedOccurances(preComStr, ')', '\\') 2555 | 2556 | "if the quote is inside brackets then assume it isn't a comment 2557 | if numLeftParen > numRightParen 2558 | return 0 2559 | endif 2560 | 2561 | "if the line has an even num of unescaped "'s then we can assume that 2562 | "any given " is not a comment delimiter 2563 | if s:IsNumEven(s:CountNonESCedOccurances(a:line, '"', '\\')) 2564 | return 0 2565 | endif 2566 | endif 2567 | 2568 | return 1 2569 | 2570 | endfunction 2571 | 2572 | " Function: s:IsNumEven(num) 2573 | " A small function the returns 1 if the input number is even and 0 otherwise 2574 | " Args: 2575 | " -num: the number to check 2576 | function! s:IsNumEven(num) abort 2577 | return (a:num % 2) ==# 0 2578 | endfunction 2579 | 2580 | " Function: s:IsEscaped(str, indx, escChar) 2581 | " This function takes a string, an index into that string and an esc char and 2582 | " returns 1 if the char at the index is escaped (i.e if it is preceded by an 2583 | " odd number of esc chars) 2584 | " Args: 2585 | " -str: the string to check 2586 | " -indx: the index into str that we want to check 2587 | " -escChar: the escape char the char at indx may be ESCed with 2588 | function! s:IsEscaped(str, indx, escChar) abort 2589 | "initialise numEscChars to 0 and look at the char before indx 2590 | let numEscChars = 0 2591 | let curIndx = a:indx-1 2592 | 2593 | "keep going back thru str until we either reach the start of the str or 2594 | "run out of esc chars 2595 | while curIndx >= 0 && strpart(a:str, curIndx, 1) ==# a:escChar 2596 | 2597 | "we have found another esc char so add one to the count and move left 2598 | "one char 2599 | let numEscChars = numEscChars + 1 2600 | let curIndx = curIndx - 1 2601 | 2602 | endwhile 2603 | 2604 | "if there is an odd num of esc chars directly before the char at indx then 2605 | "the char at indx is escaped 2606 | return !s:IsNumEven(numEscChars) 2607 | endfunction 2608 | 2609 | " Function: s:IsInSexyComment(line) 2610 | " returns 1 if the given line number is part of a sexy comment 2611 | function! s:IsInSexyComment(line) abort 2612 | return !empty(s:FindBoundingLinesOfSexyCom(a:line)) 2613 | endfunction 2614 | 2615 | " Function: s:IsSexyComment(topline, bottomline) 2616 | " This function takes in 2 line numbers and returns 1 if the lines between and 2617 | " including the given line numbers are a sexy comment. It returns 0 otherwise. 2618 | " Args: 2619 | " -topline: the line that the possible sexy comment starts on 2620 | " -bottomline: the line that the possible sexy comment stops on 2621 | function! s:IsSexyComment(topline, bottomline) abort 2622 | 2623 | "get the delimiter set that would be used for a sexy comment 2624 | let left = '' 2625 | let right = '' 2626 | if s:Multipart() 2627 | let left = s:Left() 2628 | let right = s:Right() 2629 | elseif s:AltMultipart() 2630 | let left = s:Left({'alt': 1}) 2631 | let right = s:Right({'alt': 1}) 2632 | else 2633 | return 0 2634 | endif 2635 | 2636 | "swap the top and bottom line numbers around if need be 2637 | let topline = a:topline 2638 | let bottomline = a:bottomline 2639 | if bottomline < topline 2640 | let topline = bottomline 2641 | let bottomline = a:topline 2642 | endif 2643 | 2644 | "if there is < 2 lines in the comment it cannot be sexy 2645 | if (bottomline - topline) <= 0 2646 | return 0 2647 | endif 2648 | 2649 | "if the top line doesn't begin with a left delimiter then the comment isn't sexy 2650 | if getline(a:topline) !~# '^\s*' . left 2651 | return 0 2652 | endif 2653 | 2654 | "if there is a right delimiter on the top line then this isn't a sexy comment 2655 | if s:LastIndexOfDelim(right, getline(a:topline)) !=# -1 2656 | return 0 2657 | endif 2658 | 2659 | "if there is a left delimiter on the bottom line then this isn't a sexy comment 2660 | if s:FindDelimiterIndex(left, getline(a:bottomline)) !=# -1 2661 | return 0 2662 | endif 2663 | 2664 | "if the bottom line doesn't begin with a right delimiter then the comment isn't 2665 | "sexy 2666 | if getline(a:bottomline) !~# '^.*' . right . '$' 2667 | return 0 2668 | endif 2669 | 2670 | let sexyComMarker = s:GetSexyComMarker(0, 1) 2671 | 2672 | "check each of the intermediate lines to make sure they start with a 2673 | "sexyComMarker 2674 | let currentLine = a:topline+1 2675 | while currentLine < a:bottomline 2676 | let theLine = getline(currentLine) 2677 | 2678 | if theLine !~# '^\s*' . sexyComMarker 2679 | return 0 2680 | endif 2681 | 2682 | "if there is a right delimiter in an intermediate line then the block isn't 2683 | "a sexy comment 2684 | if s:LastIndexOfDelim(right, theLine) !=# -1 2685 | return 0 2686 | endif 2687 | 2688 | let currentLine = currentLine + 1 2689 | endwhile 2690 | 2691 | "we have not found anything to suggest that this isn't a sexy comment so 2692 | return 1 2693 | 2694 | endfunction 2695 | 2696 | " Function: s:LastIndexOfDelim(delim, str) 2697 | " This function takes a string and a delimiter and returns the last index of 2698 | " that delimiter in string 2699 | " Args: 2700 | " -delim: the delimiter to look for 2701 | " -str: the string to look for delimiter in 2702 | function! s:LastIndexOfDelim(delim, str) abort 2703 | let delim = a:delim 2704 | let lenDelim = strlen(delim) 2705 | 2706 | "set index to the first occurrence of delimiter. If there is no occurrence then 2707 | "bail 2708 | let indx = s:FindDelimiterIndex(delim, a:str) 2709 | if indx ==# -1 2710 | return -1 2711 | endif 2712 | 2713 | "keep moving to the next instance of delimiter in str till there is none left 2714 | while 1 2715 | 2716 | "search for the next delimiter after the previous one 2717 | let searchStr = strpart(a:str, indx+lenDelim) 2718 | let indx2 = s:FindDelimiterIndex(delim, searchStr) 2719 | 2720 | "if we find a delimiter update indx to record the position of it, if we 2721 | "don't find another delimiter then indx is the last one so break out of 2722 | "this loop 2723 | if indx2 !=# -1 2724 | let indx = indx + indx2 + lenDelim 2725 | else 2726 | break 2727 | endif 2728 | endwhile 2729 | 2730 | return indx 2731 | 2732 | endfunction 2733 | 2734 | " Function: s:Left(...) 2735 | " returns left delimiter data 2736 | function! s:Left(...) abort 2737 | let params = a:0 ? a:1 : {} 2738 | 2739 | let delim = has_key(params, 'alt') ? b:NERDCommenterDelims['leftAlt'] : b:NERDCommenterDelims['left'] 2740 | 2741 | if delim ==# '' 2742 | return '' 2743 | endif 2744 | 2745 | if has_key(params, 'space') && g:NERDSpaceDelims 2746 | let delim = delim . s:spaceStr 2747 | endif 2748 | 2749 | if has_key(params, 'esc') 2750 | let delim = s:Esc(delim) 2751 | endif 2752 | 2753 | return delim 2754 | endfunction 2755 | 2756 | " Function: s:LeftMostIndx(countCommentedLines, countEmptyLines, topline, bottomline) 2757 | " This function takes in 2 line numbers and returns the index of the left most 2758 | " char (that is not a space or a tab) on all of these lines. 2759 | " Args: 2760 | " -countCommentedLines: 1 if lines that are commented are to be checked as 2761 | " well. 0 otherwise 2762 | " -countEmptyLines: 1 if empty lines are to be counted in the search 2763 | " -topline: the top line to be checked 2764 | " -bottomline: the bottom line to be checked 2765 | function! s:LeftMostIndx(countCommentedLines, countEmptyLines, topline, bottomline) abort 2766 | 2767 | " declare the left most index as an extreme value 2768 | let leftMostIndx = 1000 2769 | 2770 | " go thru the block line by line updating leftMostIndx 2771 | let currentLine = a:topline 2772 | while currentLine <= a:bottomline 2773 | 2774 | " get the next line and if it is allowed to be commented, or is not 2775 | " commented, check it 2776 | let theLine = getline(currentLine) 2777 | if a:countEmptyLines || theLine !~# '^\s*$' 2778 | if a:countCommentedLines || (!s:IsCommented(s:Left(), s:Right(), theLine) && !s:IsCommented(s:Left({'alt': 1}), s:Right({'alt': 1}), theLine)) 2779 | " convert spaces to tabs and get the number of leading spaces for 2780 | " this line and update leftMostIndx if need be 2781 | let theLine = s:ConvertLeadingTabsToSpaces(theLine) 2782 | let leadSpaceOfLine = strlen(matchstr(theLine, '^\s*')) 2783 | if leadSpaceOfLine < leftMostIndx 2784 | let leftMostIndx = leadSpaceOfLine 2785 | endif 2786 | endif 2787 | endif 2788 | 2789 | " move on to the next line 2790 | let currentLine = currentLine + 1 2791 | endwhile 2792 | 2793 | if leftMostIndx ==# 1000 2794 | return 0 2795 | else 2796 | return leftMostIndx 2797 | endif 2798 | endfunction 2799 | 2800 | " Function: s:Multipart() 2801 | " returns 1 if the current delimiters are multipart 2802 | function! s:Multipart() abort 2803 | return s:Right() !=# '' 2804 | endfunction 2805 | 2806 | " Function: s:NerdEcho(msg, typeOfMsg) 2807 | " Args: 2808 | " -msg: the message to echo 2809 | " -typeOfMsg: 0 = warning message 2810 | " 1 = normal message 2811 | function! s:NerdEcho(msg, typeOfMsg) abort 2812 | if a:typeOfMsg ==# 0 2813 | echohl WarningMsg 2814 | echom 'NERDCommenter:' . a:msg 2815 | echohl None 2816 | elseif a:typeOfMsg ==# 1 2817 | echom 'NERDCommenter:' . a:msg 2818 | endif 2819 | endfunction 2820 | 2821 | " Function: s:Nested() 2822 | " returns 1 if the current multipart (if any) delimiters allow nesting 2823 | function! s:Nested() abort 2824 | return b:NERDCommenterDelims['nested'] 2825 | endfunction 2826 | 2827 | " Function: s:NumberOfLeadingTabs(s) 2828 | " returns the number of leading tabs in the given string 2829 | function! s:NumberOfLeadingTabs(s) abort 2830 | return strlen(matchstr(a:s, '^\t*')) 2831 | endfunction 2832 | 2833 | " Function: s:NumLinesInBuf() 2834 | " Returns the number of lines in the current buffer 2835 | function! s:NumLinesInBuf() abort 2836 | return line('$') 2837 | endfunction 2838 | 2839 | " Function: s:ReplaceDelims(toReplace1, toReplace2, replacor1, replacor2, str) 2840 | " This function takes in a string, 2 delimiters in that string and 2 strings 2841 | " to replace these delimiters with. 2842 | " 2843 | " Args: 2844 | " -toReplace1: the first delimiter to replace 2845 | " -toReplace2: the second delimiter to replace 2846 | " -replacor1: the string to replace toReplace1 with 2847 | " -replacor2: the string to replace toReplace2 with 2848 | " -str: the string that the delimiters to be replaced are in 2849 | function! s:ReplaceDelims(toReplace1, toReplace2, replacor1, replacor2, str) abort 2850 | let line = s:ReplaceLeftMostDelim(a:toReplace1, a:replacor1, a:str) 2851 | let line = s:ReplaceRightMostDelim(a:toReplace2, a:replacor2, line) 2852 | return line 2853 | endfunction 2854 | 2855 | " Function: s:ReplaceLeftMostDelim(toReplace, replacor, str) 2856 | " This function takes a string and a delimiter and replaces the left most 2857 | " occurrence of this delimiter in the string with a given string 2858 | " 2859 | " Args: 2860 | " -toReplace: the delimiter in str that is to be replaced 2861 | " -replacor: the string to replace toReplace with 2862 | " -str: the string that contains toReplace 2863 | function! s:ReplaceLeftMostDelim(toReplace, replacor, str) abort 2864 | let toReplace = a:toReplace 2865 | let replacor = a:replacor 2866 | "get the left most occurrence of toReplace 2867 | let indxToReplace = s:FindDelimiterIndex(toReplace, a:str) 2868 | 2869 | "if there IS an occurrence of toReplace in str then replace it and return 2870 | "the resulting string 2871 | if indxToReplace !=# -1 2872 | let line = strpart(a:str, 0, indxToReplace) . replacor . strpart(a:str, indxToReplace+strlen(toReplace)) 2873 | return line 2874 | endif 2875 | 2876 | return a:str 2877 | endfunction 2878 | 2879 | " Function: s:ReplaceRightMostDelim(toReplace, replacor, str) 2880 | " This function takes a string and a delimiter and replaces the right most 2881 | " occurrence of this delimiter in the string with a given string 2882 | " 2883 | " Args: 2884 | " -toReplace: the delimiter in str that is to be replaced 2885 | " -replacor: the string to replace toReplace with 2886 | " -str: the string that contains toReplace 2887 | " 2888 | function! s:ReplaceRightMostDelim(toReplace, replacor, str) abort 2889 | let toReplace = a:toReplace 2890 | let replacor = a:replacor 2891 | let lenToReplace = strlen(toReplace) 2892 | 2893 | "get the index of the last delimiter in str 2894 | let indxToReplace = s:LastIndexOfDelim(toReplace, a:str) 2895 | 2896 | "if there IS a delimiter in str, replace it and return the result 2897 | let line = a:str 2898 | if indxToReplace !=# -1 2899 | let line = strpart(a:str, 0, indxToReplace) . replacor . strpart(a:str, indxToReplace+strlen(toReplace)) 2900 | endif 2901 | return line 2902 | endfunction 2903 | 2904 | " Function: s:Right(...) 2905 | " returns right delimiter data 2906 | function! s:Right(...) abort 2907 | let params = a:0 ? a:1 : {} 2908 | 2909 | let delim = has_key(params, 'alt') ? b:NERDCommenterDelims['rightAlt'] : b:NERDCommenterDelims['right'] 2910 | 2911 | if delim ==# '' 2912 | return '' 2913 | endif 2914 | 2915 | if has_key(params, 'space') && g:NERDSpaceDelims 2916 | let delim = s:spaceStr . delim 2917 | endif 2918 | 2919 | if has_key(params, 'esc') 2920 | let delim = s:Esc(delim) 2921 | endif 2922 | 2923 | return delim 2924 | endfunction 2925 | 2926 | " Function: s:RightMostIndx(countCommentedLines, countEmptyLines, topline, bottomline) 2927 | " This function takes in 2 line numbers and returns the index of the right most 2928 | " char on all of these lines. 2929 | " Args: 2930 | " -countCommentedLines: 1 if lines that are commented are to be checked as 2931 | " well. 0 otherwise 2932 | " -countEmptyLines: 1 if empty lines are to be counted in the search 2933 | " -topline: the top line to be checked 2934 | " -bottomline: the bottom line to be checked 2935 | function! s:RightMostIndx(countCommentedLines, countEmptyLines, topline, bottomline) abort 2936 | let rightMostIndx = -1 2937 | 2938 | " go thru the block line by line updating rightMostIndx 2939 | let currentLine = a:topline 2940 | while currentLine <= a:bottomline 2941 | 2942 | " get the next line and see if it is commentable, otherwise it doesn't 2943 | " count 2944 | let theLine = getline(currentLine) 2945 | if a:countEmptyLines || theLine !~# '^\s*$' 2946 | 2947 | if a:countCommentedLines || (!s:IsCommented(s:Left(), s:Right(), theLine) && !s:IsCommented(s:Left({'alt': 1}), s:Right({'alt': 1}), theLine)) 2948 | 2949 | " update rightMostIndx if need be 2950 | let theLine = s:ConvertLeadingTabsToSpaces(theLine) 2951 | let lineLen = strlen(theLine) 2952 | if lineLen > rightMostIndx 2953 | let rightMostIndx = lineLen 2954 | endif 2955 | endif 2956 | endif 2957 | 2958 | " move on to the next line 2959 | let currentLine = currentLine + 1 2960 | endwhile 2961 | 2962 | return rightMostIndx 2963 | endfunction 2964 | 2965 | " Function: s:SwapOuterMultiPartDelimsForPlaceHolders(line) 2966 | " This function takes a line and swaps the outer most multi-part delimiters for 2967 | " place holders 2968 | " Args: 2969 | " -line: the line to swap the delimiters in 2970 | " 2971 | function! s:SwapOuterMultiPartDelimsForPlaceHolders(line) abort 2972 | " find out if the line is commented using normal delimiters and/or 2973 | " alternate ones 2974 | let isCommented = s:IsCommented(s:Left(), s:Right(), a:line) 2975 | let isCommentedAlt = s:IsCommented(s:Left({'alt': 1}), s:Right({'alt': 1}), a:line) 2976 | 2977 | let line2 = a:line 2978 | 2979 | "if the line is commented and there is a right delimiter, replace 2980 | "the delimiters with place-holders 2981 | if isCommented && s:Multipart() 2982 | let line2 = s:ReplaceDelims(s:Left(), s:Right(), g:NERDLPlace, g:NERDRPlace, a:line) 2983 | 2984 | "similarly if the line is commented with the alternative 2985 | "delimiters 2986 | elseif isCommentedAlt && s:AltMultipart() 2987 | let line2 = s:ReplaceDelims(s:Left({'alt': 1}), s:Right({'alt': 1}), g:NERDLPlace, g:NERDRPlace, a:line) 2988 | endif 2989 | 2990 | return line2 2991 | endfunction 2992 | 2993 | " Function: s:SwapOuterPlaceHoldersForMultiPartDelims(line) 2994 | " This function takes a line and swaps the outermost place holders for 2995 | " multi-part delimiters 2996 | " Args: 2997 | " -line: the line to swap the delimiters in 2998 | " 2999 | function! s:SwapOuterPlaceHoldersForMultiPartDelims(line) abort 3000 | let left = '' 3001 | let right = '' 3002 | if s:Multipart() 3003 | let left = s:Left() 3004 | let right = s:Right() 3005 | elseif s:AltMultipart() 3006 | let left = s:Left({'alt': 1}) 3007 | let right = s:Right({'alt': 1}) 3008 | endif 3009 | 3010 | let line = s:ReplaceDelims(g:NERDLPlace, g:NERDRPlace, left, right, a:line) 3011 | return line 3012 | endfunction 3013 | 3014 | "FUNCTION: s:TabSpace() 3015 | "returns a string of spaces equal in length to &tabstop 3016 | function! s:TabSpace() abort 3017 | let tabSpace = '' 3018 | let spacesPerTab = &tabstop 3019 | while spacesPerTab > 0 3020 | let tabSpace = tabSpace . ' ' 3021 | let spacesPerTab = spacesPerTab - 1 3022 | endwhile 3023 | return tabSpace 3024 | endfunction 3025 | 3026 | " Function: s:UnEsc(str, escChar) 3027 | " This function removes all the escape chars from a string 3028 | " Args: 3029 | " -str: the string to remove esc chars from 3030 | " -escChar: the escape char to be removed 3031 | function! s:UnEsc(str, escChar) abort 3032 | return substitute(a:str, a:escChar, '', 'g') 3033 | endfunction 3034 | -------------------------------------------------------------------------------- /doc/nerdcommenter.txt: -------------------------------------------------------------------------------- 1 | *nerdcommenter.txt* Plugin for commenting code 2 | 3 | 4 | NERD COMMENTER REFERENCE MANUAL~ 5 | 6 | 7 | 8 | 9 | 10 | ============================================================================== 11 | CONTENTS *NERDCommenterContents* 12 | 13 | 1.Intro...................................|NERDCommenter| 14 | 1.1 Leader............................|NERDCommenterLeader| 15 | 2.Installation............................|NERDCommenterInstallation| 16 | 3.Functionality provided..................|NERDCommenterFunctionality| 17 | 3.1 Functionality Summary.............|NERDCommenterFunctionalitySummary| 18 | 3.2 Functionality Details.............|NERDCommenterFunctionalityDetails| 19 | 3.2.1 Comment map.................|NERDCommenterComment| 20 | 3.2.2 Nested comment map..........|NERDCommenterNested| 21 | 3.2.3 Toggle comment map..........|NERDCommenterToggle| 22 | 3.2.4 Minimal comment map.........|NERDCommenterMinimal| 23 | 3.2.5 Invert comment map..........|NERDCommenterInvert| 24 | 3.2.6 Sexy comment map............|NERDCommenterSexy| 25 | 3.2.7 Yank comment map............|NERDCommenterYank| 26 | 3.2.8 Comment to EOL map..........|NERDCommenterToEOL| 27 | 3.2.9 Append com to line map......|NERDCommenterAppend| 28 | 3.2.10 Insert comment map.........|NERDCommenterInsert| 29 | 3.2.11 Use alternate delims map...|NERDCommenterAltDelims| 30 | 3.2.12 Comment aligned maps.......|NERDCommenterAlignLeft| 31 | |NERDCommenterAlignBoth| 32 | 3.2.13 Uncomment line map.........|NERDCommenterUncomment| 33 | 3.3 Sexy Comments.....................|NERDCommenterSexyComments| 34 | 3.4 The NERDComment function..........|NERDCommenterNERDComment| 35 | 3.5 The Hooks.........................|NERDCommenterHooks| 36 | 4.Options.................................|NERDCommenterOptions| 37 | 4.1 Options summary...................|NERDCommenterOptionsSummary| 38 | 4.2 Options details...................|NERDCommenterOptionsDetails| 39 | 4.3 Default delimiter Options.........|NERDCommenterDefaultDelims| 40 | 5. Customising key mappings...............|NERDCommenterMappings| 41 | 6. Interfaces.............................|NERDCommenterInterfaces| 42 | 7. Issues with the script.................|NERDCommenterIssues| 43 | 7.1 Delimiter detection heuristics....|NERDCommenterHeuristics| 44 | 7.2 Nesting issues....................|NERDCommenterNesting| 45 | 8.About.. ............................|NERDCommenterAbout| 46 | 9.Changelog...............................|NERDCommenterChangelog| 47 | 10.Credits................................|NERDCommenterCredits| 48 | 11.License................................|NERDCommenterLicense| 49 | 50 | ============================================================================== 51 | 1. Intro *NERDCommenter* 52 | 53 | The NERD commenter provides many different commenting operations and styles 54 | which are invoked via key mappings and a menu. These operations are available 55 | for most filetypes. 56 | 57 | There are also options that allow to tweak the commenting engine to your 58 | taste. 59 | 60 | ------------------------------------------------------------------------------ 61 | 1.1 Leader key *NERDCommenterLeader* 62 | 63 | Most NERD commenter commands are executed using the || key. In Vim 64 | this is a key dedicated for user-specific customizations. It effectively 65 | creates a namespace so that custom commands don't interfere with Vim's 66 | built-in shortcuts. 67 | 68 | The leader key can be mapped to whatever the user likes (see :help mapleader). 69 | In the definition of custom commands || is the placeholder for the 70 | leader key. To see the current mapping for || type :echo mapleader. 71 | If it reports an undefined variable it means the leader key is set to the 72 | default of '\'. 73 | 74 | ============================================================================== 75 | 2. Installation *NERDCommenterInstallation* 76 | 77 | The NERD Commenter requires Vim 7 or higher. 78 | 79 | Extract the plugin files in your ~/.vim (*nix) or ~/vimfiles (Windows). You 80 | should have 2 files: > 81 | plugin/nerdcommenter.vim 82 | doc/nerdcommenter.txt 83 | < 84 | Next, to finish installing the help file run: > 85 | :helptags ~/.vim/doc 86 | < 87 | See |add-local-help| for more details. 88 | 89 | Make sure that you have filetype plugins enabled, as the script makes use of 90 | |'commentstring'| where possible (which is usually set in a filetype plugin). 91 | See |filetype-plugin-on| for details, but basically, stick this in your vimrc > 92 | filetype plugin on 93 | < 94 | 95 | ============================================================================== 96 | 3. Functionality provided *NERDCommenterFunctionality* 97 | 98 | ------------------------------------------------------------------------------ 99 | 3.1 Functionality summary *NERDCommenterFunctionalitySummary* 100 | 101 | The following key mappings are provided by default (there is also a menu 102 | with items corresponding to all the mappings below): 103 | 104 | [count]||cc |NERDCommenterComment| 105 | Comment out the current line or text selected in visual mode. 106 | 107 | 108 | [count]||cn |NERDCommenterNested| 109 | Same as ||cc but forces nesting. 110 | 111 | 112 | [count]||c |NERDCommenterToggle| 113 | Toggles the comment state of the selected line(s). If the topmost selected 114 | line is commented, all selected lines are uncommented and vice versa. 115 | 116 | 117 | [count]||cm |NERDCommenterMinimal| 118 | Comments the given lines using only one set of multipart delimiters. 119 | 120 | 121 | [count]||ci |NERDCommenterInvert| 122 | Toggles the comment state of the selected line(s) individually. 123 | 124 | 125 | [count]||cs |NERDCommenterSexy| 126 | Comments out the selected lines ``sexily'' 127 | 128 | 129 | [count]||cy |NERDCommenterYank| 130 | Same as ||cc except that the commented line(s) are yanked first. 131 | 132 | 133 | ||c$ |NERDCommenterToEOL| 134 | Comments the current line from the cursor to the end of line. 135 | 136 | 137 | ||cA |NERDCommenterAppend| 138 | Adds comment delimiters to the end of line and goes into insert mode between 139 | them. 140 | 141 | 142 | |NERDCommenterInsert| 143 | Adds comment delimiters at the current cursor position and inserts between. 144 | Disabled by default. 145 | 146 | 147 | ||ca |NERDCommenterAltDelims| 148 | Switches to the alternative set of delimiters. 149 | 150 | 151 | [count]||cl |NERDCommenterAlignLeft| 152 | [count]||cb |NERDCommenterAlignBoth| 153 | Same as |NERDCommenterComment| except that the delimiters are aligned down the 154 | left side (||cl) or both sides (||cb). 155 | 156 | 157 | [count]||cu |NERDCommenterUncomment| 158 | Uncomments the selected line(s). 159 | 160 | 161 | With the optional repeat.vim plugin (vimscript #2136), the mappings can also 162 | be repeated via |.| 163 | 164 | ------------------------------------------------------------------------------ 165 | 3.2 Functionality details *NERDCommenterFunctionalityDetails* 166 | 167 | ------------------------------------------------------------------------------ 168 | 3.2.1 Comment map *NERDCommenterComment* 169 | 170 | Default mapping: [count]||cc 171 | Mapped to: NERDCommenterComment 172 | Applicable modes: normal visual visual-line visual-block. 173 | 174 | 175 | Comments out the current line. If multiple lines are selected in visual-line 176 | mode, they are all commented out. If some text is selected in visual or 177 | visual-block mode then the script will try to comment out the exact text that 178 | is selected using multi-part delimiters if they are available. 179 | 180 | If a [count] is given in normal mode, the mapping works as though that many 181 | lines were selected in visual-line mode. 182 | 183 | ------------------------------------------------------------------------------ 184 | 3.2.2 Nested comment map *NERDCommenterNested* 185 | 186 | Default mapping: [count]||cn 187 | Mapped to: NERDCommenterNested 188 | Applicable modes: normal visual visual-line visual-block. 189 | 190 | Performs nested commenting. Works the same as ||cc except that if a line 191 | is already commented then it will be commented again. 192 | 193 | If |'NERDUsePlaceHolders'| is set then the previous comment delimiters will 194 | be replaced by place-holder delimiters if needed. Otherwise the nested 195 | comment will only be added if the current commenting delimiters have no right 196 | delimiter (to avoid syntax errors) 197 | 198 | If a [count] is given in normal mode, the mapping works as though that many 199 | lines were selected in visual-line mode. 200 | 201 | Related options: 202 | |'NERDDefaultNesting'| 203 | 204 | ------------------------------------------------------------------------------ 205 | 3.2.3 Toggle comment map *NERDCommenterToggle* 206 | 207 | Default mapping: [count]||c 208 | Mapped to: NERDCommenterToggle 209 | Applicable modes: normal visual-line. 210 | 211 | Toggles commenting of the lines selected. The behaviour of this mapping 212 | depends on whether the first line selected is commented or not. If so, all 213 | selected lines are uncommented and vice versa. 214 | 215 | With this mapping, a line is only considered to be commented if it starts with 216 | a left delimiter. 217 | 218 | If a [count] is given in normal mode, the mapping works as though that many 219 | lines were selected in visual-line mode. 220 | 221 | ------------------------------------------------------------------------------ 222 | 3.2.4 Minimal comment map *NERDCommenterMinimal* 223 | 224 | Default mapping: [count]||cm 225 | Mapped to: NERDCommenterMinimal 226 | Applicable modes: normal visual-line. 227 | 228 | Comments the selected lines using one set of multipart delimiters if possible. 229 | 230 | For example: if you are programming in c and you select 5 lines and press 231 | ||cm then a '/*' will be placed at the start of the top line and a '*/' 232 | will be placed at the end of the last line. 233 | 234 | Sets of multipart comment delimiters that are between the top and bottom 235 | selected lines are replaced with place holders (see |'NERDLPlace'|) if 236 | |'NERDUsePlaceHolders'| is set for the current filetype. If it is not, then 237 | the comment will be aborted if place holders are required to prevent illegal 238 | syntax. 239 | 240 | If a [count] is given in normal mode, the mapping works as though that many 241 | lines were selected in visual-line mode. 242 | 243 | ------------------------------------------------------------------------------ 244 | 3.2.5 Invert comment map *NERDCommenterInvert* 245 | 246 | Default mapping: ||ci 247 | Mapped to: NERDCommenterInvert 248 | Applicable modes: normal visual-line. 249 | 250 | Inverts the commented state of each selected line. If the selected line is 251 | commented then it is uncommented and vice versa. Each line is examined and 252 | commented/uncommented individually. 253 | 254 | With this mapping, a line is only considered to be commented if it starts with 255 | a left delimiter. 256 | 257 | If a [count] is given in normal mode, the mapping works as though that many 258 | lines were selected in visual-line mode. 259 | 260 | ------------------------------------------------------------------------------ 261 | 3.2.6 Sexy comment map *NERDCommenterSexy* 262 | 263 | Default mapping: [count]||cs 264 | Mapped to: NERDCommenterSexy 265 | Applicable modes: normal, visual-line. 266 | 267 | Comments the selected line(s) ``sexily''. See |NERDCommenterSexyComments| for 268 | a description of what sexy comments are. Can only be done on filetypes for 269 | which there is at least one set of multipart comment delimiters specified. 270 | 271 | Sexy comments cannot be nested and lines inside a sexy comment cannot be 272 | commented again. 273 | 274 | If a [count] is given in normal mode, the mapping works as though that many 275 | lines were selected in visual-line mode. 276 | 277 | Related options: 278 | |'NERDCompactSexyComs'| 279 | 280 | ------------------------------------------------------------------------------ 281 | 3.2.7 Yank comment map *NERDCommenterYank* 282 | 283 | Default mapping: [count]||cy 284 | Mapped to: NERDCommenterYank 285 | Applicable modes: normal visual visual-line visual-block. 286 | 287 | Same as ||cc except that it yanks the line(s) that are commented first. 288 | 289 | ------------------------------------------------------------------------------ 290 | 3.2.8 Comment to EOL map *NERDCommenterToEOL* 291 | 292 | Default mapping: ||c$ 293 | Mapped to: NERDCommenterToEOL 294 | Applicable modes: normal. 295 | 296 | Comments the current line from the current cursor position up to the end of 297 | the line. 298 | 299 | ------------------------------------------------------------------------------ 300 | 3.2.9 Append com to line map *NERDCommenterAppend* 301 | 302 | Default mapping: ||cA 303 | Mapped to: NERDCommenterAppend 304 | Applicable modes: normal. 305 | 306 | Appends comment delimiters to the end of the current line and goes 307 | to insert mode between the new delimiters. 308 | 309 | ------------------------------------------------------------------------------ 310 | 3.2.10 Insert comment map *NERDCommenterInsert* 311 | 312 | Default mapping: disabled by default. 313 | Map it to: NERDCommenterInsert 314 | Applicable modes: insert. 315 | 316 | Adds comment delimiters at the current cursor position and inserts 317 | between them. 318 | 319 | NOTE: prior to version 2.1.17 this was mapped to . To restore this 320 | mapping add > 321 | imap NERDCommenterInsert 322 | < 323 | to your vimrc. 324 | 325 | ------------------------------------------------------------------------------ 326 | 3.2.11 Use alternate delims map *NERDCommenterAltDelims* 327 | 328 | Default mapping: ||ca 329 | Mapped to: NERDCommenterAltDelims 330 | Applicable modes: normal. 331 | 332 | Changes to the alternative commenting style if one is available. For example, 333 | if the user is editing a c++ file using // comments and they hit ||ca 334 | then they will be switched over to /**/ comments. 335 | 336 | See also |NERDCommenterDefaultDelims| 337 | 338 | ------------------------------------------------------------------------------ 339 | 3.2.12 Comment aligned maps *NERDCommenterAlignLeft* 340 | *NERDCommenterAlignBoth* 341 | 342 | Default mappings: [count]||cl [count]||cb 343 | Mapped to: NERDCommenterAlignLeft 344 | NERDCommenterAlignBoth 345 | Applicable modes: normal visual-line. 346 | 347 | Same as ||cc except that the comment delimiters are aligned on the left 348 | side or both sides respectively. These comments are always nested if the 349 | line(s) are already commented. 350 | 351 | If a [count] is given in normal mode, the mapping works as though that many 352 | lines were selected in visual-line mode. 353 | 354 | ------------------------------------------------------------------------------ 355 | 3.2.13 Uncomment line map *NERDCommenterUncomment* 356 | 357 | Default mapping: [count]||cu 358 | Mapped to: NERDCommenterUncomment 359 | Applicable modes: normal visual visual-line visual-block. 360 | 361 | Uncomments the current line. If multiple lines are selected in 362 | visual mode then they are all uncommented. 363 | 364 | When uncommenting, if the line contains multiple sets of delimiters then the 365 | ``outermost'' pair of delimiters will be removed. 366 | 367 | The script uses a set of heuristics to distinguish ``real'' delimiters from 368 | ``fake'' ones when uncommenting. See |NERDCommenterIssues| for details. 369 | 370 | If a [count] is given in normal mode, the mapping works as though that many 371 | lines were selected in visual-line mode. 372 | 373 | Related options: 374 | |'NERDRemoveAltComs'| 375 | |'NERDRemoveExtraSpaces'| 376 | 377 | ------------------------------------------------------------------------------ 378 | 3.3 Sexy Comments *NERDCommenterSexyComments* 379 | These are comments that use one set of multipart comment delimiters as well as 380 | one other marker symbol. For example: > 381 | /* 382 | * This is a c style sexy comment 383 | * So there! 384 | */ 385 | 386 | /* This is a c style sexy comment 387 | * So there! 388 | * But this one is ``compact'' style */ 389 | < 390 | Here the multipart delimiters are /* and */ and the marker is *. 391 | 392 | ------------------------------------------------------------------------------ 393 | 3.4 The NERDComment function *NERDCommenterNERDComment* 394 | 395 | All of the NERD commenter mappings and menu items invoke a single function 396 | which delegates the commenting work to other functions. This function is 397 | public and has the prototype: > 398 | function! NERDComment(mode, type) 399 | < 400 | The arguments to this function are simple: 401 | - mode: a character indicating the mode in which the comment is requested: 402 | 'n' for Normal mode, 'x' for Visual mode 403 | - type: is used to specify what type of commenting operation is to be 404 | performed, and it can be one of the following: "sexy", "invert", 405 | "minimal", "toggle", "alignLeft", "alignBoth", "comment", "nested", 406 | "toEOL", "append", "insert", "uncomment", "yank" 407 | 408 | For example, if you typed > 409 | :call NERDComment(1, 'sexy') 410 | < 411 | then the script would do a sexy comment on the last visual selection. 412 | 413 | ------------------------------------------------------------------------------ 414 | 3.5 The hooks *NERDCommenterHooks* 415 | |fu! NERDCommenter_before()| Before NERDComment/SwitchToAlternativeDelimiters 416 | |fu! NERDCommenter_after()| After NERDComment/SwitchToAlternativeDelimiters 417 | 418 | For example, in order to handle different language blocks embedded in the same 419 | file such as |vim-vue|, you can change the filetype, comment something and 420 | change the filetype back: > 421 | let g:ft = '' 422 | fu! NERDCommenter_before() 423 | if &ft == 'vue' 424 | let g:ft = 'vue' 425 | let stack = synstack(line('.'), col('.')) 426 | if len(stack) > 0 427 | let syn = synIDattr((stack)[0], 'name') 428 | if len(syn) > 0 429 | let syn = tolower(syn) 430 | exe 'setf '.syn 431 | endif 432 | endif 433 | endif 434 | endfu 435 | fu! NERDCommenter_after() 436 | if g:ft == 'vue' 437 | setf vue 438 | let g:ft = '' 439 | endif 440 | endfu 441 | < 442 | 443 | ============================================================================== 444 | 4. Options *NERDCommenterOptions* 445 | 446 | ------------------------------------------------------------------------------ 447 | 4.1 Options summary *NERDCommenterOptionsSummary* 448 | 449 | |'loaded_nerd_comments'| Turns off the script. 450 | 451 | |'NERDAllowAnyVisualDelims'| Allows multipart alternative delimiters 452 | to be used when commenting in 453 | visual/visual-block mode. 454 | 455 | |'NERDBlockComIgnoreEmpty'| Forces right delimiters to be placed 456 | when doing visual-block comments. 457 | 458 | |'NERDCommentEmptyLines'| Specifies if empty lines should be 459 | commented (useful with regions). 460 | 461 | |'NERDCommentWholeLinesInVMode'| Changes behaviour of visual comments. 462 | 463 | |'NERDCreateDefaultMappings'| Turn the default mappings on/off. 464 | 465 | |'NERDCustomDelimiters'| Add or override delimiters for any 466 | filetypes. 467 | 468 | |'NERDDefaultNesting'| Tells the script to use nested comments 469 | by default. 470 | 471 | |'NERDMenuMode'| Specifies how the NERD commenter menu 472 | will appear (if at all). 473 | 474 | |'NERDLPlace'| Specifies what to use as the left 475 | delimiter placeholder when nesting 476 | comments. 477 | 478 | |'NERDUsePlaceHolders'| Specifies which filetypes may use 479 | placeholders when nesting comments. 480 | 481 | |'NERDRemoveAltComs'| Tells the script whether to remove 482 | alternative comment delimiters when 483 | uncommenting. 484 | 485 | |'NERDRemoveExtraSpaces'| Tells the script to always remove the 486 | extra spaces when uncommenting 487 | (regardless of whether NERDSpaceDelims 488 | is set). 489 | 490 | |'NERDRPlace'| Specifies what to use as the right 491 | delimiter placeholder when nesting 492 | comments. 493 | 494 | |'NERDSpaceDelims'| Specifies whether to add extra spaces 495 | around delimiters when commenting, and 496 | whether to remove them when 497 | uncommenting. 498 | 499 | |'NERDTrimTrailingWhitespace'| Specifies if trailing whitespace 500 | should be deleted when uncommenting. 501 | 502 | |'NERDCompactSexyComs'| Specifies whether to use the compact 503 | style sexy comments. 504 | 505 | |'NERDDefaultAlign'| Specifies the default alignment to use, 506 | one of 'none', 'left', 'start', or 507 | 'both'. 508 | 509 | |'NERDToggleCheckAllLines'| Enable NERDCommenterToggle to check 510 | all selected lines is commented or not. 511 | 512 | ------------------------------------------------------------------------------ 513 | 4.2 Options details *NERDCommenterOptionsDetails* 514 | 515 | To enable any of the below options you should put the given line in your 516 | ~/.vimrc 517 | 518 | *'loaded_nerd_comments'* 519 | If this script is driving you insane you can turn it off by setting this 520 | option > 521 | let loaded_nerd_comments=1 522 | < 523 | ------------------------------------------------------------------------------ 524 | *'NERDAllowAnyVisualDelims'* 525 | Values: 0 or 1. 526 | Default: 1. 527 | 528 | If set to 1 then, when doing a visual or visual-block comment (but not a 529 | visual-line comment), the script will choose the right delimiters to use for 530 | the comment. This means either using the current delimiters if they are 531 | multipart or using the alternative delimiters if THEY are multipart. For 532 | example if we are editing the following java code: > 533 | float foo = 1221; 534 | float bar = 324; 535 | System.out.println(foo * bar); 536 | < 537 | If we are using // comments and select the "foo" and "bar" in visual-block 538 | mode, as shown left below (where '|'s are used to represent the visual-block 539 | boundary), and comment it then the script will use the alternative delimiters 540 | as shown on the right: > 541 | 542 | float |foo| = 1221; float /*foo*/ = 1221; 543 | float |bar| = 324; float /*bar*/ = 324; 544 | System.out.println(foo * bar); System.out.println(foo * bar); 545 | < 546 | ------------------------------------------------------------------------------ 547 | *'NERDBlockComIgnoreEmpty'* 548 | Values: 0 or 1. 549 | Default: 1. 550 | 551 | This option affects visual-block mode commenting. If this option is turned 552 | on, lines that begin outside the right boundary of the selection block will be 553 | ignored. 554 | 555 | For example, if you are commenting this chunk of c code in visual-block mode 556 | (where the '|'s are used to represent the visual-block boundary) > 557 | #include 558 | #include 559 | #include 560 | |int| main(){ 561 | | | printf("SUCK THIS\n"); 562 | | | while(1){ 563 | | | fork(); 564 | | | } 565 | |} | 566 | < 567 | If NERDBlockComIgnoreEmpty=0 then this code will become: > 568 | #include 569 | #include 570 | #include 571 | /*int*/ main(){ 572 | /* */ printf("SUCK THIS\n"); 573 | /* */ while(1){ 574 | /* */ fork(); 575 | /* */ } 576 | /*} */ 577 | < 578 | Otherwise, the code block would become: > 579 | #include 580 | #include 581 | #include 582 | /*int*/ main(){ 583 | printf("SUCK THIS\n"); 584 | while(1){ 585 | fork(); 586 | } 587 | /*} */ 588 | < 589 | ------------------------------------------------------------------------------ 590 | *'NERDCommentEmptyLines'* 591 | Values: 0 or 1. 592 | Default: 0. 593 | 594 | This option affects commenting of empty lines. If this option is turned on, 595 | then empty lines will be commented as well. Useful when commenting regions of 596 | code. 597 | 598 | ------------------------------------------------------------------------------ 599 | *'NERDCommentWholeLinesInVMode'* 600 | Values: 0, 1 or 2. 601 | Default: 0. 602 | 603 | By default the script tries to comment out exactly what is selected in visual 604 | mode (v). For example if you select and comment the following c code (using | 605 | to represent the visual boundary): > 606 | in|t foo = 3; 607 | int bar =| 9; 608 | int baz = foo + bar; 609 | < 610 | This will result in: > 611 | in/*t foo = 3;*/ 612 | /*int bar =*/ 9; 613 | int baz = foo + bar; 614 | < 615 | But some people prefer it if the whole lines are commented like: > 616 | /*int foo = 3;*/ 617 | /*int bar = 9;*/ 618 | int baz = foo + bar; 619 | < 620 | If you prefer the second option then stick this line in your vimrc: > 621 | let NERDCommentWholeLinesInVMode=1 622 | < 623 | 624 | If the filetype you are editing only has no multipart delimiters (for example 625 | a shell script) and you hadn't set this option then the above would become > 626 | in#t foo = 3; 627 | #int bar = 9; 628 | < 629 | (where # is the comment delimiter) as this is the closest the script can 630 | come to commenting out exactly what was selected. If you prefer for whole 631 | lines to be commented out when there is no multipart delimiters but the EXACT 632 | text that was selected to be commented out if there IS multipart delimiters 633 | then stick the following line in your vimrc: > 634 | let NERDCommentWholeLinesInVMode=2 635 | < 636 | 637 | Note that this option does not affect the behaviour of commenting in 638 | |visual-block| mode. 639 | 640 | ------------------------------------------------------------------------------ 641 | *'NERDCreateDefaultMappings'* 642 | Values: 0 or 1. 643 | Default: 1. 644 | 645 | If set to 0, none of the default mappings will be created. 646 | 647 | See also |NERDCommenterMappings|. 648 | 649 | ------------------------------------------------------------------------------ 650 | *'NERDCustomDelimiters'* 651 | Values: A map (format specified below). 652 | Default: {} 653 | 654 | Use this option if you have new filetypes you want the script to handle, or if 655 | you want to override the default delimiters of a filetype. 656 | 657 | Example: > 658 | let g:NERDCustomDelimiters = { 659 | \ 'ruby': { 'left': '#', 'leftAlt': 'FOO', 'rightAlt': 'BAR' }, 660 | \ 'grondle': { 'left': '{{', 'right': '}}' } 661 | \ } 662 | < 663 | 664 | Here we override the delimiter settings for ruby and add FOO/BAR as alternative 665 | delimiters. We also add {{ and }} as delimiters for a new filetype called 666 | 'grondle'. 667 | 668 | ------------------------------------------------------------------------------ 669 | *'NERDRemoveAltComs'* 670 | Values: 0 or 1. 671 | Default: 1. 672 | 673 | When uncommenting a line (for a filetype with an alternative commenting style) 674 | this option tells the script whether to look for, and remove, comment 675 | delimiters of the alternative style. 676 | 677 | For example, if you are editing a c++ file using // style comments and you go 678 | ||cu on this line: > 679 | /* This is a c++ comment baby! */ 680 | < 681 | It will not be uncommented if the NERDRemoveAltComs is set to 0. 682 | 683 | ------------------------------------------------------------------------------ 684 | *'NERDRemoveExtraSpaces'* 685 | Values: 0 or 1. 686 | Default: 0. 687 | 688 | By default, the NERD commenter will remove spaces around comment delimiters if 689 | either: 690 | 1. |'NERDSpaceDelims'| is set to 1. 691 | 2. NERDRemoveExtraSpaces is set to 1. 692 | 693 | This means that if we have the following lines in a c code file: > 694 | /* int foo = 5; */ 695 | /* int bar = 10; */ 696 | int baz = foo + bar 697 | < 698 | If either of the above conditions hold then if these lines are uncommented 699 | they will become: > 700 | int foo = 5; 701 | int bar = 10; 702 | int baz = foo + bar 703 | < 704 | Otherwise they would become: > 705 | int foo = 5; 706 | int bar = 10; 707 | int baz = foo + bar 708 | < 709 | 710 | Note: When using 'start' as the default alignment, the enabling of 711 | NERDRemoveExtraSpaces will still result in the removal of a space after the 712 | delimiter. This can be undesirable since aligning the delimiters at the very 713 | start of the line (index 0) will usually result in spaces between the comment 714 | delimiters and the text which probably shouldn't be removed. So when using 715 | 'start' as the default alignment, take care to also disable 716 | NERDRemoveExtraSpaces. 717 | 718 | ------------------------------------------------------------------------------ 719 | *'NERDLPlace'* 720 | *'NERDRPlace'* 721 | Values: arbitrary string. 722 | Default: 723 | NERDLPlace: "[>" 724 | NERDRPlace: "<]" 725 | 726 | These options are used to control the strings used as place-holder delimiters. 727 | Place holder delimiters are used when performing nested commenting when the 728 | filetype supports commenting styles with both left and right delimiters. 729 | To set these options use lines like: > 730 | let NERDLPlace="FOO" 731 | let NERDRPlace="BAR" 732 | < 733 | Following the above example, if we have line of c code: > 734 | /* int horse */ 735 | < 736 | and we comment it with ||cn it will be changed to: > 737 | /*FOO int horse BAR*/ 738 | < 739 | When we uncomment this line it will go back to what it was. 740 | 741 | ------------------------------------------------------------------------------ 742 | *'NERDMenuMode'* 743 | Values: 0, 1, 2, 3. 744 | Default: 3 745 | 746 | This option can take 4 values: 747 | "0": Turns the menu off. 748 | "1": Turns the 'comment' menu on with no menu shortcut. 749 | "2": Turns the 'comment' menu on with -c as the shortcut. 750 | "3": Turns the 'Plugin -> comment' menu on with -c as the shortcut. 751 | 752 | ------------------------------------------------------------------------------ 753 | *'NERDUsePlaceHolders'* 754 | Values: 0 or 1. 755 | Default 1. 756 | 757 | This option is used to specify whether place-holder delimiters should be used 758 | when creating a nested comment. 759 | 760 | ------------------------------------------------------------------------------ 761 | *'NERDSpaceDelims'* 762 | Values: 0 or 1. 763 | Default 0. 764 | 765 | Some people prefer a space after the left delimiter and before the right 766 | delimiter like this: > 767 | /* int foo=2; */ 768 | < 769 | as opposed to this: > 770 | /*int foo=2;*/ 771 | < 772 | If you want spaces to be added then set NERDSpaceDelims to 1 in your vimrc. 773 | 774 | See also |'NERDRemoveExtraSpaces'|. 775 | 776 | ------------------------------------------------------------------------------ 777 | *'NERDTrimTrailingWhitespace'* 778 | Values: 0 or 1. 779 | Default 0. 780 | 781 | When uncommenting an empty line some whitespace may be left as a result of 782 | alignment padding. With this option enabled any trailing whitespace will be 783 | deleted when uncommenting a line. 784 | 785 | ------------------------------------------------------------------------------ 786 | *'NERDDefaultAlign'* 787 | Values: 'none', 'left', 'start', 'both' 788 | Default 'none'. 789 | 790 | Specifies the default alignment to use when inserting comments. 791 | 792 | Note: When using 'start' as the default alignment be sure to disable 793 | NERDRemoveExtraSpaces. See the note at the bottom of |NERDRemoveExtraSpaces| 794 | for more details. 795 | 796 | ------------------------------------------------------------------------------ 797 | *'NERDCompactSexyComs'* 798 | Values: 0 or 1. 799 | Default 0. 800 | 801 | Some people may want their sexy comments to be like this: > 802 | /* Hi There! 803 | * This is a sexy comment 804 | * in c */ 805 | < 806 | As opposed to like this: > 807 | /* 808 | * Hi There! 809 | * This is a sexy comment 810 | * in c 811 | */ 812 | < 813 | If this option is set to 1 then the top style will be used. 814 | 815 | ------------------------------------------------------------------------------ 816 | *'NERDDefaultNesting'* 817 | Values: 0 or 1. 818 | Default 1. 819 | 820 | When this option is set to 1, comments are nested automatically. That is, if 821 | you hit ||cc on a line that is already commented it will be commented 822 | again. 823 | 824 | ------------------------------------------------------------------------------ 825 | *'NERDToggleCheckAllLines'* 826 | Values: 0 or 1. 827 | Default 0. 828 | 829 | When this option is set to 1, NERDCommenterToggle will check all selected line, 830 | if there have oneline not be commented, then comment all lines. 831 | 832 | ------------------------------------------------------------------------------ 833 | *'NERDDisableTabsInBlockComm'* 834 | Values: 0 or 1. 835 | Default 0. 836 | 837 | When this option is set to 1, NERDDisableTabsInBlockComm will not add 838 | whitespaces align the start location of the ending comment symbol with the 839 | end location of the starting comment symbol. For example, in Fortran, the new 840 | style will be as the following: > 841 | close (inpt,iostat=ierr,iomsg=error_message) 842 | call io_error(pname,input_fname,2,__LINE__,__FILE__,ierr,error_message) 843 | < 844 | to > 845 | !===BEGIN===! 846 | ! close (inpt,iostat=ierr,iomsg=error_message) 847 | ! call io_error(pname,input_fname,2,__LINE__,__FILE__,ierr,error_message) 848 | !===END===! 849 | < 850 | for the block comment style if customized comment symbols are set up in vimrc 851 | file by the following line > 852 | let g:NERDCustomDelimiters = { 853 | \ 'fortran':{'left':'!','leftAlt':'!===BEGIN===!','rightAlt':'!===END===!'} 854 | \ } 855 | < 856 | 857 | ------------------------------------------------------------------------------ 858 | 4.3 Default delimiter customisation *NERDCommenterDefaultDelims* 859 | 860 | If you want the NERD commenter to use the alternative delimiters for a 861 | specific filetype by default then put a line of this form into your vimrc: > 862 | let g:NERDAltDelims_ = 1 863 | < 864 | Example: java uses // style comments by default, but you want it to default to 865 | /* */ style comments instead. You would put this line in your vimrc: > 866 | let g:NERDAltDelims_java = 1 867 | < 868 | 869 | See |NERDCommenterAltDelims| for switching commenting styles at runtime. 870 | 871 | ============================================================================== 872 | 5. Key mapping customisation *NERDCommenterMappings* 873 | 874 | To change a mapping just map another key combo to the internal mapping. 875 | For example, to remap the |NERDCommenterComment| mapping to ",omg" you would put 876 | this line in your vimrc: > 877 | map ,omg NERDCommenterComment 878 | < 879 | This will stop the corresponding default mappings from being created. 880 | 881 | See the help for the mapping in question to see which mapping to 882 | map to. 883 | 884 | See also |'NERDCreateDefaultMappings'|. 885 | 886 | ============================================================================== 887 | 6. Interfaces *NERDCommenterInterfaces* 888 | 889 | NERDCommentIsLineCommented({lineNo}) *NERDCommentIsLineCommented()* 890 | Check if the line is a comment 891 | Note this function checks if the line is **completely** a comment 892 | Args: 893 | {lineNo}: the line number of the line to check 894 | Return: Number, 1 if the line is a comment, 0 else 895 | 896 | 897 | NERDComment({mode}, {type}) *NERDComment()* 898 | This function is a Wrapper for the main commenting functions 899 | 900 | Args: 901 | {mode}: character indicating the mode in which the comment 902 | is requested: 903 | 'n' for Normal mode, 'x' for Visual mode 904 | {type}: the type of commenting requested. Can be 'Sexy', 905 | 'Invert', 'Minimal', 'Toggle', 'AlignLeft', 906 | 'AlignBoth', 'Comment', 'Nested', 'ToEOL', 'Append', 907 | 'Insert', 'Uncomment', 'Yank' 908 | 909 | 910 | NERDCommentIsCharCommented({line}, {col}) *NERDCommentIsCharCommented()* 911 | Check if the character at [{line}, {col}] is inside a comment 912 | Note the Comment delimeter it self is considered as part of the 913 | comment 914 | 915 | Args: 916 | {line} the line number of the character 917 | {col} the column number of the character 918 | Return: Number, 1 if the character is inside a comment, 0 else 919 | 920 | 921 | ============================================================================== 922 | 7. Issues with the script *NERDCommenterIssues* 923 | 924 | 925 | ------------------------------------------------------------------------------ 926 | 7.1 Delimiter detection heuristics *NERDCommenterHeuristics* 927 | 928 | Heuristics are used to distinguish the real comment delimiters 929 | 930 | Because we have comment mappings that place delimiters in the middle of lines, 931 | removing comment delimiters is a bit tricky. This is because if comment 932 | delimiters appear in a line doesn't mean they really ARE delimiters. For 933 | example, Java uses // comments but the line > 934 | System.out.println("//"); 935 | < 936 | clearly contains no real comment delimiters. 937 | 938 | To distinguish between ``real'' comment delimiters and ``fake'' ones we use a 939 | set of heuristics. For example, one such heuristic states that any comment 940 | delimiter that has an odd number of non-escaped " characters both preceding 941 | and following it on the line is not a comment because it is probably part of a 942 | string. These heuristics, while usually pretty accurate, will not work for all 943 | cases. 944 | 945 | ------------------------------------------------------------------------------ 946 | 7.2 Nesting issues *NERDCommenterNesting* 947 | 948 | If we have some line of code like this: > 949 | /*int foo */ = /*5 + 9;*/ 950 | < 951 | This will not be uncommented legally. The NERD commenter will remove the 952 | "outer most" delimiters so the line will become: > 953 | int foo */ = /*5 + 9; 954 | < 955 | which almost certainly will not be what you want. Nested sets of comments will 956 | uncomment fine though. E.g.: > 957 | /*int/* foo =*/ 5 + 9;*/ 958 | < 959 | will become: > 960 | int/* foo =*/ 5 + 9; 961 | < 962 | (Note that in the above examples I have deliberately not used place holders 963 | for simplicity) 964 | 965 | ============================================================================== 966 | 8. About *NERDCommenterAbout* 967 | 968 | This plugin was originally written in 2007 by Martin Grenfell, aka @scrooloose 969 | on Github: https://github.com/scrooloose 970 | 971 | Since 2016 it has been maintained primarily by Caleb Maclennan, aka @alerque 972 | on Github: https://github.com/alerque 973 | 974 | Lots of features and many of the supported filetypes have come from the 975 | community, see |NERDCommenterCredits|. 976 | 977 | Additional file type support, bug fixes, and new feature contributons are all 978 | welcome, please send them as Pull Requests on Github. If you can't contribute 979 | yourself please also feel free to open issues to report problems or request 980 | features: https://github.com/preservim/nerdcommenter 981 | 982 | ============================================================================== 983 | 9. Changelog *NERDCommenterChangelog* 984 | 985 | See the included CHANGELOG.md file or the Github Releases page for the latest 986 | info on tagged releases. https://github.com/preservim/nerdcommenter/releases 987 | 988 | The `master` branch is considered stable and will have the latest filetype 989 | support and bugfixes. 990 | 991 | ============================================================================== 992 | 10. Credits *NERDCommenterCredits* 993 | 994 | Well over 100 people have contributed towards this plugin, it's functions, and 995 | specific filetype support. Please check out the up do date list of all 996 | contributors on Github: 997 | 998 | https://github.com/preservim/nerdcommenter/graphs/contributors 999 | 1000 | ============================================================================== 1001 | 11. License *NERDCommenterLicense* 1002 | 1003 | NERD Commenter is released under the Creative-Commons CCO 1.0 Universal 1004 | license. See the included LICENE file for details. 1005 | -------------------------------------------------------------------------------- /plugin/nerdcommenter.vim: -------------------------------------------------------------------------------- 1 | if exists('loaded_nerd_comments') 2 | finish 3 | endif 4 | if v:version < 700 5 | echoerr "NERDCommenter: this plugin requires vim >= 7. DOWNLOAD IT! You'll thank me later!" 6 | finish 7 | endif 8 | let loaded_nerd_comments = 1 9 | 10 | " Function: s:InitVariable() function 11 | " This function is used to initialise a given variable to a given value. The 12 | " variable is only initialised if it does not exist prior 13 | " 14 | " Args: 15 | " -var: the name of the var to be initialised 16 | " -value: the value to initialise var to 17 | " 18 | " Returns: 19 | " 0 20 | function s:InitVariable(var, value) 21 | if !exists(a:var) 22 | execute 'let ' . a:var . ' = ' . string(a:value) 23 | endif 24 | endfunction 25 | 26 | " Section: variable initialization 27 | call s:InitVariable('g:NERDAllowAnyVisualDelims', 1) 28 | call s:InitVariable('g:NERDBlockComIgnoreEmpty', 0) 29 | call s:InitVariable('g:NERDCommentWholeLinesInVMode', 0) 30 | call s:InitVariable('g:NERDCommentEmptyLines', 0) 31 | call s:InitVariable('g:NERDCompactSexyComs', 0) 32 | call s:InitVariable('g:NERDCreateDefaultMappings', 1) 33 | call s:InitVariable('g:NERDDefaultNesting', 1) 34 | call s:InitVariable('g:NERDMenuMode', 3) 35 | call s:InitVariable('g:NERDLPlace', '[>') 36 | call s:InitVariable('g:NERDUsePlaceHolders', 1) 37 | call s:InitVariable('g:NERDRemoveAltComs', 1) 38 | call s:InitVariable('g:NERDRemoveExtraSpaces', 0) 39 | call s:InitVariable('g:NERDRPlace', '<]') 40 | call s:InitVariable('g:NERDSpaceDelims', 0) 41 | call s:InitVariable('g:NERDDefaultAlign', 'none') 42 | call s:InitVariable('g:NERDTrimTrailingWhitespace', 0) 43 | call s:InitVariable('g:NERDToggleCheckAllLines', 0) 44 | call s:InitVariable('g:NERDDisableTabsInBlockComm', 0) 45 | call s:InitVariable('g:NERDSuppressWarnings', 0) 46 | 47 | " Section: Comment mapping and menu item setup 48 | " =========================================================================== 49 | 50 | " Create menu items for the specified modes. If a:combo is not empty, then 51 | " also define mappings and show a:combo in the menu items. 52 | function! s:CreateMaps(modes, target, desc, combo) 53 | " Build up a map command like 54 | " 'noremap NERDCommenterComment :call nerdcommenter#Comment("n", "Comment")' 55 | let plug = 'NERDCommenter' . a:target 56 | let plug_start = 'noremap ' . plug . ' :call nerdcommenter#Comment("' 57 | let plug_end = '", "' . a:target . '")' 58 | " Build up a menu command like 59 | " 'menu comment.Comment\\cc NERDCommenterComment' 60 | let menuRoot = get(['', 'comment', '&comment', '&Plugin.&comment', '&Plugin.Nerd\ &Commenter'], 61 | \ g:NERDMenuMode, '') 62 | let menu_command = 'menu ' . menuRoot . '.' . escape(a:desc, ' ') 63 | if strlen(a:combo) 64 | let leader = exists('g:mapleader') ? g:mapleader : '\' 65 | let menu_command .= '' . escape(leader, '\') . a:combo 66 | endif 67 | let menu_command .= ' ' . (strlen(a:combo) ? plug : a:target) 68 | " Execute the commands built above for each requested mode. 69 | for mode in (a:modes ==# '') ? [''] : split(a:modes, '\zs') 70 | if strlen(a:combo) 71 | execute mode . plug_start . mode . plug_end 72 | if g:NERDCreateDefaultMappings && !hasmapto(plug, mode) 73 | execute mode . 'map ' . a:combo . ' ' . plug 74 | endif 75 | endif 76 | " Check if the user wants the menu to be displayed. 77 | if g:NERDMenuMode !=# 0 78 | execute mode . menu_command 79 | endif 80 | endfor 81 | endfunction 82 | 83 | call s:CreateMaps('nx', 'Comment', 'Comment', 'cc') 84 | call s:CreateMaps('nx', 'Toggle', 'Toggle', 'c') 85 | call s:CreateMaps('nx', 'Minimal', 'Minimal', 'cm') 86 | call s:CreateMaps('nx', 'Nested', 'Nested', 'cn') 87 | call s:CreateMaps('n', 'ToEOL', 'To EOL', 'c$') 88 | call s:CreateMaps('nx', 'Invert', 'Invert', 'ci') 89 | call s:CreateMaps('nx', 'Sexy', 'Sexy', 'cs') 90 | call s:CreateMaps('nx', 'Yank', 'Yank then comment', 'cy') 91 | call s:CreateMaps('n', 'Append', 'Append', 'cA') 92 | call s:CreateMaps('', ':', '-Sep-', '') 93 | call s:CreateMaps('nx', 'AlignLeft', 'Left aligned', 'cl') 94 | call s:CreateMaps('nx', 'AlignBoth', 'Left and right aligned', 'cb') 95 | call s:CreateMaps('', ':', '-Sep2-', '') 96 | call s:CreateMaps('nx', 'Uncomment', 'Uncomment', 'cu') 97 | call s:CreateMaps('n', 'AltDelims', 'Switch Delimiters', 'ca') 98 | call s:CreateMaps('i', 'Insert', 'Insert Comment Here', '') 99 | call s:CreateMaps('', ':', '-Sep3-', '') 100 | call s:CreateMaps('', ':help NERDCommenterContents', 'Help', '') 101 | 102 | " Shim functions so old code gets passed through to the autoload functions 103 | function! NERDComment(mode, type) range 104 | if !g:NERDSuppressWarnings 105 | echom 'Function NERDComment() has been deprecated, please use nerdcommenter#Comment() instead' 106 | endif 107 | if a:firstline != a:lastline 108 | echoerr "Sorry! We can't pass a range through this deprecation shim, please update your code." 109 | return v:false 110 | endif 111 | return nerdcommenter#Comment(a:mode, a:type) 112 | endfunction 113 | 114 | function! NERDCommentIsLineCommented(lineNo) 115 | if !g:NERDSuppressWarnings 116 | echom 'Function NERDCommentIsLineCommented() has been deprecated, please use nerdcommenter#IsLineCommented() instead' 117 | endif 118 | return nerdcommenter#IsLineCommented(a:lineNo) 119 | endfunction 120 | 121 | function! NERDCommentIsCharCommented(line, col) 122 | if !g:NERDSuppressWarnings 123 | echom 'Function NERDCommentIsCharCommented() has been deprecated, please use nerdcommenter#IsCharCommented() instead' 124 | endif 125 | return nerdcommenter#IsCharCommented(a:line, a:col) 126 | endfunction 127 | 128 | inoremap NERDCommenterInsert :call nerdcommenter#Comment('i', "Insert") 129 | 130 | " switch to/from alternative delimiters (does not use wrapper function) 131 | nnoremap NERDCommenterAltDelims :call nerdcommenter#SwitchToAlternativeDelimiters(1) 132 | --------------------------------------------------------------------------------