nerdcommenter.vim 113 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021
  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. let s:NERDFileNameEscape="[]#*$%'\" ?`!&();<>\\"
  8. let s:delimiterMap = {
  9. \ 'aap': { 'left': '#' },
  10. \ 'abc': { 'left': '%' },
  11. \ 'acedb': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  12. \ 'actionscript': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  13. \ 'ada': { 'left': '--', 'leftAlt': '-- ' },
  14. \ 'ahdl': { 'left': '--' },
  15. \ 'ahk': { 'left': ';', 'leftAlt': '/*', 'rightAlt': '*/' },
  16. \ 'amiga': { 'left': ';' },
  17. \ 'aml': { 'left': '/*' },
  18. \ 'ampl': { 'left': '#' },
  19. \ 'ansible': { 'left': '#' },
  20. \ 'apache': { 'left': '#' },
  21. \ 'apachestyle': { 'left': '#' },
  22. \ 'apdl': { 'left': '!' },
  23. \ 'applescript': { 'left': '--', 'leftAlt': '(*', 'rightAlt': '*)' },
  24. \ 'armasm': { 'left': ';' },
  25. \ 'asciidoc': { 'left': '//' },
  26. \ 'asm': { 'left': ';', 'leftAlt': '#' },
  27. \ 'asm68k': { 'left': ';' },
  28. \ 'asn': { 'left': '--' },
  29. \ 'asp': { 'left': '%', 'leftAlt': '%*', 'rightAlt': '*%' },
  30. \ 'aspvbs': { 'left': '''', 'leftAlt': '<!--', 'rightAlt': '-->' },
  31. \ 'asterisk': { 'left': ';' },
  32. \ 'asy': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  33. \ 'atlas': { 'left': 'C', 'right': '$' },
  34. \ 'ats': { 'left': '//', 'leftAlt': '(*', 'rightAlt': '*)' },
  35. \ 'augeas': { 'left': '(*', 'right': '*)' },
  36. \ 'autohotkey': { 'left': ';', 'leftAlt': '/*', 'rightAlt': '*/' },
  37. \ 'autoit': { 'left': ';' },
  38. \ 'ave': { 'left': "'" },
  39. \ 'awk': { 'left': '#' },
  40. \ 'basic': { 'left': "'", 'leftAlt': 'REM ' },
  41. \ 'bbx': { 'left': '%' },
  42. \ 'bc': { 'left': '#' },
  43. \ 'bib': { 'left': '//' },
  44. \ 'bindzone': { 'left': ';' },
  45. \ 'bind-named': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  46. \ 'blade': { 'left': '{{--', 'right': '--}}' },
  47. \ 'bst': { 'left': '%' },
  48. \ 'btm': { 'left': '::' },
  49. \ 'c': { 'left': '/*', 'right': '*/', 'leftAlt': '//' },
  50. \ 'cabal': { 'left': '--' },
  51. \ 'cairo': { 'left': '#' },
  52. \ 'calibre': { 'left': '//' },
  53. \ 'caos': { 'left': '*' },
  54. \ 'catalog': { 'left': '--', 'right': '--' },
  55. \ 'cf': { 'left': '<!---', 'right': '--->' },
  56. \ 'cfg': { 'left': '#' },
  57. \ 'cg': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  58. \ 'ch': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  59. \ 'cl': { 'left': '#' },
  60. \ 'clean': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  61. \ 'clipper': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  62. \ 'clojure': { 'left': ';' },
  63. \ 'cmake': { 'left': '#' },
  64. \ 'cocci': { 'left': '//' },
  65. \ 'coffee': { 'left': '#', 'leftAlt': '###', 'rightAlt': '###' },
  66. \ 'conkyrc': { 'left': '#' },
  67. \ 'context': { 'left': '%', 'leftAlt': '--' },
  68. \ 'coq': { 'left': '(*', 'right': '*)' },
  69. \ 'cpp': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  70. \ 'crontab': { 'left': '#' },
  71. \ 'cs': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  72. \ 'csp': { 'left': '--' },
  73. \ 'cterm': { 'left': '*' },
  74. \ 'cucumber': { 'left': '#' },
  75. \ 'cuda': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  76. \ 'cvs': { 'left': 'CVS:' },
  77. \ 'cypher': { 'left': '//' },
  78. \ 'cython': { 'left': '# ', 'leftAlt': '#' },
  79. \ 'd': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  80. \ 'dakota': { 'left': '#' },
  81. \ 'dcl': { 'left': '$!' },
  82. \ 'debcontrol': { 'left': '#' },
  83. \ 'debsources': { 'left': '#' },
  84. \ 'def': { 'left': ';' },
  85. \ 'desktop': { 'left': '#' },
  86. \ 'dhcpd': { 'left': '#' },
  87. \ 'diff': { 'left': '#' },
  88. \ 'django': { 'left': '{% comment %}', 'right': '{% endcomment %}', 'leftAlt': '{#', 'rightAlt': '#}' },
  89. \ 'dns': { 'left': ';' },
  90. \ 'docbk': { 'left': '<!--', 'right': '-->' },
  91. \ 'dockerfile': { 'left': '#' },
  92. \ 'dosbatch': { 'left': 'REM ', 'leftAlt': '::' },
  93. \ 'dosini': { 'left': ';' },
  94. \ 'dot': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  95. \ 'dracula': { 'left': ';' },
  96. \ 'dsl': { 'left': ';' },
  97. \ 'dtml': { 'left': '<dtml-comment>', 'right': '</dtml-comment>' },
  98. \ 'dylan': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  99. \ 'ebuild': { 'left': '#' },
  100. \ 'ecd': { 'left': '#' },
  101. \ 'eclass': { 'left': '#' },
  102. \ 'eiffel': { 'left': '--' },
  103. \ 'elf': { 'left': "'" },
  104. \ 'elixir': { 'left': '#' },
  105. \ 'elm': { 'left': '--', 'leftAlt': '{--', 'rightAlt': '--}' },
  106. \ 'elmfilt': { 'left': '#' },
  107. \ 'ember-script': { 'left': '#' },
  108. \ 'emblem': { 'left': '/' },
  109. \ 'erlang': { 'left': '%', 'leftAlt': '%%' },
  110. \ 'eruby': { 'left': '<%#', 'right': '%>', 'leftAlt': '<!--', 'rightAlt': '-->' },
  111. \ 'esmtprc': { 'left': '#' },
  112. \ 'exim': { 'left': '#' },
  113. \ 'expect': { 'left': '#' },
  114. \ 'exports': { 'left': '#' },
  115. \ 'factor': { 'left': '! ', 'leftAlt': '!# ' },
  116. \ 'fancy': { 'left': '#' },
  117. \ 'fasm': { 'left': ';' },
  118. \ 'faust': { 'left': '//' },
  119. \ 'fgl': { 'left': '#' },
  120. \ 'fluent': { 'left': '#', 'leftAlt': '##' },
  121. \ 'focexec': { 'left': '-*' },
  122. \ 'form': { 'left': '*' },
  123. \ 'fortran': { 'left': '!' },
  124. \ 'foxpro': { 'left': '*' },
  125. \ 'fsharp': { 'left': '(*', 'right': '*)', 'leftAlt': '//' },
  126. \ 'fstab': { 'left': '#' },
  127. \ 'fvwm': { 'left': '#' },
  128. \ 'fx': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  129. \ 'gams': { 'left': '*' },
  130. \ 'gdb': { 'left': '#' },
  131. \ 'gdmo': { 'left': '--' },
  132. \ 'gdscript3': { 'left': '# ', 'leftAlt': '#' },
  133. \ 'geek': { 'left': 'GEEK_COMMENT:' },
  134. \ 'genshi': { 'left': '<!--', 'right': '-->', 'leftAlt': '{#', 'rightAlt': '#}' },
  135. \ 'gentoo-conf-d': { 'left': '#' },
  136. \ 'gentoo-env-d': { 'left': '#' },
  137. \ 'gentoo-init-d': { 'left': '#' },
  138. \ 'gentoo-make-conf': { 'left': '#' },
  139. \ 'gentoo-package-keywords': { 'left': '#' },
  140. \ 'gentoo-package-mask': { 'left': '#' },
  141. \ 'gentoo-package-use': { 'left': '#' },
  142. \ 'gitcommit': { 'left': '#' },
  143. \ 'gitconfig': { 'left': ';' },
  144. \ 'gitignore': { 'left': '#' },
  145. \ 'gitrebase': { 'left': '#' },
  146. \ 'glsl': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  147. \ 'gnuplot': { 'left': '#' },
  148. \ 'go': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  149. \ 'groff': { 'left': '\#' },
  150. \ 'groovy': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  151. \ 'gsp': { 'left': '<%--', 'right': '--%>', 'leftAlt': '<!--', 'rightAlt': '-->' },
  152. \ 'gtkrc': { 'left': '#' },
  153. \ 'h': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  154. \ 'haml': { 'left': '-#', 'leftAlt': '/' },
  155. \ 'handlebars': { 'left': '{{!-- ', 'right': ' --}}' },
  156. \ 'haskell': { 'left': '--', 'nested': 0, 'leftAlt': '{-', 'rightAlt': '-}', 'nestedAlt': 1 },
  157. \ 'haxe': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  158. \ 'hb': { 'left': '#' },
  159. \ 'hbs': { 'left': '{{!-- ', 'right': ' --}}' },
  160. \ 'hercules': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  161. \ 'hive': { 'left': '-- ' },
  162. \ 'hocon': { 'left': '//', 'leftAlt': '#' },
  163. \ 'hog': { 'left': '#' },
  164. \ 'hostsaccess': { 'left': '#' },
  165. \ 'htmlcheetah': { 'left': '##' },
  166. \ 'htmldjango': { 'left': '{% comment %}', 'right': '{% endcomment %}', 'leftAlt': '{#', 'rightAlt': '#}' },
  167. \ 'htmlos': { 'left': '#', 'right': '/#' },
  168. \ 'hxml': { 'left': '#' },
  169. \ 'hyphy': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  170. \ 'ia64': { 'left': '#' },
  171. \ 'icon': { 'left': '#' },
  172. \ 'idl': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  173. \ 'idlang': { 'left': ';' },
  174. \ 'idris': { 'leftAlt': '--', 'left': '{-', 'right': '-}' },
  175. \ 'incar': { 'left': '!' },
  176. \ 'inform': { 'left': '!' },
  177. \ 'inittab': { 'left': '#' },
  178. \ 'ishd': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  179. \ 'iss': { 'left': ';' },
  180. \ 'ist': { 'left': '%' },
  181. \ 'jade': { 'left': '//-', 'leftAlt': '//' },
  182. \ 'java': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  183. \ 'javacc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  184. \ 'javascript': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  185. \ 'javascriptreact': { 'left': '//', 'leftAlt': '{/*', 'rightAlt': '*/}' },
  186. \ 'javascript.jquery': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  187. \ 'jess': { 'left': ';' },
  188. \ 'jgraph': { 'left': '(*', 'right': '*)' },
  189. \ 'jinja': { 'left': '{#', 'right': '#}', 'leftAlt': '<!--', 'rightAlt': '-->' },
  190. \ 'jproperties': { 'left': '#' },
  191. \ 'json5': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  192. \ 'jsonc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  193. \ 'jsonnet': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  194. \ 'jsp': { 'left': '<%--', 'right': '--%>' },
  195. \ 'julia': { 'left': '# ', 'leftAlt': '#=', 'rightAlt': '=#' },
  196. \ 'kivy': { 'left': '#' },
  197. \ 'kix': { 'left': ';' },
  198. \ 'kscript': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  199. \ 'lace': { 'left': '--' },
  200. \ 'laravel': { 'left': '{{--', 'right': '--}}' },
  201. \ 'ldif': { 'left': '#' },
  202. \ 'lean': { 'left': '--', 'leftAlt': '/-', 'rightAlt': '-/' },
  203. \ 'ledger': { 'left': '#', 'leftAlt': ';' },
  204. \ 'less': { 'left': '/*', 'right': '*/' },
  205. \ 'lhaskell': { 'left': '>{-', 'right': '-}', 'leftAlt': '>-- ' },
  206. \ 'lilo': { 'left': '#' },
  207. \ 'lilypond': { 'left': '%' },
  208. \ 'liquid': { 'left': '{% comment %}', 'right': '{% endcomment %}' },
  209. \ 'lisp': { 'left': ';', 'nested': 1, 'leftAlt': '#|', 'rightAlt': '|#', 'nestedAlt': 1 },
  210. \ 'llvm': { 'left': ';' },
  211. \ 'lotos': { 'left': '(*', 'right': '*)' },
  212. \ 'lout': { 'left': '#' },
  213. \ 'lpc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  214. \ 'lprolog': { 'left': '%' },
  215. \ 'lscript': { 'left': "'" },
  216. \ 'lss': { 'left': '#' },
  217. \ 'lua': { 'left': '--', 'leftAlt': '--[[', 'rightAlt': ']]' },
  218. \ 'lynx': { 'left': '#' },
  219. \ 'lytex': { 'left': '%' },
  220. \ 'm4': { 'left': 'dnl ' },
  221. \ 'mail': { 'left': '> ' },
  222. \ 'mako': { 'left': '##' },
  223. \ 'man': { 'left': '."' },
  224. \ 'mandoc': { 'left': '.\\"' },
  225. \ 'map': { 'left': '%' },
  226. \ 'maple': { 'left': '#' },
  227. \ 'markdown': { 'left': '<!--', 'right': '-->' },
  228. \ 'masm': { 'left': ';' },
  229. \ 'mason': { 'left': '<% #', 'right': '%>' },
  230. \ 'master': { 'left': '$' },
  231. \ 'matlab': { 'left': '%', 'leftAlt': '%{', 'rightAlt': '%}' },
  232. \ 'mel': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  233. \ 'meson': { 'left': '#' },
  234. \ 'mib': { 'left': '--' },
  235. \ 'minizinc': { 'left': '% ', 'leftAlt': '/*', 'rightAlt': '*/' },
  236. \ 'mips': { 'left': '#' },
  237. \ 'mirah': {'left': '#' },
  238. \ 'mkd': { 'left': '<!---', 'right': '-->' },
  239. \ 'mma': { 'left': '(*', 'right': '*)' },
  240. \ 'model': { 'left': '$', 'right': '$' },
  241. \ 'modula2': { 'left': '(*', 'right': '*)' },
  242. \ 'modula3': { 'left': '(*', 'right': '*)' },
  243. \ 'molpro': { 'left': '!' },
  244. \ 'monk': { 'left': ';' },
  245. \ 'mush': { 'left': '#' },
  246. \ 'mustache': { 'left': '{{!', 'right': '}}' },
  247. \ 'nagios': { 'left': ';' },
  248. \ 'named': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  249. \ 'nasm': { 'left': ';' },
  250. \ 'nastran': { 'left': '$' },
  251. \ 'natural': { 'left': '/*' },
  252. \ 'ncf': { 'left': ';' },
  253. \ 'newlisp': { 'left': ';' },
  254. \ 'nginx': { 'left': '#' },
  255. \ 'nimrod': { 'left': '#' },
  256. \ 'nix': { 'left': '#' },
  257. \ 'nroff': { 'left': '\"' },
  258. \ 'nsis': { 'left': '#' },
  259. \ 'ntp': { 'left': '#' },
  260. \ 'objc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  261. \ 'objcpp': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  262. \ 'objj': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  263. \ 'ocaml': { 'left': '(*', 'right': '*)', 'nested': 1 },
  264. \ 'occam': { 'left': '--' },
  265. \ 'octave': { 'left': '%', 'leftAlt': '#' },
  266. \ 'omlet': { 'left': '(*', 'right': '*)' },
  267. \ 'omnimark': { 'left': ';' },
  268. \ 'ooc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  269. \ 'openroad': { 'left': '//' },
  270. \ 'opl': { 'left': 'REM' },
  271. \ 'ora': { 'left': '#' },
  272. \ 'ox': { 'left': '//' },
  273. \ 'paludis-use-conf': { 'left': '#' },
  274. \ 'pandoc': { 'left': '<!--', 'right': '-->' },
  275. \ 'pascal': { 'left': '{', 'right': '}', 'leftAlt': '(*', 'rightAlt': '*)' },
  276. \ 'patran': { 'left': '$', 'leftAlt': '/*', 'rightAlt': '*/' },
  277. \ 'pcap': { 'left': '#' },
  278. \ 'pccts': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  279. \ 'pdf': { 'left': '%' },
  280. \ 'perl': { 'left': '#' },
  281. \ 'pfmain': { 'left': '//' },
  282. \ 'php': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  283. \ 'pic': { 'left': ';' },
  284. \ 'pike': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  285. \ 'pilrc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  286. \ 'pine': { 'left': '#' },
  287. \ 'plm': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  288. \ 'plsql': { 'left': '-- ', 'leftAlt': '/*', 'rightAlt': '*/' },
  289. \ 'po': { 'left': '#' },
  290. \ 'poscar': { 'left': '!' },
  291. \ 'postscr': { 'left': '%' },
  292. \ 'pov': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  293. \ 'povini': { 'left': ';' },
  294. \ 'ppd': { 'left': '%' },
  295. \ 'ppwiz': { 'left': ';;' },
  296. \ 'praat': { 'left': '#' },
  297. \ 'privoxy': { 'left': '#' },
  298. \ 'processing': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  299. \ 'prolog': { 'left': '%', 'leftAlt': '/*', 'rightAlt': '*/' },
  300. \ 'proto': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  301. \ 'ps1': { 'left': '#' },
  302. \ 'psf': { 'left': '#' },
  303. \ 'ptcap': { 'left': '#' },
  304. \ 'pug': { 'left': '//-', 'leftAlt': '//' },
  305. \ 'puppet': { 'left': '#' },
  306. \ 'pyrex': { 'left': '# ', 'leftAlt': '#' },
  307. \ 'python': { 'left': '# ', 'leftAlt': '#' },
  308. \ 'r': { 'left': '#', 'leftAlt': '#''' },
  309. \ 'racket': { 'left': ';', 'nested': 1, 'leftAlt': '#|', 'rightAlt': '|#', 'nestedAlt': 1 },
  310. \ 'radiance': { 'left': '#' },
  311. \ 'ratpoison': { 'left': '#' },
  312. \ 'rc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  313. \ 'rebol': { 'left': ';' },
  314. \ 'registry': { 'left': ';' },
  315. \ 'rego': { 'left': '#' },
  316. \ 'remind': { 'left': '#' },
  317. \ 'renpy': { 'left': '# ' },
  318. \ 'resolv': { 'left': '#' },
  319. \ 'rgb': { 'left': '!' },
  320. \ 'rib': { 'left': '#' },
  321. \ 'rmd': { 'left': '<!--', 'right': '-->', 'leftAlt': '#' },
  322. \ 'robot': { 'left': '#' },
  323. \ 'robots': { 'left': '#' },
  324. \ 'rspec': { 'left': '#' },
  325. \ 'ruby': { 'left': '#' },
  326. \ 'rust': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  327. \ 'sa': { 'left': '--' },
  328. \ 'samba': { 'left': ';', 'leftAlt': '#' },
  329. \ 'sass': { 'left': '//', 'leftAlt': '/*' },
  330. \ 'sather': { 'left': '--' },
  331. \ 'scala': { 'left': '//', 'nested': 1, 'leftAlt': '/*', 'rightAlt': '*/', 'nestedAlt': 1 },
  332. \ 'scheme': { 'left': ';', 'nested': 1, 'leftAlt': '#|', 'rightAlt': '|#', 'nestedAlt': 1 },
  333. \ 'scilab': { 'left': '//' },
  334. \ 'scilla': { 'left': '(*', 'right': '*)', 'nested': 1 },
  335. \ 'scons': { 'left': '#' },
  336. \ 'scsh': { 'left': ';' },
  337. \ 'scss': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  338. \ 'sdc': { 'left': '#' },
  339. \ 'sed': { 'left': '#' },
  340. \ 'sentinel': { 'left': '#', 'leftAlt': '/*', 'rightAlt': '*/' },
  341. \ 'sgmldecl': { 'left': '--', 'right': '--' },
  342. \ 'sgmllnx': { 'left': '<!--', 'right': '-->' },
  343. \ 'sh': { 'left': '#' },
  344. \ 'shader_test': { 'left': '#' },
  345. \ 'sicad': { 'left': '*' },
  346. \ 'sile': { 'left': '%', 'leftAlt': '--' },
  347. \ 'simula': { 'left': '%', 'leftAlt': '--' },
  348. \ 'sinda': { 'left': '$' },
  349. \ 'skill': { 'left': ';' },
  350. \ 'slang': { 'left': '%' },
  351. \ 'slice': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  352. \ 'slim': { 'left': '/', 'leftAlt': '/!' },
  353. \ 'slrnrc': { 'left': '%' },
  354. \ 'sls': { 'left': '#' },
  355. \ 'sm': { 'left': '#' },
  356. \ 'smarty': { 'left': '{*', 'right': '*}' },
  357. \ 'smil': { 'left': '<!', 'right': '>' },
  358. \ 'smith': { 'left': ';' },
  359. \ 'sml': { 'left': '(*', 'right': '*)', 'nested': 1 },
  360. \ 'snakemake': { 'left': '#' },
  361. \ 'snippets': { 'left': '#' },
  362. \ 'snnsnet': { 'left': '#' },
  363. \ 'snnspat': { 'left': '#' },
  364. \ 'snnsres': { 'left': '#' },
  365. \ 'snobol4': { 'left': '*' },
  366. \ 'spec': { 'left': '#' },
  367. \ 'specman': { 'left': '//' },
  368. \ 'spectre': { 'left': '//', 'leftAlt': '*' },
  369. \ 'spice': { 'left': '$' },
  370. \ 'spin': { 'left': '''', 'leftAlt': '{', 'rightAlt': '}' },
  371. \ 'sql': { 'left': '-- ', 'leftAlt': '/*', 'rightAlt': '*/' },
  372. \ 'sqlforms': { 'left': '-- ' },
  373. \ 'sqlj': { 'left': '-- ' },
  374. \ 'sqr': { 'left': '!' },
  375. \ 'squid': { 'left': '#' },
  376. \ 'ss': { 'left': ';', 'leftAlt': '#|', 'rightAlt': '|#' },
  377. \ 'sshconfig': { 'left': '#' },
  378. \ 'sshdconfig': { 'left': '#' },
  379. \ 'st': { 'left': '"' },
  380. \ 'stan': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  381. \ 'stp': { 'left': '/*', 'right': '*/', 'leftAlt': '//' },
  382. \ 'supercollider': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  383. \ 'swift': { 'left': '/*', 'right': '*/', 'leftAlt': '//' },
  384. \ 'systemverilog': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  385. \ 'tads': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  386. \ 'tags': { 'left': ';' },
  387. \ 'tak': { 'left': '$' },
  388. \ 'tasm': { 'left': ';' },
  389. \ 'tcl': { 'left': '#' },
  390. \ 'teak': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  391. \ 'terraform': { 'left': '#', 'leftAlt': '/*', 'rightAlt': '*/' },
  392. \ 'tex': { 'left': '%' },
  393. \ 'texinfo': { 'left': '@c ' },
  394. \ 'texmf': { 'left': '%' },
  395. \ 'tf': { 'left': '#' },
  396. \ 'tidy': { 'left': '#' },
  397. \ 'tla': { 'left': '\\*', 'leftAlt': '(*', 'rightAlt': '*)' },
  398. \ 'tli': { 'left': '#' },
  399. \ 'tmux': { 'left': '#' },
  400. \ 'toml': { 'left': '#' },
  401. \ 'trasys': { 'left': '$' },
  402. \ 'troff': { 'left': '.\\"' },
  403. \ 'tsalt': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  404. \ 'tsscl': { 'left': '#' },
  405. \ 'tssgm': { 'left': "comment = '", 'right': "'" },
  406. \ 'ttl': { 'left': '#' },
  407. \ 'tup': { 'left': '#' },
  408. \ 'twig': { 'left': '{#', 'right': '#}' },
  409. \ 'txt2tags': { 'left': '%' },
  410. \ 'typescript': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  411. \ 'typescriptreact': { 'left': '//', 'leftAlt': '{/*', 'rightAlt': '*/}' },
  412. \ 'uc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  413. \ 'uc4': { 'left': '!' },
  414. \ 'uil': { 'left': '!' },
  415. \ 'upstart': { 'left': '#' },
  416. \ 'vala': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  417. \ 'vasp': { 'left': '!' },
  418. \ 'vb': { 'left': "'" },
  419. \ 'velocity': { 'left': '##', 'right': '', 'leftAlt': '#*', 'rightAlt': '*#' },
  420. \ 'vera': { 'left': '/*', 'right': '*/', 'leftAlt': '//' },
  421. \ 'verilog': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  422. \ 'verilog_systemverilog': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' },
  423. \ 'vgrindefs': { 'left': '#' },
  424. \ 'vhdl': { 'left': '--' },
  425. \ 'vimperator': { 'left': '"' },
  426. \ 'virata': { 'left': '%' },
  427. \ 'vrml': { 'left': '#' },
  428. \ 'vsejcl': { 'left': '/*' },
  429. \ 'webmacro': { 'left': '##' },
  430. \ 'wget': { 'left': '#' },
  431. \ 'wikipedia': { 'left': '<!--', 'right': '-->' },
  432. \ 'winbatch': { 'left': ';' },
  433. \ 'wml': { 'left': '#' },
  434. \ 'wvdial': { 'left': ';' },
  435. \ 'xdefaults': { 'left': '!' },
  436. \ 'xkb': { 'left': '//' },
  437. \ 'xmath': { 'left': '#' },
  438. \ 'xpm2': { 'left': '!' },
  439. \ 'xquery': { 'left': '(:', 'right': ':)' },
  440. \ 'yaml': { 'left': '#' },
  441. \ 'z8a': { 'left': ';' },
  442. \ 'zig': { 'left': '//' }
  443. \ }
  444. let g:NERDDelimiterMap = s:delimiterMap
  445. let nerdcommenter#delimiterMap = s:delimiterMap
  446. if exists('g:NERDCustomDelimiters')
  447. call extend(s:delimiterMap, g:NERDCustomDelimiters)
  448. endif
  449. " Section: Comment mapping functions, autocommands and commands
  450. " ============================================================================
  451. " Function: nerdcommenter#SetUp() function
  452. " This function is responsible for setting up buffer scoped variables for the
  453. " current buffer.
  454. function! nerdcommenter#SetUp() abort
  455. if exists('b:NERDCommenterDelims')
  456. return
  457. endif
  458. let filetype = &filetype
  459. "for compound filetypes, if we don't know how to handle the full filetype
  460. "then break it down and use the first part that we know how to handle
  461. if filetype =~# '\.' && !has_key(s:delimiterMap, filetype)
  462. let filetypes = split(filetype, '\.')
  463. for i in filetypes
  464. if has_key(s:delimiterMap, i)
  465. let filetype = i
  466. break
  467. endif
  468. endfor
  469. endif
  470. let b:NERDSexyComMarker = ''
  471. if has_key(s:delimiterMap, filetype)
  472. let b:NERDCommenterDelims = s:delimiterMap[filetype]
  473. for i in ['left', 'leftAlt', 'right', 'rightAlt']
  474. if !has_key(b:NERDCommenterDelims, i)
  475. let b:NERDCommenterDelims[i] = ''
  476. endif
  477. endfor
  478. for i in ['nested', 'nestedAlt']
  479. if !has_key(b:NERDCommenterDelims, i)
  480. let b:NERDCommenterDelims[i] = 0
  481. endif
  482. endfor
  483. " if g:NERD_<filetype>_alt_style is defined, use the alternate style
  484. let b:NERDCommenterFirstInit = getbufvar(1,'NERDCommenterFirstInit')
  485. if exists('g:NERDAltDelims_'.filetype) && eval('g:NERDAltDelims_'.filetype) && !b:NERDCommenterFirstInit
  486. call nerdcommenter#SwitchToAlternativeDelimiters(0)
  487. let b:NERDCommenterFirstInit = 1
  488. endif
  489. else
  490. let b:NERDCommenterDelims = s:CreateDelimMapFromCms()
  491. endif
  492. endfunction
  493. function! s:CreateDelimMapFromCms() abort
  494. if &filetype ==# '' && exists('g:NERDDefaultDelims')
  495. let delims = g:NERDDefaultDelims
  496. for i in ['left', 'leftAlt', 'right', 'rightAlt']
  497. if !has_key(delims, i)
  498. let delims[i] = ''
  499. endif
  500. endfor
  501. return delims
  502. endif
  503. return {
  504. \ 'left': matchstr(&commentstring, '^\S*\ze\s*%s'),
  505. \ 'right': matchstr(&commentstring, '%s\s*\zs.*$'),
  506. \ 'nested': 0,
  507. \ 'leftAlt': '',
  508. \ 'rightAlt': '',
  509. \ 'nestedAlt': 0}
  510. endfunction
  511. " Function: nerdcommenter#SwitchToAlternativeDelimiters(printMsgs) function
  512. " This function is used to swap the delimiters that are being used to the
  513. " alternative delimiters for that filetype. For example, if a c++ file is
  514. " being edited and // comments are being used, after this function is called
  515. " /**/ comments will be used.
  516. "
  517. " Args:
  518. " -printMsgs: if this is 1 then a message is echoed to the user telling them
  519. " if this function changed the delimiters or not
  520. " function nerdcommenter#SwitchToAlternativeDelimiters(printMsgs)
  521. function! nerdcommenter#SwitchToAlternativeDelimiters(printMsgs) abort
  522. call nerdcommenter#SetUp()
  523. if exists('*NERDCommenter_before')
  524. exe 'call NERDCommenter_before()'
  525. endif
  526. "if both of the alternative delimiters are empty then there is no
  527. "alternative comment style so bail out
  528. if b:NERDCommenterDelims['leftAlt'] ==# '' && b:NERDCommenterDelims['rightAlt'] ==# ''
  529. if a:printMsgs
  530. call s:NerdEcho('Cannot use alternative delimiters, none are specified', 0)
  531. endif
  532. return 0
  533. endif
  534. "save the current delimiters
  535. let tempLeft = s:Left()
  536. let tempRight = s:Right()
  537. let tempNested = s:Nested()
  538. "swap current delimiters for alternative
  539. let b:NERDCommenterDelims['left'] = b:NERDCommenterDelims['leftAlt']
  540. let b:NERDCommenterDelims['right'] = b:NERDCommenterDelims['rightAlt']
  541. "set information on whether these are nested
  542. let b:NERDCommenterDelims['nested'] = b:NERDCommenterDelims['nestedAlt']
  543. "set the previously current delimiters to be the new alternative ones
  544. let b:NERDCommenterDelims['leftAlt'] = tempLeft
  545. let b:NERDCommenterDelims['rightAlt'] = tempRight
  546. let b:NERDCommenterDelims['nestedAlt'] = tempNested
  547. "tell the user what comment delimiters they are now using
  548. if a:printMsgs
  549. call s:NerdEcho('Now using ' . s:Left() . ' ' . s:Right() . ' to delimit comments', 1)
  550. endif
  551. if exists('*NERDCommenter_after')
  552. exe 'call NERDCommenter_after()'
  553. endif
  554. return 1
  555. endfunction
  556. " Section: Comment delimiter add/removal functions
  557. " ============================================================================
  558. " Function: s:AppendCommentToLine()
  559. " This function appends comment delimiters at the EOL and places the cursor in
  560. " position to start typing the comment
  561. function! s:AppendCommentToLine() abort
  562. let left = s:Left({'space': 1})
  563. let right = s:Right({'space': 1})
  564. " get the length of the right delimiter
  565. let lenRight = strlen(right)
  566. let isLineEmpty = strlen(getline('.')) ==# 0
  567. let insOrApp = (isLineEmpty==#1 ? 'i' : 'A')
  568. "stick the delimiters down at the end of the line. We have to format the
  569. "comment with spaces as appropriate
  570. execute ':normal! ' . insOrApp . (isLineEmpty ? '' : ' ') . left . right
  571. " if there is a right delimiter then we gotta move the cursor left
  572. " by the length of the right delimiter so we insert between the delimiters
  573. if lenRight > 0
  574. let leftMoveAmount = lenRight - 1
  575. execute ':normal! ' . leftMoveAmount . 'h'
  576. startinsert
  577. else
  578. startinsert!
  579. endif
  580. endfunction
  581. " Function: s:CommentBlock(top, bottom, lSide, rSide, forceNested )
  582. " This function is used to comment out a region of code. This region is
  583. " specified as a bounding box by arguments to the function.
  584. "
  585. " Args:
  586. " -top: the line number for the top line of code in the region
  587. " -bottom: the line number for the bottom line of code in the region
  588. " -lSide: the column number for the left most column in the region
  589. " -rSide: the column number for the right most column in the region
  590. " -forceNested: a flag indicating whether comments should be nested
  591. function! s:CommentBlock(top, bottom, lSide, rSide, forceNested) abort
  592. " we need to create local copies of these arguments so we can modify them
  593. let top = a:top
  594. let bottom = a:bottom
  595. let lSide = a:lSide
  596. let rSide = a:rSide
  597. "if the top or bottom line starts with tabs we have to adjust the left and
  598. "right boundaries so that they are set as though the tabs were spaces
  599. let topline = getline(top)
  600. let bottomline = getline(bottom)
  601. if s:HasLeadingTabs(topline, bottomline)
  602. "find out how many tabs are in the top line and adjust the left
  603. "boundary accordingly
  604. let numTabs = s:NumberOfLeadingTabs(topline)
  605. if lSide < numTabs
  606. let lSide = &tabstop * lSide
  607. else
  608. let lSide = (lSide - numTabs) + (&tabstop * numTabs)
  609. endif
  610. "find out how many tabs are in the bottom line and adjust the right
  611. "boundary accordingly
  612. let numTabs = s:NumberOfLeadingTabs(bottomline)
  613. let rSide = (rSide - numTabs) + (&tabstop * numTabs)
  614. endif
  615. "we must check that bottom IS actually below top, if it is not then we
  616. "swap top and bottom. Similarly for left and right.
  617. if bottom < top
  618. let temp = top
  619. let top = bottom
  620. let bottom = top
  621. endif
  622. if rSide < lSide
  623. let temp = lSide
  624. let lSide = rSide
  625. let rSide = temp
  626. endif
  627. "if the current delimiters aren't multipart then we will switch to the
  628. "alternative delimiters (if THEY are) as the comment will be better and more
  629. "accurate with multipart delimiters
  630. let switchedDelims = 0
  631. if !s:Multipart() && g:NERDAllowAnyVisualDelims && s:AltMultipart()
  632. let switchedDelims = 1
  633. call nerdcommenter#SwitchToAlternativeDelimiters(0)
  634. endif
  635. "start the commenting from the top and keep commenting till we reach the
  636. "bottom
  637. let currentLine=top
  638. while currentLine <= bottom
  639. "check if we are allowed to comment this line
  640. if s:CanCommentLine(a:forceNested, currentLine)
  641. "convert the leading tabs into spaces
  642. let theLine = getline(currentLine)
  643. let lineHasLeadTabs = s:HasLeadingTabs(theLine)
  644. if lineHasLeadTabs
  645. let theLine = s:ConvertLeadingTabsToSpaces(theLine)
  646. endif
  647. "don't comment lines that begin after the right boundary of the
  648. "block unless the user has specified to do so
  649. if theLine !~# '^ \{' . rSide . '\}' || !g:NERDBlockComIgnoreEmpty
  650. "attempt to place the cursor in on the left of the boundary box,
  651. "then check if we were successful, if not then we cant comment this
  652. "line
  653. call setline(currentLine, theLine)
  654. if s:CanPlaceCursor(currentLine, lSide)
  655. let leftSpaced = s:Left({'space': 1})
  656. let rightSpaced = s:Right({'space': 1})
  657. "stick the left delimiter down
  658. let theLine = strpart(theLine, 0, lSide-1) . leftSpaced . strpart(theLine, lSide-1)
  659. if s:Multipart()
  660. "stick the right delimiter down
  661. "byte idx of the char next to the last char = (byte idx of last char + 1) + (last char byte len) - 1
  662. let rIndex = (rSide+strlen(leftSpaced)) + strlen(strcharpart(strpart(theLine, rSide+strlen(leftSpaced)-1), 0, 1)) - 1
  663. let theLine = strpart(theLine, 0, rIndex) . rightSpaced . strpart(theLine, rIndex)
  664. let firstLeftDelim = s:FindDelimiterIndex(s:Left(), theLine)
  665. let lastRightDelim = s:LastIndexOfDelim(s:Right(), theLine)
  666. if firstLeftDelim !=# -1 && lastRightDelim !=# -1
  667. let searchStr = strpart(theLine, 0, lastRightDelim)
  668. let searchStr = strpart(searchStr, firstLeftDelim+strlen(s:Left()))
  669. "replace the outer most delimiters in searchStr with
  670. "place-holders
  671. let theLineWithPlaceHolders = s:ReplaceDelims(s:Left(), s:Right(), g:NERDLPlace, g:NERDRPlace, searchStr)
  672. "add the right delimiter onto the line
  673. let theLine = strpart(theLine, 0, firstLeftDelim+strlen(s:Left())) . theLineWithPlaceHolders . strpart(theLine, lastRightDelim)
  674. endif
  675. endif
  676. endif
  677. endif
  678. "restore tabs if needed
  679. if lineHasLeadTabs
  680. let theLine = s:ConvertLeadingSpacesToTabs(theLine)
  681. endif
  682. if g:NERDTrimTrailingWhitespace ==# 1
  683. let theLine = s:TrimTrailingWhitespace(theLine)
  684. endif
  685. call setline(currentLine, theLine)
  686. endif
  687. let currentLine = currentLine + 1
  688. endwhile
  689. "if we switched delimiterss then we gotta go back to what they were before
  690. if switchedDelims ==# 1
  691. call nerdcommenter#SwitchToAlternativeDelimiters(0)
  692. endif
  693. endfunction
  694. " Function: s:CommentLines(forceNested, alignLeft, alignRight, firstLine, lastLine)
  695. " This function comments a range of lines.
  696. "
  697. " Args:
  698. " -forceNested: a flag indicating whether the called is requesting the comment
  699. " to be nested if need be
  700. " -align: should be "left", "start", "both" or "none"
  701. " -firstLine/lastLine: the top and bottom lines to comment
  702. function! s:CommentLines(forceNested, align, firstLine, lastLine) abort
  703. " we need to get the left and right indexes of the leftmost char in the
  704. " block of of lines and the right most char so that we can do alignment of
  705. " the delimiters if the user has specified
  706. let leftAlignIndx = a:align ==# 'start' ? 0 : s:LeftMostIndx(a:forceNested, 0, a:firstLine, a:lastLine)
  707. let rightAlignIndx = s:RightMostIndx(a:forceNested, 0, a:firstLine, a:lastLine)
  708. " gotta add the length of the left delimiter onto the rightAlignIndx cos
  709. " we'll be adding a left delimiter to the line
  710. let rightAlignIndx = rightAlignIndx + strlen(s:Left({'space': 1}))
  711. " now we actually comment the lines. Do it line by line
  712. let currentLine = a:firstLine
  713. while currentLine <= a:lastLine
  714. " get the next line, check commentability and convert spaces to tabs
  715. let theLine = getline(currentLine)
  716. let lineHasLeadingTabs = s:HasLeadingTabs(theLine)
  717. let theLine = s:ConvertLeadingTabsToSpaces(theLine)
  718. if s:CanCommentLine(a:forceNested, currentLine)
  719. "if the user has specified forceNesting then we check to see if we
  720. "need to switch delimiters for place-holders
  721. if a:forceNested && g:NERDUsePlaceHolders && !s:Nested()
  722. let theLine = s:SwapOuterMultiPartDelimsForPlaceHolders(theLine)
  723. endif
  724. " find out if the line is commented using normal delimiters and/or
  725. " alternate ones
  726. let isCommented = s:IsCommented(s:Left(), s:Right(), theLine) || s:IsCommented(s:Left({'alt': 1}), s:Right({'alt': 1}), theLine)
  727. " check if we can comment this line
  728. if !isCommented || g:NERDUsePlaceHolders || s:Multipart()
  729. if a:align ==# 'left' || a:align ==# 'start' || a:align ==# 'both'
  730. let theLine = s:AddLeftDelimAligned(s:Left({'space': 1}), theLine, leftAlignIndx)
  731. else
  732. let theLine = s:AddLeftDelim(s:Left({'space': 1}), theLine)
  733. endif
  734. if a:align ==# 'both'
  735. let theLine = s:AddRightDelimAligned(s:Right({'space': 1}), theLine, rightAlignIndx)
  736. else
  737. let theLine = s:AddRightDelim(s:Right({'space': 1}), theLine)
  738. endif
  739. endif
  740. endif
  741. " restore leading tabs if appropriate
  742. if lineHasLeadingTabs
  743. let theLine = s:ConvertLeadingSpacesToTabs(theLine)
  744. endif
  745. if g:NERDTrimTrailingWhitespace ==# 1
  746. let theLine = s:TrimTrailingWhitespace(theLine)
  747. endif
  748. " we are done with this line
  749. call setline(currentLine, theLine)
  750. let currentLine = currentLine + 1
  751. endwhile
  752. endfunction
  753. " Function: s:CommentLinesMinimal(firstLine, lastLine)
  754. " This function comments a range of lines in a minimal style. I
  755. "
  756. " Args:
  757. " -firstLine/lastLine: the top and bottom lines to comment
  758. function! s:CommentLinesMinimal(firstLine, lastLine) abort
  759. "check that minimal comments can be done on this filetype
  760. if !s:HasMultipartDelims()
  761. throw 'NERDCommenter.Delimiters exception: Minimal comments can only be used for filetypes that have multipart delimiters'
  762. endif
  763. let sexyNested = s:SexyNested()
  764. "if we need to use place holders for the comment, make sure they are
  765. "enabled for this filetype, or the delimiterss allow nesting
  766. if !g:NERDUsePlaceHolders && !sexyNested && s:DoesBlockHaveMultipartDelim(a:firstLine, a:lastLine)
  767. throw 'NERDCommenter.Settings exception: Place holders are required but disabled.'
  768. endif
  769. "get the left and right delimiters to smack on
  770. let left = s:GetSexyComLeft(g:NERDSpaceDelims,0)
  771. let right = s:GetSexyComRight(g:NERDSpaceDelims,0)
  772. "make sure all multipart delimiters on the lines are replaced with
  773. "placeholders to prevent illegal syntax
  774. if !sexyNested
  775. let currentLine = a:firstLine
  776. while(currentLine <= a:lastLine)
  777. let theLine = getline(currentLine)
  778. let theLine = s:ReplaceDelims(left, right, g:NERDLPlace, g:NERDRPlace, theLine)
  779. call setline(currentLine, theLine)
  780. let currentLine = currentLine + 1
  781. endwhile
  782. endif
  783. "add the delimiter to the top line
  784. let theLine = getline(a:firstLine)
  785. let lineHasLeadingTabs = s:HasLeadingTabs(theLine)
  786. let theLine = s:ConvertLeadingTabsToSpaces(theLine)
  787. let theLine = s:AddLeftDelim(left, theLine)
  788. if lineHasLeadingTabs
  789. let theLine = s:ConvertLeadingSpacesToTabs(theLine)
  790. endif
  791. call setline(a:firstLine, theLine)
  792. "add the delimiter to the bottom line
  793. let theLine = getline(a:lastLine)
  794. let lineHasLeadingTabs = s:HasLeadingTabs(theLine)
  795. let theLine = s:ConvertLeadingTabsToSpaces(theLine)
  796. let theLine = s:AddRightDelim(right, theLine)
  797. if lineHasLeadingTabs
  798. let theLine = s:ConvertLeadingSpacesToTabs(theLine)
  799. endif
  800. if g:NERDTrimTrailingWhitespace ==# 1
  801. let theLine = s:TrimTrailingWhitespace(theLine)
  802. endif
  803. call setline(a:lastLine, theLine)
  804. endfunction
  805. " Function: s:CommentLinesSexy(topline, bottomline) function
  806. " This function is used to comment lines in the 'Sexy' style. E.g., in c:
  807. " /*
  808. " * This is a sexy comment
  809. " */
  810. " Args:
  811. " -topline: the line number of the top line in the sexy comment
  812. " -bottomline: the line number of the bottom line in the sexy comment
  813. function! s:CommentLinesSexy(topline, bottomline) abort
  814. let left = s:GetSexyComLeft(0, 0)
  815. let right = s:GetSexyComRight(0, 0)
  816. "check if we can do a sexy comment with the available delimiters
  817. if left ==# -1 || right ==# -1
  818. throw 'NERDCommenter.Delimiters exception: cannot perform sexy comments with available delimiters.'
  819. endif
  820. "make sure the lines aren't already commented sexually or we can nest
  821. if !s:CanSexyCommentLines(a:topline, a:bottomline)
  822. throw 'NERDCommenter.Nesting exception: cannot nest sexy comments'
  823. endif
  824. let sexyComMarker = s:GetSexyComMarker(0,0)
  825. let sexyComMarkerSpaced = s:GetSexyComMarker(1,0)
  826. " we jam the comment as far to the right as possible
  827. let leftAlignIndx = s:LeftMostIndx(1, 1, a:topline, a:bottomline)
  828. "check if we should use the compact style i.e that the left/right
  829. "delimiters should appear on the first and last lines of the code and not
  830. "on separate lines above/below the first/last lines of code
  831. if g:NERDCompactSexyComs
  832. let spaceString = (g:NERDSpaceDelims ? s:spaceStr : '')
  833. "comment the top line
  834. let theLine = getline(a:topline)
  835. let lineHasTabs = s:HasLeadingTabs(theLine)
  836. if lineHasTabs
  837. let theLine = s:ConvertLeadingTabsToSpaces(theLine)
  838. endif
  839. if !s:SexyNested()
  840. let theLine = s:SwapOuterMultiPartDelimsForPlaceHolders(theLine)
  841. endif
  842. let theLine = s:AddLeftDelimAligned(left . spaceString, theLine, leftAlignIndx)
  843. if lineHasTabs
  844. let theLine = s:ConvertLeadingSpacesToTabs(theLine)
  845. endif
  846. call setline(a:topline, theLine)
  847. "comment the bottom line
  848. if a:bottomline !=# a:topline
  849. let theLine = getline(a:bottomline)
  850. let lineHasTabs = s:HasLeadingTabs(theLine)
  851. if lineHasTabs
  852. let theLine = s:ConvertLeadingTabsToSpaces(theLine)
  853. endif
  854. if !s:SexyNested()
  855. let theLine = s:SwapOuterMultiPartDelimsForPlaceHolders(theLine)
  856. endif
  857. endif
  858. let theLine = s:AddRightDelim(spaceString . right, theLine)
  859. if lineHasTabs
  860. let theLine = s:ConvertLeadingSpacesToTabs(theLine)
  861. endif
  862. call setline(a:bottomline, theLine)
  863. else
  864. " add the left delimiter one line above the lines that are to be commented
  865. call cursor(a:topline, 1)
  866. execute 'normal! O'
  867. let theLine = repeat(' ', leftAlignIndx) . left
  868. " Make sure tabs are respected
  869. if !&expandtab
  870. let theLine = s:ConvertLeadingSpacesToTabs(theLine)
  871. endif
  872. call setline(a:topline, theLine)
  873. " add the right delimiter after bottom line (we have to add 1 cos we moved
  874. " the lines down when we added the left delimiter
  875. call cursor(a:bottomline+1, 1)
  876. execute 'normal! o'
  877. if g:NERDDisableTabsInBlockComm
  878. let theLine = repeat(' ', leftAlignIndx) . right
  879. else
  880. let theLine = repeat(' ', leftAlignIndx) . repeat(' ', strlen(left)-strlen(sexyComMarker)) . right
  881. endif
  882. " Make sure tabs are respected
  883. if !&expandtab
  884. let theLine = s:ConvertLeadingSpacesToTabs(theLine)
  885. endif
  886. call setline(a:bottomline+2, theLine)
  887. endif
  888. " go thru each line adding the sexyComMarker marker to the start of each
  889. " line in the appropriate place to align them with the comment delimiters
  890. let currentLine = a:topline+1
  891. while currentLine <= a:bottomline + !g:NERDCompactSexyComs
  892. " get the line and convert the tabs to spaces
  893. let theLine = getline(currentLine)
  894. let lineHasTabs = s:HasLeadingTabs(theLine)
  895. if lineHasTabs
  896. let theLine = s:ConvertLeadingTabsToSpaces(theLine)
  897. endif
  898. if !s:SexyNested()
  899. let theLine = s:SwapOuterMultiPartDelimsForPlaceHolders(theLine)
  900. endif
  901. " add the sexyComMarker
  902. if g:NERDDisableTabsInBlockComm
  903. let theLine = repeat(' ', leftAlignIndx) . sexyComMarkerSpaced . strpart(theLine, leftAlignIndx)
  904. else
  905. let theLine = repeat(' ', leftAlignIndx) . repeat(' ', strlen(left)-strlen(sexyComMarker)) . sexyComMarkerSpaced . strpart(theLine, leftAlignIndx)
  906. endif
  907. if lineHasTabs
  908. let theLine = s:ConvertLeadingSpacesToTabs(theLine)
  909. endif
  910. if g:NERDTrimTrailingWhitespace ==# 1
  911. let theLine = s:TrimTrailingWhitespace(theLine)
  912. endif
  913. " set the line and move onto the next one
  914. call setline(currentLine, theLine)
  915. let currentLine = currentLine + 1
  916. endwhile
  917. endfunction
  918. " Function: s:CommentLinesToggle(forceNested, firstLine, lastLine)
  919. " Applies "toggle" commenting to the given range of lines
  920. "
  921. " Args:
  922. " -forceNested: a flag indicating whether the called is requesting the comment
  923. " to be nested if need be
  924. " -firstLine/lastLine: the top and bottom lines to comment
  925. function! s:CommentLinesToggle(forceNested, firstLine, lastLine) abort
  926. let currentLine = a:firstLine
  927. let align = g:NERDDefaultAlign
  928. let leftAlignIndx = align ==# 'start' ? 0 : s:LeftMostIndx(a:forceNested, 0, a:firstLine, a:lastLine)
  929. let rightAlignIndx = s:RightMostIndx(a:forceNested, 0, a:firstLine, a:lastLine)
  930. let rightAlignIndx = rightAlignIndx + strlen(s:Left({'space': 1}))
  931. while currentLine <= a:lastLine
  932. " get the next line, check commentability and convert spaces to tabs
  933. let theLine = getline(currentLine)
  934. let lineHasLeadingTabs = s:HasLeadingTabs(theLine)
  935. let theLine = s:ConvertLeadingTabsToSpaces(theLine)
  936. if s:CanToggleCommentLine(a:forceNested, currentLine)
  937. "if the user has specified forceNesting then we check to see if we
  938. "need to switch delimiters for place-holders
  939. if g:NERDUsePlaceHolders && !s:Nested()
  940. let theLine = s:SwapOuterMultiPartDelimsForPlaceHolders(theLine)
  941. endif
  942. if align ==# 'left' || align ==# 'start' || align ==# 'both'
  943. let theLine = s:AddLeftDelimAligned(s:Left({'space': 1}), theLine, leftAlignIndx)
  944. else
  945. let theLine = s:AddLeftDelim(s:Left({'space': 1}), theLine)
  946. endif
  947. if align ==# 'both'
  948. let theLine = s:AddRightDelimAligned(s:Right({'space': 1}), theLine, rightAlignIndx)
  949. else
  950. let theLine = s:AddRightDelim(s:Right({'space': 1}), theLine)
  951. endif
  952. endif
  953. " restore leading tabs if appropriate
  954. if lineHasLeadingTabs
  955. let theLine = s:ConvertLeadingSpacesToTabs(theLine)
  956. endif
  957. if g:NERDTrimTrailingWhitespace ==# 1
  958. let theLine = s:TrimTrailingWhitespace(theLine)
  959. endif
  960. " we are done with this line
  961. call setline(currentLine, theLine)
  962. let currentLine = currentLine + 1
  963. endwhile
  964. endfunction
  965. " Function: s:CommentRegion(topline, topCol, bottomLine, bottomCol) function
  966. " This function comments chunks of text selected in visual mode.
  967. " It will comment exactly the text that they have selected.
  968. " Args:
  969. " -topLine: the line number of the top line in the sexy comment
  970. " -topCol: top left column for this comment
  971. " -bottomline: the line number of the bottom line in the sexy comment
  972. " -bottomCol: the bottom right column for this comment
  973. " -forceNested: whether the caller wants comments to be nested if the
  974. " line(s) are already commented
  975. function! s:CommentRegion(topLine, topCol, bottomLine, bottomCol, forceNested) abort
  976. "switch delimiters (if we can) if the current set isn't multipart
  977. let switchedDelims = 0
  978. if !s:Multipart() && s:AltMultipart() && g:NERDAllowAnyVisualDelims
  979. let switchedDelims = 1
  980. call nerdcommenter#SwitchToAlternativeDelimiters(0)
  981. endif
  982. "if there is only one line in the comment then just do it
  983. if a:topLine ==# a:bottomLine
  984. call s:CommentBlock(a:topLine, a:bottomLine, a:topCol, a:bottomCol, a:forceNested)
  985. "there are multiple lines in the comment
  986. else
  987. "comment the top line
  988. call s:CommentBlock(a:topLine, a:topLine, a:topCol, strlen(getline(a:topLine)), a:forceNested)
  989. "comment out all the lines in the middle of the comment
  990. let topOfRange = a:topLine+1
  991. let bottomOfRange = a:bottomLine-1
  992. if topOfRange <= bottomOfRange
  993. call s:CommentLines(a:forceNested, g:NERDDefaultAlign, topOfRange, bottomOfRange)
  994. endif
  995. "comment the bottom line
  996. let bottom = getline(a:bottomLine)
  997. let numLeadingSpacesTabs = strlen(matchstr(bottom, '^\s*'))
  998. call s:CommentBlock(a:bottomLine, a:bottomLine, numLeadingSpacesTabs+1, a:bottomCol, a:forceNested)
  999. endif
  1000. "stick the cursor back on the char it was on before the comment
  1001. call cursor(a:topLine, a:topCol + strlen(s:Left()) + g:NERDSpaceDelims)
  1002. "if we switched delimiters then we gotta go back to what they were before
  1003. if switchedDelims ==# 1
  1004. call nerdcommenter#SwitchToAlternativeDelimiters(0)
  1005. endif
  1006. endfunction
  1007. " Function: s:InvertComment(firstLine, lastLine) function
  1008. " Inverts the comments on the lines between and including the given line
  1009. " numbers i.e all commented lines are uncommented and vice versa
  1010. " Args:
  1011. " -firstLine: the top of the range of lines to be inverted
  1012. " -lastLine: the bottom of the range of lines to be inverted
  1013. function! s:InvertComment(firstLine, lastLine) abort
  1014. " go thru all lines in the given range
  1015. let currentLine = a:firstLine
  1016. while currentLine <= a:lastLine
  1017. let theLine = getline(currentLine)
  1018. let sexyComBounds = s:FindBoundingLinesOfSexyCom(currentLine)
  1019. " if the line is commented normally, uncomment it
  1020. if s:IsCommentedFromStartOfLine(s:Left(), theLine) || s:IsCommentedFromStartOfLine(s:Left({'alt': 1}), theLine)
  1021. call s:UncommentLines(currentLine, currentLine)
  1022. let currentLine = currentLine + 1
  1023. " check if the line is commented sexually
  1024. elseif !empty(sexyComBounds)
  1025. let numLinesBeforeSexyComRemoved = s:NumLinesInBuf()
  1026. call s:UncommentLinesSexy(sexyComBounds[0], sexyComBounds[1])
  1027. "move to the line after last line of the sexy comment
  1028. let numLinesAfterSexyComRemoved = s:NumLinesInBuf()
  1029. let currentLine = sexyComBounds[1] - (numLinesBeforeSexyComRemoved - numLinesAfterSexyComRemoved) + 1
  1030. " the line isn't commented
  1031. else
  1032. call s:CommentLinesToggle(1, currentLine, currentLine)
  1033. let currentLine = currentLine + 1
  1034. endif
  1035. endwhile
  1036. endfunction
  1037. " Function: nerdcommenter#IsLineCommented(lineNo)
  1038. " Check if the line is a comment
  1039. " Note this function checks if the line is **completely** a comment
  1040. " Args:
  1041. " -lineNo: the line number of the line to check
  1042. " Return: Number, 1 if the line is a comment, 0 else
  1043. function! nerdcommenter#IsLineCommented(lineNo) abort
  1044. call nerdcommenter#SetUp()
  1045. let theLine = getline(a:lineNo)
  1046. return s:IsInSexyComment(a:lineNo) || s:IsCommentedFromStartOfLine(s:Left(), theLine) || s:IsCommentedFromStartOfLine(s:Left({'alt': 1}), theLine)
  1047. endfunction
  1048. " Function: nerdcommenter#Comment(mode, type) function
  1049. " This function is a Wrapper for the main commenting functions
  1050. "
  1051. " Args:
  1052. " -mode: a character indicating the mode in which the comment is requested:
  1053. " 'n' for Normal mode, 'x' for Visual mode
  1054. " -type: the type of commenting requested. Can be 'Sexy', 'Invert',
  1055. " 'Minimal', 'Toggle', 'AlignLeft', 'AlignBoth', 'Comment',
  1056. " 'Nested', 'ToEOL', 'Append', 'Insert', 'Uncomment', 'Yank'
  1057. function! nerdcommenter#Comment(mode, type) range abort
  1058. call nerdcommenter#SetUp()
  1059. if exists('*NERDCommenter_before')
  1060. exe 'call NERDCommenter_before()'
  1061. endif
  1062. let isVisual = a:mode =~# '[vsx]'
  1063. if !exists('g:did_load_ftplugin') || g:did_load_ftplugin !=# 1
  1064. call s:NerdEcho('filetype plugins should be enabled. See :help NERDComInstallation and :help :filetype-plugin-on', 0)
  1065. endif
  1066. if isVisual
  1067. let firstLine = line("'<")
  1068. let lastLine = line("'>")
  1069. let firstCol = col("'<")
  1070. let lastCol = col("'>") - (&selection ==# 'exclusive' ? 1 : 0)
  1071. else
  1072. let firstLine = a:firstline
  1073. let lastLine = a:lastline
  1074. endif
  1075. "
  1076. " Save options we need to change so we can recover them later
  1077. let state = s:SetupStateBeforeLineComment(firstLine, lastLine)
  1078. let countWasGiven = (!isVisual && firstLine !=# lastLine)
  1079. let forceNested = (a:type ==? 'Nested' || g:NERDDefaultNesting)
  1080. if a:type ==? 'Comment' || a:type ==? 'Nested'
  1081. if isVisual && visualmode() ==# "\<C-V>"
  1082. call s:CommentBlock(firstLine, lastLine, firstCol, lastCol, forceNested)
  1083. elseif isVisual && visualmode() ==# 'v' && (g:NERDCommentWholeLinesInVMode==#0 || (g:NERDCommentWholeLinesInVMode==#2 && s:HasMultipartDelims()))
  1084. call s:CommentRegion(firstLine, firstCol, lastLine, lastCol, forceNested)
  1085. else
  1086. call s:CommentLines(forceNested, g:NERDDefaultAlign, firstLine, lastLine)
  1087. endif
  1088. elseif a:type ==? 'AlignLeft' || a:type ==? 'AlignBoth'
  1089. let align = 'none'
  1090. if a:type ==? 'AlignLeft'
  1091. let align = 'left'
  1092. elseif a:type ==? 'AlignBoth'
  1093. let align = 'both'
  1094. endif
  1095. call s:CommentLines(forceNested, align, firstLine, lastLine)
  1096. elseif a:type ==? 'Invert'
  1097. call s:InvertComment(firstLine, lastLine)
  1098. elseif a:type ==? 'Sexy'
  1099. try
  1100. call s:CommentLinesSexy(firstLine, lastLine)
  1101. catch /NERDCommenter.Delimiters/
  1102. call s:CommentLines(forceNested, g:NERDDefaultAlign, firstLine, lastLine)
  1103. catch /NERDCommenter.Nesting/
  1104. call s:NerdEcho('Sexy comment aborted. Nested sexy cannot be nested', 0)
  1105. endtry
  1106. elseif a:type ==? 'Toggle'
  1107. if g:NERDToggleCheckAllLines ==# 0
  1108. let theLine = getline(firstLine)
  1109. if s:IsInSexyComment(firstLine) || s:IsCommentedFromStartOfLine(s:Left(), theLine) || s:IsCommentedFromStartOfLine(s:Left({'alt': 1}), theLine)
  1110. call s:UncommentLines(firstLine, lastLine)
  1111. else
  1112. call s:CommentLinesToggle(forceNested, firstLine, lastLine)
  1113. endif
  1114. else
  1115. let l:commentAllLines = 0
  1116. for i in range(firstLine, lastLine)
  1117. let theLine = getline(i)
  1118. " if have one line no comment(not include blank/whitespace-only lines), then comment all lines
  1119. if theLine =~# '\S\+' && !s:IsInSexyComment(firstLine) && !s:IsCommentedFromStartOfLine(s:Left(), theLine) && !s:IsCommentedFromStartOfLine(s:Left({'alt': 1}), theLine)
  1120. let l:commentAllLines = 1
  1121. break
  1122. else
  1123. endif
  1124. endfor
  1125. if l:commentAllLines ==# 1
  1126. call s:CommentLinesToggle(forceNested, firstLine, lastLine)
  1127. else
  1128. call s:UncommentLines(firstLine, lastLine)
  1129. endif
  1130. endif
  1131. elseif a:type ==? 'Minimal'
  1132. try
  1133. call s:CommentLinesMinimal(firstLine, lastLine)
  1134. catch /NERDCommenter.Delimiters/
  1135. call s:NerdEcho('Minimal comments can only be used for filetypes that have multipart delimiters.', 0)
  1136. catch /NERDCommenter.Settings/
  1137. call s:NerdEcho('Place holders are required but disabled.', 0)
  1138. endtry
  1139. elseif a:type ==? 'ToEOL'
  1140. let view = winsaveview()
  1141. call s:CommentBlock(firstLine, firstLine, col('.'), col('$')-1, 1)
  1142. call winrestview(view)
  1143. elseif a:type ==? 'Append'
  1144. call s:AppendCommentToLine()
  1145. elseif a:type ==? 'Insert'
  1146. call s:PlaceDelimitersAndInsBetween()
  1147. elseif a:type ==? 'Uncomment'
  1148. call s:UncommentLines(firstLine, lastLine)
  1149. elseif a:type ==? 'Yank'
  1150. if isVisual
  1151. normal! gvy
  1152. elseif countWasGiven
  1153. execute firstLine .','. lastLine .'yank'
  1154. else
  1155. normal! yy
  1156. endif
  1157. execute firstLine .','. lastLine .'call nerdcommenter#Comment("'. a:mode .'", "Comment")'
  1158. endif
  1159. call s:RecoverStateAfterLineComment(state)
  1160. if isVisual
  1161. let nlines = lastLine - firstLine
  1162. silent! call repeat#set('V' . nlines . 'jo' . "\<Plug>NERDCommenter". a:type)
  1163. else
  1164. silent! call repeat#set("\<Plug>NERDCommenter". a:type)
  1165. endif
  1166. if exists('*NERDCommenter_after')
  1167. exe 'call NERDCommenter_after()'
  1168. endif
  1169. endfunction
  1170. " Function: nerdcommenter#IsCharCommented(line, col) abort
  1171. " Check if the character at [line, col] is inside a comment
  1172. " Note the Comment delimeter it self is considered as part of the comment
  1173. "
  1174. " Args:
  1175. " -line the line number of the character
  1176. " -col the column number of the character
  1177. " Return: Number, 1 if the character is inside a comment, 0 if is not
  1178. function! nerdcommenter#IsCharCommented(line, col) abort
  1179. " Function: s:searchfor(str, line, col, direction, [maxline])
  1180. " search str in the buffer, including the character at [line, col]
  1181. " Args:
  1182. " -str: the string for search
  1183. " -line: the line number where search begins
  1184. " -col: the column number where search begins
  1185. " -direction: 0 if forward, and 1 if backward
  1186. " -maxline: the max lines the search would look up
  1187. " 1 if search only one line
  1188. " if not given, search until reaches the begining or end of file
  1189. " Return: List, in the format of [line, col], where line and col is the
  1190. " position of first found result; If str cannot be found, returns
  1191. " [0, 0]
  1192. function! s:searchfor(str, line, col, direction, ...) abort
  1193. let l:curlinenr = a:line
  1194. let l:maxline = (a:0 > 0) ? a:1 : (a:direction ? a:line : line('$') - a:line + 1)
  1195. while abs(curlinenr - a:line) < maxline
  1196. let linestr = getline(curlinenr)
  1197. if curlinenr == a:line
  1198. if !a:direction
  1199. let l:partstr = strpart(linestr, a:col - strlen(a:str))
  1200. else
  1201. let l:partstr = strpart(linestr, 0, a:col + strlen(a:str) - 1)
  1202. endif
  1203. else
  1204. let l:partstr = linestr
  1205. endif
  1206. if !a:direction
  1207. " forward
  1208. let idx = stridx(partstr, a:str)
  1209. if idx != -1
  1210. if curlinenr == a:line
  1211. let idx += a:col - strlen(a:str)
  1212. else
  1213. endif
  1214. return [curlinenr, idx + 1]
  1215. endif
  1216. else
  1217. " backward
  1218. let idx = strridx(partstr, a:str)
  1219. if idx != -1
  1220. return [curlinenr, idx + 1]
  1221. endif
  1222. endif
  1223. let curlinenr += a:direction ? -1 : 1
  1224. endwhile
  1225. return [0, 0]
  1226. endfunction
  1227. " Function: s:checkwith(left, right, line, col) abort
  1228. " check if the char at [line, col] is commented using [left, right] pair
  1229. " Args:
  1230. " -left: the string begins a comment
  1231. " -right: the string ends a comment
  1232. " -line: the line position of the character
  1233. " -col: the column position of the character
  1234. " Return: Number, 1 if is in a comment, 0 else
  1235. function! s:checkwith(left, right, line, col) abort
  1236. let linecommented = 0
  1237. let blockcommented = 0
  1238. if a:right ==# ''
  1239. let leftpos = s:searchfor(a:left, a:line, a:col, 1, 1)
  1240. if leftpos == [0, 0]
  1241. if !linecommented | let linecommented = 0 | endif
  1242. else
  1243. if !linecommented | let linecommented = 1 | endif
  1244. endif
  1245. else
  1246. let leftpos = s:searchfor(a:left, a:line, a:col, 1)
  1247. if leftpos == [0, 0]
  1248. if !blockcommented | let blockcommented = 0 | endif
  1249. else
  1250. " call s:searchfor(a:right, a:line, a:col, 0)
  1251. let rightpos = s:searchfor(a:right, leftpos[0], leftpos[1] + strlen(a:right) + 1, 0)
  1252. if rightpos != [0, 0]
  1253. if rightpos[0] < a:line
  1254. if !blockcommented | let blockcommented = 0 | endif
  1255. elseif rightpos[0] == a:line
  1256. if !blockcommented
  1257. let blockcommented = (rightpos[1] + strlen(a:right) > a:col) ? 1 : 0
  1258. endif
  1259. else " rightpos > a:line
  1260. if !blockcommented | let blockcommented = 1 | endif
  1261. endif
  1262. else
  1263. if !blockcommented | let blockcommented = 1 | endif
  1264. endif
  1265. endif
  1266. endif
  1267. return linecommented || blockcommented
  1268. endfunction
  1269. return s:checkwith(
  1270. \ b:NERDCommenterDelims['left'],
  1271. \ b:NERDCommenterDelims['right'],
  1272. \ a:line,
  1273. \ a:col) ||
  1274. \ s:checkwith(
  1275. \ b:NERDCommenterDelims['leftAlt'],
  1276. \ b:NERDCommenterDelims['rightAlt'],
  1277. \ a:line,
  1278. \ a:col)
  1279. endfunction
  1280. " Function: s:PlaceDelimitersAndInsBetween() function
  1281. " This is function is called to place comment delimiters down and place the
  1282. " cursor between them
  1283. function! s:PlaceDelimitersAndInsBetween() abort
  1284. " get the left and right delimiters without any escape chars in them
  1285. let left = s:Left({'space': 1})
  1286. let right = s:Right({'space': 1})
  1287. " 0. Entered insert normal mode using <C-\><C-O> (:h i_CTRL-\_CTRL-O) to
  1288. " maintain the cursor position (from <Plug>NERDCommenterInsert).
  1289. " 1. Enter insert mode without changing the cursor position.
  1290. " If the cursor is on EOL (right of the last char), use 'a'.
  1291. " Otherwise, use 'i'.
  1292. let insert = col('.') > strlen(getline('.')) ? 'a' : 'i'
  1293. " 2. Insert comment delimiters.
  1294. " 3. Move the cursor to the left of the closing delimiter, without
  1295. " breaking undo sequence.
  1296. " 4. Enter insert normal mode again without changing the cursor position.
  1297. " This ensures that returning to the insert mode after finishing the
  1298. " script execution does not move the cursor.
  1299. " ( 1 ) ( 2 ) ( 3 ) ( 4 )
  1300. execute 'normal!' insert . left . right . repeat("\<C-G>U\<Left>", strchars(right)) . "\<C-\>\<C-O>"
  1301. endfunction
  1302. " Function: s:RemoveDelimiters(left, right, line)
  1303. " this function is called to remove the first left comment delimiter and the
  1304. " last right delimiter of the given line.
  1305. "
  1306. " The arguments left and right must be strings. If there is no right delimiter (as
  1307. " is the case for e.g vim file comments) them the argument right should be ''
  1308. "
  1309. " Args:
  1310. " -left: the left comment delimiter
  1311. " -right: the right comment delimiter
  1312. " -line: the line to remove the delimiters from
  1313. function! s:RemoveDelimiters(left, right, line) abort
  1314. let l:left = a:left
  1315. let l:right = a:right
  1316. let lenLeft = strlen(left)
  1317. let lenRight = strlen(right)
  1318. let delimsSpaced = (g:NERDSpaceDelims || g:NERDRemoveExtraSpaces)
  1319. let line = a:line
  1320. "look for the left delimiter, if we find it, remove it.
  1321. let leftIndx = s:FindDelimiterIndex(a:left, line)
  1322. if leftIndx !=# -1
  1323. let line = strpart(line, 0, leftIndx) . strpart(line, leftIndx+lenLeft)
  1324. "if the user has specified that there is a space after the left delimiter
  1325. "then check for the space and remove it if it is there
  1326. if delimsSpaced && strpart(line, leftIndx, s:lenSpaceStr) ==# s:spaceStr
  1327. let line = strpart(line, 0, leftIndx) . strpart(line, leftIndx+s:lenSpaceStr)
  1328. endif
  1329. endif
  1330. "look for the right delimiter, if we find it, remove it
  1331. let rightIndx = s:LastIndexOfDelim(a:right, line)
  1332. if rightIndx !=# -1
  1333. let line = strpart(line, 0, rightIndx) . strpart(line, rightIndx+lenRight)
  1334. "if the user has specified that there is a space before the right delimiter
  1335. "then check for the space and remove it if it is there
  1336. if delimsSpaced && strpart(line, rightIndx-s:lenSpaceStr, s:lenSpaceStr) ==# s:spaceStr && (s:Multipart() || s:AltMultipart())
  1337. let line = strpart(line, 0, rightIndx-s:lenSpaceStr) . strpart(line, rightIndx)
  1338. endif
  1339. endif
  1340. return line
  1341. endfunction
  1342. " Function: s:SetupStateBeforeLineComment(topLine, bottomLine)
  1343. " Changes ignorecase and foldmethod options before commenting lines and saves
  1344. " their original values in a dict, which is returned as a result
  1345. "
  1346. " Args:
  1347. " topLine: the top line of the visual selection to uncomment
  1348. " bottomLine: the bottom line of the visual selection to uncomment
  1349. "
  1350. " Return: a dict with the state prior to configuration changes
  1351. "
  1352. function! s:SetupStateBeforeLineComment(topLine, bottomLine) abort
  1353. let state = {'foldmethod' : &foldmethod,
  1354. \'ignorecase' : &ignorecase}
  1355. " Vim's foldmethods are evaluated every time we use 'setline', which can
  1356. " make commenting wide ranges of lines VERY slow. We'll change it to
  1357. " manual, do the commenting stuff and recover it later. To avoid slowing
  1358. " down commenting few lines, we avoid doing this for ranges smaller than
  1359. " 10 lines
  1360. if a:bottomLine - a:topLine >= 10 && &foldmethod !=# 'manual'
  1361. set foldmethod=manual
  1362. endif
  1363. " we want case sensitivity when commenting
  1364. set noignorecase
  1365. return state
  1366. endfunction
  1367. " Function: s:RecoverStateAfterLineComment(state)
  1368. " Receives the state returned by s:SetupStateBeforeLineComment and restores
  1369. " the state accordingly
  1370. "
  1371. " Args:
  1372. " state: the top line of the visual selection to uncomment
  1373. " bottomLine: the bottom line of the visual selection to uncomment
  1374. function! s:RecoverStateAfterLineComment(state) abort
  1375. if a:state['foldmethod'] !=# &foldmethod
  1376. let &foldmethod = a:state['foldmethod']
  1377. endif
  1378. if a:state['ignorecase'] !=# &ignorecase
  1379. let &ignorecase = a:state['ignorecase']
  1380. endif
  1381. endfunction
  1382. " Function: s:TrimTrailingWhitespace(line)
  1383. " This function removes all the trailing whitespace
  1384. " Args:
  1385. " -line: the target line
  1386. function! s:TrimTrailingWhitespace(line) abort
  1387. let toReturn = substitute(a:line, '\s\+$', '', 'g')
  1388. return toReturn
  1389. endfunction
  1390. " Function: s:UncommentLines(topLine, bottomLine)
  1391. " This function uncomments the given lines
  1392. "
  1393. " Args:
  1394. " topLine: the top line of the visual selection to uncomment
  1395. " bottomLine: the bottom line of the visual selection to uncomment
  1396. function! s:UncommentLines(topLine, bottomLine) abort
  1397. "make local copies of a:firstline and a:lastline and, if need be, swap
  1398. "them around if the top line is below the bottom
  1399. let l:firstline = a:topLine
  1400. let l:lastline = a:bottomLine
  1401. if firstline > lastline
  1402. let firstline = lastline
  1403. let lastline = a:topLine
  1404. endif
  1405. "go thru each line uncommenting each line removing sexy comments
  1406. let currentLine = firstline
  1407. while currentLine <= lastline
  1408. "check the current line to see if it is part of a sexy comment
  1409. let sexyComBounds = s:FindBoundingLinesOfSexyCom(currentLine)
  1410. if !empty(sexyComBounds)
  1411. "we need to store the number of lines in the buffer before the comment is
  1412. "removed so we know how many lines were removed when the sexy comment
  1413. "was removed
  1414. let numLinesBeforeSexyComRemoved = s:NumLinesInBuf()
  1415. call s:UncommentLinesSexy(sexyComBounds[0], sexyComBounds[1])
  1416. "move to the line after last line of the sexy comment
  1417. let numLinesAfterSexyComRemoved = s:NumLinesInBuf()
  1418. let numLinesRemoved = numLinesBeforeSexyComRemoved - numLinesAfterSexyComRemoved
  1419. let currentLine = sexyComBounds[1] - numLinesRemoved + 1
  1420. let lastline = lastline - numLinesRemoved
  1421. "no sexy com was detected so uncomment the line as normal
  1422. else
  1423. call s:UncommentLinesNormal(currentLine, currentLine)
  1424. let currentLine = currentLine + 1
  1425. endif
  1426. endwhile
  1427. endfunction
  1428. " Function: s:UncommentLinesSexy(topline, bottomline)
  1429. " This function removes all the comment characters associated with the sexy
  1430. " comment spanning the given lines
  1431. " Args:
  1432. " -topline/bottomline: the top/bottom lines of the sexy comment
  1433. function! s:UncommentLinesSexy(topline, bottomline) abort
  1434. let left = s:GetSexyComLeft(0,1)
  1435. let right = s:GetSexyComRight(0,1)
  1436. "check if it is even possible for sexy comments to exist with the
  1437. "available delimiters
  1438. if left ==# -1 || right ==# -1
  1439. throw 'NERDCommenter.Delimiters exception: cannot uncomment sexy comments with available delimiters.'
  1440. endif
  1441. let leftUnEsc = s:GetSexyComLeft(0,0)
  1442. let rightUnEsc = s:GetSexyComRight(0,0)
  1443. let sexyComMarker = s:GetSexyComMarker(0, 1)
  1444. let sexyComMarkerUnEsc = s:GetSexyComMarker(0, 0)
  1445. "the markerOffset is how far right we need to move the sexyComMarker to
  1446. "line it up with the end of the left delimiter
  1447. let markerOffset = strlen(leftUnEsc)-strlen(sexyComMarkerUnEsc)
  1448. " go thru the intermediate lines of the sexy comment and remove the
  1449. " sexy comment markers (e.g., the '*'s on the start of line in a c sexy
  1450. " comment)
  1451. let currentLine = a:topline+1
  1452. while currentLine < a:bottomline
  1453. let theLine = getline(currentLine)
  1454. " remove the sexy comment marker from the line. We also remove the
  1455. " space after it if there is one and if appropriate options are set
  1456. let sexyComMarkerIndx = stridx(theLine, sexyComMarkerUnEsc)
  1457. if strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc), s:lenSpaceStr) ==# s:spaceStr && g:NERDSpaceDelims
  1458. let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc)+s:lenSpaceStr)
  1459. else
  1460. let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc))
  1461. endif
  1462. let theLine = s:SwapOuterPlaceHoldersForMultiPartDelims(theLine)
  1463. let theLine = s:ConvertLeadingWhiteSpace(theLine)
  1464. if g:NERDTrimTrailingWhitespace ==# 1
  1465. let theLine = s:TrimTrailingWhitespace(theLine)
  1466. endif
  1467. " move onto the next line
  1468. call setline(currentLine, theLine)
  1469. let currentLine = currentLine + 1
  1470. endwhile
  1471. " gotta make a copy of a:bottomline cos we modify the position of the
  1472. " last line it if we remove the topline
  1473. let bottomline = a:bottomline
  1474. " get the first line so we can remove the left delimiter from it
  1475. let theLine = getline(a:topline)
  1476. " if the first line contains only the left delimiter then just delete it
  1477. if theLine =~# '^\s*' . left . '\s*$' && !g:NERDCompactSexyComs
  1478. call cursor(a:topline, 1)
  1479. normal! dd
  1480. let bottomline = bottomline - 1
  1481. " topline contains more than just the left delimiter
  1482. else
  1483. " remove the delimiter. If there is a space after it
  1484. " then remove this too if appropriate
  1485. let delimIndx = stridx(theLine, leftUnEsc)
  1486. if strpart(theLine, delimIndx+strlen(leftUnEsc), s:lenSpaceStr) ==# s:spaceStr && g:NERDSpaceDelims
  1487. let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(leftUnEsc)+s:lenSpaceStr)
  1488. else
  1489. let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(leftUnEsc))
  1490. endif
  1491. let theLine = s:SwapOuterPlaceHoldersForMultiPartDelims(theLine)
  1492. call setline(a:topline, theLine)
  1493. endif
  1494. " get the last line so we can remove the right delimiter
  1495. let theLine = getline(bottomline)
  1496. " if the bottomline contains only the right delimiter then just delete it
  1497. if theLine =~# '^\s*' . right . '\s*$'
  1498. call cursor(bottomline, 1)
  1499. normal! dd
  1500. " the last line contains more than the right delimiter
  1501. else
  1502. " remove the right delimiter. If there is a space after it and
  1503. " if the appropriate options are set then remove this too.
  1504. let delimIndx = s:LastIndexOfDelim(rightUnEsc, theLine)
  1505. if strpart(theLine, delimIndx+strlen(leftUnEsc), s:lenSpaceStr) ==# s:spaceStr && g:NERDSpaceDelims
  1506. let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(rightUnEsc)+s:lenSpaceStr)
  1507. else
  1508. let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(rightUnEsc))
  1509. endif
  1510. " if the last line also starts with a sexy comment marker then we
  1511. " remove this as well
  1512. if theLine =~# '^\s*' . sexyComMarker
  1513. " remove the sexyComMarker. If there is a space after it then
  1514. " remove that too
  1515. let sexyComMarkerIndx = stridx(theLine, sexyComMarkerUnEsc)
  1516. if strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc), s:lenSpaceStr) ==# s:spaceStr && g:NERDSpaceDelims
  1517. let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset ) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc)+s:lenSpaceStr)
  1518. else
  1519. let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset ) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc))
  1520. endif
  1521. endif
  1522. let theLine = s:SwapOuterPlaceHoldersForMultiPartDelims(theLine)
  1523. call setline(bottomline, theLine)
  1524. endif
  1525. " remove trailing whitespaces for first and last line
  1526. if g:NERDTrimTrailingWhitespace ==# 1
  1527. let theLine = getline(a:bottomline)
  1528. let theLine = s:TrimTrailingWhitespace(theLine)
  1529. call setline(a:bottomline, theLine)
  1530. let theLine = getline(a:topline)
  1531. let theLine = s:TrimTrailingWhitespace(theLine)
  1532. call setline(a:topline, theLine)
  1533. endif
  1534. endfunction
  1535. " Function: s:UncommentLineNormal(line)
  1536. " uncomments the given line and returns the result
  1537. " Args:
  1538. " -line: the line to uncomment
  1539. function! s:UncommentLineNormal(line) abort
  1540. let line = a:line
  1541. "get the positions of all delimiter types on the line
  1542. let indxLeft = s:FindDelimiterIndex(s:Left(), line)
  1543. let indxLeftAlt = s:FindDelimiterIndex(s:Left({'alt': 1}), line)
  1544. let indxRight = s:LastIndexOfDelim(s:Right(), line)
  1545. let indxRightAlt = s:LastIndexOfDelim(s:Right({'alt': 1}), line)
  1546. "get the comment status on the line so we know how it is commented
  1547. let lineCommentStatus = s:IsCommentedOutermost(s:Left(), s:Right(), s:Left({'alt': 1}), s:Right({'alt': 1}), line)
  1548. "it is commented with s:Left() and s:Right() so remove these delimiters
  1549. if lineCommentStatus ==# 1
  1550. let line = s:RemoveDelimiters(s:Left(), s:Right(), line)
  1551. "it is commented with s:Left({'alt': 1}) and s:Right({'alt': 1}) so remove these delimiters
  1552. elseif lineCommentStatus ==# 2 && g:NERDRemoveAltComs
  1553. let line = s:RemoveDelimiters(s:Left({'alt': 1}), s:Right({'alt': 1}), line)
  1554. "it is not properly commented with any delimiters so we check if it has
  1555. "any random left or right delimiters on it and remove the outermost ones
  1556. else
  1557. "remove the outer most left comment delimiter
  1558. if indxLeft !=# -1 && (indxLeft < indxLeftAlt || indxLeftAlt ==# -1)
  1559. let line = s:RemoveDelimiters(s:Left(), '', line)
  1560. elseif indxLeftAlt !=# -1 && g:NERDRemoveAltComs
  1561. let line = s:RemoveDelimiters(s:Left({'alt': 1}), '', line)
  1562. endif
  1563. "remove the outer most right comment delimiter
  1564. if indxRight !=# -1 && (indxRight < indxRightAlt || indxRightAlt ==# -1)
  1565. let line = s:RemoveDelimiters('', s:Right(), line)
  1566. elseif indxRightAlt !=# -1 && g:NERDRemoveAltComs
  1567. let line = s:RemoveDelimiters('', s:Right({'alt': 1}), line)
  1568. endif
  1569. endif
  1570. let indxLeftPlace = s:FindDelimiterIndex(g:NERDLPlace, line)
  1571. let indxRightPlace = s:FindDelimiterIndex(g:NERDRPlace, line)
  1572. let right = s:Right()
  1573. let left = s:Left()
  1574. if !s:Multipart()
  1575. let right = s:Right({'alt': 1})
  1576. let left = s:Left({'alt': 1})
  1577. endif
  1578. "if there are place-holders on the line then we check to see if they are
  1579. "the outermost delimiters on the line. If so then we replace them with
  1580. "real delimiters
  1581. if indxLeftPlace !=# -1
  1582. if (indxLeftPlace < indxLeft || indxLeft==-1) && (indxLeftPlace < indxLeftAlt || indxLeftAlt==-1)
  1583. let line = s:ReplaceDelims(g:NERDLPlace, g:NERDRPlace, left, right, line)
  1584. endif
  1585. elseif indxRightPlace !=# -1
  1586. if (indxRightPlace < indxLeft || indxLeft==-1) && (indxLeftPlace < indxLeftAlt || indxLeftAlt==-1)
  1587. let line = s:ReplaceDelims(g:NERDLPlace, g:NERDRPlace, left, right, line)
  1588. endif
  1589. endif
  1590. let line = s:ConvertLeadingWhiteSpace(line)
  1591. if g:NERDTrimTrailingWhitespace ==# 1
  1592. let line = s:TrimTrailingWhitespace(line)
  1593. endif
  1594. return line
  1595. endfunction
  1596. " Function: s:UncommentLinesNormal(topline, bottomline)
  1597. " This function is called to uncomment lines that aren't a sexy comment
  1598. " Args:
  1599. " -topline/bottomline: the top/bottom line numbers of the comment
  1600. function! s:UncommentLinesNormal(topline, bottomline) abort
  1601. let currentLine = a:topline
  1602. while currentLine <= a:bottomline
  1603. let line = getline(currentLine)
  1604. call setline(currentLine, s:UncommentLineNormal(line))
  1605. let currentLine = currentLine + 1
  1606. endwhile
  1607. endfunction
  1608. " Section: Other helper functions
  1609. " ============================================================================
  1610. " Function: s:AddLeftDelim(delim, theLine)
  1611. " Args:
  1612. function! s:AddLeftDelim(delim, theLine) abort
  1613. return substitute(a:theLine, '^\(\s*\)', '\1' . a:delim, '')
  1614. endfunction
  1615. " Function: s:AddLeftDelimAligned(delim, theLine)
  1616. " Args:
  1617. function! s:AddLeftDelimAligned(delim, theLine, alignIndx) abort
  1618. "if the line is not long enough then bung some extra spaces on the front
  1619. "so we can align the delimiter properly
  1620. let theLine = a:theLine
  1621. if strlen(theLine) < a:alignIndx
  1622. let theLine = repeat(' ', a:alignIndx - strlen(theLine))
  1623. endif
  1624. return strpart(theLine, 0, a:alignIndx) . a:delim . strpart(theLine, a:alignIndx)
  1625. endfunction
  1626. " Function: s:AddRightDelim(delim, theLine)
  1627. " Args:
  1628. function! s:AddRightDelim(delim, theLine) abort
  1629. if a:delim ==# ''
  1630. return a:theLine
  1631. else
  1632. return substitute(a:theLine, '$', a:delim, '')
  1633. endif
  1634. endfunction
  1635. " Function: s:AddRightDelimAligned(delim, theLine, alignIndx)
  1636. " Args:
  1637. function! s:AddRightDelimAligned(delim, theLine, alignIndx) abort
  1638. if a:delim ==# ''
  1639. return a:theLine
  1640. else
  1641. " when we align the right delimiter we are just adding spaces
  1642. " so we get a string containing the needed spaces (it
  1643. " could be empty)
  1644. let extraSpaces = ''
  1645. let extraSpaces = repeat(' ', a:alignIndx-strlen(a:theLine))
  1646. " add the right delimiter
  1647. return substitute(a:theLine, '$', extraSpaces . a:delim, '')
  1648. endif
  1649. endfunction
  1650. " Function: s:AltMultipart()
  1651. " returns 1 if the alternative delimiters are multipart
  1652. function! s:AltMultipart() abort
  1653. return b:NERDCommenterDelims['rightAlt'] !=# ''
  1654. endfunction
  1655. " Function: s:AltNested()
  1656. " returns 1 if the alternate multipart (if any) delimiters allow nesting
  1657. function! s:AltNested() abort
  1658. return b:NERDCommenterDelims['nestedAlt']
  1659. endfunction
  1660. " Function: s:CanCommentLine(forceNested, line)
  1661. "This function is used to determine whether the given line can be commented.
  1662. "It returns 1 if it can be and 0 otherwise
  1663. "
  1664. " Args:
  1665. " -forceNested: a flag indicating whether the caller wants comments to be nested
  1666. " if the current line is already commented
  1667. " -lineNum: the line number of the line to check for commentability
  1668. function! s:CanCommentLine(forceNested, lineNum) abort
  1669. let theLine = getline(a:lineNum)
  1670. " make sure we don't comment lines that are just spaces or tabs or empty,
  1671. " unless configured otherwise
  1672. if g:NERDCommentEmptyLines ==# 0 && theLine =~# '^\s*$'
  1673. return 0
  1674. endif
  1675. "if the line is part of a sexy comment then just flag it...
  1676. if s:IsInSexyComment(a:lineNum)
  1677. return 0
  1678. endif
  1679. let isCommented = s:IsCommentedNormOrSexy(a:lineNum)
  1680. "if the line isn't commented return true
  1681. if !isCommented
  1682. return 1
  1683. endif
  1684. "if the line is commented but nesting is allowed then return true
  1685. if s:Nested() || (a:forceNested && (!s:Multipart() || g:NERDUsePlaceHolders))
  1686. return 1
  1687. endif
  1688. return 0
  1689. endfunction
  1690. " Function: s:CanPlaceCursor(line, col)
  1691. " returns 1 if the cursor can be placed exactly in the given position
  1692. function! s:CanPlaceCursor(line, col) abort
  1693. let c = col('.')
  1694. let l = line('.')
  1695. call cursor(a:line, a:col)
  1696. let success = (line('.') ==# a:line && col('.') ==# a:col)
  1697. call cursor(l,c)
  1698. return success
  1699. endfunction
  1700. " Function: s:CanSexyCommentLines(topline, bottomline)
  1701. " Return: 1 if the given lines can be commented sexually, 0 otherwise
  1702. function! s:CanSexyCommentLines(topline, bottomline) abort
  1703. " see if the selected regions have any sexy comments
  1704. " however, if the language allows nested comments,
  1705. " we allow nested sexy comments
  1706. if s:SexyNested()
  1707. return 1
  1708. endif
  1709. let currentLine = a:topline
  1710. while(currentLine <= a:bottomline)
  1711. if s:IsInSexyComment(currentLine)
  1712. return 0
  1713. endif
  1714. let currentLine = currentLine + 1
  1715. endwhile
  1716. return 1
  1717. endfunction
  1718. " Function: s:CanToggleCommentLine(forceNested, line)
  1719. "This function is used to determine whether the given line can be toggle commented.
  1720. "It returns 1 if it can be and 0 otherwise
  1721. "
  1722. " Args:
  1723. " -lineNum: the line number of the line to check for commentability
  1724. function! s:CanToggleCommentLine(forceNested, lineNum) abort
  1725. let theLine = getline(a:lineNum)
  1726. if (s:IsCommentedFromStartOfLine(s:Left(), theLine) || s:IsCommentedFromStartOfLine(s:Left({'alt': 1}), theLine)) && !a:forceNested
  1727. return 0
  1728. endif
  1729. " make sure we don't comment lines that are just spaces or tabs or empty,
  1730. " unless configured otherwise
  1731. if g:NERDCommentEmptyLines ==# 0 && theLine =~# '^\s*$'
  1732. return 0
  1733. endif
  1734. "if the line is part of a sexy comment then just flag it...
  1735. if s:IsInSexyComment(a:lineNum)
  1736. return 0
  1737. endif
  1738. return 1
  1739. endfunction
  1740. " Function: s:ConvertLeadingSpacesToTabs(line)
  1741. " This function takes a line and converts all leading tabs on that line into
  1742. " spaces
  1743. "
  1744. " Args:
  1745. " -line: the line whose leading tabs will be converted
  1746. function! s:ConvertLeadingSpacesToTabs(line) abort
  1747. let toReturn = a:line
  1748. while toReturn =~# '^\t*' . s:TabSpace() . '\(.*\)$'
  1749. let toReturn = substitute(toReturn, '^\(\t*\)' . s:TabSpace() . '\(.*\)$' , '\1\t\2' , '')
  1750. endwhile
  1751. return toReturn
  1752. endfunction
  1753. " Function: s:ConvertLeadingTabsToSpaces(line)
  1754. " This function takes a line and converts all leading spaces on that line into
  1755. " tabs
  1756. "
  1757. " Args:
  1758. " -line: the line whose leading spaces will be converted
  1759. function! s:ConvertLeadingTabsToSpaces(line) abort
  1760. let toReturn = a:line
  1761. while toReturn =~# '^\( *\)\t'
  1762. let toReturn = substitute(toReturn, '^\( *\)\t', '\1' . s:TabSpace() , '')
  1763. endwhile
  1764. return toReturn
  1765. endfunction
  1766. " Function: s:ConvertLeadingWhiteSpace(line)
  1767. " Converts the leading white space to tabs/spaces depending on &tabstop
  1768. "
  1769. " Args:
  1770. " -line: the line to convert
  1771. function! s:ConvertLeadingWhiteSpace(line) abort
  1772. let toReturn = a:line
  1773. while toReturn =~# '^ *\t'
  1774. let toReturn = substitute(toReturn, '^ *\zs\t\ze', s:TabSpace(), 'g')
  1775. endwhile
  1776. if !&expandtab
  1777. let toReturn = s:ConvertLeadingSpacesToTabs(toReturn)
  1778. endif
  1779. return toReturn
  1780. endfunction
  1781. " Function: s:CountNonESCedOccurances(str, searchstr, escChar)
  1782. " This function counts the number of substrings contained in another string.
  1783. " These substrings are only counted if they are not escaped with escChar
  1784. " Args:
  1785. " -str: the string to look for searchstr in
  1786. " -searchstr: the substring to search for in str
  1787. " -escChar: the escape character which, when preceding an instance of
  1788. " searchstr, will cause it not to be counted
  1789. function! s:CountNonESCedOccurances(str, searchstr, escChar) abort
  1790. "get the index of the first occurrence of searchstr
  1791. let indx = stridx(a:str, a:searchstr)
  1792. "if there is an instance of searchstr in str process it
  1793. if indx !=# -1
  1794. "get the remainder of str after this instance of searchstr is removed
  1795. let lensearchstr = strlen(a:searchstr)
  1796. let strLeft = strpart(a:str, indx+lensearchstr)
  1797. "if this instance of searchstr is not escaped, add one to the count
  1798. "and recurse. If it is escaped, just recurse
  1799. if !s:IsEscaped(a:str, indx, a:escChar)
  1800. return 1 + s:CountNonESCedOccurances(strLeft, a:searchstr, a:escChar)
  1801. else
  1802. return s:CountNonESCedOccurances(strLeft, a:searchstr, a:escChar)
  1803. endif
  1804. endif
  1805. endfunction
  1806. " Function: s:DoesBlockHaveDelim(delim, top, bottom)
  1807. " Returns 1 if the given block of lines has a delimiter (a:delim) in it
  1808. " Args:
  1809. " -delim: the comment delimiter to check the block for
  1810. " -top: the top line number of the block
  1811. " -bottom: the bottom line number of the block
  1812. function! s:DoesBlockHaveDelim(delim, top, bottom) abort
  1813. let currentLine = a:top
  1814. while currentLine < a:bottom
  1815. let theline = getline(currentLine)
  1816. if s:FindDelimiterIndex(a:delim, theline) !=# -1
  1817. return 1
  1818. endif
  1819. let currentLine = currentLine + 1
  1820. endwhile
  1821. return 0
  1822. endfunction
  1823. " Function: s:DoesBlockHaveMultipartDelim(top, bottom)
  1824. " Returns 1 if the given block has a >= 1 multipart delimiter in it
  1825. " Args:
  1826. " -top: the top line number of the block
  1827. " -bottom: the bottom line number of the block
  1828. function! s:DoesBlockHaveMultipartDelim(top, bottom) abort
  1829. if s:HasMultipartDelims()
  1830. if s:Multipart()
  1831. return s:DoesBlockHaveDelim(s:Left(), a:top, a:bottom) || s:DoesBlockHaveDelim(s:Right(), a:top, a:bottom)
  1832. else
  1833. return s:DoesBlockHaveDelim(s:Left({'alt': 1}), a:top, a:bottom) || s:DoesBlockHaveDelim(s:Right({'alt': 1}), a:top, a:bottom)
  1834. endif
  1835. endif
  1836. return 0
  1837. endfunction
  1838. " Function: s:Esc(str)
  1839. " Escapes all the tricky chars in the given string
  1840. function! s:Esc(str) abort
  1841. let charsToEsc = '*/\."&$+[]'
  1842. return escape(a:str, charsToEsc)
  1843. endfunction
  1844. " Function: s:FindDelimiterIndex(delimiter, line)
  1845. " This function is used to get the string index of the input comment delimiter
  1846. " on the input line. If no valid comment delimiter is found in the line then
  1847. " -1 is returned
  1848. " Args:
  1849. " -delimiter: the delimiter we are looking to find the index of
  1850. " -line: the line we are looking for delimiter on
  1851. function! s:FindDelimiterIndex(delimiter, line) abort
  1852. "make sure the delimiter isn't empty otherwise we go into an infinite loop.
  1853. if a:delimiter ==# ''
  1854. return -1
  1855. endif
  1856. let l:delimiter = a:delimiter
  1857. let lenDel = strlen(l:delimiter)
  1858. "get the index of the first occurrence of the delimiter
  1859. let delIndx = stridx(a:line, l:delimiter)
  1860. "keep looping thru the line till we either find a real comment delimiter
  1861. "or run off the EOL
  1862. while delIndx !=# -1
  1863. "if we are not off the EOL get the str before the possible delimiter
  1864. "in question and check if it really is a delimiter. If it is, return
  1865. "its position
  1866. if delIndx !=# -1
  1867. if s:IsDelimValid(l:delimiter, delIndx, a:line)
  1868. return delIndx
  1869. endif
  1870. endif
  1871. "we have not yet found a real comment delimiter so move past the
  1872. "current one we are looking at
  1873. let restOfLine = strpart(a:line, delIndx + lenDel)
  1874. let distToNextDelim = stridx(restOfLine , l:delimiter)
  1875. "if distToNextDelim is -1 then there is no more potential delimiters
  1876. "on the line so set delIndx to -1. Otherwise, move along the line by
  1877. "distToNextDelim
  1878. if distToNextDelim ==# -1
  1879. let delIndx = -1
  1880. else
  1881. let delIndx = delIndx + lenDel + distToNextDelim
  1882. endif
  1883. endwhile
  1884. "there is no comment delimiter on this line
  1885. return -1
  1886. endfunction
  1887. " Function: s:FindBoundingLinesOfSexyCom(lineNum)
  1888. " This function takes in a line number and tests whether this line number is
  1889. " the top/bottom/middle line of a sexy comment. If it is then the top/bottom
  1890. " lines of the sexy comment are returned
  1891. " Args:
  1892. " -lineNum: the line number that is to be tested whether it is the
  1893. " top/bottom/middle line of a sexy com
  1894. " Returns:
  1895. " A string that has the top/bottom lines of the sexy comment encoded in it.
  1896. " The format is 'topline,bottomline'. If a:lineNum turns out not to be the
  1897. " top/bottom/middle of a sexy comment then -1 is returned
  1898. function! s:FindBoundingLinesOfSexyCom(lineNum) abort
  1899. "find which delimiters to look for as the start/end delimiters of the comment
  1900. let left = ''
  1901. let right = ''
  1902. if s:Multipart()
  1903. let left = s:Left({'esc': 1})
  1904. let right = s:Right({'esc': 1})
  1905. elseif s:AltMultipart()
  1906. let left = s:Left({'alt': 1, 'esc': 1})
  1907. let right = s:Right({'alt': 1, 'esc': 1})
  1908. else
  1909. return []
  1910. endif
  1911. let sexyComMarker = s:GetSexyComMarker(0, 1)
  1912. "initialise the top/bottom line numbers of the sexy comment to -1
  1913. let top = -1
  1914. let bottom = -1
  1915. let currentLine = a:lineNum
  1916. while top ==# -1 || bottom ==# -1
  1917. let theLine = getline(currentLine)
  1918. "check if the current line is the top of the sexy comment
  1919. if currentLine <= a:lineNum && theLine =~# '^\s*' . left && theLine !~# '.*' . right && currentLine < s:NumLinesInBuf()
  1920. let top = currentLine
  1921. let currentLine = a:lineNum
  1922. "check if the current line is the bottom of the sexy comment
  1923. elseif theLine =~# '^\s*' . right && theLine !~# '.*' . left && currentLine > 1
  1924. let bottom = currentLine
  1925. "the right delimiter is on the same line as the last sexyComMarker
  1926. elseif theLine =~# '^\s*' . sexyComMarker . '.*' . right
  1927. let bottom = currentLine
  1928. "we have not found the top or bottom line so we assume currentLine is an
  1929. "intermediate line and look to prove otherwise
  1930. else
  1931. "if the line doesn't start with a sexyComMarker then it is not a sexy
  1932. "comment
  1933. if theLine !~# '^\s*' . sexyComMarker
  1934. return []
  1935. endif
  1936. endif
  1937. "if top is -1 then we haven't found the top yet so keep looking up
  1938. if top ==# -1
  1939. let currentLine = currentLine - 1
  1940. "if we have found the top line then go down looking for the bottom
  1941. else
  1942. let currentLine = currentLine + 1
  1943. endif
  1944. endwhile
  1945. return [top, bottom]
  1946. endfunction
  1947. " Function: s:GetSexyComMarker()
  1948. " Returns the sexy comment marker for the current filetype.
  1949. "
  1950. " C style sexy comments are assumed if possible. If not then the sexy comment
  1951. " marker is the last char of the delimiter pair that has both left and right
  1952. " delimiters and has the longest left delimiter
  1953. "
  1954. " Args:
  1955. " -space: specifies whether the marker is to have a space string after it
  1956. " (the space string will only be added if NERDSpaceDelims is set)
  1957. " -esc: specifies whether the tricky chars in the marker are to be ESCed
  1958. function! s:GetSexyComMarker(space, esc) abort
  1959. let sexyComMarker = b:NERDSexyComMarker
  1960. "if there is no hardcoded marker then we find one
  1961. if sexyComMarker ==# ''
  1962. "if the filetype has c style comments then use standard c sexy
  1963. "comments
  1964. if s:HasCStyleComments()
  1965. let sexyComMarker = '*'
  1966. else
  1967. "find a comment marker by getting the longest available left delimiter
  1968. "(that has a corresponding right delimiter) and taking the last char
  1969. let lenLeft = strlen(s:Left())
  1970. let lenLeftAlt = strlen(s:Left({'alt': 1}))
  1971. let left = ''
  1972. let right = ''
  1973. if s:Multipart() && lenLeft >= lenLeftAlt
  1974. let left = s:Left()
  1975. elseif s:AltMultipart()
  1976. let left = s:Left({'alt': 1})
  1977. else
  1978. return -1
  1979. endif
  1980. "get the last char of left
  1981. let sexyComMarker = strpart(left, strlen(left)-1)
  1982. endif
  1983. endif
  1984. if a:space && g:NERDSpaceDelims
  1985. let sexyComMarker = sexyComMarker . s:spaceStr
  1986. endif
  1987. if a:esc
  1988. let sexyComMarker = s:Esc(sexyComMarker)
  1989. endif
  1990. return sexyComMarker
  1991. endfunction
  1992. " Function: s:SexyNested()
  1993. " Returns 1 if the sexy delimeters allow nesting
  1994. " TODO this is ugly copy&paste from the GetSexyComLeft/Right functions,
  1995. " these could all be cleaned up
  1996. function! s:SexyNested() abort
  1997. let lenLeft = strlen(s:Left())
  1998. let lenLeftAlt = strlen(s:Left({'alt': 1}))
  1999. "assume c style sexy comments if possible
  2000. if s:HasCStyleComments()
  2001. return (s:Left() ==# '/*' && s:Nested()) || (s:Left({'alt': 1}) ==# '/*' && s:AltNested())
  2002. else
  2003. "grab the longest left delim that has a right
  2004. if s:Multipart() && lenLeft >= lenLeftAlt
  2005. return s:Nested()
  2006. elseif s:AltMultipart()
  2007. return s:AltNested()
  2008. else
  2009. return 0
  2010. endif
  2011. endif
  2012. endfunction
  2013. " Function: s:GetSexyComLeft(space, esc)
  2014. " Returns the left delimiter for sexy comments for this filetype or -1 if
  2015. " there is none. C style sexy comments are used if possible
  2016. " Args:
  2017. " -space: specifies if the delimiter has a space string on the end
  2018. " (the space string will only be added if NERDSpaceDelims is set)
  2019. " -esc: specifies whether the tricky chars in the string are ESCed
  2020. function! s:GetSexyComLeft(space, esc) abort
  2021. let lenLeft = strlen(s:Left())
  2022. let lenLeftAlt = strlen(s:Left({'alt': 1}))
  2023. let left = ''
  2024. "assume c style sexy comments if possible
  2025. if s:HasCStyleComments()
  2026. let left = '/*'
  2027. else
  2028. "grab the longest left delimiter that has a right
  2029. if s:Multipart() && lenLeft >= lenLeftAlt
  2030. let left = s:Left()
  2031. elseif s:AltMultipart()
  2032. let left = s:Left({'alt': 1})
  2033. else
  2034. return -1
  2035. endif
  2036. endif
  2037. if a:space && g:NERDSpaceDelims
  2038. let left = left . s:spaceStr
  2039. endif
  2040. if a:esc
  2041. let left = s:Esc(left)
  2042. endif
  2043. return left
  2044. endfunction
  2045. " Function: s:GetSexyComRight(space, esc)
  2046. " Returns the right delimiter for sexy comments for this filetype or -1 if
  2047. " there is none. C style sexy comments are used if possible.
  2048. " Args:
  2049. " -space: specifies if the delimiter has a space string on the start
  2050. " (the space string will only be added if NERDSpaceDelims
  2051. " is specified for the current filetype)
  2052. " -esc: specifies whether the tricky chars in the string are ESCed
  2053. function! s:GetSexyComRight(space, esc) abort
  2054. let lenLeft = strlen(s:Left())
  2055. let lenLeftAlt = strlen(s:Left({'alt': 1}))
  2056. let right = ''
  2057. "assume c style sexy comments if possible
  2058. if s:HasCStyleComments()
  2059. let right = '*/'
  2060. else
  2061. "grab the right delimiter that pairs with the longest left delimiter
  2062. if s:Multipart() && lenLeft >= lenLeftAlt
  2063. let right = s:Right()
  2064. elseif s:AltMultipart()
  2065. let right = s:Right({'alt': 1})
  2066. else
  2067. return -1
  2068. endif
  2069. endif
  2070. if a:space && g:NERDSpaceDelims
  2071. let right = s:spaceStr . right
  2072. endif
  2073. if a:esc
  2074. let right = s:Esc(right)
  2075. endif
  2076. return right
  2077. endfunction
  2078. " Function: s:HasMultipartDelims()
  2079. " Returns 1 if the current filetype has at least one set of multipart delimiters
  2080. function! s:HasMultipartDelims() abort
  2081. return s:Multipart() || s:AltMultipart()
  2082. endfunction
  2083. " Function: s:HasLeadingTabs(...)
  2084. " Returns 1 if any of the given strings have leading tabs
  2085. function! s:HasLeadingTabs(...) abort
  2086. for s in a:000
  2087. if s =~# '^\t.*'
  2088. return 1
  2089. end
  2090. endfor
  2091. return 0
  2092. endfunction
  2093. " Function: s:HasCStyleComments()
  2094. " Returns 1 if the current filetype has c style comment delimiters
  2095. function! s:HasCStyleComments() abort
  2096. return (s:Left() ==# '/*' && s:Right() ==# '*/') || (s:Left({'alt': 1}) ==# '/*' && s:Right({'alt': 1}) ==# '*/')
  2097. endfunction
  2098. " Function: s:IsCommentedNormOrSexy(lineNum)
  2099. "This function is used to determine whether the given line is commented with
  2100. "either set of delimiters or if it is part of a sexy comment
  2101. "
  2102. " Args:
  2103. " -lineNum: the line number of the line to check
  2104. function! s:IsCommentedNormOrSexy(lineNum) abort
  2105. let theLine = getline(a:lineNum)
  2106. "if the line is commented normally return 1
  2107. if s:IsCommented(s:Left(), s:Right(), theLine) || s:IsCommented(s:Left({'alt': 1}), s:Right({'alt': 1}), theLine)
  2108. return 1
  2109. endif
  2110. "if the line is part of a sexy comment return 1
  2111. if s:IsInSexyComment(a:lineNum)
  2112. return 1
  2113. endif
  2114. return 0
  2115. endfunction
  2116. " Function: s:IsCommented(left, right, line)
  2117. "This function is used to determine whether the given line is commented with
  2118. "the given delimiters
  2119. "
  2120. " Args:
  2121. " -line: the line that to check if commented
  2122. " -left/right: the left and right delimiters to check for
  2123. function! s:IsCommented(left, right, line) abort
  2124. "if the line isn't commented return true
  2125. if s:FindDelimiterIndex(a:left, a:line) !=# -1 && (s:LastIndexOfDelim(a:right, a:line) !=# -1 || !s:Multipart())
  2126. return 1
  2127. endif
  2128. return 0
  2129. endfunction
  2130. " Function: s:IsCommentedFromStartOfLine(left, line)
  2131. "This function is used to determine whether the given line is commented with
  2132. "the given delimiters at the start of the line i.e the left delimiter is the
  2133. "first thing on the line (apart from spaces\tabs)
  2134. "
  2135. " Args:
  2136. " -line: the line that to check if commented
  2137. " -left: the left delimiter to check for
  2138. function! s:IsCommentedFromStartOfLine(left, line) abort
  2139. let theLine = s:ConvertLeadingTabsToSpaces(a:line)
  2140. let numSpaces = strlen(matchstr(theLine, '^ *'))
  2141. let delimIndx = s:FindDelimiterIndex(a:left, theLine)
  2142. return delimIndx ==# numSpaces
  2143. endfunction
  2144. " Function: s:IsCommentedOutermost(left, right, leftAlt, rightAlt, line)
  2145. " Finds the type of the outermost delimiters on the line
  2146. "
  2147. " Args:
  2148. " -line: the line that to check if the outermost comments on it are
  2149. " left/right
  2150. " -left/right: the left and right delimiters to check for
  2151. " -leftAlt/rightAlt: the left and right alternative delimiters to check for
  2152. "
  2153. " Returns:
  2154. " 0 if the line is not commented with either set of delimiters
  2155. " 1 if the line is commented with the left/right delimiter set
  2156. " 2 if the line is commented with the leftAlt/rightAlt delim set
  2157. function! s:IsCommentedOutermost(left, right, leftAlt, rightAlt, line) abort
  2158. "get the first positions of the left delimiters and the last positions of the
  2159. "right delimiters
  2160. let indxLeft = s:FindDelimiterIndex(a:left, a:line)
  2161. let indxLeftAlt = s:FindDelimiterIndex(a:leftAlt, a:line)
  2162. let indxRight = s:LastIndexOfDelim(a:right, a:line)
  2163. let indxRightAlt = s:LastIndexOfDelim(a:rightAlt, a:line)
  2164. "check if the line has a left delimiter before a leftAlt delimiter
  2165. if (indxLeft <= indxLeftAlt || indxLeftAlt ==# -1) && indxLeft !=# -1
  2166. "check if the line has a right delimiter after any rightAlt delimiter
  2167. if (indxRight > indxRightAlt && indxRight > indxLeft) || !s:Multipart()
  2168. return 1
  2169. endif
  2170. "check if the line has a leftAlt delimiter before a left delimiter
  2171. elseif (indxLeftAlt <= indxLeft || indxLeft ==# -1) && indxLeftAlt !=# -1
  2172. "check if the line has a rightAlt delimiter after any right delimiter
  2173. if (indxRightAlt > indxRight && indxRightAlt > indxLeftAlt) || !s:AltMultipart()
  2174. return 2
  2175. endif
  2176. else
  2177. return 0
  2178. endif
  2179. return 0
  2180. endfunction
  2181. " Function: s:IsDelimValid(delimiter, delIndx, line)
  2182. " This function is responsible for determining whether a given instance of a
  2183. " comment delimiter is a real delimiter or not. For example, in java the
  2184. " // string is a comment delimiter but in the line:
  2185. " System.out.println("//");
  2186. " it does not count as a comment delimiter. This function is responsible for
  2187. " distinguishing between such cases. It does so by applying a set of
  2188. " heuristics that are not fool proof but should work most of the time.
  2189. "
  2190. " Args:
  2191. " -delimiter: the delimiter we are validating
  2192. " -delIndx: the position of delimiter in line
  2193. " -line: the line that delimiter occurs in
  2194. "
  2195. " Returns:
  2196. " 0 if the given delimiter is not a real delimiter (as far as we can tell) ,
  2197. " 1 otherwise
  2198. function! s:IsDelimValid(delimiter, delIndx, line) abort
  2199. "get the delimiter without the escchars
  2200. let l:delimiter = a:delimiter
  2201. "get the strings before and after the delimiter
  2202. let preComStr = strpart(a:line, 0, a:delIndx)
  2203. let postComStr = strpart(a:line, a:delIndx+strlen(delimiter))
  2204. "to check if the delimiter is real, make sure it isn't preceded by
  2205. "an odd number of quotes and followed by the same (which would indicate
  2206. "that it is part of a string and therefore is not a comment)
  2207. if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, '"', "\\")) && !s:IsNumEven(s:CountNonESCedOccurances(postComStr, '"', '\\'))
  2208. return 0
  2209. endif
  2210. if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, "'", '\\')) && !s:IsNumEven(s:CountNonESCedOccurances(postComStr, "'", '\\'))
  2211. return 0
  2212. endif
  2213. if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, '`', '\\')) && !s:IsNumEven(s:CountNonESCedOccurances(postComStr, '`', '\\'))
  2214. return 0
  2215. endif
  2216. "if the comment delimiter is escaped, assume it isn't a real delimiter
  2217. if s:IsEscaped(a:line, a:delIndx, "\\")
  2218. return 0
  2219. endif
  2220. "vim comments are so fucking stupid!! Why the hell do they have comment
  2221. "delimiters that are used elsewhere in the syntax?!?! We need to check
  2222. "some conditions especially for vim
  2223. if &filetype ==# 'vim'
  2224. if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, '"', "\\"))
  2225. return 0
  2226. endif
  2227. "if the delimiter is on the very first char of the line or is the
  2228. "first non-tab/space char on the line then it is a valid comment delimiter
  2229. if a:delIndx ==# 0 || a:line =~# "^\s\\{" . a:delIndx . "\\}\".*$"
  2230. return 1
  2231. endif
  2232. let numLeftParen =s:CountNonESCedOccurances(preComStr, '(', '\\')
  2233. let numRightParen =s:CountNonESCedOccurances(preComStr, ')', '\\')
  2234. "if the quote is inside brackets then assume it isn't a comment
  2235. if numLeftParen > numRightParen
  2236. return 0
  2237. endif
  2238. "if the line has an even num of unescaped "'s then we can assume that
  2239. "any given " is not a comment delimiter
  2240. if s:IsNumEven(s:CountNonESCedOccurances(a:line, '"', '\\'))
  2241. return 0
  2242. endif
  2243. endif
  2244. return 1
  2245. endfunction
  2246. " Function: s:IsNumEven(num)
  2247. " A small function the returns 1 if the input number is even and 0 otherwise
  2248. " Args:
  2249. " -num: the number to check
  2250. function! s:IsNumEven(num) abort
  2251. return (a:num % 2) ==# 0
  2252. endfunction
  2253. " Function: s:IsEscaped(str, indx, escChar)
  2254. " This function takes a string, an index into that string and an esc char and
  2255. " returns 1 if the char at the index is escaped (i.e if it is preceded by an
  2256. " odd number of esc chars)
  2257. " Args:
  2258. " -str: the string to check
  2259. " -indx: the index into str that we want to check
  2260. " -escChar: the escape char the char at indx may be ESCed with
  2261. function! s:IsEscaped(str, indx, escChar) abort
  2262. "initialise numEscChars to 0 and look at the char before indx
  2263. let numEscChars = 0
  2264. let curIndx = a:indx-1
  2265. "keep going back thru str until we either reach the start of the str or
  2266. "run out of esc chars
  2267. while curIndx >= 0 && strpart(a:str, curIndx, 1) ==# a:escChar
  2268. "we have found another esc char so add one to the count and move left
  2269. "one char
  2270. let numEscChars = numEscChars + 1
  2271. let curIndx = curIndx - 1
  2272. endwhile
  2273. "if there is an odd num of esc chars directly before the char at indx then
  2274. "the char at indx is escaped
  2275. return !s:IsNumEven(numEscChars)
  2276. endfunction
  2277. " Function: s:IsInSexyComment(line)
  2278. " returns 1 if the given line number is part of a sexy comment
  2279. function! s:IsInSexyComment(line) abort
  2280. return !empty(s:FindBoundingLinesOfSexyCom(a:line))
  2281. endfunction
  2282. " Function: s:IsSexyComment(topline, bottomline)
  2283. " This function takes in 2 line numbers and returns 1 if the lines between and
  2284. " including the given line numbers are a sexy comment. It returns 0 otherwise.
  2285. " Args:
  2286. " -topline: the line that the possible sexy comment starts on
  2287. " -bottomline: the line that the possible sexy comment stops on
  2288. function! s:IsSexyComment(topline, bottomline) abort
  2289. "get the delimiter set that would be used for a sexy comment
  2290. let left = ''
  2291. let right = ''
  2292. if s:Multipart()
  2293. let left = s:Left()
  2294. let right = s:Right()
  2295. elseif s:AltMultipart()
  2296. let left = s:Left({'alt': 1})
  2297. let right = s:Right({'alt': 1})
  2298. else
  2299. return 0
  2300. endif
  2301. "swap the top and bottom line numbers around if need be
  2302. let topline = a:topline
  2303. let bottomline = a:bottomline
  2304. if bottomline < topline
  2305. let topline = bottomline
  2306. let bottomline = a:topline
  2307. endif
  2308. "if there is < 2 lines in the comment it cannot be sexy
  2309. if (bottomline - topline) <= 0
  2310. return 0
  2311. endif
  2312. "if the top line doesn't begin with a left delimiter then the comment isn't sexy
  2313. if getline(a:topline) !~# '^\s*' . left
  2314. return 0
  2315. endif
  2316. "if there is a right delimiter on the top line then this isn't a sexy comment
  2317. if s:LastIndexOfDelim(right, getline(a:topline)) !=# -1
  2318. return 0
  2319. endif
  2320. "if there is a left delimiter on the bottom line then this isn't a sexy comment
  2321. if s:FindDelimiterIndex(left, getline(a:bottomline)) !=# -1
  2322. return 0
  2323. endif
  2324. "if the bottom line doesn't begin with a right delimiter then the comment isn't
  2325. "sexy
  2326. if getline(a:bottomline) !~# '^.*' . right . '$'
  2327. return 0
  2328. endif
  2329. let sexyComMarker = s:GetSexyComMarker(0, 1)
  2330. "check each of the intermediate lines to make sure they start with a
  2331. "sexyComMarker
  2332. let currentLine = a:topline+1
  2333. while currentLine < a:bottomline
  2334. let theLine = getline(currentLine)
  2335. if theLine !~# '^\s*' . sexyComMarker
  2336. return 0
  2337. endif
  2338. "if there is a right delimiter in an intermediate line then the block isn't
  2339. "a sexy comment
  2340. if s:LastIndexOfDelim(right, theLine) !=# -1
  2341. return 0
  2342. endif
  2343. let currentLine = currentLine + 1
  2344. endwhile
  2345. "we have not found anything to suggest that this isn't a sexy comment so
  2346. return 1
  2347. endfunction
  2348. " Function: s:LastIndexOfDelim(delim, str)
  2349. " This function takes a string and a delimiter and returns the last index of
  2350. " that delimiter in string
  2351. " Args:
  2352. " -delim: the delimiter to look for
  2353. " -str: the string to look for delimiter in
  2354. function! s:LastIndexOfDelim(delim, str) abort
  2355. let delim = a:delim
  2356. let lenDelim = strlen(delim)
  2357. "set index to the first occurrence of delimiter. If there is no occurrence then
  2358. "bail
  2359. let indx = s:FindDelimiterIndex(delim, a:str)
  2360. if indx ==# -1
  2361. return -1
  2362. endif
  2363. "keep moving to the next instance of delimiter in str till there is none left
  2364. while 1
  2365. "search for the next delimiter after the previous one
  2366. let searchStr = strpart(a:str, indx+lenDelim)
  2367. let indx2 = s:FindDelimiterIndex(delim, searchStr)
  2368. "if we find a delimiter update indx to record the position of it, if we
  2369. "don't find another delimiter then indx is the last one so break out of
  2370. "this loop
  2371. if indx2 !=# -1
  2372. let indx = indx + indx2 + lenDelim
  2373. else
  2374. break
  2375. endif
  2376. endwhile
  2377. return indx
  2378. endfunction
  2379. " Function: s:Left(...)
  2380. " returns left delimiter data
  2381. function! s:Left(...) abort
  2382. let params = a:0 ? a:1 : {}
  2383. let delim = has_key(params, 'alt') ? b:NERDCommenterDelims['leftAlt'] : b:NERDCommenterDelims['left']
  2384. if delim ==# ''
  2385. return ''
  2386. endif
  2387. if has_key(params, 'space') && g:NERDSpaceDelims
  2388. let delim = delim . s:spaceStr
  2389. endif
  2390. if has_key(params, 'esc')
  2391. let delim = s:Esc(delim)
  2392. endif
  2393. return delim
  2394. endfunction
  2395. " Function: s:LeftMostIndx(countCommentedLines, countEmptyLines, topline, bottomline)
  2396. " This function takes in 2 line numbers and returns the index of the left most
  2397. " char (that is not a space or a tab) on all of these lines.
  2398. " Args:
  2399. " -countCommentedLines: 1 if lines that are commented are to be checked as
  2400. " well. 0 otherwise
  2401. " -countEmptyLines: 1 if empty lines are to be counted in the search
  2402. " -topline: the top line to be checked
  2403. " -bottomline: the bottom line to be checked
  2404. function! s:LeftMostIndx(countCommentedLines, countEmptyLines, topline, bottomline) abort
  2405. " declare the left most index as an extreme value
  2406. let leftMostIndx = 1000
  2407. " go thru the block line by line updating leftMostIndx
  2408. let currentLine = a:topline
  2409. while currentLine <= a:bottomline
  2410. " get the next line and if it is allowed to be commented, or is not
  2411. " commented, check it
  2412. let theLine = getline(currentLine)
  2413. if a:countEmptyLines || theLine !~# '^\s*$'
  2414. if a:countCommentedLines || (!s:IsCommented(s:Left(), s:Right(), theLine) && !s:IsCommented(s:Left({'alt': 1}), s:Right({'alt': 1}), theLine))
  2415. " convert spaces to tabs and get the number of leading spaces for
  2416. " this line and update leftMostIndx if need be
  2417. let theLine = s:ConvertLeadingTabsToSpaces(theLine)
  2418. let leadSpaceOfLine = strlen(matchstr(theLine, '^\s*'))
  2419. if leadSpaceOfLine < leftMostIndx
  2420. let leftMostIndx = leadSpaceOfLine
  2421. endif
  2422. endif
  2423. endif
  2424. " move on to the next line
  2425. let currentLine = currentLine + 1
  2426. endwhile
  2427. if leftMostIndx ==# 1000
  2428. return 0
  2429. else
  2430. return leftMostIndx
  2431. endif
  2432. endfunction
  2433. " Function: s:Multipart()
  2434. " returns 1 if the current delimiters are multipart
  2435. function! s:Multipart() abort
  2436. return s:Right() !=# ''
  2437. endfunction
  2438. " Function: s:NerdEcho(msg, typeOfMsg)
  2439. " Args:
  2440. " -msg: the message to echo
  2441. " -typeOfMsg: 0 = warning message
  2442. " 1 = normal message
  2443. function! s:NerdEcho(msg, typeOfMsg) abort
  2444. if a:typeOfMsg ==# 0
  2445. echohl WarningMsg
  2446. echom 'NERDCommenter:' . a:msg
  2447. echohl None
  2448. elseif a:typeOfMsg ==# 1
  2449. echom 'NERDCommenter:' . a:msg
  2450. endif
  2451. endfunction
  2452. " Function: s:Nested()
  2453. " returns 1 if the current multipart (if any) delimiters allow nesting
  2454. function! s:Nested() abort
  2455. return b:NERDCommenterDelims['nested']
  2456. endfunction
  2457. " Function: s:NumberOfLeadingTabs(s)
  2458. " returns the number of leading tabs in the given string
  2459. function! s:NumberOfLeadingTabs(s) abort
  2460. return strlen(matchstr(a:s, '^\t*'))
  2461. endfunction
  2462. " Function: s:NumLinesInBuf()
  2463. " Returns the number of lines in the current buffer
  2464. function! s:NumLinesInBuf() abort
  2465. return line('$')
  2466. endfunction
  2467. " Function: s:ReplaceDelims(toReplace1, toReplace2, replacor1, replacor2, str)
  2468. " This function takes in a string, 2 delimiters in that string and 2 strings
  2469. " to replace these delimiters with.
  2470. "
  2471. " Args:
  2472. " -toReplace1: the first delimiter to replace
  2473. " -toReplace2: the second delimiter to replace
  2474. " -replacor1: the string to replace toReplace1 with
  2475. " -replacor2: the string to replace toReplace2 with
  2476. " -str: the string that the delimiters to be replaced are in
  2477. function! s:ReplaceDelims(toReplace1, toReplace2, replacor1, replacor2, str) abort
  2478. let line = s:ReplaceLeftMostDelim(a:toReplace1, a:replacor1, a:str)
  2479. let line = s:ReplaceRightMostDelim(a:toReplace2, a:replacor2, line)
  2480. return line
  2481. endfunction
  2482. " Function: s:ReplaceLeftMostDelim(toReplace, replacor, str)
  2483. " This function takes a string and a delimiter and replaces the left most
  2484. " occurrence of this delimiter in the string with a given string
  2485. "
  2486. " Args:
  2487. " -toReplace: the delimiter in str that is to be replaced
  2488. " -replacor: the string to replace toReplace with
  2489. " -str: the string that contains toReplace
  2490. function! s:ReplaceLeftMostDelim(toReplace, replacor, str) abort
  2491. let toReplace = a:toReplace
  2492. let replacor = a:replacor
  2493. "get the left most occurrence of toReplace
  2494. let indxToReplace = s:FindDelimiterIndex(toReplace, a:str)
  2495. "if there IS an occurrence of toReplace in str then replace it and return
  2496. "the resulting string
  2497. if indxToReplace !=# -1
  2498. let line = strpart(a:str, 0, indxToReplace) . replacor . strpart(a:str, indxToReplace+strlen(toReplace))
  2499. return line
  2500. endif
  2501. return a:str
  2502. endfunction
  2503. " Function: s:ReplaceRightMostDelim(toReplace, replacor, str)
  2504. " This function takes a string and a delimiter and replaces the right most
  2505. " occurrence of this delimiter in the string with a given string
  2506. "
  2507. " Args:
  2508. " -toReplace: the delimiter in str that is to be replaced
  2509. " -replacor: the string to replace toReplace with
  2510. " -str: the string that contains toReplace
  2511. "
  2512. function! s:ReplaceRightMostDelim(toReplace, replacor, str) abort
  2513. let toReplace = a:toReplace
  2514. let replacor = a:replacor
  2515. let lenToReplace = strlen(toReplace)
  2516. "get the index of the last delimiter in str
  2517. let indxToReplace = s:LastIndexOfDelim(toReplace, a:str)
  2518. "if there IS a delimiter in str, replace it and return the result
  2519. let line = a:str
  2520. if indxToReplace !=# -1
  2521. let line = strpart(a:str, 0, indxToReplace) . replacor . strpart(a:str, indxToReplace+strlen(toReplace))
  2522. endif
  2523. return line
  2524. endfunction
  2525. " Function: s:Right(...)
  2526. " returns right delimiter data
  2527. function! s:Right(...) abort
  2528. let params = a:0 ? a:1 : {}
  2529. let delim = has_key(params, 'alt') ? b:NERDCommenterDelims['rightAlt'] : b:NERDCommenterDelims['right']
  2530. if delim ==# ''
  2531. return ''
  2532. endif
  2533. if has_key(params, 'space') && g:NERDSpaceDelims
  2534. let delim = s:spaceStr . delim
  2535. endif
  2536. if has_key(params, 'esc')
  2537. let delim = s:Esc(delim)
  2538. endif
  2539. return delim
  2540. endfunction
  2541. " Function: s:RightMostIndx(countCommentedLines, countEmptyLines, topline, bottomline)
  2542. " This function takes in 2 line numbers and returns the index of the right most
  2543. " char on all of these lines.
  2544. " Args:
  2545. " -countCommentedLines: 1 if lines that are commented are to be checked as
  2546. " well. 0 otherwise
  2547. " -countEmptyLines: 1 if empty lines are to be counted in the search
  2548. " -topline: the top line to be checked
  2549. " -bottomline: the bottom line to be checked
  2550. function! s:RightMostIndx(countCommentedLines, countEmptyLines, topline, bottomline) abort
  2551. let rightMostIndx = -1
  2552. " go thru the block line by line updating rightMostIndx
  2553. let currentLine = a:topline
  2554. while currentLine <= a:bottomline
  2555. " get the next line and see if it is commentable, otherwise it doesn't
  2556. " count
  2557. let theLine = getline(currentLine)
  2558. if a:countEmptyLines || theLine !~# '^\s*$'
  2559. if a:countCommentedLines || (!s:IsCommented(s:Left(), s:Right(), theLine) && !s:IsCommented(s:Left({'alt': 1}), s:Right({'alt': 1}), theLine))
  2560. " update rightMostIndx if need be
  2561. let theLine = s:ConvertLeadingTabsToSpaces(theLine)
  2562. let lineLen = strlen(theLine)
  2563. if lineLen > rightMostIndx
  2564. let rightMostIndx = lineLen
  2565. endif
  2566. endif
  2567. endif
  2568. " move on to the next line
  2569. let currentLine = currentLine + 1
  2570. endwhile
  2571. return rightMostIndx
  2572. endfunction
  2573. " Function: s:SwapOuterMultiPartDelimsForPlaceHolders(line)
  2574. " This function takes a line and swaps the outer most multi-part delimiters for
  2575. " place holders
  2576. " Args:
  2577. " -line: the line to swap the delimiters in
  2578. "
  2579. function! s:SwapOuterMultiPartDelimsForPlaceHolders(line) abort
  2580. " find out if the line is commented using normal delimiters and/or
  2581. " alternate ones
  2582. let isCommented = s:IsCommented(s:Left(), s:Right(), a:line)
  2583. let isCommentedAlt = s:IsCommented(s:Left({'alt': 1}), s:Right({'alt': 1}), a:line)
  2584. let line2 = a:line
  2585. "if the line is commented and there is a right delimiter, replace
  2586. "the delimiters with place-holders
  2587. if isCommented && s:Multipart()
  2588. let line2 = s:ReplaceDelims(s:Left(), s:Right(), g:NERDLPlace, g:NERDRPlace, a:line)
  2589. "similarly if the line is commented with the alternative
  2590. "delimiters
  2591. elseif isCommentedAlt && s:AltMultipart()
  2592. let line2 = s:ReplaceDelims(s:Left({'alt': 1}), s:Right({'alt': 1}), g:NERDLPlace, g:NERDRPlace, a:line)
  2593. endif
  2594. return line2
  2595. endfunction
  2596. " Function: s:SwapOuterPlaceHoldersForMultiPartDelims(line)
  2597. " This function takes a line and swaps the outermost place holders for
  2598. " multi-part delimiters
  2599. " Args:
  2600. " -line: the line to swap the delimiters in
  2601. "
  2602. function! s:SwapOuterPlaceHoldersForMultiPartDelims(line) abort
  2603. let left = ''
  2604. let right = ''
  2605. if s:Multipart()
  2606. let left = s:Left()
  2607. let right = s:Right()
  2608. elseif s:AltMultipart()
  2609. let left = s:Left({'alt': 1})
  2610. let right = s:Right({'alt': 1})
  2611. endif
  2612. let line = s:ReplaceDelims(g:NERDLPlace, g:NERDRPlace, left, right, a:line)
  2613. return line
  2614. endfunction
  2615. "FUNCTION: s:TabSpace()
  2616. "returns a string of spaces equal in length to &tabstop
  2617. function! s:TabSpace() abort
  2618. let tabSpace = ''
  2619. let spacesPerTab = &tabstop
  2620. while spacesPerTab > 0
  2621. let tabSpace = tabSpace . ' '
  2622. let spacesPerTab = spacesPerTab - 1
  2623. endwhile
  2624. return tabSpace
  2625. endfunction
  2626. " Function: s:UnEsc(str, escChar)
  2627. " This function removes all the escape chars from a string
  2628. " Args:
  2629. " -str: the string to remove esc chars from
  2630. " -escChar: the escape char to be removed
  2631. function! s:UnEsc(str, escChar) abort
  2632. return substitute(a:str, a:escChar, '', 'g')
  2633. endfunction