From 70f0ef31d89e361cb7c37de9b1b73a829c41c9a4 Mon Sep 17 00:00:00 2001 From: Florian Pritz Date: Sat, 4 Dec 2010 23:01:02 +0100 Subject: vim: add new plugins; add movement keymappings Signed-off-by: Florian Pritz --- .vim/autoload/rainbow_parenthsis.vim | 172 +++ .vim/doc/rainbow_parenthsis.txt | 88 ++ .vim/doc/tags | 32 + .vim/ftplugin/html/sparkup.py | 1087 +++++++++++++ .vim/ftplugin/html/sparkup.vim | 76 + .vim/plugin/NERD_commenter.vim | 2786 ++++++++++++++++++++++++++++++++++ .vim/plugin/rainbow_parenthsis.vim | 40 + .vim/rainbow_parenthsis_options.vim | 55 + 8 files changed, 4336 insertions(+) create mode 100644 .vim/autoload/rainbow_parenthsis.vim create mode 100644 .vim/doc/rainbow_parenthsis.txt create mode 100755 .vim/ftplugin/html/sparkup.py create mode 100644 .vim/ftplugin/html/sparkup.vim create mode 100644 .vim/plugin/NERD_commenter.vim create mode 100644 .vim/plugin/rainbow_parenthsis.vim create mode 100644 .vim/rainbow_parenthsis_options.vim (limited to '.vim') diff --git a/.vim/autoload/rainbow_parenthsis.vim b/.vim/autoload/rainbow_parenthsis.vim new file mode 100644 index 0000000..ffbd4fe --- /dev/null +++ b/.vim/autoload/rainbow_parenthsis.vim @@ -0,0 +1,172 @@ +"------------------------------------------------------------------------------ +" Description: Rainbow colors for parenthsis +" $Id: rainbow_parenthsis.vim 50 2007-10-08 18:42:51Z krischik@users.sourceforge.net $ +" Copyright: Copyright (C) 2007 Martin Krischik +" Maintainer: Martin Krischik (krischik@users.sourceforge.net) +" John Gilmore +" Luc Hermitte (hermitte@free.fr) +" $Author: krischik@users.sourceforge.net $ +" $Date: 2007-10-08 20:42:51 +0200 (Mo, 08 Okt 2007) $ +" Version: 4.0 +" $Revision: 50 $ +" $HeadURL: https://vim-scripts.googlecode.com/svn/trunk/1561%20Rainbow%20Parenthsis%20Bundle/autoload/rainbow_parenthsis.vim $ +" History: 24.05.2006 MK Unified Headers +" 15.10.2006 MK Bram's suggestion for runtime integration +" 06.09.2007 LH Buffer friendly (can be used in different buffers), +" can be toggled +" 09.09.2007 MK Use on LH's suggestion but use autoload to +" impove memory consumtion and startup performance +" 09.10.2007 MK Now with round, square brackets, curly and angle +" brackets. +" Usage: copy to autoload directory. +"------------------------------------------------------------------------------ +" This is a simple script. It extends the syntax highlighting to +" highlight each matching set of parens in different colors, to make +" it visually obvious what matches which. +" +" Obviously, most useful when working with lisp or Ada. But it's also nice other +" times. +"------------------------------------------------------------------------------ + +" Section: highlight {{{1 + +function rainbow_parenthsis#Activate() + highlight default level1c ctermbg=LightGray ctermfg=brown guibg=WhiteSmoke guifg=RoyalBlue3 + highlight default level2c ctermbg=LightGray ctermfg=Darkblue guibg=WhiteSmoke guifg=SeaGreen3 + highlight default level3c ctermbg=LightGray ctermfg=darkgray guibg=WhiteSmoke guifg=DarkOrchid3 + highlight default level4c ctermbg=LightGray ctermfg=darkgreen guibg=WhiteSmoke guifg=firebrick3 + highlight default level5c ctermbg=LightGray ctermfg=darkcyan guibg=AntiqueWhite guifg=RoyalBlue3 + highlight default level6c ctermbg=LightGray ctermfg=darkred guibg=AntiqueWhite guifg=SeaGreen3 + highlight default level7c ctermbg=LightGray ctermfg=darkmagenta guibg=AntiqueWhite guifg=DarkOrchid3 + highlight default level8c ctermbg=LightGray ctermfg=brown guibg=AntiqueWhite guifg=firebrick3 + highlight default level9c ctermbg=LightGray ctermfg=gray guibg=LemonChiffon guifg=RoyalBlue3 + highlight default level10c ctermbg=LightGray ctermfg=black guibg=LemonChiffon guifg=SeaGreen3 + highlight default level11c ctermbg=LightGray ctermfg=darkmagenta guibg=LemonChiffon guifg=DarkOrchid3 + highlight default level12c ctermbg=LightGray ctermfg=Darkblue guibg=LemonChiffon guifg=firebrick3 + highlight default level13c ctermbg=LightGray ctermfg=darkgreen guibg=AliceBlue guifg=RoyalBlue3 + highlight default level14c ctermbg=LightGray ctermfg=darkcyan guibg=AliceBlue guifg=SeaGreen3 + highlight default level15c ctermbg=LightGray ctermfg=darkred guibg=AliceBlue guifg=DarkOrchid3 + highlight default level16c ctermbg=LightGray ctermfg=red guibg=AliceBlue guifg=firebrick3 + let rainbow_parenthesis#active = 1 +endfunction + +function rainbow_parenthsis#Clear() + let i = 0 + while i != 16 + let i = i + 1 + exe 'highlight clear level' . i . 'c' + endwhile + let rainbow_parenthesis#active = 0 +endfunction + +function rainbow_parenthsis#Toggle () + if ! exists('rainbow_parenthesis#active') + call rainbow_parenthsis#LoadRound () + endif + if rainbow_parenthesis#active != 0 + call rainbow_parenthsis#Clear () + else + call rainbow_parenthsis#Activate () + endif +endfunction + +" Section: syntax {{{1 +" +" Subsection: parentheses or round brackets: {{{2 +" +function rainbow_parenthsis#LoadRound () + syntax region level1 matchgroup=level1c start=/(/ end=/)/ contains=TOP,level1,level2,level3,level4,level5,level6,level7,level8,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level2 matchgroup=level2c start=/(/ end=/)/ contains=TOP,level2,level3,level4,level5,level6,level7,level8,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level3 matchgroup=level3c start=/(/ end=/)/ contains=TOP,level3,level4,level5,level6,level7,level8,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level4 matchgroup=level4c start=/(/ end=/)/ contains=TOP,level4,level5,level6,level7,level8,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level5 matchgroup=level5c start=/(/ end=/)/ contains=TOP,level5,level6,level7,level8,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level6 matchgroup=level6c start=/(/ end=/)/ contains=TOP,level6,level7,level8,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level7 matchgroup=level7c start=/(/ end=/)/ contains=TOP,level7,level8,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level8 matchgroup=level8c start=/(/ end=/)/ contains=TOP,level8,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level9 matchgroup=level9c start=/(/ end=/)/ contains=TOP,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level10 matchgroup=level10c start=/(/ end=/)/ contains=TOP,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level11 matchgroup=level11c start=/(/ end=/)/ contains=TOP,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level12 matchgroup=level12c start=/(/ end=/)/ contains=TOP,level12,level13,level14,level15, level16,NoInParens + syntax region level13 matchgroup=level13c start=/(/ end=/)/ contains=TOP,level13,level14,level15, level16,NoInParens + syntax region level14 matchgroup=level14c start=/(/ end=/)/ contains=TOP,level14,level15, level16,NoInParens + syntax region level15 matchgroup=level15c start=/(/ end=/)/ contains=TOP,level15, level16,NoInParens + syntax region level16 matchgroup=level16c start=/(/ end=/)/ contains=TOP,level16,NoInParens + let rainbow_parenthesis#active = 0 +endfunction + +" Subsection: box brackets or square brackets: {{{2 +" +function rainbow_parenthsis#LoadSquare () + syntax region level1 matchgroup=level1c start=/\[/ end=/\]/ contains=TOP,level1,level2,level3,level4,level5,level6,level7,level8,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level2 matchgroup=level2c start=/\[/ end=/\]/ contains=TOP,level2,level3,level4,level5,level6,level7,level8,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level3 matchgroup=level3c start=/\[/ end=/\]/ contains=TOP,level3,level4,level5,level6,level7,level8,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level4 matchgroup=level4c start=/\[/ end=/\]/ contains=TOP,level4,level5,level6,level7,level8,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level5 matchgroup=level5c start=/\[/ end=/\]/ contains=TOP,level5,level6,level7,level8,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level6 matchgroup=level6c start=/\[/ end=/\]/ contains=TOP,level6,level7,level8,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level7 matchgroup=level7c start=/\[/ end=/\]/ contains=TOP,level7,level8,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level8 matchgroup=level8c start=/\[/ end=/\]/ contains=TOP,level8,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level9 matchgroup=level9c start=/\[/ end=/\]/ contains=TOP,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level10 matchgroup=level10c start=/\[/ end=/\]/ contains=TOP,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level11 matchgroup=level11c start=/\[/ end=/\]/ contains=TOP,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level12 matchgroup=level12c start=/\[/ end=/\]/ contains=TOP,level12,level13,level14,level15, level16,NoInParens + syntax region level13 matchgroup=level13c start=/\[/ end=/\]/ contains=TOP,level13,level14,level15, level16,NoInParens + syntax region level14 matchgroup=level14c start=/\[/ end=/\]/ contains=TOP,level14,level15, level16,NoInParens + syntax region level15 matchgroup=level15c start=/\[/ end=/\]/ contains=TOP,level15, level16,NoInParens + syntax region level16 matchgroup=level16c start=/\[/ end=/\]/ contains=TOP,level16,NoInParens + let rainbow_parenthesis#active = 0 +endfunction + +" Subsection: curly brackets or braces: {{{2 +" +function rainbow_parenthsis#LoadBraces () + syntax region level1 matchgroup=level1c start=/{/ end=/}/ contains=TOP,level1,level2,level3,level4,level5,level6,level7,level8,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level2 matchgroup=level2c start=/{/ end=/}/ contains=TOP,level2,level3,level4,level5,level6,level7,level8,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level3 matchgroup=level3c start=/{/ end=/}/ contains=TOP,level3,level4,level5,level6,level7,level8,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level4 matchgroup=level4c start=/{/ end=/}/ contains=TOP,level4,level5,level6,level7,level8,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level5 matchgroup=level5c start=/{/ end=/}/ contains=TOP,level5,level6,level7,level8,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level6 matchgroup=level6c start=/{/ end=/}/ contains=TOP,level6,level7,level8,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level7 matchgroup=level7c start=/{/ end=/}/ contains=TOP,level7,level8,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level8 matchgroup=level8c start=/{/ end=/}/ contains=TOP,level8,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level9 matchgroup=level9c start=/{/ end=/}/ contains=TOP,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level10 matchgroup=level10c start=/{/ end=/}/ contains=TOP,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level11 matchgroup=level11c start=/{/ end=/}/ contains=TOP,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level12 matchgroup=level12c start=/{/ end=/}/ contains=TOP,level12,level13,level14,level15, level16,NoInParens + syntax region level13 matchgroup=level13c start=/{/ end=/}/ contains=TOP,level13,level14,level15, level16,NoInParens + syntax region level14 matchgroup=level14c start=/{/ end=/}/ contains=TOP,level14,level15, level16,NoInParens + syntax region level15 matchgroup=level15c start=/{/ end=/}/ contains=TOP,level15, level16,NoInParens + syntax region level16 matchgroup=level16c start=/{/ end=/}/ contains=TOP,level16,NoInParens + let rainbow_parenthesis#active = 0 +endfunction + +" Subsection: angle brackets or chevrons: {{{2 +" +function rainbow_parenthsis#LoadChevrons () + syntax region level1 matchgroup=level1c start=// contains=TOP,level1,level2,level3,level4,level5,level6,level7,level8,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level2 matchgroup=level2c start=// contains=TOP,level2,level3,level4,level5,level6,level7,level8,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level3 matchgroup=level3c start=// contains=TOP,level3,level4,level5,level6,level7,level8,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level4 matchgroup=level4c start=// contains=TOP,level4,level5,level6,level7,level8,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level5 matchgroup=level5c start=// contains=TOP,level5,level6,level7,level8,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level6 matchgroup=level6c start=// contains=TOP,level6,level7,level8,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level7 matchgroup=level7c start=// contains=TOP,level7,level8,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level8 matchgroup=level8c start=// contains=TOP,level8,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level9 matchgroup=level9c start=// contains=TOP,level9,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level10 matchgroup=level10c start=// contains=TOP,level10,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level11 matchgroup=level11c start=// contains=TOP,level11,level12,level13,level14,level15, level16,NoInParens + syntax region level12 matchgroup=level12c start=// contains=TOP,level12,level13,level14,level15, level16,NoInParens + syntax region level13 matchgroup=level13c start=// contains=TOP,level13,level14,level15, level16,NoInParens + syntax region level14 matchgroup=level14c start=// contains=TOP,level14,level15, level16,NoInParens + syntax region level15 matchgroup=level15c start=// contains=TOP,level15, level16,NoInParens + syntax region level16 matchgroup=level16c start=// contains=TOP,level16,NoInParens + let rainbow_parenthesis#active = 0 +endfunction + + " }}}1 +finish + +"------------------------------------------------------------------------------ +" Copyright (C) 2006 Martin Krischik +" +" Vim is Charityware - see ":help license" or uganda.txt for licence details. +"------------------------------------------------------------------------------ +" vim: textwidth=78 wrap tabstop=8 shiftwidth=4 softtabstop=4 expandtab +" vim: filetype=vim foldmethod=marker diff --git a/.vim/doc/rainbow_parenthsis.txt b/.vim/doc/rainbow_parenthsis.txt new file mode 100644 index 0000000..c8f15ec --- /dev/null +++ b/.vim/doc/rainbow_parenthsis.txt @@ -0,0 +1,88 @@ +*rainbow_parenthsis.txt* Colorize Parenthsis + +Author: Martin Krischik (krischik@users.sourceforge.net) + John Gilmore + Luc Hermitte (hermitte@free.fr) + +For Vim version 7.0 and above +Last change: 09 Oct, 2007 + +1. Overview |rainbow_parenthsis-about| +2. Commands |rainbow_parenthsis-commands| +2. Functions |rainbow_parenthsis-functions| +3. Configuration |rainbow_parenthsis-configure| + +============================================================================== + *rainbow_parenthsis-about* +1. Overview~ + +rainbow_parenthsis allows you to view the contents of a file in real time. When a +change in the file is detected, the window displaying the file is updated and +repositioned to the last line. + +The update is not exactly real time, but usually updates within a few seconds +of the file change. The update interval of the output is determined by the +|updatetime| parameter, along with continued usage of Vim. This means that if +you are not doing any editing or motion commands, the preview window will not +be updated. See |CursorHold| for more information. + +Because this window becomes the preview window, it will accept all related +commands. For more information, see |preview-window|. + +============================================================================== + *rainbow_parenthsis-commands* +2. Commands~ + +The rainbow_parenthsis plugin does not create any automatic mappings, but provides the +following commands: + + *:ToggleRaibowParenthesis* +|:ToggleRaibowParenthesis| + Manualy start rainbow parenthesis.. If no bracket type has been loaded + yet then round brackets will be loaded by default. + +============================================================================== + *rainbow_parenthsis-functions* +2. Functions~ + +|rainbow_parenthsis#Activate()| *rainbow_parenthsis#Activate()* + Acticate the loaded parenthsis + +|rainbow_parenthsis#Clear()| *rainbow_parenthsis#Clear()* + Deactivate rainbow parenthesis + +|rainbow_parenthsis#Toggle()| *rainbow_parenthsis#Toggle()* + Toogles rainbow parenthesis status. If no bracket type has been loaded + yet then round brackets will be loaded. + +|rainbow_parenthsis#LoadRound()| *rainbow_parenthsis#LoadRound()* + Load syntax for parenthesis or round brackets '(' ')' - This will be + loaded by default if nothing else has been loaded. + +|rainbow_parenthsis#LoadSquare()| *rainbow_parenthsis#LoadSquare()* + Load syntax for box brackets or square brackets '[' ']' + +|rainbow_parenthsis#LoadBraces()| *rainbow_parenthsis#LoadBraces()* + Load syntax for curly brackets or braces '{' '}' + +|rainbow_parenthsis#LoadChevrons()| *rainbow_parenthsis#LoadChevrons()* + Load syntax for angle brackets or chevrons '<' '>' + +============================================================================== + *rainbow_parenthsis-configure* +3. Configuration~ + +The best way to use rainbow_parenthsis is to add it to sytax plugin of any +filetype used: +> + >if exists("g:btm_rainbow_color") && g:btm_rainbow_color + > call rainbow_parenthsis#LoadSquare () + > call rainbow_parenthsis#LoadRound () + > call rainbow_parenthsis#Activate () + >endif +> +This way you don't need to load all options available but only those which +are of importance to the actual filetype. + +============================================================================== +vim:textwidth=78:tabstop=8:noexpandtab:filetype=help diff --git a/.vim/doc/tags b/.vim/doc/tags index 93b871e..8bc6648 100644 --- a/.vim/doc/tags +++ b/.vim/doc/tags @@ -1,6 +1,7 @@ 'snippets' snipMate.txt /*'snippets'* .snippet snipMate.txt /*.snippet* .snippets snipMate.txt /*.snippets* +:ToggleRaibowParenthesis rainbow_parenthsis.txt /*:ToggleRaibowParenthesis* Align-copyright Align.txt /*Align-copyright* ExtractSnips() snipMate.txt /*ExtractSnips()* ExtractSnipsFile() snipMate.txt /*ExtractSnipsFile()* @@ -90,12 +91,28 @@ alignmap-tt Align.txt /*alignmap-tt* alignmap-t~ Align.txt /*alignmap-t~* alignmaps Align.txt /*alignmaps* alignusage Align.txt /*alignusage* +cs surround.txt /*cs* +ds surround.txt /*ds* g:snippets_dir snipMate.txt /*g:snippets_dir* g:snips_author snipMate.txt /*g:snips_author* +i_CTRL-G_S surround.txt /*i_CTRL-G_S* +i_CTRL-G_s surround.txt /*i_CTRL-G_s* i_CTRL-R_ snipMate.txt /*i_CTRL-R_* list-snippets snipMate.txt /*list-snippets* multi_snip snipMate.txt /*multi_snip* otl2html vo_readme.txt /*otl2html* +rainbow_parenthsis#Activate() rainbow_parenthsis.txt /*rainbow_parenthsis#Activate()* +rainbow_parenthsis#Clear() rainbow_parenthsis.txt /*rainbow_parenthsis#Clear()* +rainbow_parenthsis#LoadBraces() rainbow_parenthsis.txt /*rainbow_parenthsis#LoadBraces()* +rainbow_parenthsis#LoadChevrons() rainbow_parenthsis.txt /*rainbow_parenthsis#LoadChevrons()* +rainbow_parenthsis#LoadRound() rainbow_parenthsis.txt /*rainbow_parenthsis#LoadRound()* +rainbow_parenthsis#LoadSquare() rainbow_parenthsis.txt /*rainbow_parenthsis#LoadSquare()* +rainbow_parenthsis#Toggle() rainbow_parenthsis.txt /*rainbow_parenthsis#Toggle()* +rainbow_parenthsis-about rainbow_parenthsis.txt /*rainbow_parenthsis-about* +rainbow_parenthsis-commands rainbow_parenthsis.txt /*rainbow_parenthsis-commands* +rainbow_parenthsis-configure rainbow_parenthsis.txt /*rainbow_parenthsis-configure* +rainbow_parenthsis-functions rainbow_parenthsis.txt /*rainbow_parenthsis-functions* +rainbow_parenthsis.txt rainbow_parenthsis.txt /*rainbow_parenthsis.txt* snipMate snipMate.txt /*snipMate* snipMate-$# snipMate.txt /*snipMate-$#* snipMate-${#:} snipMate.txt /*snipMate-${#:}* @@ -117,6 +134,16 @@ snipMate.txt snipMate.txt /*snipMate.txt* snippet snipMate.txt /*snippet* snippet-syntax snipMate.txt /*snippet-syntax* snippets snipMate.txt /*snippets* +surround surround.txt /*surround* +surround-author surround.txt /*surround-author* +surround-customizing surround.txt /*surround-customizing* +surround-issues surround.txt /*surround-issues* +surround-mappings surround.txt /*surround-mappings* +surround-replacements surround.txt /*surround-replacements* +surround-targets surround.txt /*surround-targets* +surround.txt surround.txt /*surround.txt* +vS surround.txt /*vS* +vgS surround.txt /*vgS* vimoutliner vo_readme.txt /*vimoutliner* vo vo_readme.txt /*vo* vo-activities vo_readme.txt /*vo-activities* @@ -147,3 +174,8 @@ vo-troubleshooting vo_readme.txt /*vo-troubleshooting* vo-updating vo_readme.txt /*vo-updating* vo-version vo_readme.txt /*vo-version* vo_readme.txt vo_readme.txt /*vo_readme.txt* +vs surround.txt /*vs* +yS surround.txt /*yS* +ySS surround.txt /*ySS* +ys surround.txt /*ys* +yss surround.txt /*yss* diff --git a/.vim/ftplugin/html/sparkup.py b/.vim/ftplugin/html/sparkup.py new file mode 100755 index 0000000..f968d17 --- /dev/null +++ b/.vim/ftplugin/html/sparkup.py @@ -0,0 +1,1087 @@ +#!/usr/bin/python2 +# -*- coding: utf-8 -*- +version = "0.1.3" + +import os +import fileinput +import getopt +import sys +import re + +# =============================================================================== + +class Dialect: + shortcuts = {} + synonyms = {} + required = {} + short_tags = () + +class HtmlDialect(Dialect): + shortcuts = { + 'cc:ie': { + 'opening_tag': ''}, + 'cc:ie6': { + 'opening_tag': ''}, + 'cc:ie7': { + 'opening_tag': ''}, + 'cc:noie': { + 'opening_tag': '', + 'closing_tag': ''}, + 'html:4t': { + 'expand': True, + 'opening_tag': + '\n' + + '\n' + + '\n' + + ' ' + '\n' + + ' ' + '\n' + + '\n' + + '', + 'closing_tag': + '\n' + + ''}, + 'html:4s': { + 'expand': True, + 'opening_tag': + '\n' + + '\n' + + '\n' + + ' ' + '\n' + + ' ' + '\n' + + '\n' + + '', + 'closing_tag': + '\n' + + ''}, + 'html:xt': { + 'expand': True, + 'opening_tag': + '\n' + + '\n' + + '\n' + + ' ' + '\n' + + ' ' + '\n' + + '\n' + + '', + 'closing_tag': + '\n' + + ''}, + 'html:xs': { + 'expand': True, + 'opening_tag': + '\n' + + '\n' + + '\n' + + ' ' + '\n' + + ' ' + '\n' + + '\n' + + '', + 'closing_tag': + '\n' + + ''}, + 'html:xxs': { + 'expand': True, + 'opening_tag': + '\n' + + '\n' + + '\n' + + ' ' + '\n' + + ' ' + '\n' + + '\n' + + '', + 'closing_tag': + '\n' + + ''}, + 'html:5': { + 'expand': True, + 'opening_tag': + '\n' + + '\n' + + '\n' + + ' ' + '\n' + + ' ' + '\n' + + '\n' + + '', + 'closing_tag': + '\n' + + ''}, + 'input:button': { + 'name': 'input', + 'attributes': { 'class': 'button', 'type': 'button', 'name': '', 'value': '' } + }, + 'input:password': { + 'name': 'input', + 'attributes': { 'class': 'text password', 'type': 'password', 'name': '', 'value': '' } + }, + 'input:radio': { + 'name': 'input', + 'attributes': { 'class': 'radio', 'type': 'radio', 'name': '', 'value': '' } + }, + 'input:checkbox': { + 'name': 'input', + 'attributes': { 'class': 'checkbox', 'type': 'checkbox', 'name': '', 'value': '' } + }, + 'input:file': { + 'name': 'input', + 'attributes': { 'class': 'file', 'type': 'file', 'name': '', 'value': '' } + }, + 'input:text': { + 'name': 'input', + 'attributes': { 'class': 'text', 'type': 'text', 'name': '', 'value': '' } + }, + 'input:submit': { + 'name': 'input', + 'attributes': { 'class': 'submit', 'type': 'submit', 'value': '' } + }, + 'input:hidden': { + 'name': 'input', + 'attributes': { 'type': 'hidden', 'name': '', 'value': '' } + }, + 'script:src': { + 'name': 'script', + 'attributes': { 'src': '' } + }, + 'script:jquery': { + 'name': 'script', + 'attributes': { 'src': 'http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js' } + }, + 'script:jsapi': { + 'name': 'script', + 'attributes': { 'src': 'http://www.google.com/jsapi' } + }, + 'script:jsapix': { + 'name': 'script', + 'text': '\n google.load("jquery", "1.3.2");\n google.setOnLoadCallback(function() {\n \n });\n' + }, + 'link:css': { + 'name': 'link', + 'attributes': { 'rel': 'stylesheet', 'type': 'text/css', 'href': '', 'media': 'all' }, + }, + 'link:print': { + 'name': 'link', + 'attributes': { 'rel': 'stylesheet', 'type': 'text/css', 'href': '', 'media': 'print' }, + }, + 'link:favicon': { + 'name': 'link', + 'attributes': { 'rel': 'shortcut icon', 'type': 'image/x-icon', 'href': '' }, + }, + 'link:touch': { + 'name': 'link', + 'attributes': { 'rel': 'apple-touch-icon', 'href': '' }, + }, + 'link:rss': { + 'name': 'link', + 'attributes': { 'rel': 'alternate', 'type': 'application/rss+xml', 'title': 'RSS', 'href': '' }, + }, + 'link:atom': { + 'name': 'link', + 'attributes': { 'rel': 'alternate', 'type': 'application/atom+xml', 'title': 'Atom', 'href': '' }, + }, + 'meta:ie7': { + 'name': 'meta', + 'attributes': { 'http-equiv': 'X-UA-Compatible', 'content': 'IE=7' }, + }, + 'meta:ie8': { + 'name': 'meta', + 'attributes': { 'http-equiv': 'X-UA-Compatible', 'content': 'IE=8' }, + }, + 'form:get': { + 'name': 'form', + 'attributes': { 'method': 'get' }, + }, + 'form:g': { + 'name': 'form', + 'attributes': { 'method': 'get' }, + }, + 'form:post': { + 'name': 'form', + 'attributes': { 'method': 'post' }, + }, + 'form:p': { + 'name': 'form', + 'attributes': { 'method': 'post' }, + }, + } + synonyms = { + 'checkbox': 'input:checkbox', + 'check': 'input:checkbox', + 'input:c': 'input:checkbox', + 'button': 'input:button', + 'input:b': 'input:button', + 'input:h': 'input:hidden', + 'hidden': 'input:hidden', + 'submit': 'input:submit', + 'input:s': 'input:submit', + 'radio': 'input:radio', + 'input:r': 'input:radio', + 'text': 'input:text', + 'passwd': 'input:password', + 'password': 'input:password', + 'pw': 'input:password', + 'input:t': 'input:text', + 'linkcss': 'link:css', + 'scriptsrc': 'script:src', + 'jquery': 'script:jquery', + 'jsapi': 'script:jsapi', + 'html5': 'html:5', + 'html4': 'html:4s', + 'html4s': 'html:4s', + 'html4t': 'html:4t', + 'xhtml': 'html:xxs', + 'xhtmlt': 'html:xt', + 'xhtmls': 'html:xs', + 'xhtml11': 'html:xxs', + 'opt': 'option', + 'st': 'strong', + 'css': 'style', + 'csss': 'link:css', + 'css:src': 'link:css', + 'csssrc': 'link:css', + 'js': 'script', + 'jss': 'script:src', + 'js:src': 'script:src', + 'jssrc': 'script:src', + } + short_tags = ( + 'area', 'base', 'basefont', 'br', 'embed', 'hr', \ + 'input', 'img', 'link', 'param', 'meta') + required = { + 'a': {'href':''}, + 'base': {'href':''}, + 'abbr': {'title': ''}, + 'acronym':{'title': ''}, + 'bdo': {'dir': ''}, + 'link': {'rel': 'stylesheet', 'href': ''}, + 'style': {'type': 'text/css'}, + 'script': {'type': 'text/javascript'}, + 'img': {'src':'', 'alt':''}, + 'iframe': {'src': '', 'frameborder': '0'}, + 'embed': {'src': '', 'type': ''}, + 'object': {'data': '', 'type': ''}, + 'param': {'name': '', 'value': ''}, + 'form': {'action': '', 'method': 'post'}, + 'table': {'cellspacing': '0'}, + 'input': {'type': '', 'name': '', 'value': ''}, + 'base': {'href': ''}, + 'area': {'shape': '', 'coords': '', 'href': '', 'alt': ''}, + 'select': {'name': ''}, + 'option': {'value': ''}, + 'textarea':{'name': ''}, + 'meta': {'content': ''}, + } + +class Parser: + """The parser. + """ + + # Constructor + # --------------------------------------------------------------------------- + + def __init__(self, options=None, str='', dialect=HtmlDialect()): + """Constructor. + """ + + self.tokens = [] + self.str = str + self.options = options + self.dialect = dialect + self.root = Element(parser=self) + self.caret = [] + self.caret.append(self.root) + self._last = [] + + # Methods + # --------------------------------------------------------------------------- + + def load_string(self, str): + """Loads a string to parse. + """ + + self.str = str + self._tokenize() + self._parse() + + def render(self): + """Renders. + Called by [[Router]]. + """ + + # Get the initial render of the root node + output = self.root.render() + + # Indent by whatever the input is indented with + indent = re.findall("^[\r\n]*(\s*)", self.str)[0] + output = indent + output.replace("\n", "\n" + indent) + + # Strip newline if not needed + if self.options.has("no-last-newline") \ + or self.prefix or self.suffix: + output = re.sub(r'\n\s*$', '', output) + + # TextMate mode + if self.options.has("textmate"): + output = self._textmatify(output) + + return output + + # Protected methods + # --------------------------------------------------------------------------- + + def _textmatify(self, output): + """Returns a version of the output with TextMate placeholders in it. + """ + + matches = re.findall(r'(>$%i]+>\s*)", str) + if match is None: break + if self.prefix is None: self.prefix = '' + self.prefix += match.group(0) + str = str[len(match.group(0)):] + + while True: + match = re.findall(r"(\s*<[^>]+>[\s\n\r]*)$", str) + if not match: break + if self.suffix is None: self.suffix = '' + self.suffix = match[0] + self.suffix + str = str[:-len(match[0])] + + # Split by the element separators + for token in re.split('(<|>|\+(?!\\s*\+|$))', str): + if token.strip() != '': + self.tokens.append(Token(token, parser=self)) + + def _parse(self): + """Takes the tokens and does its thing. + Populates [[self.root]]. + """ + + # Carry it over to the root node. + if self.prefix or self.suffix: + self.root.prefix = self.prefix + self.root.suffix = self.suffix + self.root.depth += 1 + + for token in self.tokens: + if token.type == Token.ELEMENT: + # Reset the "last elements added" list. We will + # repopulate this with the new elements added now. + self._last[:] = [] + + # Create [[Element]]s from a [[Token]]. + # They will be created as many as the multiplier specifies, + # multiplied by how many carets we have + count = 0 + for caret in self.caret: + local_count = 0 + for i in range(token.multiplier): + count += 1 + local_count += 1 + new = Element(token, caret, + count = count, + local_count = local_count, + parser = self) + self._last.append(new) + caret.append(new) + + # For > + elif token.type == Token.CHILD: + # The last children added. + self.caret[:] = self._last + + # For < + elif token.type == Token.PARENT: + # If we're the root node, don't do anything + parent = self.caret[0].parent + if parent is not None: + self.caret[:] = [parent] + return + + # Properties + # --------------------------------------------------------------------------- + + # Property: dialect + # The dialect of XML + dialect = None + + # Property: str + # The string + str = '' + + # Property: tokens + # The list of tokens + tokens = [] + + # Property: options + # Reference to the [[Options]] instance + options = None + + # Property: root + # The root [[Element]] node. + root = None + + # Property: caret + # The current insertion point. + caret = None + + # Property: _last + # List of the last appended stuff + _last = None + + # Property: indent + # Yeah + indent = '' + + # Property: prefix + # (String) The trailing tag in the beginning. + # + # Description: + # For instance, in `
ul>li
`, the `prefix` is `
`. + prefix = '' + + # Property: suffix + # (string) The trailing tag at the end. + suffix = '' + pass + +# =============================================================================== + +class Element: + """An element. + """ + + def __init__(self, token=None, parent=None, count=None, local_count=None, \ + parser=None, opening_tag=None, closing_tag=None, \ + attributes=None, name=None, text=None): + """Constructor. + + This is called by ???. + + Description: + All parameters are optional. + + token - (Token) The token (required) + parent - (Element) Parent element; `None` if root + count - (Int) The number to substitute for `&` (e.g., in `li.item-$`) + local_count - (Int) The number to substitute for `$` (e.g., in `li.item-&`) + parser - (Parser) The parser + + attributes - ... + name - ... + text - ... + """ + + self.children = [] + self.attributes = {} + self.parser = parser + + if token is not None: + # Assumption is that token is of type [[Token]] and is + # a [[Token.ELEMENT]]. + self.name = token.name + self.attributes = token.attributes.copy() + self.text = token.text + self.populate = token.populate + self.expand = token.expand + self.opening_tag = token.opening_tag + self.closing_tag = token.closing_tag + + # `count` can be given. This will substitude & in classname and ID + if count is not None: + for key in self.attributes: + attrib = self.attributes[key] + attrib = attrib.replace('&', ("%i" % count)) + if local_count is not None: + attrib = attrib.replace('$', ("%i" % local_count)) + self.attributes[key] = attrib + + # Copy over from parameters + if attributes: self.attributes = attribues + if name: self.name = name + if text: self.text = text + + self._fill_attributes() + + self.parent = parent + if parent is not None: + self.depth = parent.depth + 1 + + if self.populate: self._populate() + + def render(self): + """Renders the element, along with it's subelements, into HTML code. + + [Grouped under "Rendering methods"] + """ + + output = "" + try: spaces_count = int(self.parser.options.options['indent-spaces']) + except: spaces_count = 4 + spaces = ' ' * spaces_count + indent = self.depth * spaces + + prefix, suffix = ('', '') + if self.prefix: prefix = self.prefix + "\n" + if self.suffix: suffix = self.suffix + + # Make the guide from the ID (/#header), or the class if there's no ID (/.item) + # This is for the start-guide, end-guide and post-tag-guides + guide_str = '' + if 'id' in self.attributes: + guide_str += "#%s" % self.attributes['id'] + elif 'class' in self.attributes: + guide_str += ".%s" % self.attributes['class'].replace(' ', '.') + + # Build the post-tag guide (e.g.,
), + # the start guide, and the end guide. + guide = '' + start_guide = '' + end_guide = '' + if ((self.name == 'div') and \ + (('id' in self.attributes) or ('class' in self.attributes))): + + if (self.parser.options.has('post-tag-guides')): + guide = "" % guide_str + + if (self.parser.options.has('start-guide-format')): + format = self.parser.options.get('start-guide-format') + try: start_guide = format % guide_str + except: start_guide = (format + " " + guide_str).strip() + start_guide = "%s\n" % (indent, start_guide) + + if (self.parser.options.has('end-guide-format')): + format = self.parser.options.get('end-guide-format') + try: end_guide = format % guide_str + except: end_guide = (format + " " + guide_str).strip() + end_guide = "\n%s" % (indent, end_guide) + + # Short, self-closing tags (
) + short_tags = self.parser.dialect.short_tags + + # When it should be expanded.. + # (That is,
\n...\n
or similar -- wherein something must go + # inside the opening/closing tags) + if len(self.children) > 0 \ + or self.expand \ + or prefix or suffix \ + or (self.parser.options.has('expand-divs') and self.name == 'div'): + + for child in self.children: + output += child.render() + + # For expand divs: if there are no children (that is, `output` + # is still blank despite above), fill it with a blank line. + if (output == ''): output = indent + spaces + "\n" + + # If we're a root node and we have a prefix or suffix... + # (Only the root node can have a prefix or suffix.) + if prefix or suffix: + output = "%s%s%s%s%s\n" % \ + (indent, prefix, output, suffix, guide) + + # Uh.. + elif self.name != '' or \ + self.opening_tag is not None or \ + self.closing_tag is not None: + output = start_guide + \ + indent + self.get_opening_tag() + "\n" + \ + output + \ + indent + self.get_closing_tag() + \ + guide + end_guide + "\n" + + + # Short, self-closing tags (
) + elif self.name in short_tags: + output = "%s<%s />\n" % (indent, self.get_default_tag()) + + # Tags with text, possibly + elif self.name != '' or \ + self.opening_tag is not None or \ + self.closing_tag is not None: + output = "%s%s%s%s%s%s%s%s" % \ + (start_guide, indent, self.get_opening_tag(), \ + self.text, \ + self.get_closing_tag(), \ + guide, end_guide, "\n") + + # Else, it's an empty-named element (like the root). Pass. + else: pass + + + return output + + def get_default_tag(self): + """Returns the opening tag (without brackets). + + Usage: + element.get_default_tag() + + [Grouped under "Rendering methods"] + """ + + output = '%s' % (self.name) + for key, value in self.attributes.iteritems(): + output += ' %s="%s"' % (key, value) + return output + + def get_opening_tag(self): + if self.opening_tag is None: + return "<%s>" % self.get_default_tag() + else: + return self.opening_tag + + def get_closing_tag(self): + if self.closing_tag is None: + return "" % self.name + else: + return self.closing_tag + + def append(self, object): + """Registers an element as a child of this element. + + Usage: + element.append(child) + + Description: + Adds a given element `child` to the children list of this element. It + will be rendered when [[render()]] is called on the element. + + See also: + - [[get_last_child()]] + + [Grouped under "Traversion methods"] + """ + + self.children.append(object) + + def get_last_child(self): + """Returns the last child element which was [[append()]]ed to this element. + + Usage: + element.get_last_child() + + Description: + This is the same as using `element.children[-1]`. + + [Grouped under "Traversion methods"] + """ + + return self.children[-1] + + def _populate(self): + """Expands with default items. + + This is called when the [[populate]] flag is turned on. + """ + + if self.name == 'ul': + elements = [Element(name='li', parent=self, parser=self.parser)] + + elif self.name == 'dl': + elements = [ + Element(name='dt', parent=self, parser=self.parser), + Element(name='dd', parent=self, parser=self.parser)] + + elif self.name == 'table': + tr = Element(name='tr', parent=self, parser=self.parser) + td = Element(name='td', parent=tr, parser=self.parser) + tr.children.append(td) + elements = [tr] + + else: + elements = [] + + for el in elements: + self.children.append(el) + + def _fill_attributes(self): + """Fills default attributes for certain elements. + + Description: + This is called by the constructor. + + [Protected, grouped under "Protected methods"] + """ + + # Make sure 's have a href, 's have an src, etc. + required = self.parser.dialect.required + + for element, attribs in required.iteritems(): + if self.name == element: + for attrib in attribs: + if attrib not in self.attributes: + self.attributes[attrib] = attribs[attrib] + + # --------------------------------------------------------------------------- + + # Property: last_child + # [Read-only] + last_child = property(get_last_child) + + # --------------------------------------------------------------------------- + + # Property: parent + # (Element) The parent element. + parent = None + + # Property: name + # (String) The name of the element (e.g., `div`) + name = '' + + # Property: attributes + # (Dict) The dictionary of attributes (e.g., `{'src': 'image.jpg'}`) + attributes = None + + # Property: children + # (List of Elements) The children + children = None + + # Property: opening_tag + # (String or None) The opening tag. Optional; will use `name` and + # `attributes` if this is not given. + opening_tag = None + + # Property: closing_tag + # (String or None) The closing tag + closing_tag = None + + text = '' + depth = -1 + expand = False + populate = False + parser = None + + # Property: prefix + # Only the root note can have this. + prefix = None + suffix = None + +# =============================================================================== + +class Token: + def __init__(self, str, parser=None): + """Token. + + Description: + str - The string to parse + + In the string `div > ul`, there are 3 tokens. (`div`, `>`, and `ul`) + + For `>`, it will be a `Token` with `type` set to `Token.CHILD` + """ + + self.str = str.strip() + self.attributes = {} + self.parser = parser + + # Set the type. + if self.str == '<': + self.type = Token.PARENT + elif self.str == '>': + self.type = Token.CHILD + elif self.str == '+': + self.type = Token.SIBLING + else: + self.type = Token.ELEMENT + self._init_element() + + def _init_element(self): + """Initializes. Only called if the token is an element token. + [Private] + """ + + # Get the tag name. Default to DIV if none given. + name = re.findall('^([\w\-:]*)', self.str)[0] + name = name.lower().replace('-', ':') + + # Find synonyms through this thesaurus + synonyms = self.parser.dialect.synonyms + if name in synonyms.keys(): + name = synonyms[name] + + if ':' in name: + try: spaces_count = int(self.parser.options.get('indent-spaces')) + except: spaces_count = 4 + indent = ' ' * spaces_count + + shortcuts = self.parser.dialect.shortcuts + if name in shortcuts.keys(): + for key, value in shortcuts[name].iteritems(): + setattr(self, key, value) + if 'html' in name: + return + else: + self.name = name + + elif (name == ''): self.name = 'div' + else: self.name = name + + # Look for attributes + attribs = [] + for attrib in re.findall('\[([^\]]*)\]', self.str): + attribs.append(attrib) + self.str = self.str.replace("[" + attrib + "]", "") + if len(attribs) > 0: + for attrib in attribs: + try: key, value = attrib.split('=', 1) + except: key, value = attrib, '' + self.attributes[key] = value + + # Try looking for text + text = None + for text in re.findall('\{([^\}]*)\}', self.str): + self.str = self.str.replace("{" + text + "}", "") + if text is not None: + self.text = text + + # Get the class names + classes = [] + for classname in re.findall('\.([\$a-zA-Z0-9_\-\&]+)', self.str): + classes.append(classname) + if len(classes) > 0: + try: self.attributes['class'] + except: self.attributes['class'] = '' + self.attributes['class'] += ' ' + ' '.join(classes) + self.attributes['class'] = self.attributes['class'].strip() + + # Get the ID + id = None + for id in re.findall('#([\$a-zA-Z0-9_\-\&]+)', self.str): pass + if id is not None: + self.attributes['id'] = id + + # See if there's a multiplier (e.g., "li*3") + multiplier = None + for multiplier in re.findall('\*\s*([0-9]+)', self.str): pass + if multiplier is not None: + self.multiplier = int(multiplier) + + # Populate flag (e.g., ul+) + flags = None + for flags in re.findall('[\+\!]+$', self.str): pass + if flags is not None: + if '+' in flags: self.populate = True + if '!' in flags: self.expand = True + + def __str__(self): + return self.str + + str = '' + parser = None + + # For elements + # See the properties of `Element` for description on these. + name = '' + attributes = None + multiplier = 1 + expand = False + populate = False + text = '' + opening_tag = None + closing_tag = None + + # Type + type = 0 + ELEMENT = 2 + CHILD = 4 + PARENT = 8 + SIBLING = 16 + +# =============================================================================== + +class Router: + """The router. + """ + + # Constructor + # --------------------------------------------------------------------------- + + def __init__(self): + pass + + # Methods + # --------------------------------------------------------------------------- + + def start(self, options=None, str=None, ret=None): + if (options): + self.options = Options(router=self, options=options, argv=None) + else: + self.options = Options(router=self, argv=sys.argv[1:], options=None) + + if (self.options.has('help')): + return self.help() + + elif (self.options.has('version')): + return self.version() + + else: + return self.parse(str=str, ret=ret) + + def help(self): + print "Usage: %s [OPTIONS]" % sys.argv[0] + print "Expands input into HTML." + print "" + for short, long, info in self.options.cmdline_keys: + if "Deprecated" in info: continue + if not short == '': short = '-%s,' % short + if not long == '': long = '--%s' % long.replace("=", "=XXX") + + print "%6s %-25s %s" % (short, long, info) + print "" + print "\n".join(self.help_content) + + def version(self): + print "Uhm, yeah." + + def parse(self, str=None, ret=None): + self.parser = Parser(self.options) + + try: + # Read the files + # for line in fileinput.input(): lines.append(line.rstrip(os.linesep)) + if str is not None: + lines = str + else: + lines = [sys.stdin.read()] + lines = " ".join(lines) + + except KeyboardInterrupt: + pass + + except: + sys.stderr.write("Reading failed.\n") + return + + try: + self.parser.load_string(lines) + output = self.parser.render() + if ret: return output + sys.stdout.write(output) + + except: + sys.stderr.write("Parse error. Check your input.\n") + print sys.exc_info()[0] + print sys.exc_info()[1] + + def exit(self): + sys.exit() + + help_content = [ + "Please refer to the manual for more information.", + ] + +# =============================================================================== + +class Options: + def __init__(self, router, argv, options=None): + # Init self + self.router = router + + # `options` can be given as a dict of stuff to preload + if options: + for k, v in options.iteritems(): + self.options[k] = v + return + + # Prepare for getopt() + short_keys, long_keys = "", [] + for short, long, info in self.cmdline_keys: # 'v', 'version' + short_keys += short + long_keys.append(long) + + try: + getoptions, arguments = getopt.getopt(argv, short_keys, long_keys) + + except getopt.GetoptError: + err = sys.exc_info()[1] + sys.stderr.write("Options error: %s\n" % err) + sys.stderr.write("Try --help for a list of arguments.\n") + return router.exit() + + # Sort them out into options + options = {} + i = 0 + for option in getoptions: + key, value = option # '--version', '' + if (value == ''): value = True + + # If the key is long, write it + if key[0:2] == '--': + clean_key = key[2:] + options[clean_key] = value + + # If the key is short, look for the long version of it + elif key[0:1] == '-': + for short, long, info in self.cmdline_keys: + if short == key[1:]: + print long + options[long] = True + + # Done + for k, v in options.iteritems(): + self.options[k] = v + + def __getattr__(self, attr): + return self.get(attr) + + def get(self, attr): + try: return self.options[attr] + except: return None + + def has(self, attr): + try: return self.options.has_key(attr) + except: return False + + options = { + 'indent-spaces': 4 + } + cmdline_keys = [ + ('h', 'help', 'Shows help'), + ('v', 'version', 'Shows the version'), + ('', 'no-guides', 'Deprecated'), + ('', 'post-tag-guides', 'Adds comments at the end of DIV tags'), + ('', 'textmate', 'Adds snippet info (textmate mode)'), + ('', 'indent-spaces=', 'Indent spaces'), + ('', 'expand-divs', 'Automatically expand divs'), + ('', 'no-last-newline', 'Skip the trailing newline'), + ('', 'start-guide-format=', 'To be documented'), + ('', 'end-guide-format=', 'To be documented'), + ] + + # Property: router + # Router + router = 1 + +# =============================================================================== + +if __name__ == "__main__": + z = Router() + z.start() diff --git a/.vim/ftplugin/html/sparkup.vim b/.vim/ftplugin/html/sparkup.vim new file mode 100644 index 0000000..ddf9a89 --- /dev/null +++ b/.vim/ftplugin/html/sparkup.vim @@ -0,0 +1,76 @@ +" Sparkup +" Installation: +" Copy the contents of vim/ftplugin/ to your ~/.vim/ftplugin directory. +" +" $ cp -R vim/ftplugin ~/.vim/ftplugin/ +" +" Configuration: +" g:sparkup (Default: 'sparkup') - +" Location of the sparkup executable. You shouldn't need to change this +" setting if you used the install option above. +" +" g:sparkupArgs (Default: '--no-last-newline') - +" Additional args passed to sparkup. +" +" g:sparkupExecuteMapping (Default: '') - +" Mapping used to execute sparkup. +" +" g:sparkupNextMapping (Default: '') - +" Mapping used to jump to the next empty tag/attribute. + +set rtp+=~/.vim/ftplugin/html + +if !exists('g:sparkupExecuteMapping') + let g:sparkupExecuteMapping = '' +endif + +if !exists('g:sparkupNextMapping') + let g:sparkupNextMapping = '' +endif + +exec 'nmap ' . g:sparkupExecuteMapping . ' :call Sparkup()' +exec 'imap ' . g:sparkupExecuteMapping . ' u:call Sparkup()' +exec 'nmap ' . g:sparkupNextMapping . ' :call SparkupNext()' +exec 'imap ' . g:sparkupNextMapping . ' u:call SparkupNext()' + +if exists('*s:Sparkup') + finish +endif + +function! s:Sparkup() + if !exists('s:sparkup') + let s:sparkup = exists('g:sparkup') ? g:sparkup : 'sparkup' + let s:sparkupArgs = exists('g:sparkupArgs') ? g:sparkupArgs : '--no-last-newline' + " check the user's path first. if not found then search relative to + " sparkup.vim in the runtimepath. + if !executable(s:sparkup) + let paths = substitute(escape(&runtimepath, ' '), '\(,\|$\)', '/**\1', 'g') + let s:sparkup = findfile('sparkup.py', paths) + + if !filereadable(s:sparkup) + echohl WarningMsg + echom 'Warning: could not find sparkup on your path or in your vim runtime path.' + echohl None + finish + endif + endif + let s:sparkup = '"' . s:sparkup . '"' + let s:sparkup .= printf(' %s --indent-spaces=%s', s:sparkupArgs, &shiftwidth) + if has('win32') || has('win64') + let s:sparkup = 'python ' . s:sparkup + endif + endif + exec '.!' . s:sparkup + call s:SparkupNext() +endfunction + +function! s:SparkupNext() + " 1: empty tag, 2: empty attribute, 3: empty line + let n = search('><\/\|\(""\)\|^\s*$', 'Wp') + if n == 3 + startinsert! + else + execute 'normal l' + startinsert + endif +endfunction diff --git a/.vim/plugin/NERD_commenter.vim b/.vim/plugin/NERD_commenter.vim new file mode 100644 index 0000000..982b140 --- /dev/null +++ b/.vim/plugin/NERD_commenter.vim @@ -0,0 +1,2786 @@ +" ============================================================================ +" File: NERD_commenter.vim +" Description: vim global plugin that provides easy code commenting +" Maintainer: Martin Grenfell +" Version: 2.2.2 +" Last Change: 09th October, 2010 +" License: This program is free software. It comes without any warranty, +" to the extent permitted by applicable law. You can redistribute +" it and/or modify it under the terms of the Do What The Fuck You +" Want To Public License, Version 2, as published by Sam Hocevar. +" See http://sam.zoy.org/wtfpl/COPYING for more details. +" +" ============================================================================ + +" Section: script init stuff {{{1 +if exists("loaded_nerd_comments") + finish +endif +if v:version < 700 + echoerr "NERDCommenter: this plugin requires vim >= 7. DOWNLOAD IT! You'll thank me later!" + finish +endif +let loaded_nerd_comments = 1 + +" Function: s:InitVariable() function {{{2 +" This function is used to initialise a given variable to a given value. The +" variable is only initialised if it does not exist prior +" +" Args: +" -var: the name of the var to be initialised +" -value: the value to initialise var to +" +" Returns: +" 1 if the var is set, 0 otherwise +function s:InitVariable(var, value) + if !exists(a:var) + exec 'let ' . a:var . ' = ' . "'" . a:value . "'" + return 1 + endif + return 0 +endfunction + +" Section: space string init{{{2 +" When putting spaces after the left delim and before the right we use +" s:spaceStr for the space char. This way we can make it add anything after +" the left and before the right by modifying this variable +let s:spaceStr = ' ' +let s:lenSpaceStr = strlen(s:spaceStr) + +" Section: variable init calls {{{2 +call s:InitVariable("g:NERDAllowAnyVisualDelims", 1) +call s:InitVariable("g:NERDBlockComIgnoreEmpty", 0) +call s:InitVariable("g:NERDCommentWholeLinesInVMode", 0) +call s:InitVariable("g:NERDCompactSexyComs", 0) +call s:InitVariable("g:NERDCreateDefaultMappings", 1) +call s:InitVariable("g:NERDDefaultNesting", 1) +call s:InitVariable("g:NERDMenuMode", 3) +call s:InitVariable("g:NERDLPlace", "[>") +call s:InitVariable("g:NERDUsePlaceHolders", 1) +call s:InitVariable("g:NERDRemoveAltComs", 1) +call s:InitVariable("g:NERDRemoveExtraSpaces", 1) +call s:InitVariable("g:NERDRPlace", "<]") +call s:InitVariable("g:NERDSpaceDelims", 0) +call s:InitVariable("g:NERDDelimiterRequests", 1) + +let s:NERDFileNameEscape="[]#*$%'\" ?`!&();<>\\" +"vf ;;dA:hcs"'A {j^f(lyi(k$p0f{a A }0f{a 'left':jdd^ + +let s:delimiterMap = { + \ 'aap': { 'left': '#' }, + \ 'abc': { 'left': '%' }, + \ 'acedb': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'actionscript': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'ada': { 'left': '--', 'leftAlt': '-- ' }, + \ 'ahdl': { 'left': '--' }, + \ 'ahk': { 'left': ';', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'amiga': { 'left': ';' }, + \ 'aml': { 'left': '/*' }, + \ 'ampl': { 'left': '#' }, + \ 'apache': { 'left': '#' }, + \ 'apachestyle': { 'left': '#' }, + \ 'asciidoc': { 'left': '//' }, + \ 'applescript': { 'left': '--', 'leftAlt': '(*', 'rightAlt': '*)' }, + \ 'asm68k': { 'left': ';' }, + \ 'asm': { 'left': ';', 'leftAlt': '#' }, + \ 'asn': { 'left': '--' }, + \ 'aspvbs': { 'left': '''' }, + \ 'asterisk': { 'left': ';' }, + \ 'asy': { 'left': '//' }, + \ 'atlas': { 'left': 'C', 'right': '$' }, + \ 'autohotkey': { 'left': ';' }, + \ 'autoit': { 'left': ';' }, + \ 'ave': { 'left': "'" }, + \ 'awk': { 'left': '#' }, + \ 'basic': { 'left': "'", 'leftAlt': 'REM ' }, + \ 'bbx': { 'left': '%' }, + \ 'bc': { 'left': '#' }, + \ 'bib': { 'left': '%' }, + \ 'bindzone': { 'left': ';' }, + \ 'bst': { 'left': '%' }, + \ 'btm': { 'left': '::' }, + \ 'caos': { 'left': '*' }, + \ 'calibre': { 'left': '//' }, + \ 'catalog': { 'left': '--', 'right': '--' }, + \ 'c': { 'left': '/*','right': '*/', 'leftAlt': '//' }, + \ 'cfg': { 'left': '#' }, + \ 'cg': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'ch': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'cl': { 'left': '#' }, + \ 'clean': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'clipper': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'clojure': { 'left': ';' }, + \ 'cmake': { 'left': '#' }, + \ 'conkyrc': { 'left': '#' }, + \ 'cpp': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'crontab': { 'left': '#' }, + \ 'cs': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'csp': { 'left': '--' }, + \ 'cterm': { 'left': '*' }, + \ 'cucumber': { 'left': '#' }, + \ 'cvs': { 'left': 'CVS:' }, + \ 'd': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'dcl': { 'left': '$!' }, + \ 'dakota': { 'left': '#' }, + \ 'debcontrol': { 'left': '#' }, + \ 'debsources': { 'left': '#' }, + \ 'def': { 'left': ';' }, + \ 'desktop': { 'left': '#' }, + \ 'dhcpd': { 'left': '#' }, + \ 'diff': { 'left': '#' }, + \ 'django': { 'left': '', 'leftAlt': '{#', 'rightAlt': '#}' }, + \ 'docbk': { 'left': '' }, + \ 'dns': { 'left': ';' }, + \ 'dosbatch': { 'left': 'REM ', 'leftAlt': '::' }, + \ 'dosini': { 'left': ';' }, + \ 'dot': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'dracula': { 'left': ';' }, + \ 'dsl': { 'left': ';' }, + \ 'dtml': { 'left': '', 'right': '' }, + \ 'dylan': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'ebuild': { 'left': '#' }, + \ 'ecd': { 'left': '#' }, + \ 'eclass': { 'left': '#' }, + \ 'eiffel': { 'left': '--' }, + \ 'elf': { 'left': "'" }, + \ 'elmfilt': { 'left': '#' }, + \ 'erlang': { 'left': '%' }, + \ 'eruby': { 'left': '<%#', 'right': '%>', 'leftAlt': '' }, + \ 'expect': { 'left': '#' }, + \ 'exports': { 'left': '#' }, + \ 'factor': { 'left': '! ', 'leftAlt': '!# ' }, + \ 'fgl': { 'left': '#' }, + \ 'focexec': { 'left': '-*' }, + \ 'form': { 'left': '*' }, + \ 'foxpro': { 'left': '*' }, + \ 'fstab': { 'left': '#' }, + \ 'fvwm': { 'left': '#' }, + \ 'fx': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'gams': { 'left': '*' }, + \ 'gdb': { 'left': '#' }, + \ 'gdmo': { 'left': '--' }, + \ 'geek': { 'left': 'GEEK_COMMENT:' }, + \ 'genshi': { 'left': '', 'leftAlt': '{#', 'rightAlt': '#}' }, + \ 'gentoo-conf-d': { 'left': '#' }, + \ 'gentoo-env-d': { 'left': '#' }, + \ 'gentoo-init-d': { 'left': '#' }, + \ 'gentoo-make-conf': { 'left': '#' }, + \ 'gentoo-package-keywords': { 'left': '#' }, + \ 'gentoo-package-mask': { 'left': '#' }, + \ 'gentoo-package-use': { 'left': '#' }, + \ 'gitcommit': { 'left': '#' }, + \ 'gitconfig': { 'left': ';' }, + \ 'gitrebase': { 'left': '#' }, + \ 'gnuplot': { 'left': '#' }, + \ 'groovy': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'gsp': { 'left': '<%--', 'right': '--%>' }, + \ 'gtkrc': { 'left': '#' }, + \ 'haskell': { 'left': '{-','right': '-}', 'leftAlt': '--' }, + \ 'hb': { 'left': '#' }, + \ 'h': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'haml': { 'left': '-#', 'leftAlt': '/' }, + \ 'hercules': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'hog': { 'left': '#' }, + \ 'hostsaccess': { 'left': '#' }, + \ 'htmlcheetah': { 'left': '##' }, + \ 'htmldjango': { 'left': '', 'leftAlt': '{#', 'rightAlt': '#}' }, + \ 'htmlos': { 'left': '#', 'right': '/#' }, + \ 'ia64': { 'left': '#' }, + \ 'icon': { 'left': '#' }, + \ 'idlang': { 'left': ';' }, + \ 'idl': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'inform': { 'left': '!' }, + \ 'inittab': { 'left': '#' }, + \ 'ishd': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'iss': { 'left': ';' }, + \ 'ist': { 'left': '%' }, + \ 'java': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'javacc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'javascript': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'javascript.jquery': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'jess': { 'left': ';' }, + \ 'jgraph': { 'left': '(*', 'right': '*)' }, + \ 'jproperties': { 'left': '#' }, + \ 'jsp': { 'left': '<%--', 'right': '--%>' }, + \ 'kix': { 'left': ';' }, + \ 'kscript': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'lace': { 'left': '--' }, + \ 'ldif': { 'left': '#' }, + \ 'lilo': { 'left': '#' }, + \ 'lilypond': { 'left': '%' }, + \ 'liquid': { 'left': '{%', 'right': '%}' }, + \ 'lisp': { 'left': ';', 'leftAlt': '#|', 'rightAlt': '|#' }, + \ 'llvm': { 'left': ';' }, + \ 'lotos': { 'left': '(*', 'right': '*)' }, + \ 'lout': { 'left': '#' }, + \ 'lprolog': { 'left': '%' }, + \ 'lscript': { 'left': "'" }, + \ 'lss': { 'left': '#' }, + \ 'lua': { 'left': '--', 'leftAlt': '--[[', 'rightAlt': ']]' }, + \ 'lynx': { 'left': '#' }, + \ 'lytex': { 'left': '%' }, + \ 'mail': { 'left': '> ' }, + \ 'mako': { 'left': '##' }, + \ 'man': { 'left': '."' }, + \ 'map': { 'left': '%' }, + \ 'maple': { 'left': '#' }, + \ 'markdown': { 'left': '' }, + \ 'masm': { 'left': ';' }, + \ 'mason': { 'left': '<% #', 'right': '%>' }, + \ 'master': { 'left': '$' }, + \ 'matlab': { 'left': '%' }, + \ 'mel': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'mib': { 'left': '--' }, + \ 'mkd': { 'left': '>' }, + \ 'mma': { 'left': '(*', 'right': '*)' }, + \ 'model': { 'left': '$', 'right': '$' }, + \ 'moduala.': { 'left': '(*', 'right': '*)' }, + \ 'modula2': { 'left': '(*', 'right': '*)' }, + \ 'modula3': { 'left': '(*', 'right': '*)' }, + \ 'monk': { 'left': ';' }, + \ 'mush': { 'left': '#' }, + \ 'named': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'nasm': { 'left': ';' }, + \ 'nastran': { 'left': '$' }, + \ 'natural': { 'left': '/*' }, + \ 'ncf': { 'left': ';' }, + \ 'newlisp': { 'left': ';' }, + \ 'nroff': { 'left': '\"' }, + \ 'nsis': { 'left': '#' }, + \ 'ntp': { 'left': '#' }, + \ 'objc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'objcpp': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'objj': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'ocaml': { 'left': '(*', 'right': '*)' }, + \ 'occam': { 'left': '--' }, + \ 'omlet': { 'left': '(*', 'right': '*)' }, + \ 'omnimark': { 'left': ';' }, + \ 'openroad': { 'left': '//' }, + \ 'opl': { 'left': "REM" }, + \ 'ora': { 'left': '#' }, + \ 'ox': { 'left': '//' }, + \ 'pascal': { 'left': '{','right': '}', 'leftAlt': '(*', 'rightAlt': '*)' }, + \ 'patran': { 'left': '$', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'pcap': { 'left': '#' }, + \ 'pccts': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'pdf': { 'left': '%' }, + \ 'pfmain': { 'left': '//' }, + \ 'php': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'pic': { 'left': ';' }, + \ 'pike': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'pilrc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'pine': { 'left': '#' }, + \ 'plm': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'plsql': { 'left': '--', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'po': { 'left': '#' }, + \ 'postscr': { 'left': '%' }, + \ 'pov': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'povini': { 'left': ';' }, + \ 'ppd': { 'left': '%' }, + \ 'ppwiz': { 'left': ';;' }, + \ 'processing': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'prolog': { 'left': '%', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'ps1': { 'left': '#' }, + \ 'psf': { 'left': '#' }, + \ 'ptcap': { 'left': '#' }, + \ 'python': { 'left': '#' }, + \ 'radiance': { 'left': '#' }, + \ 'ratpoison': { 'left': '#' }, + \ 'r': { 'left': '#' }, + \ 'rc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'rebol': { 'left': ';' }, + \ 'registry': { 'left': ';' }, + \ 'remind': { 'left': '#' }, + \ 'resolv': { 'left': '#' }, + \ 'rgb': { 'left': '!' }, + \ 'rib': { 'left': '#' }, + \ 'robots': { 'left': '#' }, + \ 'sa': { 'left': '--' }, + \ 'samba': { 'left': ';', 'leftAlt': '#' }, + \ 'sass': { 'left': '//', 'leftAlt': '/*' }, + \ 'sather': { 'left': '--' }, + \ 'scala': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'scilab': { 'left': '//' }, + \ 'scsh': { 'left': ';' }, + \ 'sed': { 'left': '#' }, + \ 'sgmldecl': { 'left': '--', 'right': '--' }, + \ 'sgmllnx': { 'left': '' }, + \ 'sicad': { 'left': '*' }, + \ 'simula': { 'left': '%', 'leftAlt': '--' }, + \ 'sinda': { 'left': '$' }, + \ 'skill': { 'left': ';' }, + \ 'slang': { 'left': '%' }, + \ 'slice': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'slrnrc': { 'left': '%' }, + \ 'sm': { 'left': '#' }, + \ 'smarty': { 'left': '{*', 'right': '*}' }, + \ 'smil': { 'left': '' }, + \ 'smith': { 'left': ';' }, + \ 'sml': { 'left': '(*', 'right': '*)' }, + \ 'snnsnet': { 'left': '#' }, + \ 'snnspat': { 'left': '#' }, + \ 'snnsres': { 'left': '#' }, + \ 'snobol4': { 'left': '*' }, + \ 'spec': { 'left': '#' }, + \ 'specman': { 'left': '//' }, + \ 'spectre': { 'left': '//', 'leftAlt': '*' }, + \ 'spice': { 'left': '$' }, + \ 'sql': { 'left': '--' }, + \ 'sqlforms': { 'left': '--' }, + \ 'sqlj': { 'left': '--' }, + \ 'sqr': { 'left': '!' }, + \ 'squid': { 'left': '#' }, + \ 'st': { 'left': '"' }, + \ 'stp': { 'left': '--' }, + \ 'systemverilog': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'tads': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'tags': { 'left': ';' }, + \ 'tak': { 'left': '$' }, + \ 'tasm': { 'left': ';' }, + \ 'tcl': { 'left': '#' }, + \ 'texinfo': { 'left': "@c " }, + \ 'texmf': { 'left': '%' }, + \ 'tf': { 'left': ';' }, + \ 'tidy': { 'left': '#' }, + \ 'tli': { 'left': '#' }, + \ 'tmux': { 'left': '#' }, + \ 'trasys': { 'left': "$" }, + \ 'tsalt': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'tsscl': { 'left': '#' }, + \ 'tssgm': { 'left': "comment = '", 'right': "'" }, + \ 'txt2tags': { 'left': '%' }, + \ 'uc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'uil': { 'left': '!' }, + \ 'vb': { 'left': "'" }, + \ 'velocity': { 'left': "##", 'right': "", 'leftAlt': '#*', 'rightAlt': '*#' }, + \ 'vera': { 'left': '/*','right': '*/', 'leftAlt': '//' }, + \ 'verilog': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'verilog_systemverilog': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'vgrindefs': { 'left': '#' }, + \ 'vhdl': { 'left': '--' }, + \ 'vimperator': { 'left': '"' }, + \ 'virata': { 'left': '%' }, + \ 'vrml': { 'left': '#' }, + \ 'vsejcl': { 'left': '/*' }, + \ 'webmacro': { 'left': '##' }, + \ 'wget': { 'left': '#' }, + \ 'Wikipedia': { 'left': '' }, + \ 'winbatch': { 'left': ';' }, + \ 'wml': { 'left': '#' }, + \ 'wvdial': { 'left': ';' }, + \ 'xdefaults': { 'left': '!' }, + \ 'xkb': { 'left': '//' }, + \ 'xmath': { 'left': '#' }, + \ 'xpm2': { 'left': '!' }, + \ 'xquery': { 'left': '(:', 'right': ':)' }, + \ 'z8a': { 'left': ';' } + \ } + +" Section: Comment mapping functions, autocommands and commands {{{1 +" ============================================================================ +" Section: Comment enabler autocommands {{{2 +" ============================================================================ + +augroup commentEnablers + + "if the user enters a buffer or reads a buffer then we gotta set up + "the comment delimiters for that new filetype + autocmd BufEnter,BufRead * :call s:SetUpForNewFiletype(&filetype, 0) + + "if the filetype of a buffer changes, force the script to reset the + "delims for the buffer + autocmd Filetype * :call s:SetUpForNewFiletype(&filetype, 1) +augroup END + + +" Function: s:SetUpForNewFiletype(filetype) function {{{2 +" This function is responsible for setting up buffer scoped variables for the +" given filetype. +" +" Args: +" -filetype: the filetype to set delimiters for +" -forceReset: 1 if the delimiters should be reset if they have already be +" set for this buffer. +" +function s:SetUpForNewFiletype(filetype, forceReset) + let b:NERDSexyComMarker = '' + + if has_key(s:delimiterMap, a:filetype) + let b:NERDCommenterDelims = s:delimiterMap[a:filetype] + for i in ['left', 'leftAlt', 'right', 'rightAlt'] + if !has_key(b:NERDCommenterDelims, i) + let b:NERDCommenterDelims[i] = '' + endif + endfor + else + let b:NERDCommenterDelims = s:CreateDelimMapFromCms() + endif + +endfunction + +function s:CreateDelimMapFromCms() + return { + \ 'left': substitute(&commentstring, '\([^ \t]*\)\s*%s.*', '\1', ''), + \ 'right': substitute(&commentstring, '.*%s\s*\(.*\)', '\1', 'g'), + \ 'leftAlt': '', + \ 'rightAlt': '' } +endfunction + +" Function: s:SwitchToAlternativeDelimiters(printMsgs) function {{{2 +" This function is used to swap the delimiters that are being used to the +" alternative delimiters for that filetype. For example, if a c++ file is +" being edited and // comments are being used, after this function is called +" /**/ comments will be used. +" +" Args: +" -printMsgs: if this is 1 then a message is echoed to the user telling them +" if this function changed the delimiters or not +function s:SwitchToAlternativeDelimiters(printMsgs) + "if both of the alternative delimiters are empty then there is no + "alternative comment style so bail out + if b:NERDCommenterDelims['leftAlt'] == '' && b:NERDCommenterDelims['rightAlt'] == '' + if a:printMsgs + call s:NerdEcho("Cannot use alternative delimiters, none are specified", 0) + endif + return 0 + endif + + "save the current delimiters + let tempLeft = s:Left() + let tempRight = s:Right() + + "swap current delimiters for alternative + let b:NERDCommenterDelims['left'] = b:NERDCommenterDelims['leftAlt'] + let b:NERDCommenterDelims['right'] = b:NERDCommenterDelims['rightAlt'] + + "set the previously current delimiters to be the new alternative ones + let b:NERDCommenterDelims['leftAlt'] = tempLeft + let b:NERDCommenterDelims['rightAlt'] = tempRight + + "tell the user what comment delimiters they are now using + if a:printMsgs + call s:NerdEcho("Now using " . s:Left() . " " . s:Right() . " to delimit comments", 1) + endif + + return 1 +endfunction + +" Section: Comment delimiter add/removal functions {{{1 +" ============================================================================ +" Function: s:AppendCommentToLine(){{{2 +" This function appends comment delimiters at the EOL and places the cursor in +" position to start typing the comment +function s:AppendCommentToLine() + let left = s:Left({'space': 1}) + let right = s:Right({'space': 1}) + + " get the len of the right delim + let lenRight = strlen(right) + + let isLineEmpty = strlen(getline(".")) == 0 + let insOrApp = (isLineEmpty==1 ? 'i' : 'A') + + "stick the delimiters down at the end of the line. We have to format the + "comment with spaces as appropriate + execute ":normal! " . insOrApp . (isLineEmpty ? '' : ' ') . left . right . " " + + " if there is a right delimiter then we gotta move the cursor left + " by the len of the right delimiter so we insert between the delimiters + if lenRight > 0 + let leftMoveAmount = lenRight + execute ":normal! " . leftMoveAmount . "h" + endif + startinsert +endfunction + +" Function: s:CommentBlock(top, bottom, lSide, rSide, forceNested ) {{{2 +" This function is used to comment out a region of code. This region is +" specified as a bounding box by arguments to the function. +" +" Args: +" -top: the line number for the top line of code in the region +" -bottom: the line number for the bottom line of code in the region +" -lSide: the column number for the left most column in the region +" -rSide: the column number for the right most column in the region +" -forceNested: a flag indicating whether comments should be nested +function s:CommentBlock(top, bottom, lSide, rSide, forceNested ) + " we need to create local copies of these arguments so we can modify them + let top = a:top + let bottom = a:bottom + let lSide = a:lSide + let rSide = a:rSide + + "if the top or bottom line starts with tabs we have to adjust the left and + "right boundaries so that they are set as though the tabs were spaces + let topline = getline(top) + let bottomline = getline(bottom) + if s:HasLeadingTabs(topline, bottomline) + + "find out how many tabs are in the top line and adjust the left + "boundary accordingly + let numTabs = s:NumberOfLeadingTabs(topline) + if lSide < numTabs + let lSide = &ts * lSide + else + let lSide = (lSide - numTabs) + (&ts * numTabs) + endif + + "find out how many tabs are in the bottom line and adjust the right + "boundary accordingly + let numTabs = s:NumberOfLeadingTabs(bottomline) + let rSide = (rSide - numTabs) + (&ts * numTabs) + endif + + "we must check that bottom IS actually below top, if it is not then we + "swap top and bottom. Similarly for left and right. + if bottom < top + let temp = top + let top = bottom + let bottom = top + endif + if rSide < lSide + let temp = lSide + let lSide = rSide + let rSide = temp + endif + + "if the current delimiters arent multipart then we will switch to the + "alternative delims (if THEY are) as the comment will be better and more + "accurate with multipart delims + let switchedDelims = 0 + if !s:Multipart() && g:NERDAllowAnyVisualDelims && s:AltMultipart() + let switchedDelims = 1 + call s:SwitchToAlternativeDelimiters(0) + endif + + "start the commenting from the top and keep commenting till we reach the + "bottom + let currentLine=top + while currentLine <= bottom + + "check if we are allowed to comment this line + if s:CanCommentLine(a:forceNested, currentLine) + + "convert the leading tabs into spaces + let theLine = getline(currentLine) + let lineHasLeadTabs = s:HasLeadingTabs(theLine) + if lineHasLeadTabs + let theLine = s:ConvertLeadingTabsToSpaces(theLine) + endif + + "dont comment lines that begin after the right boundary of the + "block unless the user has specified to do so + if theLine !~ '^ \{' . rSide . '\}' || !g:NERDBlockComIgnoreEmpty + + "attempt to place the cursor in on the left of the boundary box, + "then check if we were successful, if not then we cant comment this + "line + call setline(currentLine, theLine) + if s:CanPlaceCursor(currentLine, lSide) + + let leftSpaced = s:Left({'space': 1}) + let rightSpaced = s:Right({'space': 1}) + + "stick the left delimiter down + let theLine = strpart(theLine, 0, lSide-1) . leftSpaced . strpart(theLine, lSide-1) + + if s:Multipart() + "stick the right delimiter down + let theLine = strpart(theLine, 0, rSide+strlen(leftSpaced)) . rightSpaced . strpart(theLine, rSide+strlen(leftSpaced)) + + let firstLeftDelim = s:FindDelimiterIndex(s:Left(), theLine) + let lastRightDelim = s:LastIndexOfDelim(s:Right(), theLine) + + if firstLeftDelim != -1 && lastRightDelim != -1 + let searchStr = strpart(theLine, 0, lastRightDelim) + let searchStr = strpart(searchStr, firstLeftDelim+strlen(s:Left())) + + "replace the outter most delims in searchStr with + "place-holders + let theLineWithPlaceHolders = s:ReplaceDelims(s:Left(), s:Right(), g:NERDLPlace, g:NERDRPlace, searchStr) + + "add the right delimiter onto the line + let theLine = strpart(theLine, 0, firstLeftDelim+strlen(s:Left())) . theLineWithPlaceHolders . strpart(theLine, lastRightDelim) + endif + endif + endif + endif + + "restore tabs if needed + if lineHasLeadTabs + let theLine = s:ConvertLeadingSpacesToTabs(theLine) + endif + + call setline(currentLine, theLine) + endif + + let currentLine = currentLine + 1 + endwhile + + "if we switched delims then we gotta go back to what they were before + if switchedDelims == 1 + call s:SwitchToAlternativeDelimiters(0) + endif +endfunction + +" Function: s:CommentLines(forceNested, alignLeft, alignRight, firstLine, lastLine) {{{2 +" This function comments a range of lines. +" +" Args: +" -forceNested: a flag indicating whether the called is requesting the comment +" to be nested if need be +" -align: should be "left" or "both" or "none" +" -firstLine/lastLine: the top and bottom lines to comment +function s:CommentLines(forceNested, align, firstLine, lastLine) + " we need to get the left and right indexes of the leftmost char in the + " block of of lines and the right most char so that we can do alignment of + " the delimiters if the user has specified + let leftAlignIndx = s:LeftMostIndx(a:forceNested, 0, a:firstLine, a:lastLine) + let rightAlignIndx = s:RightMostIndx(a:forceNested, 0, a:firstLine, a:lastLine) + + " gotta add the length of the left delimiter onto the rightAlignIndx cos + " we'll be adding a left delim to the line + let rightAlignIndx = rightAlignIndx + strlen(s:Left({'space': 1})) + + " now we actually comment the lines. Do it line by line + let currentLine = a:firstLine + while currentLine <= a:lastLine + + " get the next line, check commentability and convert spaces to tabs + let theLine = getline(currentLine) + let lineHasLeadingTabs = s:HasLeadingTabs(theLine) + let theLine = s:ConvertLeadingTabsToSpaces(theLine) + if s:CanCommentLine(a:forceNested, currentLine) + "if the user has specified forceNesting then we check to see if we + "need to switch delimiters for place-holders + if a:forceNested && g:NERDUsePlaceHolders + let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine) + endif + + " find out if the line is commented using normal delims and/or + " alternate ones + let isCommented = s:IsCommented(s:Left(), s:Right(), theLine) || s:IsCommented(s:Left({'alt': 1}), s:Right({'alt': 1}), theLine) + + " check if we can comment this line + if !isCommented || g:NERDUsePlaceHolders || s:Multipart() + if a:align == "left" || a:align == "both" + let theLine = s:AddLeftDelimAligned(s:Left({'space': 1}), theLine, leftAlignIndx) + else + let theLine = s:AddLeftDelim(s:Left({'space': 1}), theLine) + endif + if a:align == "both" + let theLine = s:AddRightDelimAligned(s:Right({'space': 1}), theLine, rightAlignIndx) + else + let theLine = s:AddRightDelim(s:Right({'space': 1}), theLine) + endif + endif + endif + + " restore leading tabs if appropriate + if lineHasLeadingTabs + let theLine = s:ConvertLeadingSpacesToTabs(theLine) + endif + + " we are done with this line + call setline(currentLine, theLine) + let currentLine = currentLine + 1 + endwhile + +endfunction + +" Function: s:CommentLinesMinimal(firstLine, lastLine) {{{2 +" This function comments a range of lines in a minimal style. I +" +" Args: +" -firstLine/lastLine: the top and bottom lines to comment +function s:CommentLinesMinimal(firstLine, lastLine) + "check that minimal comments can be done on this filetype + if !s:HasMultipartDelims() + throw 'NERDCommenter.Delimiters exception: Minimal comments can only be used for filetypes that have multipart delimiters' + endif + + "if we need to use place holders for the comment, make sure they are + "enabled for this filetype + if !g:NERDUsePlaceHolders && s:DoesBlockHaveMultipartDelim(a:firstLine, a:lastLine) + throw 'NERDCommenter.Settings exception: Place holders are required but disabled.' + endif + + "get the left and right delims to smack on + let left = s:GetSexyComLeft(g:NERDSpaceDelims,0) + let right = s:GetSexyComRight(g:NERDSpaceDelims,0) + + "make sure all multipart delims on the lines are replaced with + "placeholders to prevent illegal syntax + let currentLine = a:firstLine + while(currentLine <= a:lastLine) + let theLine = getline(currentLine) + let theLine = s:ReplaceDelims(left, right, g:NERDLPlace, g:NERDRPlace, theLine) + call setline(currentLine, theLine) + let currentLine = currentLine + 1 + endwhile + + "add the delim to the top line + let theLine = getline(a:firstLine) + let lineHasLeadingTabs = s:HasLeadingTabs(theLine) + let theLine = s:ConvertLeadingTabsToSpaces(theLine) + let theLine = s:AddLeftDelim(left, theLine) + if lineHasLeadingTabs + let theLine = s:ConvertLeadingSpacesToTabs(theLine) + endif + call setline(a:firstLine, theLine) + + "add the delim to the bottom line + let theLine = getline(a:lastLine) + let lineHasLeadingTabs = s:HasLeadingTabs(theLine) + let theLine = s:ConvertLeadingTabsToSpaces(theLine) + let theLine = s:AddRightDelim(right, theLine) + if lineHasLeadingTabs + let theLine = s:ConvertLeadingSpacesToTabs(theLine) + endif + call setline(a:lastLine, theLine) +endfunction + +" Function: s:CommentLinesSexy(topline, bottomline) function {{{2 +" This function is used to comment lines in the 'Sexy' style. eg in c: +" /* +" * This is a sexy comment +" */ +" Args: +" -topline: the line num of the top line in the sexy comment +" -bottomline: the line num of the bottom line in the sexy comment +function s:CommentLinesSexy(topline, bottomline) + let left = s:GetSexyComLeft(0, 0) + let right = s:GetSexyComRight(0, 0) + + "check if we can do a sexy comment with the available delimiters + if left == -1 || right == -1 + throw 'NERDCommenter.Delimiters exception: cannot perform sexy comments with available delimiters.' + endif + + "make sure the lines arent already commented sexually + if !s:CanSexyCommentLines(a:topline, a:bottomline) + throw 'NERDCommenter.Nesting exception: cannot nest sexy comments' + endif + + + let sexyComMarker = s:GetSexyComMarker(0,0) + let sexyComMarkerSpaced = s:GetSexyComMarker(1,0) + + + " we jam the comment as far to the right as possible + let leftAlignIndx = s:LeftMostIndx(1, 1, a:topline, a:bottomline) + + "check if we should use the compact style i.e that the left/right + "delimiters should appear on the first and last lines of the code and not + "on separate lines above/below the first/last lines of code + if g:NERDCompactSexyComs + let spaceString = (g:NERDSpaceDelims ? s:spaceStr : '') + + "comment the top line + let theLine = getline(a:topline) + let lineHasTabs = s:HasLeadingTabs(theLine) + if lineHasTabs + let theLine = s:ConvertLeadingTabsToSpaces(theLine) + endif + let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine) + let theLine = s:AddLeftDelimAligned(left . spaceString, theLine, leftAlignIndx) + if lineHasTabs + let theLine = s:ConvertLeadingSpacesToTabs(theLine) + endif + call setline(a:topline, theLine) + + "comment the bottom line + if a:bottomline != a:topline + let theLine = getline(a:bottomline) + let lineHasTabs = s:HasLeadingTabs(theLine) + if lineHasTabs + let theLine = s:ConvertLeadingTabsToSpaces(theLine) + endif + let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine) + endif + let theLine = s:AddRightDelim(spaceString . right, theLine) + if lineHasTabs + let theLine = s:ConvertLeadingSpacesToTabs(theLine) + endif + call setline(a:bottomline, theLine) + else + + " add the left delimiter one line above the lines that are to be commented + call cursor(a:topline, 1) + execute 'normal! O' + let theLine = repeat(' ', leftAlignIndx) . left + + " Make sure tabs are respected + if !&expandtab + let theLine = s:ConvertLeadingSpacesToTabs(theLine) + endif + call setline(a:topline, theLine) + + " add the right delimiter after bottom line (we have to add 1 cos we moved + " the lines down when we added the left delim + call cursor(a:bottomline+1, 1) + execute 'normal! o' + let theLine = repeat(' ', leftAlignIndx) . repeat(' ', strlen(left)-strlen(sexyComMarker)) . right + + " Make sure tabs are respected + if !&expandtab + let theLine = s:ConvertLeadingSpacesToTabs(theLine) + endif + call setline(a:bottomline+2, theLine) + + endif + + " go thru each line adding the sexyComMarker marker to the start of each + " line in the appropriate place to align them with the comment delims + let currentLine = a:topline+1 + while currentLine <= a:bottomline + !g:NERDCompactSexyComs + " get the line and convert the tabs to spaces + let theLine = getline(currentLine) + let lineHasTabs = s:HasLeadingTabs(theLine) + if lineHasTabs + let theLine = s:ConvertLeadingTabsToSpaces(theLine) + endif + + let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine) + + " add the sexyComMarker + let theLine = repeat(' ', leftAlignIndx) . repeat(' ', strlen(left)-strlen(sexyComMarker)) . sexyComMarkerSpaced . strpart(theLine, leftAlignIndx) + + if lineHasTabs + let theLine = s:ConvertLeadingSpacesToTabs(theLine) + endif + + + " set the line and move onto the next one + call setline(currentLine, theLine) + let currentLine = currentLine + 1 + endwhile + +endfunction + +" Function: s:CommentLinesToggle(forceNested, firstLine, lastLine) {{{2 +" Applies "toggle" commenting to the given range of lines +" +" Args: +" -forceNested: a flag indicating whether the called is requesting the comment +" to be nested if need be +" -firstLine/lastLine: the top and bottom lines to comment +function s:CommentLinesToggle(forceNested, firstLine, lastLine) + let currentLine = a:firstLine + while currentLine <= a:lastLine + + " get the next line, check commentability and convert spaces to tabs + let theLine = getline(currentLine) + let lineHasLeadingTabs = s:HasLeadingTabs(theLine) + let theLine = s:ConvertLeadingTabsToSpaces(theLine) + if s:CanToggleCommentLine(a:forceNested, currentLine) + + "if the user has specified forceNesting then we check to see if we + "need to switch delimiters for place-holders + if g:NERDUsePlaceHolders + let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine) + endif + + let theLine = s:AddLeftDelim(s:Left({'space': 1}), theLine) + let theLine = s:AddRightDelim(s:Right({'space': 1}), theLine) + endif + + " restore leading tabs if appropriate + if lineHasLeadingTabs + let theLine = s:ConvertLeadingSpacesToTabs(theLine) + endif + + " we are done with this line + call setline(currentLine, theLine) + let currentLine = currentLine + 1 + endwhile + +endfunction + +" Function: s:CommentRegion(topline, topCol, bottomLine, bottomCol) function {{{2 +" This function comments chunks of text selected in visual mode. +" It will comment exactly the text that they have selected. +" Args: +" -topLine: the line num of the top line in the sexy comment +" -topCol: top left col for this comment +" -bottomline: the line num of the bottom line in the sexy comment +" -bottomCol: the bottom right col for this comment +" -forceNested: whether the caller wants comments to be nested if the +" line(s) are already commented +function s:CommentRegion(topLine, topCol, bottomLine, bottomCol, forceNested) + + "switch delims (if we can) if the current set isnt multipart + let switchedDelims = 0 + if !s:Multipart() && s:AltMultipart() && !g:NERDAllowAnyVisualDelims + let switchedDelims = 1 + call s:SwitchToAlternativeDelimiters(0) + endif + + "if there is only one line in the comment then just do it + if a:topLine == a:bottomLine + call s:CommentBlock(a:topLine, a:bottomLine, a:topCol, a:bottomCol, a:forceNested) + + "there are multiple lines in the comment + else + "comment the top line + call s:CommentBlock(a:topLine, a:topLine, a:topCol, strlen(getline(a:topLine)), a:forceNested) + + "comment out all the lines in the middle of the comment + let topOfRange = a:topLine+1 + let bottomOfRange = a:bottomLine-1 + if topOfRange <= bottomOfRange + call s:CommentLines(a:forceNested, "none", topOfRange, bottomOfRange) + endif + + "comment the bottom line + let bottom = getline(a:bottomLine) + let numLeadingSpacesTabs = strlen(substitute(bottom, '^\([ \t]*\).*$', '\1', '')) + call s:CommentBlock(a:bottomLine, a:bottomLine, numLeadingSpacesTabs+1, a:bottomCol, a:forceNested) + + endif + + "stick the cursor back on the char it was on before the comment + call cursor(a:topLine, a:topCol + strlen(s:Left()) + g:NERDSpaceDelims) + + "if we switched delims then we gotta go back to what they were before + if switchedDelims == 1 + call s:SwitchToAlternativeDelimiters(0) + endif + +endfunction + +" Function: s:InvertComment(firstLine, lastLine) function {{{2 +" Inverts the comments on the lines between and including the given line +" numbers i.e all commented lines are uncommented and vice versa +" Args: +" -firstLine: the top of the range of lines to be inverted +" -lastLine: the bottom of the range of lines to be inverted +function s:InvertComment(firstLine, lastLine) + + " go thru all lines in the given range + let currentLine = a:firstLine + while currentLine <= a:lastLine + let theLine = getline(currentLine) + + let sexyComBounds = s:FindBoundingLinesOfSexyCom(currentLine) + + " if the line is commented normally, uncomment it + if s:IsCommentedFromStartOfLine(s:Left(), theLine) || s:IsCommentedFromStartOfLine(s:Left({'alt': 1}), theLine) + call s:UncommentLines(currentLine, currentLine) + let currentLine = currentLine + 1 + + " check if the line is commented sexually + elseif !empty(sexyComBounds) + let numLinesBeforeSexyComRemoved = s:NumLinesInBuf() + call s:UncommentLinesSexy(sexyComBounds[0], sexyComBounds[1]) + + "move to the line after last line of the sexy comment + let numLinesAfterSexyComRemoved = s:NumLinesInBuf() + let currentLine = sexyComBounds[1] - (numLinesBeforeSexyComRemoved - numLinesAfterSexyComRemoved) + 1 + + " the line isnt commented + else + call s:CommentLinesToggle(1, currentLine, currentLine) + let currentLine = currentLine + 1 + endif + + endwhile +endfunction + +" Function: NERDComment(isVisual, type) function {{{2 +" This function is a Wrapper for the main commenting functions +" +" Args: +" -isVisual: a flag indicating whether the comment is requested in visual +" mode or not +" -type: the type of commenting requested. Can be 'sexy', 'invert', +" 'minimal', 'toggle', 'alignLeft', 'alignBoth', 'norm', +" 'nested', 'toEOL', 'append', 'insert', 'uncomment', 'yank' +function! NERDComment(isVisual, type) range + " we want case sensitivity when commenting + let oldIgnoreCase = &ignorecase + set noignorecase + + if a:isVisual + let firstLine = line("'<") + let lastLine = line("'>") + let firstCol = col("'<") + let lastCol = col("'>") - (&selection == 'exclusive' ? 1 : 0) + else + let firstLine = a:firstline + let lastLine = a:lastline + endif + + let countWasGiven = (a:isVisual == 0 && firstLine != lastLine) + + let forceNested = (a:type == 'nested' || g:NERDDefaultNesting) + + if a:type == 'norm' || a:type == 'nested' + if a:isVisual && visualmode() == "" + call s:CommentBlock(firstLine, lastLine, firstCol, lastCol, forceNested) + elseif a:isVisual && visualmode() == "v" && (g:NERDCommentWholeLinesInVMode==0 || (g:NERDCommentWholeLinesInVMode==2 && s:HasMultipartDelims())) + call s:CommentRegion(firstLine, firstCol, lastLine, lastCol, forceNested) + else + call s:CommentLines(forceNested, "none", firstLine, lastLine) + endif + + elseif a:type == 'alignLeft' || a:type == 'alignBoth' + let align = "none" + if a:type == "alignLeft" + let align = "left" + elseif a:type == "alignBoth" + let align = "both" + endif + call s:CommentLines(forceNested, align, firstLine, lastLine) + + elseif a:type == 'invert' + call s:InvertComment(firstLine, lastLine) + + elseif a:type == 'sexy' + try + call s:CommentLinesSexy(firstLine, lastLine) + catch /NERDCommenter.Delimiters/ + call s:CommentLines(forceNested, "none", firstLine, lastLine) + catch /NERDCommenter.Nesting/ + call s:NerdEcho("Sexy comment aborted. Nested sexy cannot be nested", 0) + endtry + + elseif a:type == 'toggle' + let theLine = getline(firstLine) + + if s:IsInSexyComment(firstLine) || s:IsCommentedFromStartOfLine(s:Left(), theLine) || s:IsCommentedFromStartOfLine(s:Left({'alt': 1}), theLine) + call s:UncommentLines(firstLine, lastLine) + else + call s:CommentLinesToggle(forceNested, firstLine, lastLine) + endif + + elseif a:type == 'minimal' + try + call s:CommentLinesMinimal(firstLine, lastLine) + catch /NERDCommenter.Delimiters/ + call s:NerdEcho("Minimal comments can only be used for filetypes that have multipart delimiters.", 0) + catch /NERDCommenter.Settings/ + call s:NerdEcho("Place holders are required but disabled.", 0) + endtry + + elseif a:type == 'toEOL' + call s:SaveScreenState() + call s:CommentBlock(firstLine, firstLine, col("."), col("$")-1, 1) + call s:RestoreScreenState() + + elseif a:type == 'append' + call s:AppendCommentToLine() + + elseif a:type == 'insert' + call s:PlaceDelimitersAndInsBetween() + + elseif a:type == 'uncomment' + call s:UncommentLines(firstLine, lastLine) + + elseif a:type == 'yank' + if a:isVisual + normal! gvy + elseif countWasGiven + execute firstLine .','. lastLine .'yank' + else + normal! yy + endif + execute firstLine .','. lastLine .'call NERDComment('. a:isVisual .', "norm")' + endif + + let &ignorecase = oldIgnoreCase +endfunction + +" Function: s:PlaceDelimitersAndInsBetween() function {{{2 +" This is function is called to place comment delimiters down and place the +" cursor between them +function s:PlaceDelimitersAndInsBetween() + " get the left and right delimiters without any escape chars in them + let left = s:Left({'space': 1}) + let right = s:Right({'space': 1}) + + let theLine = getline(".") + let lineHasLeadTabs = s:HasLeadingTabs(theLine) || (theLine =~ '^ *$' && !&expandtab) + + "convert tabs to spaces and adjust the cursors column to take this into + "account + let untabbedCol = s:UntabbedCol(theLine, col(".")) + call setline(line("."), s:ConvertLeadingTabsToSpaces(theLine)) + call cursor(line("."), untabbedCol) + + " get the len of the right delim + let lenRight = strlen(right) + + let isDelimOnEOL = col(".") >= strlen(getline(".")) + + " if the cursor is in the first col then we gotta insert rather than + " append the comment delimiters here + let insOrApp = (col(".")==1 ? 'i' : 'a') + + " place the delimiters down. We do it differently depending on whether + " there is a left AND right delimiter + if lenRight > 0 + execute ":normal! " . insOrApp . left . right + execute ":normal! " . lenRight . "h" + else + execute ":normal! " . insOrApp . left + + " if we are tacking the delim on the EOL then we gotta add a space + " after it cos when we go out of insert mode the cursor will move back + " one and the user wont be in position to type the comment. + if isDelimOnEOL + execute 'normal! a ' + endif + endif + normal! l + + "if needed convert spaces back to tabs and adjust the cursors col + "accordingly + if lineHasLeadTabs + let tabbedCol = s:TabbedCol(getline("."), col(".")) + call setline(line("."), s:ConvertLeadingSpacesToTabs(getline("."))) + call cursor(line("."), tabbedCol) + endif + + startinsert +endfunction + +" Function: s:RemoveDelimiters(left, right, line) {{{2 +" this function is called to remove the first left comment delimiter and the +" last right delimiter of the given line. +" +" The args left and right must be strings. If there is no right delimiter (as +" is the case for e.g vim file comments) them the arg right should be "" +" +" Args: +" -left: the left comment delimiter +" -right: the right comment delimiter +" -line: the line to remove the delimiters from +function s:RemoveDelimiters(left, right, line) + + let l:left = a:left + let l:right = a:right + let lenLeft = strlen(left) + let lenRight = strlen(right) + + let delimsSpaced = (g:NERDSpaceDelims || g:NERDRemoveExtraSpaces) + + let line = a:line + + "look for the left delimiter, if we find it, remove it. + let leftIndx = s:FindDelimiterIndex(a:left, line) + if leftIndx != -1 + let line = strpart(line, 0, leftIndx) . strpart(line, leftIndx+lenLeft) + + "if the user has specified that there is a space after the left delim + "then check for the space and remove it if it is there + if delimsSpaced && strpart(line, leftIndx, s:lenSpaceStr) == s:spaceStr + let line = strpart(line, 0, leftIndx) . strpart(line, leftIndx+s:lenSpaceStr) + endif + endif + + "look for the right delimiter, if we find it, remove it + let rightIndx = s:FindDelimiterIndex(a:right, line) + if rightIndx != -1 + let line = strpart(line, 0, rightIndx) . strpart(line, rightIndx+lenRight) + + "if the user has specified that there is a space before the right delim + "then check for the space and remove it if it is there + if delimsSpaced && strpart(line, rightIndx-s:lenSpaceStr, s:lenSpaceStr) == s:spaceStr && s:Multipart() + let line = strpart(line, 0, rightIndx-s:lenSpaceStr) . strpart(line, rightIndx) + endif + endif + + return line +endfunction + +" Function: s:UncommentLines(topLine, bottomLine) {{{2 +" This function uncomments the given lines +" +" Args: +" topLine: the top line of the visual selection to uncomment +" bottomLine: the bottom line of the visual selection to uncomment +function s:UncommentLines(topLine, bottomLine) + "make local copies of a:firstline and a:lastline and, if need be, swap + "them around if the top line is below the bottom + let l:firstline = a:topLine + let l:lastline = a:bottomLine + if firstline > lastline + let firstline = lastline + let lastline = a:topLine + endif + + "go thru each line uncommenting each line removing sexy comments + let currentLine = firstline + while currentLine <= lastline + + "check the current line to see if it is part of a sexy comment + let sexyComBounds = s:FindBoundingLinesOfSexyCom(currentLine) + if !empty(sexyComBounds) + + "we need to store the num lines in the buf before the comment is + "removed so we know how many lines were removed when the sexy com + "was removed + let numLinesBeforeSexyComRemoved = s:NumLinesInBuf() + + call s:UncommentLinesSexy(sexyComBounds[0], sexyComBounds[1]) + + "move to the line after last line of the sexy comment + let numLinesAfterSexyComRemoved = s:NumLinesInBuf() + let numLinesRemoved = numLinesBeforeSexyComRemoved - numLinesAfterSexyComRemoved + let currentLine = sexyComBounds[1] - numLinesRemoved + 1 + let lastline = lastline - numLinesRemoved + + "no sexy com was detected so uncomment the line as normal + else + call s:UncommentLinesNormal(currentLine, currentLine) + let currentLine = currentLine + 1 + endif + endwhile + +endfunction + +" Function: s:UncommentLinesSexy(topline, bottomline) {{{2 +" This function removes all the comment characters associated with the sexy +" comment spanning the given lines +" Args: +" -topline/bottomline: the top/bottom lines of the sexy comment +function s:UncommentLinesSexy(topline, bottomline) + let left = s:GetSexyComLeft(0,1) + let right = s:GetSexyComRight(0,1) + + + "check if it is even possible for sexy comments to exist with the + "available delimiters + if left == -1 || right == -1 + throw 'NERDCommenter.Delimiters exception: cannot uncomment sexy comments with available delimiters.' + endif + + let leftUnEsc = s:GetSexyComLeft(0,0) + let rightUnEsc = s:GetSexyComRight(0,0) + + let sexyComMarker = s:GetSexyComMarker(0, 1) + let sexyComMarkerUnEsc = s:GetSexyComMarker(0, 0) + + "the markerOffset is how far right we need to move the sexyComMarker to + "line it up with the end of the left delim + let markerOffset = strlen(leftUnEsc)-strlen(sexyComMarkerUnEsc) + + " go thru the intermediate lines of the sexy comment and remove the + " sexy comment markers (eg the '*'s on the start of line in a c sexy + " comment) + let currentLine = a:topline+1 + while currentLine < a:bottomline + let theLine = getline(currentLine) + + " remove the sexy comment marker from the line. We also remove the + " space after it if there is one and if appropriate options are set + let sexyComMarkerIndx = stridx(theLine, sexyComMarkerUnEsc) + if strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc), s:lenSpaceStr) == s:spaceStr && g:NERDSpaceDelims + let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc)+s:lenSpaceStr) + else + let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc)) + endif + + let theLine = s:SwapOutterPlaceHoldersForMultiPartDelims(theLine) + + let theLine = s:ConvertLeadingWhiteSpace(theLine) + + " move onto the next line + call setline(currentLine, theLine) + let currentLine = currentLine + 1 + endwhile + + " gotta make a copy of a:bottomline cos we modify the position of the + " last line it if we remove the topline + let bottomline = a:bottomline + + " get the first line so we can remove the left delim from it + let theLine = getline(a:topline) + + " if the first line contains only the left delim then just delete it + if theLine =~ '^[ \t]*' . left . '[ \t]*$' && !g:NERDCompactSexyComs + call cursor(a:topline, 1) + normal! dd + let bottomline = bottomline - 1 + + " topline contains more than just the left delim + else + + " remove the delim. If there is a space after it + " then remove this too if appropriate + let delimIndx = stridx(theLine, leftUnEsc) + if strpart(theLine, delimIndx+strlen(leftUnEsc), s:lenSpaceStr) == s:spaceStr && g:NERDSpaceDelims + let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(leftUnEsc)+s:lenSpaceStr) + else + let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(leftUnEsc)) + endif + let theLine = s:SwapOutterPlaceHoldersForMultiPartDelims(theLine) + call setline(a:topline, theLine) + endif + + " get the last line so we can remove the right delim + let theLine = getline(bottomline) + + " if the bottomline contains only the right delim then just delete it + if theLine =~ '^[ \t]*' . right . '[ \t]*$' + call cursor(bottomline, 1) + normal! dd + + " the last line contains more than the right delim + else + " remove the right delim. If there is a space after it and + " if the appropriate options are set then remove this too. + let delimIndx = s:LastIndexOfDelim(rightUnEsc, theLine) + if strpart(theLine, delimIndx+strlen(leftUnEsc), s:lenSpaceStr) == s:spaceStr && g:NERDSpaceDelims + let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(rightUnEsc)+s:lenSpaceStr) + else + let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(rightUnEsc)) + endif + + " if the last line also starts with a sexy comment marker then we + " remove this as well + if theLine =~ '^[ \t]*' . sexyComMarker + + " remove the sexyComMarker. If there is a space after it then + " remove that too + let sexyComMarkerIndx = stridx(theLine, sexyComMarkerUnEsc) + if strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc), s:lenSpaceStr) == s:spaceStr && g:NERDSpaceDelims + let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset ) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc)+s:lenSpaceStr) + else + let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset ) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc)) + endif + endif + + let theLine = s:SwapOutterPlaceHoldersForMultiPartDelims(theLine) + call setline(bottomline, theLine) + endif +endfunction + +" Function: s:UncommentLineNormal(line) {{{2 +" uncomments the given line and returns the result +" Args: +" -line: the line to uncomment +function s:UncommentLineNormal(line) + let line = a:line + + "get the comment status on the line so we know how it is commented + let lineCommentStatus = s:IsCommentedOuttermost(s:Left(), s:Right(), s:Left({'alt': 1}), s:Right({'alt': 1}), line) + + "it is commented with s:Left() and s:Right() so remove these delims + if lineCommentStatus == 1 + let line = s:RemoveDelimiters(s:Left(), s:Right(), line) + + "it is commented with s:Left({'alt': 1}) and s:Right({'alt': 1}) so remove these delims + elseif lineCommentStatus == 2 && g:NERDRemoveAltComs + let line = s:RemoveDelimiters(s:Left({'alt': 1}), s:Right({'alt': 1}), line) + + "it is not properly commented with any delims so we check if it has + "any random left or right delims on it and remove the outtermost ones + else + "get the positions of all delim types on the line + let indxLeft = s:FindDelimiterIndex(s:Left(), line) + let indxLeftAlt = s:FindDelimiterIndex(s:Left({'alt': 1}), line) + let indxRight = s:FindDelimiterIndex(s:Right(), line) + let indxRightAlt = s:FindDelimiterIndex(s:Right({'alt': 1}), line) + + "remove the outter most left comment delim + if indxLeft != -1 && (indxLeft < indxLeftAlt || indxLeftAlt == -1) + let line = s:RemoveDelimiters(s:Left(), '', line) + elseif indxLeftAlt != -1 + let line = s:RemoveDelimiters(s:Left({'alt': 1}), '', line) + endif + + "remove the outter most right comment delim + if indxRight != -1 && (indxRight < indxRightAlt || indxRightAlt == -1) + let line = s:RemoveDelimiters('', s:Right(), line) + elseif indxRightAlt != -1 + let line = s:RemoveDelimiters('', s:Right({'alt': 1}), line) + endif + endif + + + let indxLeft = s:FindDelimiterIndex(s:Left(), line) + let indxLeftAlt = s:FindDelimiterIndex(s:Left({'alt': 1}), line) + let indxLeftPlace = s:FindDelimiterIndex(g:NERDLPlace, line) + + let indxRightPlace = s:FindDelimiterIndex(g:NERDRPlace, line) + let indxRightAlt = s:FindDelimiterIndex(s:Right({'alt': 1}), line) + let indxRightPlace = s:FindDelimiterIndex(g:NERDRPlace, line) + + let right = s:Right() + let left = s:Left() + if !s:Multipart() + let right = s:Right({'alt': 1}) + let left = s:Left({'alt': 1}) + endif + + + "if there are place-holders on the line then we check to see if they are + "the outtermost delimiters on the line. If so then we replace them with + "real delimiters + if indxLeftPlace != -1 + if (indxLeftPlace < indxLeft || indxLeft==-1) && (indxLeftPlace < indxLeftAlt || indxLeftAlt==-1) + let line = s:ReplaceDelims(g:NERDLPlace, g:NERDRPlace, left, right, line) + endif + elseif indxRightPlace != -1 + if (indxRightPlace < indxLeft || indxLeft==-1) && (indxLeftPlace < indxLeftAlt || indxLeftAlt==-1) + let line = s:ReplaceDelims(g:NERDLPlace, g:NERDRPlace, left, right, line) + endif + + endif + + let line = s:ConvertLeadingWhiteSpace(line) + + return line +endfunction + +" Function: s:UncommentLinesNormal(topline, bottomline) {{{2 +" This function is called to uncomment lines that arent a sexy comment +" Args: +" -topline/bottomline: the top/bottom line numbers of the comment +function s:UncommentLinesNormal(topline, bottomline) + let currentLine = a:topline + while currentLine <= a:bottomline + let line = getline(currentLine) + call setline(currentLine, s:UncommentLineNormal(line)) + let currentLine = currentLine + 1 + endwhile +endfunction + + +" Section: Other helper functions {{{1 +" ============================================================================ + +" Function: s:AddLeftDelim(delim, theLine) {{{2 +" Args: +function s:AddLeftDelim(delim, theLine) + return substitute(a:theLine, '^\([ \t]*\)', '\1' . a:delim, '') +endfunction + +" Function: s:AddLeftDelimAligned(delim, theLine) {{{2 +" Args: +function s:AddLeftDelimAligned(delim, theLine, alignIndx) + + "if the line is not long enough then bung some extra spaces on the front + "so we can align the delim properly + let theLine = a:theLine + if strlen(theLine) < a:alignIndx + let theLine = repeat(' ', a:alignIndx - strlen(theLine)) + endif + + return strpart(theLine, 0, a:alignIndx) . a:delim . strpart(theLine, a:alignIndx) +endfunction + +" Function: s:AddRightDelim(delim, theLine) {{{2 +" Args: +function s:AddRightDelim(delim, theLine) + if a:delim == '' + return a:theLine + else + return substitute(a:theLine, '$', a:delim, '') + endif +endfunction + +" Function: s:AddRightDelimAligned(delim, theLine, alignIndx) {{{2 +" Args: +function s:AddRightDelimAligned(delim, theLine, alignIndx) + if a:delim == "" + return a:theLine + else + + " when we align the right delim we are just adding spaces + " so we get a string containing the needed spaces (it + " could be empty) + let extraSpaces = '' + let extraSpaces = repeat(' ', a:alignIndx-strlen(a:theLine)) + + " add the right delim + return substitute(a:theLine, '$', extraSpaces . a:delim, '') + endif +endfunction + +" Function: s:AltMultipart() {{{2 +" returns 1 if the alternative delims are multipart +function s:AltMultipart() + return b:NERDCommenterDelims['rightAlt'] != '' +endfunction + +" Function: s:CanCommentLine(forceNested, line) {{{2 +"This function is used to determine whether the given line can be commented. +"It returns 1 if it can be and 0 otherwise +" +" Args: +" -forceNested: a flag indicating whether the caller wants comments to be nested +" if the current line is already commented +" -lineNum: the line num of the line to check for commentability +function s:CanCommentLine(forceNested, lineNum) + let theLine = getline(a:lineNum) + + " make sure we don't comment lines that are just spaces or tabs or empty. + if theLine =~ "^[ \t]*$" + return 0 + endif + + "if the line is part of a sexy comment then just flag it... + if s:IsInSexyComment(a:lineNum) + return 0 + endif + + let isCommented = s:IsCommentedNormOrSexy(a:lineNum) + + "if the line isnt commented return true + if !isCommented + return 1 + endif + + "if the line is commented but nesting is allowed then return true + if a:forceNested && (!s:Multipart() || g:NERDUsePlaceHolders) + return 1 + endif + + return 0 +endfunction + +" Function: s:CanPlaceCursor(line, col) {{{2 +" returns 1 if the cursor can be placed exactly in the given position +function s:CanPlaceCursor(line, col) + let c = col(".") + let l = line(".") + call cursor(a:line, a:col) + let success = (line(".") == a:line && col(".") == a:col) + call cursor(l,c) + return success +endfunction + +" Function: s:CanSexyCommentLines(topline, bottomline) {{{2 +" Return: 1 if the given lines can be commented sexually, 0 otherwise +function s:CanSexyCommentLines(topline, bottomline) + " see if the selected regions have any sexy comments + let currentLine = a:topline + while(currentLine <= a:bottomline) + if s:IsInSexyComment(currentLine) + return 0 + endif + let currentLine = currentLine + 1 + endwhile + return 1 +endfunction +" Function: s:CanToggleCommentLine(forceNested, line) {{{2 +"This function is used to determine whether the given line can be toggle commented. +"It returns 1 if it can be and 0 otherwise +" +" Args: +" -lineNum: the line num of the line to check for commentability +function s:CanToggleCommentLine(forceNested, lineNum) + let theLine = getline(a:lineNum) + if (s:IsCommentedFromStartOfLine(s:Left(), theLine) || s:IsCommentedFromStartOfLine(s:Left({'alt': 1}), theLine)) && !a:forceNested + return 0 + endif + + " make sure we don't comment lines that are just spaces or tabs or empty. + if theLine =~ "^[ \t]*$" + return 0 + endif + + "if the line is part of a sexy comment then just flag it... + if s:IsInSexyComment(a:lineNum) + return 0 + endif + + return 1 +endfunction + +" Function: s:ConvertLeadingSpacesToTabs(line) {{{2 +" This function takes a line and converts all leading tabs on that line into +" spaces +" +" Args: +" -line: the line whose leading tabs will be converted +function s:ConvertLeadingSpacesToTabs(line) + let toReturn = a:line + while toReturn =~ '^\t*' . s:TabSpace() . '\(.*\)$' + let toReturn = substitute(toReturn, '^\(\t*\)' . s:TabSpace() . '\(.*\)$' , '\1\t\2' , "") + endwhile + + return toReturn +endfunction + + +" Function: s:ConvertLeadingTabsToSpaces(line) {{{2 +" This function takes a line and converts all leading spaces on that line into +" tabs +" +" Args: +" -line: the line whose leading spaces will be converted +function s:ConvertLeadingTabsToSpaces(line) + let toReturn = a:line + while toReturn =~ '^\( *\)\t' + let toReturn = substitute(toReturn, '^\( *\)\t', '\1' . s:TabSpace() , "") + endwhile + + return toReturn +endfunction + +" Function: s:ConvertLeadingWhiteSpace(line) {{{2 +" Converts the leading white space to tabs/spaces depending on &ts +" +" Args: +" -line: the line to convert +function s:ConvertLeadingWhiteSpace(line) + let toReturn = a:line + while toReturn =~ '^ *\t' + let toReturn = substitute(toReturn, '^ *\zs\t\ze', s:TabSpace(), "g") + endwhile + + if !&expandtab + let toReturn = s:ConvertLeadingSpacesToTabs(toReturn) + endif + + return toReturn +endfunction + + +" Function: s:CountNonESCedOccurances(str, searchstr, escChar) {{{2 +" This function counts the number of substrings contained in another string. +" These substrings are only counted if they are not escaped with escChar +" Args: +" -str: the string to look for searchstr in +" -searchstr: the substring to search for in str +" -escChar: the escape character which, when preceding an instance of +" searchstr, will cause it not to be counted +function s:CountNonESCedOccurances(str, searchstr, escChar) + "get the index of the first occurrence of searchstr + let indx = stridx(a:str, a:searchstr) + + "if there is an instance of searchstr in str process it + if indx != -1 + "get the remainder of str after this instance of searchstr is removed + let lensearchstr = strlen(a:searchstr) + let strLeft = strpart(a:str, indx+lensearchstr) + + "if this instance of searchstr is not escaped, add one to the count + "and recurse. If it is escaped, just recurse + if !s:IsEscaped(a:str, indx, a:escChar) + return 1 + s:CountNonESCedOccurances(strLeft, a:searchstr, a:escChar) + else + return s:CountNonESCedOccurances(strLeft, a:searchstr, a:escChar) + endif + endif +endfunction +" Function: s:DoesBlockHaveDelim(delim, top, bottom) {{{2 +" Returns 1 if the given block of lines has a delimiter (a:delim) in it +" Args: +" -delim: the comment delimiter to check the block for +" -top: the top line number of the block +" -bottom: the bottom line number of the block +function s:DoesBlockHaveDelim(delim, top, bottom) + let currentLine = a:top + while currentLine < a:bottom + let theline = getline(currentLine) + if s:FindDelimiterIndex(a:delim, theline) != -1 + return 1 + endif + let currentLine = currentLine + 1 + endwhile + return 0 +endfunction + +" Function: s:DoesBlockHaveMultipartDelim(top, bottom) {{{2 +" Returns 1 if the given block has a >= 1 multipart delimiter in it +" Args: +" -top: the top line number of the block +" -bottom: the bottom line number of the block +function s:DoesBlockHaveMultipartDelim(top, bottom) + if s:HasMultipartDelims() + if s:Multipart() + return s:DoesBlockHaveDelim(s:Left(), a:top, a:bottom) || s:DoesBlockHaveDelim(s:Right(), a:top, a:bottom) + else + return s:DoesBlockHaveDelim(s:Left({'alt': 1}), a:top, a:bottom) || s:DoesBlockHaveDelim(s:Right({'alt': 1}), a:top, a:bottom) + endif + endif + return 0 +endfunction + + +" Function: s:Esc(str) {{{2 +" Escapes all the tricky chars in the given string +function s:Esc(str) + let charsToEsc = '*/\."&$+' + return escape(a:str, charsToEsc) +endfunction + +" Function: s:FindDelimiterIndex(delimiter, line) {{{2 +" This function is used to get the string index of the input comment delimiter +" on the input line. If no valid comment delimiter is found in the line then +" -1 is returned +" Args: +" -delimiter: the delimiter we are looking to find the index of +" -line: the line we are looking for delimiter on +function s:FindDelimiterIndex(delimiter, line) + + "make sure the delimiter isnt empty otherwise we go into an infinite loop. + if a:delimiter == "" + return -1 + endif + + + let l:delimiter = a:delimiter + let lenDel = strlen(l:delimiter) + + "get the index of the first occurrence of the delimiter + let delIndx = stridx(a:line, l:delimiter) + + "keep looping thru the line till we either find a real comment delimiter + "or run off the EOL + while delIndx != -1 + + "if we are not off the EOL get the str before the possible delimiter + "in question and check if it really is a delimiter. If it is, return + "its position + if delIndx != -1 + if s:IsDelimValid(l:delimiter, delIndx, a:line) + return delIndx + endif + endif + + "we have not yet found a real comment delimiter so move past the + "current one we are lookin at + let restOfLine = strpart(a:line, delIndx + lenDel) + let distToNextDelim = stridx(restOfLine , l:delimiter) + + "if distToNextDelim is -1 then there is no more potential delimiters + "on the line so set delIndx to -1. Otherwise, move along the line by + "distToNextDelim + if distToNextDelim == -1 + let delIndx = -1 + else + let delIndx = delIndx + lenDel + distToNextDelim + endif + endwhile + + "there is no comment delimiter on this line + return -1 +endfunction + +" Function: s:FindBoundingLinesOfSexyCom(lineNum) {{{2 +" This function takes in a line number and tests whether this line number is +" the top/bottom/middle line of a sexy comment. If it is then the top/bottom +" lines of the sexy comment are returned +" Args: +" -lineNum: the line number that is to be tested whether it is the +" top/bottom/middle line of a sexy com +" Returns: +" A string that has the top/bottom lines of the sexy comment encoded in it. +" The format is 'topline,bottomline'. If a:lineNum turns out not to be the +" top/bottom/middle of a sexy comment then -1 is returned +function s:FindBoundingLinesOfSexyCom(lineNum) + + "find which delimiters to look for as the start/end delims of the comment + let left = '' + let right = '' + if s:Multipart() + let left = s:Left({'esc': 1}) + let right = s:Right({'esc': 1}) + elseif s:AltMultipart() + let left = s:Left({'alt': 1, 'esc': 1}) + let right = s:Right({'alt': 1, 'esc': 1}) + else + return [] + endif + + let sexyComMarker = s:GetSexyComMarker(0, 1) + + "initialise the top/bottom line numbers of the sexy comment to -1 + let top = -1 + let bottom = -1 + + let currentLine = a:lineNum + while top == -1 || bottom == -1 + let theLine = getline(currentLine) + + "check if the current line is the top of the sexy comment + if currentLine <= a:lineNum && theLine =~ '^[ \t]*' . left && theLine !~ '.*' . right && currentLine < s:NumLinesInBuf() + let top = currentLine + let currentLine = a:lineNum + + "check if the current line is the bottom of the sexy comment + elseif theLine =~ '^[ \t]*' . right && theLine !~ '.*' . left && currentLine > 1 + let bottom = currentLine + + "the right delimiter is on the same line as the last sexyComMarker + elseif theLine =~ '^[ \t]*' . sexyComMarker . '.*' . right + let bottom = currentLine + + "we have not found the top or bottom line so we assume currentLine is an + "intermediate line and look to prove otherwise + else + + "if the line doesnt start with a sexyComMarker then it is not a sexy + "comment + if theLine !~ '^[ \t]*' . sexyComMarker + return [] + endif + + endif + + "if top is -1 then we havent found the top yet so keep looking up + if top == -1 + let currentLine = currentLine - 1 + "if we have found the top line then go down looking for the bottom + else + let currentLine = currentLine + 1 + endif + + endwhile + + return [top, bottom] +endfunction + + +" Function: s:GetSexyComMarker() {{{2 +" Returns the sexy comment marker for the current filetype. +" +" C style sexy comments are assumed if possible. If not then the sexy comment +" marker is the last char of the delimiter pair that has both left and right +" delims and has the longest left delim +" +" Args: +" -space: specifies whether the marker is to have a space string after it +" (the space string will only be added if NERDSpaceDelims is set) +" -esc: specifies whether the tricky chars in the marker are to be ESCed +function s:GetSexyComMarker(space, esc) + let sexyComMarker = b:NERDSexyComMarker + + "if there is no hardcoded marker then we find one + if sexyComMarker == '' + + "if the filetype has c style comments then use standard c sexy + "comments + if s:HasCStyleComments() + let sexyComMarker = '*' + else + "find a comment marker by getting the longest available left delim + "(that has a corresponding right delim) and taking the last char + let lenLeft = strlen(s:Left()) + let lenLeftAlt = strlen(s:Left({'alt': 1})) + let left = '' + let right = '' + if s:Multipart() && lenLeft >= lenLeftAlt + let left = s:Left() + elseif s:AltMultipart() + let left = s:Left({'alt': 1}) + else + return -1 + endif + + "get the last char of left + let sexyComMarker = strpart(left, strlen(left)-1) + endif + endif + + if a:space && g:NERDSpaceDelims + let sexyComMarker = sexyComMarker . s:spaceStr + endif + + if a:esc + let sexyComMarker = s:Esc(sexyComMarker) + endif + + return sexyComMarker +endfunction + +" Function: s:GetSexyComLeft(space, esc) {{{2 +" Returns the left delimiter for sexy comments for this filetype or -1 if +" there is none. C style sexy comments are used if possible +" Args: +" -space: specifies if the delim has a space string on the end +" (the space string will only be added if NERDSpaceDelims is set) +" -esc: specifies whether the tricky chars in the string are ESCed +function s:GetSexyComLeft(space, esc) + let lenLeft = strlen(s:Left()) + let lenLeftAlt = strlen(s:Left({'alt': 1})) + let left = '' + + "assume c style sexy comments if possible + if s:HasCStyleComments() + let left = '/*' + else + "grab the longest left delim that has a right + if s:Multipart() && lenLeft >= lenLeftAlt + let left = s:Left() + elseif s:AltMultipart() + let left = s:Left({'alt': 1}) + else + return -1 + endif + endif + + if a:space && g:NERDSpaceDelims + let left = left . s:spaceStr + endif + + if a:esc + let left = s:Esc(left) + endif + + return left +endfunction + +" Function: s:GetSexyComRight(space, esc) {{{2 +" Returns the right delimiter for sexy comments for this filetype or -1 if +" there is none. C style sexy comments are used if possible. +" Args: +" -space: specifies if the delim has a space string on the start +" (the space string will only be added if NERDSpaceDelims +" is specified for the current filetype) +" -esc: specifies whether the tricky chars in the string are ESCed +function s:GetSexyComRight(space, esc) + let lenLeft = strlen(s:Left()) + let lenLeftAlt = strlen(s:Left({'alt': 1})) + let right = '' + + "assume c style sexy comments if possible + if s:HasCStyleComments() + let right = '*/' + else + "grab the right delim that pairs with the longest left delim + if s:Multipart() && lenLeft >= lenLeftAlt + let right = s:Right() + elseif s:AltMultipart() + let right = s:Right({'alt': 1}) + else + return -1 + endif + endif + + if a:space && g:NERDSpaceDelims + let right = s:spaceStr . right + endif + + if a:esc + let right = s:Esc(right) + endif + + return right +endfunction + +" Function: s:HasMultipartDelims() {{{2 +" Returns 1 iff the current filetype has at least one set of multipart delims +function s:HasMultipartDelims() + return s:Multipart() || s:AltMultipart() +endfunction + +" Function: s:HasLeadingTabs(...) {{{2 +" Returns 1 if any of the given strings have leading tabs +function s:HasLeadingTabs(...) + for s in a:000 + if s =~ '^\t.*' + return 1 + end + endfor + return 0 +endfunction +" Function: s:HasCStyleComments() {{{2 +" Returns 1 iff the current filetype has c style comment delimiters +function s:HasCStyleComments() + return (s:Left() == '/*' && s:Right() == '*/') || (s:Left({'alt': 1}) == '/*' && s:Right({'alt': 1}) == '*/') +endfunction + +" Function: s:IsCommentedNormOrSexy(lineNum) {{{2 +"This function is used to determine whether the given line is commented with +"either set of delimiters or if it is part of a sexy comment +" +" Args: +" -lineNum: the line number of the line to check +function s:IsCommentedNormOrSexy(lineNum) + let theLine = getline(a:lineNum) + + "if the line is commented normally return 1 + if s:IsCommented(s:Left(), s:Right(), theLine) || s:IsCommented(s:Left({'alt': 1}), s:Right({'alt': 1}), theLine) + return 1 + endif + + "if the line is part of a sexy comment return 1 + if s:IsInSexyComment(a:lineNum) + return 1 + endif + return 0 +endfunction + +" Function: s:IsCommented(left, right, line) {{{2 +"This function is used to determine whether the given line is commented with +"the given delimiters +" +" Args: +" -line: the line that to check if commented +" -left/right: the left and right delimiters to check for +function s:IsCommented(left, right, line) + "if the line isnt commented return true + if s:FindDelimiterIndex(a:left, a:line) != -1 && (s:FindDelimiterIndex(a:right, a:line) != -1 || !s:Multipart()) + return 1 + endif + return 0 +endfunction + +" Function: s:IsCommentedFromStartOfLine(left, line) {{{2 +"This function is used to determine whether the given line is commented with +"the given delimiters at the start of the line i.e the left delimiter is the +"first thing on the line (apart from spaces\tabs) +" +" Args: +" -line: the line that to check if commented +" -left: the left delimiter to check for +function s:IsCommentedFromStartOfLine(left, line) + let theLine = s:ConvertLeadingTabsToSpaces(a:line) + let numSpaces = strlen(substitute(theLine, '^\( *\).*$', '\1', '')) + let delimIndx = s:FindDelimiterIndex(a:left, theLine) + return delimIndx == numSpaces +endfunction + +" Function: s:IsCommentedOuttermost(left, right, leftAlt, rightAlt, line) {{{2 +" Finds the type of the outtermost delims on the line +" +" Args: +" -line: the line that to check if the outtermost comments on it are +" left/right +" -left/right: the left and right delimiters to check for +" -leftAlt/rightAlt: the left and right alternative delimiters to check for +" +" Returns: +" 0 if the line is not commented with either set of delims +" 1 if the line is commented with the left/right delim set +" 2 if the line is commented with the leftAlt/rightAlt delim set +function s:IsCommentedOuttermost(left, right, leftAlt, rightAlt, line) + "get the first positions of the left delims and the last positions of the + "right delims + let indxLeft = s:FindDelimiterIndex(a:left, a:line) + let indxLeftAlt = s:FindDelimiterIndex(a:leftAlt, a:line) + let indxRight = s:LastIndexOfDelim(a:right, a:line) + let indxRightAlt = s:LastIndexOfDelim(a:rightAlt, a:line) + + "check if the line has a left delim before a leftAlt delim + if (indxLeft <= indxLeftAlt || indxLeftAlt == -1) && indxLeft != -1 + "check if the line has a right delim after any rightAlt delim + if (indxRight > indxRightAlt && indxRight > indxLeft) || !s:Multipart() + return 1 + endif + + "check if the line has a leftAlt delim before a left delim + elseif (indxLeftAlt <= indxLeft || indxLeft == -1) && indxLeftAlt != -1 + "check if the line has a rightAlt delim after any right delim + if (indxRightAlt > indxRight && indxRightAlt > indxLeftAlt) || !s:AltMultipart() + return 2 + endif + else + return 0 + endif + + return 0 + +endfunction + + +" Function: s:IsDelimValid(delimiter, delIndx, line) {{{2 +" This function is responsible for determining whether a given instance of a +" comment delimiter is a real delimiter or not. For example, in java the +" // string is a comment delimiter but in the line: +" System.out.println("//"); +" it does not count as a comment delimiter. This function is responsible for +" distinguishing between such cases. It does so by applying a set of +" heuristics that are not fool proof but should work most of the time. +" +" Args: +" -delimiter: the delimiter we are validating +" -delIndx: the position of delimiter in line +" -line: the line that delimiter occurs in +" +" Returns: +" 0 if the given delimiter is not a real delimiter (as far as we can tell) , +" 1 otherwise +function s:IsDelimValid(delimiter, delIndx, line) + "get the delimiter without the escchars + let l:delimiter = a:delimiter + + "get the strings before and after the delimiter + let preComStr = strpart(a:line, 0, a:delIndx) + let postComStr = strpart(a:line, a:delIndx+strlen(delimiter)) + + "to check if the delimiter is real, make sure it isnt preceded by + "an odd number of quotes and followed by the same (which would indicate + "that it is part of a string and therefore is not a comment) + if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, '"', "\\")) && !s:IsNumEven(s:CountNonESCedOccurances(postComStr, '"', "\\")) + return 0 + endif + if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, "'", "\\")) && !s:IsNumEven(s:CountNonESCedOccurances(postComStr, "'", "\\")) + return 0 + endif + if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, "`", "\\")) && !s:IsNumEven(s:CountNonESCedOccurances(postComStr, "`", "\\")) + return 0 + endif + + + "if the comment delimiter is escaped, assume it isnt a real delimiter + if s:IsEscaped(a:line, a:delIndx, "\\") + return 0 + endif + + "vim comments are so fuckin stupid!! Why the hell do they have comment + "delimiters that are used elsewhere in the syntax?!?! We need to check + "some conditions especially for vim + if &filetype == "vim" + if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, '"', "\\")) + return 0 + endif + + "if the delimiter is on the very first char of the line or is the + "first non-tab/space char on the line then it is a valid comment delimiter + if a:delIndx == 0 || a:line =~ "^[ \t]\\{" . a:delIndx . "\\}\".*$" + return 1 + endif + + let numLeftParen =s:CountNonESCedOccurances(preComStr, "(", "\\") + let numRightParen =s:CountNonESCedOccurances(preComStr, ")", "\\") + + "if the quote is inside brackets then assume it isnt a comment + if numLeftParen > numRightParen + return 0 + endif + + "if the line has an even num of unescaped "'s then we can assume that + "any given " is not a comment delimiter + if s:IsNumEven(s:CountNonESCedOccurances(a:line, "\"", "\\")) + return 0 + endif + endif + + return 1 + +endfunction + +" Function: s:IsNumEven(num) {{{2 +" A small function the returns 1 if the input number is even and 0 otherwise +" Args: +" -num: the number to check +function s:IsNumEven(num) + return (a:num % 2) == 0 +endfunction + +" Function: s:IsEscaped(str, indx, escChar) {{{2 +" This function takes a string, an index into that string and an esc char and +" returns 1 if the char at the index is escaped (i.e if it is preceded by an +" odd number of esc chars) +" Args: +" -str: the string to check +" -indx: the index into str that we want to check +" -escChar: the escape char the char at indx may be ESCed with +function s:IsEscaped(str, indx, escChar) + "initialise numEscChars to 0 and look at the char before indx + let numEscChars = 0 + let curIndx = a:indx-1 + + "keep going back thru str until we either reach the start of the str or + "run out of esc chars + while curIndx >= 0 && strpart(a:str, curIndx, 1) == a:escChar + + "we have found another esc char so add one to the count and move left + "one char + let numEscChars = numEscChars + 1 + let curIndx = curIndx - 1 + + endwhile + + "if there is an odd num of esc chars directly before the char at indx then + "the char at indx is escaped + return !s:IsNumEven(numEscChars) +endfunction + +" Function: s:IsInSexyComment(line) {{{2 +" returns 1 if the given line number is part of a sexy comment +function s:IsInSexyComment(line) + return !empty(s:FindBoundingLinesOfSexyCom(a:line)) +endfunction + +" Function: s:IsSexyComment(topline, bottomline) {{{2 +" This function takes in 2 line numbers and returns 1 if the lines between and +" including the given line numbers are a sexy comment. It returns 0 otherwise. +" Args: +" -topline: the line that the possible sexy comment starts on +" -bottomline: the line that the possible sexy comment stops on +function s:IsSexyComment(topline, bottomline) + + "get the delim set that would be used for a sexy comment + let left = '' + let right = '' + if s:Multipart() + let left = s:Left() + let right = s:Right() + elseif s:AltMultipart() + let left = s:Left({'alt': 1}) + let right = s:Right({'alt': 1}) + else + return 0 + endif + + "swap the top and bottom line numbers around if need be + let topline = a:topline + let bottomline = a:bottomline + if bottomline < topline + topline = bottomline + bottomline = a:topline + endif + + "if there is < 2 lines in the comment it cannot be sexy + if (bottomline - topline) <= 0 + return 0 + endif + + "if the top line doesnt begin with a left delim then the comment isnt sexy + if getline(a:topline) !~ '^[ \t]*' . left + return 0 + endif + + "if there is a right delim on the top line then this isnt a sexy comment + if s:FindDelimiterIndex(right, getline(a:topline)) != -1 + return 0 + endif + + "if there is a left delim on the bottom line then this isnt a sexy comment + if s:FindDelimiterIndex(left, getline(a:bottomline)) != -1 + return 0 + endif + + "if the bottom line doesnt begin with a right delim then the comment isnt + "sexy + if getline(a:bottomline) !~ '^.*' . right . '$' + return 0 + endif + + let sexyComMarker = s:GetSexyComMarker(0, 1) + + "check each of the intermediate lines to make sure they start with a + "sexyComMarker + let currentLine = a:topline+1 + while currentLine < a:bottomline + let theLine = getline(currentLine) + + if theLine !~ '^[ \t]*' . sexyComMarker + return 0 + endif + + "if there is a right delim in an intermediate line then the block isnt + "a sexy comment + if s:FindDelimiterIndex(right, theLine) != -1 + return 0 + endif + + let currentLine = currentLine + 1 + endwhile + + "we have not found anything to suggest that this isnt a sexy comment so + return 1 + +endfunction + +" Function: s:LastIndexOfDelim(delim, str) {{{2 +" This function takes a string and a delimiter and returns the last index of +" that delimiter in string +" Args: +" -delim: the delimiter to look for +" -str: the string to look for delim in +function s:LastIndexOfDelim(delim, str) + let delim = a:delim + let lenDelim = strlen(delim) + + "set index to the first occurrence of delim. If there is no occurrence then + "bail + let indx = s:FindDelimiterIndex(delim, a:str) + if indx == -1 + return -1 + endif + + "keep moving to the next instance of delim in str till there is none left + while 1 + + "search for the next delim after the previous one + let searchStr = strpart(a:str, indx+lenDelim) + let indx2 = s:FindDelimiterIndex(delim, searchStr) + + "if we find a delim update indx to record the position of it, if we + "dont find another delim then indx is the last one so break out of + "this loop + if indx2 != -1 + let indx = indx + indx2 + lenDelim + else + break + endif + endwhile + + return indx + +endfunction + +" Function: s:Left(...) {{{2 +" returns left delimiter data +function s:Left(...) + let params = a:0 ? a:1 : {} + + let delim = has_key(params, 'alt') ? b:NERDCommenterDelims['leftAlt'] : b:NERDCommenterDelims['left'] + + if delim == '' + return '' + endif + + if has_key(params, 'space') && g:NERDSpaceDelims + let delim = delim . s:spaceStr + endif + + if has_key(params, 'esc') + let delim = s:Esc(delim) + endif + + return delim +endfunction + +" Function: s:LeftMostIndx(countCommentedLines, countEmptyLines, topline, bottomline) {{{2 +" This function takes in 2 line numbers and returns the index of the left most +" char (that is not a space or a tab) on all of these lines. +" Args: +" -countCommentedLines: 1 if lines that are commented are to be checked as +" well. 0 otherwise +" -countEmptyLines: 1 if empty lines are to be counted in the search +" -topline: the top line to be checked +" -bottomline: the bottom line to be checked +function s:LeftMostIndx(countCommentedLines, countEmptyLines, topline, bottomline) + + " declare the left most index as an extreme value + let leftMostIndx = 1000 + + " go thru the block line by line updating leftMostIndx + let currentLine = a:topline + while currentLine <= a:bottomline + + " get the next line and if it is allowed to be commented, or is not + " commented, check it + let theLine = getline(currentLine) + if a:countEmptyLines || theLine !~ '^[ \t]*$' + if a:countCommentedLines || (!s:IsCommented(s:Left(), s:Right(), theLine) && !s:IsCommented(s:Left({'alt': 1}), s:Right({'alt': 1}), theLine)) + " convert spaces to tabs and get the number of leading spaces for + " this line and update leftMostIndx if need be + let theLine = s:ConvertLeadingTabsToSpaces(theLine) + let leadSpaceOfLine = strlen( substitute(theLine, '\(^[ \t]*\).*$','\1','') ) + if leadSpaceOfLine < leftMostIndx + let leftMostIndx = leadSpaceOfLine + endif + endif + endif + + " move on to the next line + let currentLine = currentLine + 1 + endwhile + + if leftMostIndx == 1000 + return 0 + else + return leftMostIndx + endif +endfunction + +" Function: s:Multipart() {{{2 +" returns 1 if the current delims are multipart +function s:Multipart() + return s:Right() != '' +endfunction + +" Function: s:NerdEcho(msg, typeOfMsg) {{{2 +" Args: +" -msg: the message to echo +" -typeOfMsg: 0 = warning message +" 1 = normal message +function s:NerdEcho(msg, typeOfMsg) + if a:typeOfMsg == 0 + echohl WarningMsg + echo 'NERDCommenter:' . a:msg + echohl None + elseif a:typeOfMsg == 1 + echo 'NERDCommenter:' . a:msg + endif +endfunction + +" Function: s:NumberOfLeadingTabs(s) {{{2 +" returns the number of leading tabs in the given string +function s:NumberOfLeadingTabs(s) + return strlen(substitute(a:s, '^\(\t*\).*$', '\1', "")) +endfunction + +" Function: s:NumLinesInBuf() {{{2 +" Returns the number of lines in the current buffer +function s:NumLinesInBuf() + return line('$') +endfunction + +" Function: s:ReplaceDelims(toReplace1, toReplace2, replacor1, replacor2, str) {{{2 +" This function takes in a string, 2 delimiters in that string and 2 strings +" to replace these delimiters with. +" +" Args: +" -toReplace1: the first delimiter to replace +" -toReplace2: the second delimiter to replace +" -replacor1: the string to replace toReplace1 with +" -replacor2: the string to replace toReplace2 with +" -str: the string that the delimiters to be replaced are in +function s:ReplaceDelims(toReplace1, toReplace2, replacor1, replacor2, str) + let line = s:ReplaceLeftMostDelim(a:toReplace1, a:replacor1, a:str) + let line = s:ReplaceRightMostDelim(a:toReplace2, a:replacor2, line) + return line +endfunction + +" Function: s:ReplaceLeftMostDelim(toReplace, replacor, str) {{{2 +" This function takes a string and a delimiter and replaces the left most +" occurrence of this delimiter in the string with a given string +" +" Args: +" -toReplace: the delimiter in str that is to be replaced +" -replacor: the string to replace toReplace with +" -str: the string that contains toReplace +function s:ReplaceLeftMostDelim(toReplace, replacor, str) + let toReplace = a:toReplace + let replacor = a:replacor + "get the left most occurrence of toReplace + let indxToReplace = s:FindDelimiterIndex(toReplace, a:str) + + "if there IS an occurrence of toReplace in str then replace it and return + "the resulting string + if indxToReplace != -1 + let line = strpart(a:str, 0, indxToReplace) . replacor . strpart(a:str, indxToReplace+strlen(toReplace)) + return line + endif + + return a:str +endfunction + +" Function: s:ReplaceRightMostDelim(toReplace, replacor, str) {{{2 +" This function takes a string and a delimiter and replaces the right most +" occurrence of this delimiter in the string with a given string +" +" Args: +" -toReplace: the delimiter in str that is to be replaced +" -replacor: the string to replace toReplace with +" -str: the string that contains toReplace +" +function s:ReplaceRightMostDelim(toReplace, replacor, str) + let toReplace = a:toReplace + let replacor = a:replacor + let lenToReplace = strlen(toReplace) + + "get the index of the last delim in str + let indxToReplace = s:LastIndexOfDelim(toReplace, a:str) + + "if there IS a delimiter in str, replace it and return the result + let line = a:str + if indxToReplace != -1 + let line = strpart(a:str, 0, indxToReplace) . replacor . strpart(a:str, indxToReplace+strlen(toReplace)) + endif + return line +endfunction + +"FUNCTION: s:RestoreScreenState() {{{2 +" +"Sets the screen state back to what it was when s:SaveScreenState was last +"called. +" +function s:RestoreScreenState() + if !exists("t:NERDComOldTopLine") || !exists("t:NERDComOldPos") + throw 'NERDCommenter exception: cannot restore screen' + endif + + call cursor(t:NERDComOldTopLine, 0) + normal! zt + call setpos(".", t:NERDComOldPos) +endfunction + +" Function: s:Right(...) {{{2 +" returns right delimiter data +function s:Right(...) + let params = a:0 ? a:1 : {} + + let delim = has_key(params, 'alt') ? b:NERDCommenterDelims['rightAlt'] : b:NERDCommenterDelims['right'] + + if delim == '' + return '' + endif + + if has_key(params, 'space') && g:NERDSpaceDelims + let delim = s:spaceStr . delim + endif + + if has_key(params, 'esc') + let delim = s:Esc(delim) + endif + + return delim +endfunction + +" Function: s:RightMostIndx(countCommentedLines, countEmptyLines, topline, bottomline) {{{2 +" This function takes in 2 line numbers and returns the index of the right most +" char on all of these lines. +" Args: +" -countCommentedLines: 1 if lines that are commented are to be checked as +" well. 0 otherwise +" -countEmptyLines: 1 if empty lines are to be counted in the search +" -topline: the top line to be checked +" -bottomline: the bottom line to be checked +function s:RightMostIndx(countCommentedLines, countEmptyLines, topline, bottomline) + let rightMostIndx = -1 + + " go thru the block line by line updating rightMostIndx + let currentLine = a:topline + while currentLine <= a:bottomline + + " get the next line and see if it is commentable, otherwise it doesnt + " count + let theLine = getline(currentLine) + if a:countEmptyLines || theLine !~ '^[ \t]*$' + + if a:countCommentedLines || (!s:IsCommented(s:Left(), s:Right(), theLine) && !s:IsCommented(s:Left({'alt': 1}), s:Right({'alt': 1}), theLine)) + + " update rightMostIndx if need be + let theLine = s:ConvertLeadingTabsToSpaces(theLine) + let lineLen = strlen(theLine) + if lineLen > rightMostIndx + let rightMostIndx = lineLen + endif + endif + endif + + " move on to the next line + let currentLine = currentLine + 1 + endwhile + + return rightMostIndx +endfunction + +"FUNCTION: s:SaveScreenState() {{{2 +"Saves the current cursor position in the current buffer and the window +"scroll position +function s:SaveScreenState() + let t:NERDComOldPos = getpos(".") + let t:NERDComOldTopLine = line("w0") +endfunction + +" Function: s:SwapOutterMultiPartDelimsForPlaceHolders(line) {{{2 +" This function takes a line and swaps the outter most multi-part delims for +" place holders +" Args: +" -line: the line to swap the delims in +" +function s:SwapOutterMultiPartDelimsForPlaceHolders(line) + " find out if the line is commented using normal delims and/or + " alternate ones + let isCommented = s:IsCommented(s:Left(), s:Right(), a:line) + let isCommentedAlt = s:IsCommented(s:Left({'alt': 1}), s:Right({'alt': 1}), a:line) + + let line2 = a:line + + "if the line is commented and there is a right delimiter, replace + "the delims with place-holders + if isCommented && s:Multipart() + let line2 = s:ReplaceDelims(s:Left(), s:Right(), g:NERDLPlace, g:NERDRPlace, a:line) + + "similarly if the line is commented with the alternative + "delimiters + elseif isCommentedAlt && s:AltMultipart() + let line2 = s:ReplaceDelims(s:Left({'alt': 1}), s:Right({'alt': 1}), g:NERDLPlace, g:NERDRPlace, a:line) + endif + + return line2 +endfunction + +" Function: s:SwapOutterPlaceHoldersForMultiPartDelims(line) {{{2 +" This function takes a line and swaps the outtermost place holders for +" multi-part delims +" Args: +" -line: the line to swap the delims in +" +function s:SwapOutterPlaceHoldersForMultiPartDelims(line) + let left = '' + let right = '' + if s:Multipart() + let left = s:Left() + let right = s:Right() + elseif s:AltMultipart() + let left = s:Left({'alt': 1}) + let right = s:Right({'alt': 1}) + endif + + let line = s:ReplaceDelims(g:NERDLPlace, g:NERDRPlace, left, right, a:line) + return line +endfunction +" Function: s:TabbedCol(line, col) {{{2 +" Gets the col number for given line and existing col number. The new col +" number is the col number when all leading spaces are converted to tabs +" Args: +" -line:the line to get the rel col for +" -col: the abs col +function s:TabbedCol(line, col) + let lineTruncated = strpart(a:line, 0, a:col) + let lineSpacesToTabs = substitute(lineTruncated, s:TabSpace(), '\t', 'g') + return strlen(lineSpacesToTabs) +endfunction +"FUNCTION: s:TabSpace() {{{2 +"returns a string of spaces equal in length to &tabstop +function s:TabSpace() + let tabSpace = "" + let spacesPerTab = &tabstop + while spacesPerTab > 0 + let tabSpace = tabSpace . " " + let spacesPerTab = spacesPerTab - 1 + endwhile + return tabSpace +endfunction + +" Function: s:UnEsc(str, escChar) {{{2 +" This function removes all the escape chars from a string +" Args: +" -str: the string to remove esc chars from +" -escChar: the escape char to be removed +function s:UnEsc(str, escChar) + return substitute(a:str, a:escChar, "", "g") +endfunction + +" Function: s:UntabbedCol(line, col) {{{2 +" Takes a line and a col and returns the absolute column of col taking into +" account that a tab is worth 3 or 4 (or whatever) spaces. +" Args: +" -line:the line to get the abs col for +" -col: the col that doesnt take into account tabs +function s:UntabbedCol(line, col) + let lineTruncated = strpart(a:line, 0, a:col) + let lineTabsToSpaces = substitute(lineTruncated, '\t', s:TabSpace(), 'g') + return strlen(lineTabsToSpaces) +endfunction +" Section: Comment mapping setup {{{1 +" =========================================================================== + +" switch to/from alternative delimiters +nnoremap NERDCommenterAltDelims :call SwitchToAlternativeDelimiters(1) + +" comment out lines +nnoremap NERDCommenterComment :call NERDComment(0, "norm") +vnoremap NERDCommenterComment :call NERDComment(1, "norm") + +" toggle comments +nnoremap NERDCommenterToggle :call NERDComment(0, "toggle") +vnoremap NERDCommenterToggle :call NERDComment(1, "toggle") + +" minimal comments +nnoremap NERDCommenterMinimal :call NERDComment(0, "minimal") +vnoremap NERDCommenterMinimal :call NERDComment(1, "minimal") + +" sexy comments +nnoremap NERDCommenterSexy :call NERDComment(0, "sexy") +vnoremap NERDCommenterSexy :call NERDComment(1, "sexy") + +" invert comments +nnoremap NERDCommenterInvert :call NERDComment(0, "invert") +vnoremap NERDCommenterInvert :call NERDComment(1, "invert") + +" yank then comment +nmap NERDCommenterYank :call NERDComment(0, "yank") +vmap NERDCommenterYank :call NERDComment(1, "yank") + +" left aligned comments +nnoremap NERDCommenterAlignLeft :call NERDComment(0, "alignLeft") +vnoremap NERDCommenterAlignLeft :call NERDComment(1, "alignLeft") + +" left and right aligned comments +nnoremap NERDCommenterAlignBoth :call NERDComment(0, "alignBoth") +vnoremap NERDCommenterAlignBoth :call NERDComment(1, "alignBoth") + +" nested comments +nnoremap NERDCommenterNest :call NERDComment(0, "nested") +vnoremap NERDCommenterNest :call NERDComment(1, "nested") + +" uncomment +nnoremap NERDCommenterUncomment :call NERDComment(0, "uncomment") +vnoremap NERDCommenterUncomment :call NERDComment(1, "uncomment") + +" comment till the end of the line +nnoremap NERDCommenterToEOL :call NERDComment(0, "toEOL") + +" append comments +nmap NERDCommenterAppend :call NERDComment(0, "append") + +" insert comments +inoremap NERDCommenterInInsert :call NERDComment(0, "insert") + + +function! s:CreateMaps(target, combo) + if !hasmapto(a:target, 'n') + exec 'nmap ' . a:combo . ' ' . a:target + endif + + if !hasmapto(a:target, 'v') + exec 'vmap ' . a:combo . ' ' . a:target + endif +endfunction + +if g:NERDCreateDefaultMappings + call s:CreateMaps('NERDCommenterComment', 'cc') + call s:CreateMaps('NERDCommenterToggle', 'c') + call s:CreateMaps('NERDCommenterMinimal', 'cm') + call s:CreateMaps('NERDCommenterSexy', 'cs') + call s:CreateMaps('NERDCommenterInvert', 'ci') + call s:CreateMaps('NERDCommenterYank', 'cy') + call s:CreateMaps('NERDCommenterAlignLeft', 'cl') + call s:CreateMaps('NERDCommenterAlignBoth', 'cb') + call s:CreateMaps('NERDCommenterNest', 'cn') + call s:CreateMaps('NERDCommenterUncomment', 'cu') + call s:CreateMaps('NERDCommenterToEOL', 'c$') + call s:CreateMaps('NERDCommenterAppend', 'cA') + + if !hasmapto('NERDCommenterAltDelims', 'n') + nmap ca NERDCommenterAltDelims + endif +endif + + + +" Section: Menu item setup {{{1 +" =========================================================================== +"check if the user wants the menu to be displayed +if g:NERDMenuMode != 0 + + let menuRoot = "" + if g:NERDMenuMode == 1 + let menuRoot = 'comment' + elseif g:NERDMenuMode == 2 + let menuRoot = '&comment' + elseif g:NERDMenuMode == 3 + let menuRoot = '&Plugin.&comment' + endif + + function! s:CreateMenuItems(target, desc, root) + exec 'nmenu ' . a:root . '.' . a:desc . ' ' . a:target + exec 'vmenu ' . a:root . '.' . a:desc . ' ' . a:target + endfunction + call s:CreateMenuItems("NERDCommenterComment", 'Comment', menuRoot) + call s:CreateMenuItems("NERDCommenterToggle", 'Toggle', menuRoot) + call s:CreateMenuItems('NERDCommenterMinimal', 'Minimal', menuRoot) + call s:CreateMenuItems('NERDCommenterNest', 'Nested', menuRoot) + exec 'nmenu '. menuRoot .'.To\ EOL NERDCommenterToEOL' + call s:CreateMenuItems('NERDCommenterInvert', 'Invert', menuRoot) + call s:CreateMenuItems('NERDCommenterSexy', 'Sexy', menuRoot) + call s:CreateMenuItems('NERDCommenterYank', 'Yank\ then\ comment', menuRoot) + exec 'nmenu '. menuRoot .'.Append NERDCommenterAppend' + exec 'menu '. menuRoot .'.-Sep- :' + call s:CreateMenuItems('NERDCommenterAlignLeft', 'Left\ aligned', menuRoot) + call s:CreateMenuItems('NERDCommenterAlignBoth', 'Left\ and\ right\ aligned', menuRoot) + exec 'menu '. menuRoot .'.-Sep2- :' + call s:CreateMenuItems('NERDCommenterUncomment', 'Uncomment', menuRoot) + exec 'nmenu '. menuRoot .'.Switch\ Delimiters NERDCommenterAltDelims' + exec 'imenu '. menuRoot .'.Insert\ Comment\ Here NERDCommenterInInsert' + exec 'menu '. menuRoot .'.-Sep3- :' + exec 'menu '. menuRoot .'.Help :help NERDCommenterContents' +endif +" vim: set foldmethod=marker : diff --git a/.vim/plugin/rainbow_parenthsis.vim b/.vim/plugin/rainbow_parenthsis.vim new file mode 100644 index 0000000..e5e3806 --- /dev/null +++ b/.vim/plugin/rainbow_parenthsis.vim @@ -0,0 +1,40 @@ +"------------------------------------------------------------------------------ +" Description: Rainbow colors for parenthsis +" $Id: rainbow_parenthsis.vim 29 2007-09-24 11:40:36Z krischik@users.sourceforge.net $ +" Copyright: Copyright (C) 2006 Martin Krischik +" Maintainer: Martin Krischik +" John Gilmore +" $Author: krischik@users.sourceforge.net $ +" $Date: 2007-09-24 13:40:36 +0200 (Mo, 24 Sep 2007) $ +" Version: 4.0 +" $Revision: 29 $ +" $HeadURL: https://vim-scripts.googlecode.com/svn/trunk/1561%20Rainbow%20Parenthsis%20Bundle/plugin/rainbow_parenthsis.vim $ +" History: 24.05.2006 MK Unified Headers +" 15.10.2006 MK Bram's suggestion for runtime integration +" 06.09.2007 LH Buffer friendly (can be used in different buffers), +" can be toggled +" 09.09.2007 MK Use on LH's suggestion but use autoload to +" impove memory consumtion and startup performance +" 09.10.2007 MK Now with round, square brackets, curly and angle +" brackets. +" Usage: copy to plugin directory. +"------------------------------------------------------------------------------ +" This is a simple script. It extends the syntax highlighting to +" highlight each matching set of parens in different colors, to make +" it visually obvious what matches which. +" +" Obviously, most useful when working with lisp or Ada. But it's also nice other +" times. +"------------------------------------------------------------------------------ + +command! -nargs=0 ToggleRaibowParenthesis call rainbow_parenthsis#Toggle() + +finish + +"------------------------------------------------------------------------------ +" Copyright (C) 2006 Martin Krischik +" +" Vim is Charityware - see ":help license" or uganda.txt for licence details. +"------------------------------------------------------------------------------ +" vim: textwidth=78 wrap tabstop=8 shiftwidth=4 softtabstop=4 expandtab +" vim: filetype=vim foldmethod=marker diff --git a/.vim/rainbow_parenthsis_options.vim b/.vim/rainbow_parenthsis_options.vim new file mode 100644 index 0000000..a36a9ad --- /dev/null +++ b/.vim/rainbow_parenthsis_options.vim @@ -0,0 +1,55 @@ +"------------------------------------------------------------------------------ +" Description: Options setable by the rainbow_parenthsis plugin +" $Id: rainbow_parenthsis_options.vim 29 2007-09-24 11:40:36Z krischik@users.sourceforge.net $ +" Copyright: Copyright (C) 2006 Martin Krischik +" Maintainer: Martin Krischik (krischik@users.sourceforge.net) +" $Author: krischik@users.sourceforge.net $ +" $Date: 2007-09-24 13:40:36 +0200 (Mo, 24 Sep 2007) $ +" Version: 4.0 +" $Revision: 29 $ +" $HeadURL: https://vim-scripts.googlecode.com/svn/trunk/1561%20Rainbow%20Parenthsis%20Bundle/rainbow_parenthsis_options.vim $ +" History: 17.11.2006 MK rainbow_parenthsis_Options +" 01.01.2007 MK Bug fixing +" 09.10.2007 MK Now with round, square brackets, curly and angle +" brackets. +" Usage: copy content into your .vimrc and change options to your +" likeing. +" Help Page: rainbow_parenthsis.txt +"------------------------------------------------------------------------------ + +echoerr 'It is suggested to copy the content of ada_options into .vimrc!' +finish " 1}}} + +" Section: rainbow_parenthsis options {{{1 + +" }}}1 + +" Section: Vimball options {{{1 +:set noexpandtab fileformat=unix encoding=utf-8 +:31,34 MkVimball rainbow_parenthsis-4.0.vba + +autoload/rainbow_parenthsis.vim +doc/rainbow_parenthsis.txt +plugin/rainbow_parenthsis.vim +rainbow_parenthsis_options.vim + +" }}}1 + +" Section: Tar options {{{1 + +tar --create --bzip2 \ + --file="rainbow_parenthsis-4.0.tar.bz2" \ + rainbow_parenthsis_options.vim \ + doc/rainbow_parenthsis.txt \ + autoload/rainbow_parenthsis.vim \ + plugin/rainbow_parenthsis.vim ; + +" }}}1 + +"------------------------------------------------------------------------------ +" Copyright (C) 2006 Martin Krischik +" +" Vim is Charityware - see ":help license" or uganda.txt for licence derainbow_parenthsiss. +"------------------------------------------------------------------------------ +" vim: textwidth=0 nowrap tabstop=8 shiftwidth=3 softtabstop=3 noexpandtab +" vim: foldmethod=marker -- cgit v1.2.3-24-g4f1b