From 96a93bce9e8dead3d9b90ee1be59ceededd61dad Mon Sep 17 00:00:00 2001 From: michener Date: Tue, 21 Sep 2010 23:59:55 +0000 Subject: [PATCH] Pathogen and new bundles git-svn-id: http://photonzero.com/dotfiles/trunk@65 23f722f6-122a-0410-8cef-c75bd312dd78 --- .vim/autoload/pathogen.vim | 139 + .vim/bundle/ack.vim/.gitignore | 1 + .vim/bundle/ack.vim/README.md | 80 + .vim/bundle/ack.vim/Rakefile | 23 + .vim/bundle/ack.vim/doc/ack.txt | 50 + .vim/bundle/ack.vim/plugin/ack.vim | 61 + .vim/bundle/command-t/.bundle/config | 2 + .vim/bundle/command-t/.mailmap | 1 + .vim/bundle/command-t/.rspec | 1 + .vim/bundle/command-t/Gemfile | 3 + .vim/bundle/command-t/Gemfile.lock | 21 + .vim/bundle/command-t/LICENSE | 22 + .vim/bundle/command-t/Makefile | 19 + .vim/bundle/command-t/README.txt | 710 +++++ .vim/bundle/command-t/Rakefile | 68 + .vim/bundle/command-t/bin/htmldiff | 14 + .vim/bundle/command-t/bin/ldiff | 14 + .vim/bundle/command-t/bin/rake | 14 + .vim/bundle/command-t/bin/rspec | 14 + .vim/bundle/command-t/compile-test.sh | 10 + .vim/bundle/command-t/doc/.gitignore | 1 + .vim/bundle/command-t/doc/command-t.txt | 1 + .vim/bundle/command-t/fixtures/bar/abc | 1 + .vim/bundle/command-t/fixtures/bar/xyz | 1 + .vim/bundle/command-t/fixtures/baz | 1 + .vim/bundle/command-t/fixtures/bing | 1 + .vim/bundle/command-t/fixtures/foo/alpha/t1 | 1 + .vim/bundle/command-t/fixtures/foo/alpha/t2 | 1 + .vim/bundle/command-t/fixtures/foo/beta | 1 + .vim/bundle/command-t/multi-spec.sh | 25 + .vim/bundle/command-t/plugin/command-t.vim | 151 ++ .vim/bundle/command-t/ruby/command-t/.gitignore | 6 + .vim/bundle/command-t/ruby/command-t/controller.rb | 289 ++ .vim/bundle/command-t/ruby/command-t/depend | 24 + .vim/bundle/command-t/ruby/command-t/ext.c | 65 + .vim/bundle/command-t/ruby/command-t/ext.h | 36 + .vim/bundle/command-t/ruby/command-t/extconf.rb | 32 + .vim/bundle/command-t/ruby/command-t/finder.rb | 51 + .vim/bundle/command-t/ruby/command-t/match.c | 189 ++ .vim/bundle/command-t/ruby/command-t/match.h | 29 + .../command-t/ruby/command-t/match_window.rb | 340 +++ .vim/bundle/command-t/ruby/command-t/matcher.c | 164 ++ .vim/bundle/command-t/ruby/command-t/matcher.h | 30 + .vim/bundle/command-t/ruby/command-t/prompt.rb | 165 ++ .vim/bundle/command-t/ruby/command-t/ruby_compat.h | 49 + .vim/bundle/command-t/ruby/command-t/scanner.rb | 93 + .vim/bundle/command-t/ruby/command-t/settings.rb | 77 + .vim/bundle/command-t/ruby/command-t/stub.rb | 46 + .vim/bundle/command-t/ruby/command-t/vim.rb | 43 + .vim/bundle/command-t/ruby/command-t/vim/screen.rb | 32 + .vim/bundle/command-t/ruby/command-t/vim/window.rb | 38 + .../bundle/command-t/spec/command-t/finder_spec.rb | 80 + .vim/bundle/command-t/spec/command-t/match_spec.rb | 236 ++ .../command-t/spec/command-t/matcher_spec.rb | 76 + .../command-t/spec/command-t/scanner_spec.rb | 82 + .vim/bundle/command-t/spec/spec_helper.rb | 38 + .vim/bundle/command-t/spec/vim_formatter.rb | 41 + .vim/bundle/nerdcommenter/.gitignore | 3 + .vim/bundle/nerdcommenter/Rakefile | 76 + .vim/bundle/nerdcommenter/doc/NERD_commenter.txt | 979 +++++++ .../bundle/nerdcommenter/plugin/NERD_commenter.vim | 2786 ++++++++++++++++++++ .vim/bundle/sparkup/.gitignore | 14 + .vim/bundle/sparkup/Makefile | 39 + .vim/bundle/sparkup/README.md | 130 + .vim/bundle/sparkup/ftplugin/html/sparkup.py | 1087 ++++++++ .vim/bundle/sparkup/ftplugin/html/sparkup.vim | 74 + .vim/bundle/sparkup/mit-license.txt | 22 + .vim/bundle/sparkup/sparkup | 1087 ++++++++ .vim/bundle/sparkup/sparkup-unittest.py | 138 + .vim/bundle/sparkup/sparkup.py | 1 + .vim/bundle/sparkup/vim/README.txt | 23 + .vim/bundle/vim-coffee-script/ftdetect/coffee.vim | 7 + .vim/bundle/vim-coffee-script/ftplugin/coffee.vim | 14 + .vim/bundle/vim-coffee-script/indent/coffee.vim | 157 ++ .vim/bundle/vim-coffee-script/readme.md | 77 + .vim/bundle/vim-coffee-script/syntax/coffee.vim | 161 ++ .vim/bundle/vim-coffee-script/todo.md | 35 + .vim/filetype.vim | 4 + 78 files changed, 10717 insertions(+) create mode 100644 .vim/autoload/pathogen.vim create mode 100644 .vim/bundle/ack.vim/.gitignore create mode 100644 .vim/bundle/ack.vim/README.md create mode 100644 .vim/bundle/ack.vim/Rakefile create mode 100644 .vim/bundle/ack.vim/doc/ack.txt create mode 100644 .vim/bundle/ack.vim/plugin/ack.vim create mode 100644 .vim/bundle/command-t/.bundle/config create mode 100644 .vim/bundle/command-t/.mailmap create mode 100644 .vim/bundle/command-t/.rspec create mode 100644 .vim/bundle/command-t/Gemfile create mode 100644 .vim/bundle/command-t/Gemfile.lock create mode 100644 .vim/bundle/command-t/LICENSE create mode 100644 .vim/bundle/command-t/Makefile create mode 100644 .vim/bundle/command-t/README.txt create mode 100644 .vim/bundle/command-t/Rakefile create mode 100755 .vim/bundle/command-t/bin/htmldiff create mode 100755 .vim/bundle/command-t/bin/ldiff create mode 100755 .vim/bundle/command-t/bin/rake create mode 100755 .vim/bundle/command-t/bin/rspec create mode 100755 .vim/bundle/command-t/compile-test.sh create mode 100644 .vim/bundle/command-t/doc/.gitignore create mode 120000 .vim/bundle/command-t/doc/command-t.txt create mode 100644 .vim/bundle/command-t/fixtures/bar/abc create mode 100644 .vim/bundle/command-t/fixtures/bar/xyz create mode 100644 .vim/bundle/command-t/fixtures/baz create mode 100644 .vim/bundle/command-t/fixtures/bing create mode 100644 .vim/bundle/command-t/fixtures/foo/alpha/t1 create mode 100644 .vim/bundle/command-t/fixtures/foo/alpha/t2 create mode 100644 .vim/bundle/command-t/fixtures/foo/beta create mode 100755 .vim/bundle/command-t/multi-spec.sh create mode 100644 .vim/bundle/command-t/plugin/command-t.vim create mode 100644 .vim/bundle/command-t/ruby/command-t/.gitignore create mode 100644 .vim/bundle/command-t/ruby/command-t/controller.rb create mode 100644 .vim/bundle/command-t/ruby/command-t/depend create mode 100644 .vim/bundle/command-t/ruby/command-t/ext.c create mode 100644 .vim/bundle/command-t/ruby/command-t/ext.h create mode 100644 .vim/bundle/command-t/ruby/command-t/extconf.rb create mode 100644 .vim/bundle/command-t/ruby/command-t/finder.rb create mode 100644 .vim/bundle/command-t/ruby/command-t/match.c create mode 100644 .vim/bundle/command-t/ruby/command-t/match.h create mode 100644 .vim/bundle/command-t/ruby/command-t/match_window.rb create mode 100644 .vim/bundle/command-t/ruby/command-t/matcher.c create mode 100644 .vim/bundle/command-t/ruby/command-t/matcher.h create mode 100644 .vim/bundle/command-t/ruby/command-t/prompt.rb create mode 100644 .vim/bundle/command-t/ruby/command-t/ruby_compat.h create mode 100644 .vim/bundle/command-t/ruby/command-t/scanner.rb create mode 100644 .vim/bundle/command-t/ruby/command-t/settings.rb create mode 100644 .vim/bundle/command-t/ruby/command-t/stub.rb create mode 100644 .vim/bundle/command-t/ruby/command-t/vim.rb create mode 100644 .vim/bundle/command-t/ruby/command-t/vim/screen.rb create mode 100644 .vim/bundle/command-t/ruby/command-t/vim/window.rb create mode 100644 .vim/bundle/command-t/spec/command-t/finder_spec.rb create mode 100644 .vim/bundle/command-t/spec/command-t/match_spec.rb create mode 100644 .vim/bundle/command-t/spec/command-t/matcher_spec.rb create mode 100644 .vim/bundle/command-t/spec/command-t/scanner_spec.rb create mode 100644 .vim/bundle/command-t/spec/spec_helper.rb create mode 100644 .vim/bundle/command-t/spec/vim_formatter.rb create mode 100644 .vim/bundle/nerdcommenter/.gitignore create mode 100644 .vim/bundle/nerdcommenter/Rakefile create mode 100644 .vim/bundle/nerdcommenter/doc/NERD_commenter.txt create mode 100644 .vim/bundle/nerdcommenter/plugin/NERD_commenter.vim create mode 100644 .vim/bundle/sparkup/.gitignore create mode 100644 .vim/bundle/sparkup/Makefile create mode 100644 .vim/bundle/sparkup/README.md create mode 100755 .vim/bundle/sparkup/ftplugin/html/sparkup.py create mode 100644 .vim/bundle/sparkup/ftplugin/html/sparkup.vim create mode 100644 .vim/bundle/sparkup/mit-license.txt create mode 100755 .vim/bundle/sparkup/sparkup create mode 100755 .vim/bundle/sparkup/sparkup-unittest.py create mode 120000 .vim/bundle/sparkup/sparkup.py create mode 100644 .vim/bundle/sparkup/vim/README.txt create mode 100644 .vim/bundle/vim-coffee-script/ftdetect/coffee.vim create mode 100644 .vim/bundle/vim-coffee-script/ftplugin/coffee.vim create mode 100644 .vim/bundle/vim-coffee-script/indent/coffee.vim create mode 100644 .vim/bundle/vim-coffee-script/readme.md create mode 100644 .vim/bundle/vim-coffee-script/syntax/coffee.vim create mode 100644 .vim/bundle/vim-coffee-script/todo.md diff --git a/.vim/autoload/pathogen.vim b/.vim/autoload/pathogen.vim new file mode 100644 index 0000000..ff7dba3 --- /dev/null +++ b/.vim/autoload/pathogen.vim @@ -0,0 +1,139 @@ +" pathogen.vim - path option manipulation +" Maintainer: Tim Pope +" Version: 1.2 + +" Install in ~/.vim/autoload (or ~\vimfiles\autoload). +" +" API is documented below. + +if exists("g:loaded_pathogen") || &cp + finish +endif +let g:loaded_pathogen = 1 + +" Split a path into a list. +function! pathogen#split(path) abort " {{{1 + if type(a:path) == type([]) | return a:path | endif + let split = split(a:path,'\\\@ output + silent filetype + redir END + let result = {} + let result.detection = match(output,'detection:ON') >= 0 + let result.indent = match(output,'indent:ON') >= 0 + let result.plugin = match(output,'plugin:ON') >= 0 + return result +endfunction " }}}1 + +" \ on Windows unless shellslash is set, / everywhere else. +function! pathogen#separator() abort " {{{1 + return !exists("+shellslash") || &shellslash ? '/' : '\' +endfunction " }}}1 + +" Convenience wrapper around glob() which returns a list. +function! pathogen#glob(pattern) abort " {{{1 + let files = split(glob(a:pattern),"\n") + return map(files,'substitute(v:val,"[".pathogen#separator()."/]$","","")') +endfunction "}}}1 + +" Like pathogen#glob(), only limit the results to directories. +function! pathogen#glob_directories(pattern) abort " {{{1 + return filter(pathogen#glob(a:pattern),'isdirectory(v:val)') +endfunction "}}}1 + +" Prepend all subdirectories of path to the rtp, and append all after +" directories in those subdirectories. +function! pathogen#runtime_prepend_subdirectories(path) " {{{1 + let sep = pathogen#separator() + let before = pathogen#glob_directories(a:path.sep."*[^~]") + let after = pathogen#glob_directories(a:path.sep."*[^~]".sep."after") + let rtp = pathogen#split(&rtp) + let path = expand(a:path) + call filter(rtp,'v:val[0:strlen(path)-1] !=# path') + let &rtp = pathogen#join(pathogen#uniq(before + rtp + after)) + return &rtp +endfunction " }}}1 + +" For each directory in rtp, check for a subdirectory named dir. If it +" exists, add all subdirectories of that subdirectory to the rtp, immediately +" after the original directory. If no argument is given, 'bundle' is used. +" Repeated calls with the same arguments are ignored. +function! pathogen#runtime_append_all_bundles(...) " {{{1 + let sep = pathogen#separator() + let name = a:0 ? a:1 : 'bundle' + let list = [] + for dir in pathogen#split(&rtp) + if dir =~# '\ *ack-author* +License: Same terms as Vim itself (see |license|) + +============================================================================== +INTRODUCTION *ack* + +This plugin is a front for the Perl module App::Ack. Ack can be used as a +replacement for grep. This plugin will allow you to run ack from vim, and +shows the results in a split window. + +:Ack [options] {pattern} [{directory}] *:Ack* + + Search recursively in {directory} (which defaults to the current + directory) for the {pattern}. Behaves just like the |:grep| command, but + will open the |Quickfix| window for you. + +:AckAdd [options] {pattern} [{directory}] *:AckAdd* + + Just like |:Ack|, but instead of making a new list, the matches are + appended to the current |quickfix| list. + +:AckFromSearch [{directory}] *:AckFromSearch* + + Just like |:Ack| but the pattern is from previous search. + +:LAck [options] {pattern} [{directory}] *:LAck* + + Just like |:Ack| but instead of the |quickfix| list, matches are placed in + the current |location-list|. + +:LAckAdd [options] {pattern} [{directory}] *:LAckAdd* + + Just like |:AckAdd| but instead of the |quickfix| list, matches are added + to the current |location-list| + +:AckFile [options] {pattern} [{directory}] *:AckFile* + + Search recursively in {directory} (which defaults to the current + directory) for filenames matching the {pattern}. Behaves just like the + |:grep| command, but will open the |Quickfix| window for you. + +Files containing the search term will be listed in the split window, along +with the line number of the occurrence, once for each occurrence. on +a line in this window will open the file, and place the cursor on the matching +line. + +See http://search.cpan.org/~petdance/ack/ack for more information. diff --git a/.vim/bundle/ack.vim/plugin/ack.vim b/.vim/bundle/ack.vim/plugin/ack.vim new file mode 100644 index 0000000..b05041b --- /dev/null +++ b/.vim/bundle/ack.vim/plugin/ack.vim @@ -0,0 +1,61 @@ +" NOTE: You must, of course, install the ack script +" in your path. +" On Debian / Ubuntu: +" sudo apt-get install ack-grep +" On your vimrc: +" let g:ackprg="ack-grep -H --nocolor --nogroup --column" +" +" With MacPorts: +" sudo port install p5-app-ack + +" Location of the ack utility +if !exists("g:ackprg") + let g:ackprg="ack -H --nocolor --nogroup --column" +endif + +function! s:Ack(cmd, args) + redraw + echo "Searching ..." + + " Format, used to manage column jump + if a:cmd =~# '-g$' + let g:ackformat="%f" + else + let g:ackformat="%f:%l:%c:%m" + end + + let grepprg_bak=&grepprg + let grepformat_bak=&grepformat + try + let &grepprg=g:ackprg + let &grepformat=g:ackformat + silent execute a:cmd . " " . a:args + finally + let &grepprg=grepprg_bak + let &grepformat=grepformat_bak + endtry + + if a:cmd =~# '^l' + botright lopen + else + botright copen + endif + + exec "nnoremap q :ccl" + + redraw! +endfunction + +function! s:AckFromSearch(cmd, args) + let search = getreg('/') + " translate vim regular expression to perl regular expression. + let search = substitute(search,'\(\\<\|\\>\)','\\b','g') + call s:Ack(a:cmd, '"' . search .'" '. a:args) +endfunction + +command! -bang -nargs=* -complete=file Ack call s:Ack('grep',) +command! -bang -nargs=* -complete=file AckAdd call s:Ack('grepadd', ) +command! -bang -nargs=* -complete=file AckFromSearch call s:AckFromSearch('grep', ) +command! -bang -nargs=* -complete=file LAck call s:Ack('lgrep', ) +command! -bang -nargs=* -complete=file LAckAdd call s:Ack('lgrepadd', ) +command! -bang -nargs=* -complete=file AckFile call s:Ack('grep -g', ) diff --git a/.vim/bundle/command-t/.bundle/config b/.vim/bundle/command-t/.bundle/config new file mode 100644 index 0000000..53b74b2 --- /dev/null +++ b/.vim/bundle/command-t/.bundle/config @@ -0,0 +1,2 @@ +--- +BUNDLE_BIN: bin diff --git a/.vim/bundle/command-t/.mailmap b/.vim/bundle/command-t/.mailmap new file mode 100644 index 0000000..7da337a --- /dev/null +++ b/.vim/bundle/command-t/.mailmap @@ -0,0 +1 @@ +Sung Pae diff --git a/.vim/bundle/command-t/.rspec b/.vim/bundle/command-t/.rspec new file mode 100644 index 0000000..53607ea --- /dev/null +++ b/.vim/bundle/command-t/.rspec @@ -0,0 +1 @@ +--colour diff --git a/.vim/bundle/command-t/Gemfile b/.vim/bundle/command-t/Gemfile new file mode 100644 index 0000000..d9e2a8f --- /dev/null +++ b/.vim/bundle/command-t/Gemfile @@ -0,0 +1,3 @@ +gem 'rake' +gem 'rr' +gem 'rspec', '>= 2.0.0.beta.16' diff --git a/.vim/bundle/command-t/Gemfile.lock b/.vim/bundle/command-t/Gemfile.lock new file mode 100644 index 0000000..d1721dd --- /dev/null +++ b/.vim/bundle/command-t/Gemfile.lock @@ -0,0 +1,21 @@ +GEM + specs: + diff-lcs (1.1.2) + rake (0.8.7) + rr (0.10.11) + rspec (2.0.0.beta.16) + rspec-core (= 2.0.0.beta.16) + rspec-expectations (= 2.0.0.beta.16) + rspec-mocks (= 2.0.0.beta.16) + rspec-core (2.0.0.beta.16) + rspec-expectations (2.0.0.beta.16) + diff-lcs (>= 1.1.2) + rspec-mocks (2.0.0.beta.16) + +PLATFORMS + ruby + +DEPENDENCIES + rake + rr + rspec (>= 2.0.0.beta.16) diff --git a/.vim/bundle/command-t/LICENSE b/.vim/bundle/command-t/LICENSE new file mode 100644 index 0000000..de5696c --- /dev/null +++ b/.vim/bundle/command-t/LICENSE @@ -0,0 +1,22 @@ +Copyright 2010 Wincent Colaiuta. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/.vim/bundle/command-t/Makefile b/.vim/bundle/command-t/Makefile new file mode 100644 index 0000000..3bd6da4 --- /dev/null +++ b/.vim/bundle/command-t/Makefile @@ -0,0 +1,19 @@ +rubyfiles := $(shell find ruby -name '*.rb') +cfiles := $(shell find ruby -name '*.c') +cheaders := $(shell find ruby -name '*.h') +depends := $(shell find ruby -name depend) +txtfiles := $(shell find doc -name '*.txt') +vimfiles := $(shell find plugin -name '*.vim') + +vimball: command-t.vba + +command-t.vba: $(rubyfiles) $(cfiles) $(cheaders) $(depends) $(txtfiles) $(vimfiles) + mkvimball $(basename $@) $^ + +.PHONY: spec +spec: + rspec spec + +.PHONY: clean +clean: + rm -f command-t.vba diff --git a/.vim/bundle/command-t/README.txt b/.vim/bundle/command-t/README.txt new file mode 100644 index 0000000..bb0b8ef --- /dev/null +++ b/.vim/bundle/command-t/README.txt @@ -0,0 +1,710 @@ +*command-t.txt* Command-T plug-in for Vim *command-t* + +CONTENTS *command-t-contents* + + 1. Introduction |command-t-intro| + 2. Requirements |command-t-requirements| + 3. Installation |command-t-installation| + 3. Managing using Pathogen |command-t-pathogen| + 4. Trouble-shooting |command-t-trouble-shooting| + 5. Usage |command-t-usage| + 6. Commands |command-t-commands| + 7. Mappings |command-t-mappings| + 8. Options |command-t-options| + 9. Authors |command-t-authors| +10. Website |command-t-website| +11. Donations |command-t-donations| +12. License |command-t-license| +13. History |command-t-history| + + +INTRODUCTION *command-t-intro* + +The Command-T plug-in provides an extremely fast, intuitive mechanism for +opening files with a minimal number of keystrokes. It's named "Command-T" +because it is inspired by the "Go to File" window bound to Command-T in +TextMate. + +Files are selected by typing characters that appear in their paths, and are +ordered by an algorithm which knows that characters that appear in certain +locations (for example, immediately after a path separator) should be given +more weight. + +To search efficiently, especially in large projects, you should adopt a +"path-centric" rather than a "filename-centric" mentality. That is you should +think more about where the desired file is found rather than what it is +called. This means narrowing your search down by including some characters +from the upper path components rather than just entering characters from the +filename itself. + +Screencasts demonstrating the plug-in can be viewed at: + + https://wincent.com/products/command-t + + +REQUIREMENTS *command-t-requirements* + +The plug-in requires Vim compiled with Ruby support, a compatible Ruby +installation at the operating system level, and a C compiler to build +the Ruby extension. + + +1. Vim compiled with Ruby support + +You can check for Ruby support by launching Vim with the --version switch: + + vim --version + +If "+ruby" appears in the version information then your version of Vim has +Ruby support. + +Another way to check is to simply try using the :ruby command from within Vim +itself: + + :ruby 1 + +If your Vim lacks support you'll see an error message like this: + + E319: Sorry, the command is not available in this version + +The version of Vim distributed with Mac OS X does not include Ruby support, +while MacVim does; it is available from: + + http://github.com/b4winckler/macvim/downloads + +For Windows users, the Vim 7.2 executable available from www.vim.org does +include Ruby support, and is recommended over version 7.3 (which links against +Ruby 1.9, but apparently has some bugs that need to be resolved). + + +2. Ruby + +In addition to having Ruby support in Vim, your system itself must have a +compatible Ruby install. "Compatible" means the same version as Vim itself +links against. If you use a different version then Command-T is unlikely +to work (see TROUBLE-SHOOTING below). + +On Mac OS X Snow Leopard, the system comes with Ruby 1.8.7 and all recent +versions of MacVim (the 7.2 snapshots and 7.3) are linked against it. + +On Linux and similar platforms, the linked version of Ruby will depend on +your distribution. You can usually find this out by examining the +compilation and linking flags displayed by the |:version| command in Vim, and +by looking at the output of: + + :ruby puts RUBY_VERSION + +A suitable Ruby environment for Windows can be installed using the Ruby +1.8.7-p299 RubyInstaller available at: + + http://rubyinstaller.org/downloads/archives + +If using RubyInstaller be sure to download the installer executable, not the +7-zip archive. When installing mark the checkbox "Add Ruby executables to your +PATH" so that Vim can find them. + + +3. C compiler + +Part of Command-T is implemented in C as a Ruby extension for speed, allowing +it to work responsively even on directory hierarchies containing enormous +numbers of files. As such, a C compiler is required in order to build the +extension and complete the installation. + +On Mac OS X, this can be obtained by installing the Xcode Tools that come on +the Mac OS X install disc. + +On Windows, the RubyInstaller Development Kit can be used to conveniently +install the necessary tool chain: + + http://rubyinstaller.org/downloads/archives + +At the time of writing, the appropriate development kit for use with Ruby +1.8.7 is DevKit-3.4.5r3-20091110. + +To use the Development Kit extract the archive contents to your C:\Ruby +folder. + + +INSTALLATION *command-t-installation* + +Command-T is distributed as a "vimball" which means that it can be installed +by opening it in Vim and then sourcing it: + + :e command-t.vba + :so % + +The files will be installed in your |'runtimepath'|. To check where this is +you can issue: + + :echo &rtp + +The C extension must then be built, which can be done from the shell. If you +use a typical |'runtimepath'| then the files were installed inside ~/.vim and +you can build the extension with: + + cd ~/.vim/ruby/command-t + ruby extconf.rb + make + +Note: If you are an RVM user, you must perform the build using the same +version of Ruby that Vim itself is linked against. This will often be the +system Ruby, which can be selected before issuing the "make" command with: + + rvm use system + + +MANAGING USING PATHOGEN *command-t-pathogen* + +Pathogen is a plugin that allows you to maintain plugin installations in +separate, isolated subdirectories under the "bundle" directory in your +|'runtimepath'|. The following examples assume that you already have +Pathogen installed and configured, and that you are installing into +~/.vim/bundle. For more information about Pathogen, see: + + http://www.vim.org/scripts/script.php?script_id=2332 + +If you manage your entire ~/.vim folder using Git then you can add the +Command-T repository as a submodule: + + cd ~/.vim + git submodule add git://git.wincent.com/command-t.git bundle/command-t + git submodule init + +Or if you just wish to do a simple clone instead of using submodules: + + cd ~/.vim + git clone git://git.wincent.com/command-t.git bundle/command-t + +Once you have a local copy of the repository you can update it at any time +with: + + cd ~/.vim/bundle/command-t + git pull + +Or you can switch to a specific release with: + + cd ~/.vim/bundle/command-t + git checkout 0.8b + +After installing or updating you must build the extension: + + cd ~/.vim/bundle/command-t + rake make + +While the Vimball installation automatically generates the help tags, under +Pathogen it is necessary to do so explicitly from inside Vim: + + :call pathogen#helptags() + + +TROUBLE-SHOOTING *command-t-trouble-shooting* + +Most installation problems are caused by a mismatch between the version of +Ruby on the host operating system, and the version of Ruby that Vim itself +linked against at compile time. For example, if one is 32-bit and the other is +64-bit, or one is from the Ruby 1.9 series and the other is from the 1.8 +series, then the plug-in is not likely to work. + +As such, on Mac OS X, I recommend using the standard Ruby that comes with the +system (currently 1.8.7) along with the latest version of MacVim (currently +version 7.3). If you wish to use custom builds of Ruby or of MacVim (not +recommmended) then you will have to take extra care to ensure that the exact +same Ruby environment is in effect when building Ruby, Vim and the Command-T +extension. + +For Windows, the following combination is known to work: + + - Vim 7.2 from http://www.vim.org/download.php: + ftp://ftp.vim.org/pub/vim/pc/gvim72.exe + - Ruby 1.8.7-p299 from http://rubyinstaller.org/downloads/archives: + http://rubyforge.org/frs/download.php/71492/rubyinstaller-1.8.7-p299.exe + - DevKit 3.4.5r3-20091110 from http://rubyinstaller.org/downloads/archives: + http://rubyforge.org/frs/download.php/66888/devkit-3.4.5r3-20091110.7z + +If a problem occurs the first thing you should do is inspect the output of: + + ruby extconf.rb + make + +During the installation, and: + + vim --version + +And compare the compilation and linker flags that were passed to the +extension and to Vim itself when they were built. If the Ruby-related +flags or architecture flags are different then it is likely that something +has changed in your Ruby environment and the extension may not work until +you eliminate the discrepancy. + + +USAGE *command-t-usage* + +Bring up the Command-T match window by typing: + + t + +This mapping is set up automatically for you, provided you do not already have +a mapping for t or |:CommandT|. You can also bring up the match window +by issuing the command: + + :CommandT + +A prompt will appear at the bottom of the screen along with a match window +showing all of the files in the current directory (as returned by the +|:pwd| command). + +For the most efficient file navigation within a project it's recommended that +you |:cd| into the root directory of your project when starting to work on it. +If you wish to open a file from outside of the project folder you can pass in +an optional path argument (relative or absolute) to |:CommandT|: + + :CommandT ../path/to/other/files + +Type letters in the prompt to narrow down the selection, showing only the +files whose paths contain those letters in the specified order. Letters do not +need to appear consecutively in a path in order for it to be classified as a +match. + +Once the desired file has been selected it can be opened by pressing . +(By default files are opened in the current window, but there are other +mappings that you can use to open in a vertical or horizontal split, or in +a new tab.) Note that if you have |'nohidden'| set and there are unsaved +changes in the current window when you press then opening in the current +window would fail; in this case Command-T will open the file in a new split. + +The following mappings are active when the prompt has focus: + + delete the character to the left of the cursor + delete the character at the cursor + move the cursor one character to the left + move the cursor one character to the left + move the cursor one character to the right + move the cursor one character to the right + move the cursor to the start (left) + move the cursor to the end (right) + clear the contents of the prompt + change focus to the match listing + +The following mappings are active when the match listing has focus: + + change focus to the prompt + +The following mappings are active when either the prompt or the match listing +has focus: + + open the selected file + open the selected file in a new split window + open the selected file in a new split window + open the selected file in a new vertical split window + open the selected file in a new tab + select next file in the match listing + select next file in the match listing + select next file in the match listing + select previous file in the match listing + select previous file in the match listing + select previous file in the match listing + cancel (dismisses match listing) + +The following is also available on terminals which support it: + + cancel (dismisses match listing) + +Note that the default mappings can be overriden by setting options in your +~/.vimrc file (see the OPTIONS section for a full list of available options). + +In addition, when the match listing has focus, typing a character will cause +the selection to jump to the first path which begins with that character. +Typing multiple characters consecutively can be used to distinguish between +paths which begin with the same prefix. + + +COMMANDS *command-t-commands* + + *:CommandT* +|:CommandT| Brings up the Command-T match window, starting in the + current working directory as returned by the|:pwd| + command. + + *:CommandTFlush* +|:CommandTFlush|Instructs the plug-in to flush its path cache, causing + the directory to be rescanned for new or deleted paths + the next time the match window is shown. In addition, all + configuration settings are re-evaluated, causing any + changes made to settings via the |:let| command to be picked + up. + + +MAPPINGS *command-t-mappings* + +By default Command-T comes with only one mapping: + + t bring up the Command-T match window + +However, Command-T won't overwrite a pre-existing mapping so if you prefer +to define a different mapping use a line like this in your ~/.vimrc: + + nmap t :CommandT + +Replacing "t" with your mapping of choice. + +Note that in the case of MacVim you actually can map to Command-T (written +as in Vim) in your ~/.gvimrc file if you first unmap the existing menu +binding of Command-T to "New Tab": + + if has("gui_macvim") + macmenu &File.New\ Tab key= + map :CommandT + endif + +When the Command-T window is active a number of other additional mappings +become available for doing things like moving between and selecting matches. +These are fully described above in the USAGE section, and settings for +overriding the mappings are listed below under OPTIONS. + + +OPTIONS *command-t-options* + +A number of options may be set in your ~/.vimrc to influence the behaviour of +the plug-in. To set an option, you include a line like this in your ~/.vimrc: + + let g:CommandTMaxFiles=20000 + +To have Command-T pick up new settings immediately (that is, without having +to restart Vim) you can issue the |:CommandTFlush| command after making +changes via |:let|. + +Following is a list of all available options: + + *g:CommandTMaxFiles* + |g:CommandTMaxFiles| number (default 10000) + + The maximum number of files that will be considered when scanning the + current directory. Upon reaching this number scanning stops. + + *g:CommandTMaxDepth* + |g:CommandTMaxDepth| number (default 15) + + The maximum depth (levels of recursion) to be explored when scanning the + current directory. Any directories at levels beyond this depth will be + skipped. + + *g:CommandTMaxHeight* + |g:CommandTMaxHeight| number (default: 0) + + The maximum height in lines the match window is allowed to expand to. + If set to 0, the window will occupy as much of the available space as + needed to show matching entries. + + *g:CommandTAlwaysShowDotFiles* + |g:CommandTAlwaysShowDotFiles| boolean (default: 0) + + By default Command-T will show dot-files only if the entered search + string contains a dot that could cause a dot-file to match. When set to + a non-zero value, this setting instructs Command-T to always include + matching dot-files in the match list regardless of whether the search + string contains a dot. See also |g:CommandTNeverShowDotFiles|. + + *g:CommandTNeverShowDotFiles* + |g:CommandTNeverShowDotFiles| boolean (default: 0) + + By default Command-T will show dot-files if the entered search string + contains a dot that could cause a dot-file to match. When set to a + non-zero value, this setting instructs Command-T to never show dot-files + under any circumstances. Note that it is contradictory to set both this + setting and |g:CommandTAlwaysShowDotFiles| to true, and if you do so Vim + will suffer from headaches, nervous twitches, and sudden mood swings. + + *g:CommandTScanDotDirectories* + |g:CommandTScanDotDirectories| boolean (default: 0) + + Normally Command-T will not recurse into "dot-directories" (directories + whose names begin with a dot) while performing its initial scan. Set + this setting to a non-zero value to override this behavior and recurse. + Note that this setting is completely independent of the + |g:CommandTAlwaysShowDotFiles| and |g:CommandTNeverShowDotFiles| + settings; those apply only to the selection and display of matches + (after scanning has been performed), whereas + |g:CommandTScanDotDirectories| affects the behaviour at scan-time. + + Note also that even with this setting on you can still use Command-T to + open files inside a "dot-directory" such as ~/.vim, but you have to use + the |:cd| command to change into that directory first. For example: + + :cd ~/.vim + :CommandT + + *g:CommandTMatchWindowAtTop* + |g:CommandTMatchWindowAtTop| boolean (default: 0) + + When this settings is off (the default) the match window will appear at + the bottom so as to keep it near to the prompt. Turning it on causes the + match window to appear at the top instead. This may be preferable if you + want the best match (usually the first one) to appear in a fixed location + on the screen rather than moving as the number of matches changes during + typing. + +As well as the basic options listed above, there are a number of settings that +can be used to override the default key mappings used by Command-T. For +example, to set as the mapping for cancelling (dismissing) the Command-T +window, you would add the following to your ~/.vimrc: + + let g:CommandTCancelMap='' + +Multiple, alternative mappings may be specified using list syntax: + + let g:CommandTCancelMap=['', ''] + +Following is a list of all map settings and their defaults: + + Setting Default mapping(s) + + *g:CommandTBackspaceMap* + |g:CommandTBackspaceMap| + + *g:CommandTDeleteMap* + |g:CommandTDeleteMap| + + *g:CommandTAcceptSelectionMap* + |g:CommandTAcceptSelectionMap| + + *g:CommandTAcceptSelectionSplitMap* + |g:CommandTAcceptSelectionSplitMap| + + + *g:CommandTAcceptSelectionTabMap* + |g:CommandTAcceptSelectionTabMap| + + *g:CommandTAcceptSelectionVSplitMap* + |g:CommandTAcceptSelectionVSplitMap| + + *g:CommandTToggleFocusMap* + |g:CommandTToggleFocusMap| + + *g:CommandTCancelMap* + |g:CommandTCancelMap| + (not on all terminals) + + *g:CommandTSelectNextMap* + |g:CommandTSelectNextMap| + + + + *g:CommandTSelectPrevMap* + |g:CommandTSelectPrevMap| + + + + *g:CommandTClearMap* + |g:CommandTClearMap| + + *g:CommandTCursorLeftMap* + |g:CommandTCursorLeftMap| + + + *g:CommandTCursorRightMap* + |g:CommandTCursorRightMap| + + + *g:CommandTCursorEndMap* + |g:CommandTCursorEndMap| + + *g:CommandTCursorStartMap* + |g:CommandTCursorStartMap| + +In addition to the options provided by Command-T itself, some of Vim's own +settings can be used to control behavior: + + *command-t-wildignore* + |'wildignore'| string (default: '') + + Vim's |'wildignore'| setting is used to determine which files should be + excluded from listings. This is a comma-separated list of glob patterns. + It defaults to the empty string, but common settings include "*.o,*.obj" + (to exclude object files) or ".git,.svn" (to exclude SCM metadata + directories). For example: + + :set wildignore+=*.o,*.obj,.git + + A pattern such as "vendor/rails/**" would exclude all files and + subdirectories inside the "vendor/rails" directory (relative to + directory Command-T starts in). + + See the |'wildignore'| documentation for more information. + + +AUTHORS *command-t-authors* + +Command-T is written and maintained by Wincent Colaiuta . +Other contributors that have submitted patches include (in alphabetical +order): + + Lucas de Vries + Mike Lundy + Scott Bronson + Sung Pae + Zak Johnson + +As this was the first Vim plug-in I had ever written I was heavily influenced +by the design of the LustyExplorer plug-in by Stephen Bach, which I understand +is one of the largest Ruby-based Vim plug-ins to date. + +While the Command-T codebase doesn't contain any code directly copied from +LustyExplorer, I did use it as a reference for answers to basic questions (like +"How do you do 'X' in a Ruby-based Vim plug-in?"), and also copied some basic +architectural decisions (like the division of the code into Prompt, Settings +and MatchWindow classes). + +LustyExplorer is available from: + + http://www.vim.org/scripts/script.php?script_id=1890 + + +WEBSITE *command-t-website* + +The official website for Command-T is: + + https://wincent.com/products/command-t + +The latest release will always be available from there. + +Development in progress can be inspected via the project's Git repository +browser at: + + http://git.wincent.com/command-t.git + +A copy of each release is also available from the official Vim scripts site +at: + + http://www.vim.org/scripts/script.php?script_id=3025 + +Bug reports should be submitted to the issue tracker at: + + https://wincent.com/issues + + +DONATIONS *command-t-donations* + +Command-T itself is free software released under the terms of the BSD license. +If you would like to support further development you can make a donation via +PayPal to win@wincent.com: + + https://wincent.com/products/command-t/donations + + +LICENSE *command-t-license* + +Copyright 2010 Wincent Colaiuta. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + + +HISTORY *command-t-history* + +0.8.1 (14 September 2010) + +- fix mapping issues for users who have set |'notimeout'| (patch from Sung + Pae) + +0.8 (19 August 2010) + +- overrides for the default mappings can now be lists of strings, allowing + multiple mappings to be defined for any given action +- t mapping only set up if no other map for |:CommandT| exists + (patch from Scott Bronson) +- prevent folds from appearing in the match listing +- tweaks to avoid the likelihood of "Not enough room" errors when trying to + open files +- watch out for "nil" windows when restoring window dimensions +- optimizations (avoid some repeated downcasing) +- move all Ruby files under the "command-t" subdirectory and avoid polluting + the "Vim" module namespace + +0.8b (11 July 2010) + +- large overhaul of the scoring algorithm to make the ordering of returned + results more intuitive; given the scope of the changes and room for + optimization of the new algorithm, this release is labelled as "beta" + +0.7 (10 June 2010) + +- handle more |'wildignore'| patterns by delegating to Vim's own |expand()| + function; with this change it is now viable to exclude patterns such as + 'vendor/rails/**' in addition to filename-only patterns like '*.o' and + '.git' (patch from Mike Lundy) +- always sort results alphabetically for empty search strings; this eliminates + filesystem-specific variations (patch from Mike Lundy) + +0.6 (28 April 2010) + +- |:CommandT| now accepts an optional parameter to specify the starting + directory, temporarily overriding the usual default of Vim's |:pwd| +- fix truncated paths when operating from root directory + +0.5.1 (11 April 2010) + +- fix for Ruby 1.9 compatibility regression introduced in 0.5 +- documentation enhancements, specifically targetted at Windows users + +0.5 (3 April 2010) + +- |:CommandTFlush| now re-evaluates settings, allowing changes made via |let| + to be picked up without having to restart Vim +- fix premature abort when scanning very deep directory hierarchies +- remove broken || key mapping on vt100 and xterm terminals +- provide settings for overriding default mappings +- minor performance optimization + +0.4 (27 March 2010) + +- add |g:CommandTMatchWindowAtTop| setting (patch from Zak Johnson) +- documentation fixes and enhancements +- internal refactoring and simplification + +0.3 (24 March 2010) + +- add |g:CommandTMaxHeight| setting for controlling the maximum height of the + match window (patch from Lucas de Vries) +- fix bug where |'list'| setting might be inappropriately set after dismissing + Command-T +- compatibility fix for different behaviour of "autoload" under Ruby 1.9.1 +- avoid "highlight group not found" warning when run under a version of Vim + that does not have syntax highlighting support +- open in split when opening normally would fail due to |'hidden'| and + |'modified'| values + +0.2 (23 March 2010) + +- compatibility fixes for compilation under Ruby 1.9 series +- compatibility fixes for compilation under Ruby 1.8.5 +- compatibility fixes for Windows and other non-UNIX platforms +- suppress "mapping already exists" message if t mapping is already + defined when plug-in is loaded +- exclude paths based on |'wildignore'| setting rather than a hardcoded + regular expression + +0.1 (22 March 2010) + +- initial public release + +------------------------------------------------------------------------------ +vim:tw=78:ft=help: diff --git a/.vim/bundle/command-t/Rakefile b/.vim/bundle/command-t/Rakefile new file mode 100644 index 0000000..1d737d5 --- /dev/null +++ b/.vim/bundle/command-t/Rakefile @@ -0,0 +1,68 @@ +def bail_on_failure + exitstatus = $?.exitstatus + if exitstatus != 0 + raise "last command failed with exit status #{exitstatus}" + end +end + +task :default => :spec + +desc 'Run specs' +task :spec do + system 'bin/rspec spec' + bail_on_failure +end + +desc 'Create vimball archive' +task :vimball do + system 'make' + bail_on_failure +end + +desc 'Clean compiled products' +task :clean do + Dir.chdir 'ruby/command-t' do + system 'make clean' + end +end + +desc 'Clobber all generated files' +task :clobber => :clean do + system 'make clean' +end + +desc 'Compile extension' +task :make do + Dir.chdir 'ruby/command-t' do + ruby 'extconf.rb' + system 'make clean && make' + bail_on_failure + end +end + +namespace :make do + desc 'Compile under all multiruby versions' + task :all do + system './compile-test.sh' + bail_on_failure + end +end + +namespace :spec do + desc 'Run specs under all multiruby versions' + task :all do + system './multi-spec.sh' + bail_on_failure + end +end + +desc 'Check that the current HEAD is tagged' +task :check_tag do + system 'git describe --exact-match HEAD 2> /dev/null' + if $?.exitstatus != 0 + puts 'warning: current HEAD is not tagged' + end +end + +desc 'Run checks prior to release' +task :prerelease => ['make:all', 'spec:all', :vimball, :check_tag] diff --git a/.vim/bundle/command-t/bin/htmldiff b/.vim/bundle/command-t/bin/htmldiff new file mode 100755 index 0000000..80266d3 --- /dev/null +++ b/.vim/bundle/command-t/bin/htmldiff @@ -0,0 +1,14 @@ +#!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'htmldiff' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", __FILE__) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('diff-lcs', 'htmldiff') diff --git a/.vim/bundle/command-t/bin/ldiff b/.vim/bundle/command-t/bin/ldiff new file mode 100755 index 0000000..55ef3aa --- /dev/null +++ b/.vim/bundle/command-t/bin/ldiff @@ -0,0 +1,14 @@ +#!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'ldiff' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", __FILE__) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('diff-lcs', 'ldiff') diff --git a/.vim/bundle/command-t/bin/rake b/.vim/bundle/command-t/bin/rake new file mode 100755 index 0000000..9f826fd --- /dev/null +++ b/.vim/bundle/command-t/bin/rake @@ -0,0 +1,14 @@ +#!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'rake' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", __FILE__) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('rake', 'rake') diff --git a/.vim/bundle/command-t/bin/rspec b/.vim/bundle/command-t/bin/rspec new file mode 100755 index 0000000..d7f4c7b --- /dev/null +++ b/.vim/bundle/command-t/bin/rspec @@ -0,0 +1,14 @@ +#!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'rspec' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", __FILE__) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('rspec-core', 'rspec') diff --git a/.vim/bundle/command-t/compile-test.sh b/.vim/bundle/command-t/compile-test.sh new file mode 100755 index 0000000..6f94f6a --- /dev/null +++ b/.vim/bundle/command-t/compile-test.sh @@ -0,0 +1,10 @@ +#!/bin/sh -e +cd ruby/command-t +for RUBY_VERSION in $(ls ~/.multiruby/install); do + echo "$RUBY_VERSION: building" + export PATH=~/.multiruby/install/$RUBY_VERSION/bin:$PATH + ruby extconf.rb + make clean + make + echo "$RUBY_VERSION: finished" +done diff --git a/.vim/bundle/command-t/doc/.gitignore b/.vim/bundle/command-t/doc/.gitignore new file mode 100644 index 0000000..6e92f57 --- /dev/null +++ b/.vim/bundle/command-t/doc/.gitignore @@ -0,0 +1 @@ +tags diff --git a/.vim/bundle/command-t/doc/command-t.txt b/.vim/bundle/command-t/doc/command-t.txt new file mode 120000 index 0000000..ecfa029 --- /dev/null +++ b/.vim/bundle/command-t/doc/command-t.txt @@ -0,0 +1 @@ +../README.txt \ No newline at end of file diff --git a/.vim/bundle/command-t/fixtures/bar/abc b/.vim/bundle/command-t/fixtures/bar/abc new file mode 100644 index 0000000..9c558e3 --- /dev/null +++ b/.vim/bundle/command-t/fixtures/bar/abc @@ -0,0 +1 @@ +. diff --git a/.vim/bundle/command-t/fixtures/bar/xyz b/.vim/bundle/command-t/fixtures/bar/xyz new file mode 100644 index 0000000..9c558e3 --- /dev/null +++ b/.vim/bundle/command-t/fixtures/bar/xyz @@ -0,0 +1 @@ +. diff --git a/.vim/bundle/command-t/fixtures/baz b/.vim/bundle/command-t/fixtures/baz new file mode 100644 index 0000000..9c558e3 --- /dev/null +++ b/.vim/bundle/command-t/fixtures/baz @@ -0,0 +1 @@ +. diff --git a/.vim/bundle/command-t/fixtures/bing b/.vim/bundle/command-t/fixtures/bing new file mode 100644 index 0000000..9c558e3 --- /dev/null +++ b/.vim/bundle/command-t/fixtures/bing @@ -0,0 +1 @@ +. diff --git a/.vim/bundle/command-t/fixtures/foo/alpha/t1 b/.vim/bundle/command-t/fixtures/foo/alpha/t1 new file mode 100644 index 0000000..9c558e3 --- /dev/null +++ b/.vim/bundle/command-t/fixtures/foo/alpha/t1 @@ -0,0 +1 @@ +. diff --git a/.vim/bundle/command-t/fixtures/foo/alpha/t2 b/.vim/bundle/command-t/fixtures/foo/alpha/t2 new file mode 100644 index 0000000..9c558e3 --- /dev/null +++ b/.vim/bundle/command-t/fixtures/foo/alpha/t2 @@ -0,0 +1 @@ +. diff --git a/.vim/bundle/command-t/fixtures/foo/beta b/.vim/bundle/command-t/fixtures/foo/beta new file mode 100644 index 0000000..9c558e3 --- /dev/null +++ b/.vim/bundle/command-t/fixtures/foo/beta @@ -0,0 +1 @@ +. diff --git a/.vim/bundle/command-t/multi-spec.sh b/.vim/bundle/command-t/multi-spec.sh new file mode 100755 index 0000000..50143ae --- /dev/null +++ b/.vim/bundle/command-t/multi-spec.sh @@ -0,0 +1,25 @@ +#!/bin/sh -e + +function build_quietly() +{ + (bundle install > /dev/null && + cd ruby/command-t && + ruby extconf.rb > /dev/null && + make clean > /dev/null && + make > /dev/null) +} + +OLD_PATH=$PATH +for RUBY_VERSION in $(ls ~/.multiruby/install); do + echo "$RUBY_VERSION: building" + export PATH=~/.multiruby/install/$RUBY_VERSION/bin:$OLD_PATH + build_quietly + echo "$RUBY_VERSION: running spec suite" + bin/rspec spec + echo "$RUBY_VERSION: finished" +done + +# put things back the way we found them +export PATH=$OLD_PATH +echo "Restoring: $(ruby -v)" +build_quietly diff --git a/.vim/bundle/command-t/plugin/command-t.vim b/.vim/bundle/command-t/plugin/command-t.vim new file mode 100644 index 0000000..716a889 --- /dev/null +++ b/.vim/bundle/command-t/plugin/command-t.vim @@ -0,0 +1,151 @@ +" command-t.vim +" Copyright 2010 Wincent Colaiuta. All rights reserved. +" +" Redistribution and use in source and binary forms, with or without +" modification, are permitted provided that the following conditions are met: +" +" 1. Redistributions of source code must retain the above copyright notice, +" this list of conditions and the following disclaimer. +" 2. Redistributions in binary form must reproduce the above copyright notice, +" this list of conditions and the following disclaimer in the documentation +" and/or other materials provided with the distribution. +" +" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +" POSSIBILITY OF SUCH DAMAGE. + +if exists("g:command_t_loaded") + finish +endif +let g:command_t_loaded = 1 + +command -nargs=? -complete=dir CommandT call CommandTShow() +command CommandTFlush call CommandTFlush() + +if !hasmapto('CommandT') + silent! nmap t :CommandT +endif + +function s:CommandTRubyWarning() + echohl WarningMsg + echo "command-t.vim requires Vim to be compiled with Ruby support" + echo "For more information type: :help command-t" + echohl none +endfunction + +function s:CommandTShow(arg) + if has('ruby') + ruby $command_t.show + else + call s:CommandTRubyWarning() + endif +endfunction + +function s:CommandTFlush() + if has('ruby') + ruby $command_t.flush + else + call s:CommandTRubyWarning() + endif +endfunction + +if !has('ruby') + finish +endif + +function CommandTHandleKey(arg) + ruby $command_t.handle_key +endfunction + +function CommandTBackspace() + ruby $command_t.backspace +endfunction + +function CommandTDelete() + ruby $command_t.delete +endfunction + +function CommandTAcceptSelection() + ruby $command_t.accept_selection +endfunction + +function CommandTAcceptSelectionTab() + ruby $command_t.accept_selection :command => 'tabe' +endfunction + +function CommandTAcceptSelectionSplit() + ruby $command_t.accept_selection :command => 'sp' +endfunction + +function CommandTAcceptSelectionVSplit() + ruby $command_t.accept_selection :command => 'vs' +endfunction + +function CommandTToggleFocus() + ruby $command_t.toggle_focus +endfunction + +function CommandTCancel() + ruby $command_t.cancel +endfunction + +function CommandTSelectNext() + ruby $command_t.select_next +endfunction + +function CommandTSelectPrev() + ruby $command_t.select_prev +endfunction + +function CommandTClear() + ruby $command_t.clear +endfunction + +function CommandTCursorLeft() + ruby $command_t.cursor_left +endfunction + +function CommandTCursorRight() + ruby $command_t.cursor_right +endfunction + +function CommandTCursorEnd() + ruby $command_t.cursor_end +endfunction + +function CommandTCursorStart() + ruby $command_t.cursor_start +endfunction + +ruby << EOF + # require Ruby files + begin + # prepare controller + require 'command-t/vim' + require 'command-t/controller' + $command_t = CommandT::Controller.new + rescue LoadError + load_path_modified = false + ::VIM::evaluate('&runtimepath').to_s.split(',').each do |path| + lib = "#{path}/ruby" + if !$LOAD_PATH.include?(lib) and File.exist?(lib) + $LOAD_PATH << lib + load_path_modified = true + end + end + retry if load_path_modified + + # could get here if C extension was not compiled, or was compiled + # for the wrong architecture or Ruby version + require 'command-t/stub' + $command_t = CommandT::Stub.new + end +EOF diff --git a/.vim/bundle/command-t/ruby/command-t/.gitignore b/.vim/bundle/command-t/ruby/command-t/.gitignore new file mode 100644 index 0000000..c98bad5 --- /dev/null +++ b/.vim/bundle/command-t/ruby/command-t/.gitignore @@ -0,0 +1,6 @@ +Makefile +*.o +*.log +ext.* +!ext.c +!ext.h diff --git a/.vim/bundle/command-t/ruby/command-t/controller.rb b/.vim/bundle/command-t/ruby/command-t/controller.rb new file mode 100644 index 0000000..2f8f59a --- /dev/null +++ b/.vim/bundle/command-t/ruby/command-t/controller.rb @@ -0,0 +1,289 @@ +# Copyright 2010 Wincent Colaiuta. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +require 'command-t/finder' +require 'command-t/match_window' +require 'command-t/prompt' + +module CommandT + class Controller + def initialize + @prompt = Prompt.new + set_up_max_height + set_up_finder + end + + def show + # optional parameter will be desired starting directory, or "" + @path = File.expand_path(::VIM::evaluate('a:arg'), VIM::pwd) + @finder.path = @path + @initial_window = $curwin + @initial_buffer = $curbuf + @match_window = MatchWindow.new \ + :prompt => @prompt, + :match_window_at_top => get_bool('g:CommandTMatchWindowAtTop') + @focus = @prompt + @prompt.focus + register_for_key_presses + clear # clears prompt and list matches + rescue Errno::ENOENT + # probably a problem with the optional parameter + @match_window.print_no_such_file_or_directory + end + + def hide + @match_window.close + if VIM::Window.select @initial_window + ::VIM::command "silent b #{@initial_buffer.number}" + end + end + + def flush + set_up_max_height + set_up_finder + end + + def handle_key + key = ::VIM::evaluate('a:arg').to_i.chr + if @focus == @prompt + @prompt.add! key + list_matches + else + @match_window.find key + end + end + + def backspace + if @focus == @prompt + @prompt.backspace! + list_matches + end + end + + def delete + if @focus == @prompt + @prompt.delete! + list_matches + end + end + + def accept_selection options = {} + selection = @match_window.selection + hide + open_selection(selection, options) unless selection.nil? + end + + def toggle_focus + @focus.unfocus # old focus + if @focus == @prompt + @focus = @match_window + else + @focus = @prompt + end + @focus.focus # new focus + end + + def cancel + hide + end + + def select_next + @match_window.select_next + end + + def select_prev + @match_window.select_prev + end + + def clear + @prompt.clear! + list_matches + end + + def cursor_left + @prompt.cursor_left if @focus == @prompt + end + + def cursor_right + @prompt.cursor_right if @focus == @prompt + end + + def cursor_end + @prompt.cursor_end if @focus == @prompt + end + + def cursor_start + @prompt.cursor_start if @focus == @prompt + end + + private + + def set_up_max_height + @max_height = get_number('g:CommandTMaxHeight') || 0 + end + + def set_up_finder + @finder = CommandT::Finder.new nil, + :max_files => get_number('g:CommandTMaxFiles'), + :max_depth => get_number('g:CommandTMaxDepth'), + :always_show_dot_files => get_bool('g:CommandTAlwaysShowDotFiles'), + :never_show_dot_files => get_bool('g:CommandTNeverShowDotFiles'), + :scan_dot_directories => get_bool('g:CommandTScanDotDirectories') + end + + def exists? name + ::VIM::evaluate("exists(\"#{name}\")").to_i != 0 + end + + def get_number name + exists?(name) ? ::VIM::evaluate("#{name}").to_i : nil + end + + def get_bool name + exists?(name) ? ::VIM::evaluate("#{name}").to_i != 0 : nil + end + + def get_string name + exists?(name) ? ::VIM::evaluate("#{name}").to_s : nil + end + + # expect a string or a list of strings + def get_list_or_string name + return nil unless exists?(name) + list_or_string = ::VIM::evaluate("#{name}") + if list_or_string.kind_of?(Array) + list_or_string.map { |item| item.to_s } + else + list_or_string.to_s + end + end + + # Backslash-escape space, \, |, %, #, " + def sanitize_path_string str + # for details on escaping command-line mode arguments see: :h : + # (that is, help on ":") in the Vim documentation. + str.gsub(/[ \\|%#"]/, '\\\\\0') + end + + def default_open_command + if !get_bool('&hidden') && get_bool('&modified') + 'sp' + else + 'e' + end + end + + def ensure_appropriate_window_selection + # normally we try to open the selection in the current window, but there + # is one exception: + # + # - we don't touch any "unlisted" buffer with buftype "nofile" (such as + # NERDTree or MiniBufExplorer); this is to avoid things like the "Not + # enough room" error which occurs when trying to open in a split in a + # shallow (potentially 1-line) buffer like MiniBufExplorer is current + # + # Other "unlisted" buffers, such as those with buftype "help" are treated + # normally. + initial = $curwin + while true do + break unless ::VIM::evaluate('&buflisted').to_i == 0 && + ::VIM::evaluate('&buftype').to_s == 'nofile' + ::VIM::command 'wincmd w' # try next window + break if $curwin == initial # have already tried all + end + end + + def open_selection selection, options = {} + command = options[:command] || default_open_command + selection = File.expand_path selection, @path + selection = sanitize_path_string selection + ensure_appropriate_window_selection + ::VIM::command "silent #{command} #{selection}" + end + + def map key, function, param = nil + ::VIM::command "noremap #{key} " \ + ":call CommandT#{function}(#{param})" + end + + def xterm? + !!(::VIM::evaluate('&term') =~ /\Axterm/) + end + + def vt100? + !!(::VIM::evaluate('&term') =~ /\Avt100/) + end + + def register_for_key_presses + # "normal" keys (interpreted literally) + numbers = ('0'..'9').to_a.join + lowercase = ('a'..'z').to_a.join + uppercase = lowercase.upcase + punctuation = '<>`@#~!"$%&/()=+*-_.,;:?\\\'{}[] ' # and space + (numbers + lowercase + uppercase + punctuation).each_byte do |b| + map "", 'HandleKey', b + end + + # "special" keys (overridable by settings) + { 'Backspace' => '', + 'Delete' => '', + 'AcceptSelection' => '', + 'AcceptSelectionSplit' => ['', ''], + 'AcceptSelectionTab' => '', + 'AcceptSelectionVSplit' => '', + 'ToggleFocus' => '', + 'Cancel' => ['', ''], + 'SelectNext' => ['', '', ''], + 'SelectPrev' => ['', '', ''], + 'Clear' => '', + 'CursorLeft' => ['', ''], + 'CursorRight' => ['', ''], + 'CursorEnd' => '', + 'CursorStart' => '' }.each do |key, value| + if override = get_list_or_string("g:CommandT#{key}Map") + [override].flatten.each do |mapping| + map mapping, key + end + else + [value].flatten.each do |mapping| + map mapping, key unless mapping == '' && (xterm? || vt100?) + end + end + end + end + + # Returns the desired maximum number of matches, based on available + # vertical space and the g:CommandTMaxHeight option. + def match_limit + limit = VIM::Screen.lines - 5 + limit = 1 if limit < 0 + limit = [limit, @max_height].min if @max_height > 0 + limit + end + + def list_matches + matches = @finder.sorted_matches_for @prompt.abbrev, :limit => match_limit + @match_window.matches = matches + end + end # class Controller +end # module commandT diff --git a/.vim/bundle/command-t/ruby/command-t/depend b/.vim/bundle/command-t/ruby/command-t/depend new file mode 100644 index 0000000..bfa9552 --- /dev/null +++ b/.vim/bundle/command-t/ruby/command-t/depend @@ -0,0 +1,24 @@ +# Copyright 2010 Wincent Colaiuta. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +CFLAGS += -std=c99 -Wall -Wextra -Wno-unused-parameter diff --git a/.vim/bundle/command-t/ruby/command-t/ext.c b/.vim/bundle/command-t/ruby/command-t/ext.c new file mode 100644 index 0000000..714956b --- /dev/null +++ b/.vim/bundle/command-t/ruby/command-t/ext.c @@ -0,0 +1,65 @@ +// Copyright 2010 Wincent Colaiuta. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#include "match.h" +#include "matcher.h" + +VALUE mCommandT = 0; // module CommandT +VALUE cCommandTMatch = 0; // class CommandT::Match +VALUE cCommandTMatcher = 0; // class CommandT::Matcher + +VALUE CommandT_option_from_hash(const char *option, VALUE hash) +{ + if (NIL_P(hash)) + return Qnil; + VALUE key = ID2SYM(rb_intern(option)); + if (rb_funcall(hash, rb_intern("has_key?"), 1, key) == Qtrue) + return rb_hash_aref(hash, key); + else + return Qnil; +} + +void Init_ext() +{ + // module CommandT + mCommandT = rb_define_module("CommandT"); + + // class CommandT::Match + cCommandTMatch = rb_define_class_under(mCommandT, "Match", rb_cObject); + + // methods + rb_define_method(cCommandTMatch, "initialize", CommandTMatch_initialize, -1); + rb_define_method(cCommandTMatch, "matches?", CommandTMatch_matches, 0); + rb_define_method(cCommandTMatch, "to_s", CommandTMatch_to_s, 0); + + // attributes + rb_define_attr(cCommandTMatch, "score", Qtrue, Qfalse); // reader: true, writer: false + + // class CommandT::Matcher + cCommandTMatcher = rb_define_class_under(mCommandT, "Matcher", rb_cObject); + + // methods + rb_define_method(cCommandTMatcher, "initialize", CommandTMatcher_initialize, -1); + rb_define_method(cCommandTMatcher, "sorted_matches_for", CommandTMatcher_sorted_matchers_for, 2); + rb_define_method(cCommandTMatcher, "matches_for", CommandTMatcher_matches_for, 1); +} diff --git a/.vim/bundle/command-t/ruby/command-t/ext.h b/.vim/bundle/command-t/ruby/command-t/ext.h new file mode 100644 index 0000000..89ff076 --- /dev/null +++ b/.vim/bundle/command-t/ruby/command-t/ext.h @@ -0,0 +1,36 @@ +// Copyright 2010 Wincent Colaiuta. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#include + +extern VALUE mCommandT; // module CommandT +extern VALUE cCommandTMatch; // class CommandT::Match +extern VALUE cCommandTMatcher; // class CommandT::Matcher + +// Encapsulates common pattern of checking for an option in an optional +// options hash. The hash itself may be nil, but an exception will be +// raised if it is not nil and not a hash. +VALUE CommandT_option_from_hash(const char *option, VALUE hash); + +// Debugging macro. +#define ruby_inspect(obj) rb_funcall(rb_mKernel, rb_intern("p"), 1, obj) diff --git a/.vim/bundle/command-t/ruby/command-t/extconf.rb b/.vim/bundle/command-t/ruby/command-t/extconf.rb new file mode 100644 index 0000000..58503b6 --- /dev/null +++ b/.vim/bundle/command-t/ruby/command-t/extconf.rb @@ -0,0 +1,32 @@ +# Copyright 2010 Wincent Colaiuta. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +require 'mkmf' + +def missing item + puts "couldn't find #{item} (required)" + exit 1 +end + +have_header('ruby.h') or missing('ruby.h') +create_makefile('ext') diff --git a/.vim/bundle/command-t/ruby/command-t/finder.rb b/.vim/bundle/command-t/ruby/command-t/finder.rb new file mode 100644 index 0000000..8ef959d --- /dev/null +++ b/.vim/bundle/command-t/ruby/command-t/finder.rb @@ -0,0 +1,51 @@ +# Copyright 2010 Wincent Colaiuta. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +require 'command-t/ext' # CommandT::Matcher +require 'command-t/scanner' + +module CommandT + # Encapsulates a Scanner instance (which builds up a list of available files + # in a directory) and a Matcher instance (which selects from that list based + # on a search string). + class Finder + def initialize path = Dir.pwd, options = {} + @scanner = Scanner.new path, options + @matcher = Matcher.new @scanner, options + end + + # Options: + # :limit (integer): limit the number of returned matches + def sorted_matches_for str, options = {} + @matcher.sorted_matches_for str, options + end + + def flush + @scanner.flush + end + + def path= path + @scanner.path = path + end + end # class Finder +end # CommandT diff --git a/.vim/bundle/command-t/ruby/command-t/match.c b/.vim/bundle/command-t/ruby/command-t/match.c new file mode 100644 index 0000000..e32fb0b --- /dev/null +++ b/.vim/bundle/command-t/ruby/command-t/match.c @@ -0,0 +1,189 @@ +// Copyright 2010 Wincent Colaiuta. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#include "match.h" +#include "ext.h" +#include "ruby_compat.h" + +// use a struct to make passing params during recursion easier +typedef struct +{ + char *str_p; // pointer to string to be searched + long str_len; // length of same + char *abbrev_p; // pointer to search string (abbreviation) + long abbrev_len; // length of same + double max_score_per_char; + int dot_file; // boolean: true if str is a dot-file + int always_show_dot_files; // boolean + int never_show_dot_files; // boolean +} matchinfo_t; + +double recursive_match(matchinfo_t *m, // sharable meta-data + long str_idx, // where in the path string to start + long abbrev_idx, // where in the search string to start + long last_idx, // location of last matched character + double score) // cumulative score so far +{ + double seen_score = 0; // remember best score seen via recursion + int dot_file_match = 0; // true if abbrev matches a dot-file + int dot_search = 0; // true if searching for a dot + + for (long i = abbrev_idx; i < m->abbrev_len; i++) + { + char c = m->abbrev_p[i]; + if (c == '.') + dot_search = 1; + int found = 0; + for (long j = str_idx; j < m->str_len; j++, str_idx++) + { + char d = m->str_p[j]; + if (d == '.') + { + if (j == 0 || m->str_p[j - 1] == '/') + { + m->dot_file = 1; // this is a dot-file + if (dot_search) // and we are searching for a dot + dot_file_match = 1; // so this must be a match + } + } + else if (d >= 'A' && d <= 'Z') + d += 'a' - 'A'; // add 32 to downcase + if (c == d) + { + found = 1; + dot_search = 0; + + // calculate score + double score_for_char = m->max_score_per_char; + long distance = j - last_idx; + if (distance > 1) + { + double factor = 1.0; + char last = m->str_p[j - 1]; + char curr = m->str_p[j]; // case matters, so get again + if (last == '/') + factor = 0.9; + else if (last == '-' || + last == '_' || + last == ' ' || + (last >= '0' && last <= '9')) + factor = 0.8; + else if (last >= 'a' && last <= 'z' && + curr >= 'A' && curr <= 'Z') + factor = 0.8; + else if (last == '.') + factor = 0.7; + else + // if no "special" chars behind char, factor diminishes + // as distance from last matched char increases + factor = (1.0 / distance) * 0.75; + score_for_char *= factor; + } + + if (++j < m->str_len) + { + // bump cursor one char to the right and + // use recursion to try and find a better match + double sub_score = recursive_match(m, j, i, last_idx, score); + if (sub_score > seen_score) + seen_score = sub_score; + } + + score += score_for_char; + last_idx = str_idx++; + break; + } + } + if (!found) + return 0.0; + } + if (m->dot_file) + { + if (m->never_show_dot_files || + (!dot_file_match && !m->always_show_dot_files)) + return 0.0; + } + return (score > seen_score) ? score : seen_score; +} + +// Match.new abbrev, string, options = {} +VALUE CommandTMatch_initialize(int argc, VALUE *argv, VALUE self) +{ + // process arguments: 2 mandatory, 1 optional + VALUE str, abbrev, options; + if (rb_scan_args(argc, argv, "21", &str, &abbrev, &options) == 2) + options = Qnil; + str = StringValue(str); + abbrev = StringValue(abbrev); // already downcased by caller + + // check optional options hash for overrides + VALUE always_show_dot_files = CommandT_option_from_hash("always_show_dot_files", options); + VALUE never_show_dot_files = CommandT_option_from_hash("never_show_dot_files", options); + + matchinfo_t m; + m.str_p = RSTRING_PTR(str); + m.str_len = RSTRING_LEN(str); + m.abbrev_p = RSTRING_PTR(abbrev); + m.abbrev_len = RSTRING_LEN(abbrev); + m.max_score_per_char = (1.0 / m.str_len + 1.0 / m.abbrev_len) / 2; + m.dot_file = 0; + m.always_show_dot_files = always_show_dot_files == Qtrue; + m.never_show_dot_files = never_show_dot_files == Qtrue; + + // calculate score + double score = 1.0; + if (m.abbrev_len == 0) // special case for zero-length search string + { + // filter out dot files + if (!m.always_show_dot_files) + { + for (long i = 0; i < m.str_len; i++) + { + char c = m.str_p[i]; + if (c == '.' && (i == 0 || m.str_p[i - 1] == '/')) + { + score = 0.0; + break; + } + } + } + } + else // normal case + score = recursive_match(&m, 0, 0, 0, 0.0); + + // clean-up and final book-keeping + rb_iv_set(self, "@score", rb_float_new(score)); + rb_iv_set(self, "@str", str); + return Qnil; +} + +VALUE CommandTMatch_matches(VALUE self) +{ + double score = NUM2DBL(rb_iv_get(self, "@score")); + return score > 0 ? Qtrue : Qfalse; +} + +VALUE CommandTMatch_to_s(VALUE self) +{ + return rb_iv_get(self, "@str"); +} diff --git a/.vim/bundle/command-t/ruby/command-t/match.h b/.vim/bundle/command-t/ruby/command-t/match.h new file mode 100644 index 0000000..c3ce929 --- /dev/null +++ b/.vim/bundle/command-t/ruby/command-t/match.h @@ -0,0 +1,29 @@ +// Copyright 2010 Wincent Colaiuta. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#include + +extern VALUE CommandTMatch_initialize(int argc, VALUE *argv, VALUE self); +extern VALUE CommandTMatch_matches(VALUE self); +extern VALUE CommandTMatch_score(VALUE self); +extern VALUE CommandTMatch_to_s(VALUE self); diff --git a/.vim/bundle/command-t/ruby/command-t/match_window.rb b/.vim/bundle/command-t/ruby/command-t/match_window.rb new file mode 100644 index 0000000..eae0f87 --- /dev/null +++ b/.vim/bundle/command-t/ruby/command-t/match_window.rb @@ -0,0 +1,340 @@ +# Copyright 2010 Wincent Colaiuta. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +require 'ostruct' +require 'command-t/settings' + +module CommandT + class MatchWindow + @@selection_marker = '> ' + @@marker_length = @@selection_marker.length + @@unselected_marker = ' ' * @@marker_length + + def initialize options = {} + @prompt = options[:prompt] + + # save existing window dimensions so we can restore them later + @windows = [] + (0..(::VIM::Window.count - 1)).each do |i| + window = OpenStruct.new :index => i, :height => ::VIM::Window[i].height + @windows << window + end + + # global settings (must manually save and restore) + @settings = Settings.new + ::VIM::set_option 'timeout' # ensure mappings timeout + ::VIM::set_option 'timeoutlen=0' # respond immediately to mappings + ::VIM::set_option 'nohlsearch' # don't highlight search strings + ::VIM::set_option 'noinsertmode' # don't make Insert mode the default + ::VIM::set_option 'noshowcmd' # don't show command info on last line + ::VIM::set_option 'report=9999' # don't show "X lines changed" reports + ::VIM::set_option 'sidescroll=0' # don't sidescroll in jumps + ::VIM::set_option 'sidescrolloff=0' # don't sidescroll automatically + ::VIM::set_option 'noequalalways' # don't auto-balance window sizes + + # create match window and set it up + split_location = options[:match_window_at_top] ? 'topleft' : 'botright' + split_command = "silent! #{split_location} 1split GoToFile" + [ + split_command, + 'setlocal bufhidden=delete', # delete buf when no longer displayed + 'setlocal buftype=nofile', # buffer is not related to any file + 'setlocal nomodifiable', # prevent manual edits + 'setlocal noswapfile', # don't create a swapfile + 'setlocal nowrap', # don't soft-wrap + 'setlocal nonumber', # don't show line numbers + 'setlocal nolist', # don't use List mode (visible tabs etc) + 'setlocal foldcolumn=0', # don't show a fold column at side + 'setlocal foldlevel=99', # don't fold anything + 'setlocal nocursorline', # don't highlight line cursor is on + 'setlocal nospell', # spell-checking off + 'setlocal nobuflisted', # don't show up in the buffer list + 'setlocal textwidth=0' # don't hard-wrap (break long lines) + ].each { |command| ::VIM::command command } + + # sanity check: make sure the buffer really was created + raise "Can't find buffer" unless $curbuf.name.match /GoToFile/ + + # syntax coloring + if VIM::has_syntax? + ::VIM::command "syntax match CommandTSelection \"^#{@@selection_marker}.\\+$\"" + ::VIM::command 'syntax match CommandTNoEntries "^-- NO MATCHES --$"' + ::VIM::command 'syntax match CommandTNoEntries "^-- NO SUCH FILE OR DIRECTORY --$"' + ::VIM::command 'highlight link CommandTSelection Visual' + ::VIM::command 'highlight link CommandTNoEntries Error' + ::VIM::evaluate 'clearmatches()' + + # hide cursor + @cursor_highlight = get_cursor_highlight + hide_cursor + end + + + @has_focus = false + @selection = nil + @abbrev = '' + @window = $curwin + @buffer = $curbuf + end + + def close + ::VIM::command "bwipeout! #{@buffer.number}" + restore_window_dimensions + @settings.restore + @prompt.dispose + show_cursor + end + + def add! char + @abbrev += char + end + + def backspace! + @abbrev.chop! + end + + def select_next + if @selection < @matches.length - 1 + @selection += 1 + print_match(@selection - 1) # redraw old selection (removes marker) + print_match(@selection) # redraw new selection (adds marker) + else + # (possibly) loop or scroll + end + end + + def select_prev + if @selection > 0 + @selection -= 1 + print_match(@selection + 1) # redraw old selection (removes marker) + print_match(@selection) # redraw new selection (adds marker) + else + # (possibly) loop or scroll + end + end + + def matches= matches + if matches != @matches + @matches = matches + @selection = 0 + print_matches + end + end + + def focus + unless @has_focus + @has_focus = true + if VIM::has_syntax? + ::VIM::command 'highlight link CommandTSelection Search' + end + end + end + + def unfocus + if @has_focus + @has_focus = false + if VIM::has_syntax? + ::VIM::command 'highlight link CommandTSelection Visual' + end + end + end + + def find char + # is this a new search or the continuation of a previous one? + now = Time.now + if @last_key_time.nil? or @last_key_time < (now - 0.5) + @find_string = char + else + @find_string += char + end + @last_key_time = now + + # see if there's anything up ahead that matches + @matches.each_with_index do |match, idx| + if match[0, @find_string.length].casecmp(@find_string) == 0 + old_selection = @selection + @selection = idx + print_match(old_selection) # redraw old selection (removes marker) + print_match(@selection) # redraw new selection (adds marker) + break + end + end + end + + # Returns the currently selected item as a String. + def selection + @matches[@selection] + end + + def print_no_such_file_or_directory + print_error 'NO SUCH FILE OR DIRECTORY' + end + + private + + def print_error msg + return unless VIM::Window.select(@window) + unlock + clear + @window.height = 1 + @buffer[1] = "-- #{msg} --" + lock + end + + def restore_window_dimensions + # sort from tallest to shortest + @windows.sort! { |a, b| b.height <=> a.height } + + # starting with the tallest ensures that there are no constraints + # preventing windows on the side of vertical splits from regaining + # their original full size + @windows.each do |w| + # beware: window may be nil + window = ::VIM::Window[w.index] + window.height = w.height if window + end + end + + def match_text_for_idx idx + match = truncated_match @matches[idx] + if idx == @selection + prefix = @@selection_marker + suffix = padding_for_selected_match match + else + prefix = @@unselected_marker + suffix = '' + end + prefix + match + suffix + end + + # Print just the specified match. + def print_match idx + return unless VIM::Window.select(@window) + unlock + @buffer[idx + 1] = match_text_for_idx idx + lock + end + + # Print all matches. + def print_matches + match_count = @matches.length + if match_count == 0 + print_error 'NO MATCHES' + else + return unless VIM::Window.select(@window) + unlock + clear + actual_lines = 1 + @window_width = @window.width # update cached value + max_lines = VIM::Screen.lines - 5 + max_lines = 1 if max_lines < 0 + actual_lines = match_count > max_lines ? max_lines : match_count + @window.height = actual_lines + (1..actual_lines).each do |line| + idx = line - 1 + if @buffer.count >= line + @buffer[line] = match_text_for_idx idx + else + @buffer.append line - 1, match_text_for_idx(idx) + end + end + lock + end + end + + # Prepare padding for match text (trailing spaces) so that selection + # highlighting extends all the way to the right edge of the window. + def padding_for_selected_match str + len = str.length + if len >= @window_width - @@marker_length + '' + else + ' ' * (@window_width - @@marker_length - len) + end + end + + # Convert "really/long/path" into "really...path" based on available + # window width. + def truncated_match str + len = str.length + available_width = @window_width - @@marker_length + return str if len <= available_width + left = (available_width / 2) - 1 + right = (available_width / 2) - 2 + (available_width % 2) + str[0, left] + '...' + str[-right, right] + end + + def clear + # range = % (whole buffer) + # action = d (delete) + # register = _ (black hole register, don't record deleted text) + ::VIM::command 'silent %d _' + end + + def get_cursor_highlight + # as :highlight returns nothing and only prints, + # must redirect its output to a variable + ::VIM::command 'silent redir => g:command_t_cursor_highlight' + + # force 0 verbosity to ensure origin information isn't printed as well + ::VIM::command 'silent! 0verbose highlight Cursor' + ::VIM::command 'silent redir END' + + # there are 3 possible formats to check for, each needing to be + # transformed in a certain way in order to reapply the highlight: + # Cursor xxx guifg=bg guibg=fg -> :hi! Cursor guifg=bg guibg=fg + # Cursor xxx links to SomethingElse -> :hi! link Cursor SomethingElse + # Cursor xxx cleared -> :hi! clear Cursor + highlight = ::VIM::evaluate 'g:command_t_cursor_highlight' + if highlight =~ /^Cursor\s+xxx\s+links to (\w+)/ + "link Cursor #{$~[1]}" + elsif highlight =~ /^Cursor\s+xxx\s+cleared/ + 'clear Cursor' + elsif highlight =~ /Cursor\s+xxx\s+(.+)/ + "Cursor #{$~[1]}" + else # likely cause E411 Cursor highlight group not found + nil + end + end + + def hide_cursor + if @cursor_highlight + ::VIM::command 'highlight Cursor NONE' + end + end + + def show_cursor + if @cursor_highlight + ::VIM::command "highlight #{@cursor_highlight}" + end + end + + def lock + ::VIM::command 'setlocal nomodifiable' + end + + def unlock + ::VIM::command 'setlocal modifiable' + end + end +end diff --git a/.vim/bundle/command-t/ruby/command-t/matcher.c b/.vim/bundle/command-t/ruby/command-t/matcher.c new file mode 100644 index 0000000..9d4a101 --- /dev/null +++ b/.vim/bundle/command-t/ruby/command-t/matcher.c @@ -0,0 +1,164 @@ +// Copyright 2010 Wincent Colaiuta. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#include /* for qsort() */ +#include /* for strcmp() */ +#include "matcher.h" +#include "ext.h" +#include "ruby_compat.h" + +// comparison function for use with qsort +int comp_alpha(const void *a, const void *b) +{ + VALUE a_val = *(VALUE *)a; + VALUE b_val = *(VALUE *)b; + ID to_s = rb_intern("to_s"); + + VALUE a_str = rb_funcall(a_val, to_s, 0); + VALUE b_str = rb_funcall(b_val, to_s, 0); + char *a_p = RSTRING_PTR(a_str); + long a_len = RSTRING_LEN(a_str); + char *b_p = RSTRING_PTR(b_str); + long b_len = RSTRING_LEN(b_str); + int order = 0; + if (a_len > b_len) + { + order = strncmp(a_p, b_p, b_len); + if (order == 0) + order = 1; // shorter string (b) wins + } + else if (a_len < b_len) + { + order = strncmp(a_p, b_p, a_len); + if (order == 0) + order = -1; // shorter string (a) wins + } + else + order = strncmp(a_p, b_p, a_len); + return order; +} + +// comparison function for use with qsort +int comp_score(const void *a, const void *b) +{ + VALUE a_val = *(VALUE *)a; + VALUE b_val = *(VALUE *)b; + ID score = rb_intern("score"); + double a_score = RFLOAT_VALUE(rb_funcall(a_val, score, 0)); + double b_score = RFLOAT_VALUE(rb_funcall(b_val, score, 0)); + if (a_score > b_score) + return -1; // a scores higher, a should appear sooner + else if (a_score < b_score) + return 1; // b scores higher, a should appear later + else + return comp_alpha(a, b); +} + +VALUE CommandTMatcher_initialize(int argc, VALUE *argv, VALUE self) +{ + // process arguments: 1 mandatory, 1 optional + VALUE scanner, options; + if (rb_scan_args(argc, argv, "11", &scanner, &options) == 1) + options = Qnil; + if (NIL_P(scanner)) + rb_raise(rb_eArgError, "nil scanner"); + rb_iv_set(self, "@scanner", scanner); + + // check optional options hash for overrides + VALUE always_show_dot_files = CommandT_option_from_hash("always_show_dot_files", options); + if (always_show_dot_files != Qtrue) + always_show_dot_files = Qfalse; + VALUE never_show_dot_files = CommandT_option_from_hash("never_show_dot_files", options); + if (never_show_dot_files != Qtrue) + never_show_dot_files = Qfalse; + rb_iv_set(self, "@always_show_dot_files", always_show_dot_files); + rb_iv_set(self, "@never_show_dot_files", never_show_dot_files); + return Qnil; +} + +VALUE CommandTMatcher_sorted_matchers_for(VALUE self, VALUE abbrev, VALUE options) +{ + // process optional options hash + VALUE limit_option = CommandT_option_from_hash("limit", options); + + // get unsorted matches + VALUE matches = CommandTMatcher_matches_for(self, abbrev); + + abbrev = StringValue(abbrev); + if (RSTRING_LEN(abbrev) == 0 || + (RSTRING_LEN(abbrev) == 1 && RSTRING_PTR(abbrev)[0] == '.')) + // alphabetic order if search string is only "" or "." + qsort(RARRAY_PTR(matches), RARRAY_LEN(matches), sizeof(VALUE), comp_alpha); + else + // for all other non-empty search strings, sort by score + qsort(RARRAY_PTR(matches), RARRAY_LEN(matches), sizeof(VALUE), comp_score); + + // apply optional limit option + long limit = NIL_P(limit_option) ? 0 : NUM2LONG(limit_option); + if (limit == 0 || RARRAY_LEN(matches)< limit) + limit = RARRAY_LEN(matches); + + // will return an array of strings, not an array of Match objects + for (long i = 0; i < limit; i++) + { + VALUE str = rb_funcall(RARRAY_PTR(matches)[i], rb_intern("to_s"), 0); + RARRAY_PTR(matches)[i] = str; + } + + // trim off any items beyond the limit + if (limit < RARRAY_LEN(matches)) + (void)rb_funcall(matches, rb_intern("slice!"), 2, LONG2NUM(limit), + LONG2NUM(RARRAY_LEN(matches) - limit)); + return matches; +} + +VALUE CommandTMatcher_matches_for(VALUE self, VALUE abbrev) +{ + if (NIL_P(abbrev)) + rb_raise(rb_eArgError, "nil abbrev"); + VALUE matches = rb_ary_new(); + VALUE scanner = rb_iv_get(self, "@scanner"); + VALUE always_show_dot_files = rb_iv_get(self, "@always_show_dot_files"); + VALUE never_show_dot_files = rb_iv_get(self, "@never_show_dot_files"); + VALUE options = Qnil; + if (always_show_dot_files == Qtrue) + { + options = rb_hash_new(); + rb_hash_aset(options, ID2SYM(rb_intern("always_show_dot_files")), always_show_dot_files); + } + else if (never_show_dot_files == Qtrue) + { + options = rb_hash_new(); + rb_hash_aset(options, ID2SYM(rb_intern("never_show_dot_files")), never_show_dot_files); + } + abbrev = rb_funcall(abbrev, rb_intern("downcase"), 0); + VALUE paths = rb_funcall(scanner, rb_intern("paths"), 0); + for (long i = 0, max = RARRAY_LEN(paths); i < max; i++) + { + VALUE path = RARRAY_PTR(paths)[i]; + VALUE match = rb_funcall(cCommandTMatch, rb_intern("new"), 3, path, abbrev, options); + if (rb_funcall(match, rb_intern("matches?"), 0) == Qtrue) + rb_funcall(matches, rb_intern("push"), 1, match); + } + return matches; +} diff --git a/.vim/bundle/command-t/ruby/command-t/matcher.h b/.vim/bundle/command-t/ruby/command-t/matcher.h new file mode 100644 index 0000000..ce079d1 --- /dev/null +++ b/.vim/bundle/command-t/ruby/command-t/matcher.h @@ -0,0 +1,30 @@ +// Copyright 2010 Wincent Colaiuta. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#include + +extern VALUE CommandTMatcher_initialize(int argc, VALUE *argv, VALUE self); +extern VALUE CommandTMatcher_sorted_matchers_for(VALUE self, VALUE abbrev, VALUE options); + +// most likely the function will be subsumed by the sorted_matcher_for function +extern VALUE CommandTMatcher_matches_for(VALUE self, VALUE abbrev); diff --git a/.vim/bundle/command-t/ruby/command-t/prompt.rb b/.vim/bundle/command-t/ruby/command-t/prompt.rb new file mode 100644 index 0000000..743e873 --- /dev/null +++ b/.vim/bundle/command-t/ruby/command-t/prompt.rb @@ -0,0 +1,165 @@ +# Copyright 2010 Wincent Colaiuta. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +module CommandT + # Abuse the status line as a prompt. + class Prompt + attr_accessor :abbrev + + def initialize + @abbrev = '' # abbreviation entered so far + @col = 0 # cursor position + @has_focus = false + end + + # Erase whatever is displayed in the prompt line, + # effectively disposing of the prompt + def dispose + ::VIM::command 'echo' + ::VIM::command 'redraw' + end + + # Clear any entered text. + def clear! + @abbrev = '' + @col = 0 + redraw + end + + # Insert a character at (before) the current cursor position. + def add! char + left, cursor, right = abbrev_segments + @abbrev = left + char + cursor + right + @col += 1 + redraw + end + + # Delete a character to the left of the current cursor position. + def backspace! + if @col > 0 + left, cursor, right = abbrev_segments + @abbrev = left.chop! + cursor + right + @col -= 1 + redraw + end + end + + # Delete a character at the current cursor position. + def delete! + if @col < @abbrev.length + left, cursor, right = abbrev_segments + @abbrev = left + right + redraw + end + end + + def cursor_left + if @col > 0 + @col -= 1 + redraw + end + end + + def cursor_right + if @col < @abbrev.length + @col += 1 + redraw + end + end + + def cursor_end + if @col < @abbrev.length + @col = @abbrev.length + redraw + end + end + + def cursor_start + if @col != 0 + @col = 0 + redraw + end + end + + def redraw + if @has_focus + prompt_highlight = 'Comment' + normal_highlight = 'None' + cursor_highlight = 'Underlined' + else + prompt_highlight = 'NonText' + normal_highlight = 'NonText' + cursor_highlight = 'NonText' + end + left, cursor, right = abbrev_segments + components = [prompt_highlight, '>>', 'None', ' '] + components += [normal_highlight, left] unless left.empty? + components += [cursor_highlight, cursor] unless cursor.empty? + components += [normal_highlight, right] unless right.empty? + components += [cursor_highlight, ' '] if cursor.empty? + set_status *components + end + + def focus + unless @has_focus + @has_focus = true + redraw + end + end + + def unfocus + if @has_focus + @has_focus = false + redraw + end + end + + private + + # Returns the @abbrev string divided up into three sections, any of + # which may actually be zero width, depending on the location of the + # cursor: + # - left segment (to left of cursor) + # - cursor segment (character at cursor) + # - right segment (to right of cursor) + def abbrev_segments + left = @abbrev[0, @col] + cursor = @abbrev[@col, 1] + right = @abbrev[(@col + 1)..-1] || '' + [left, cursor, right] + end + + def set_status *args + # see ':help :echo' for why forcing a redraw here helps + # prevent the status line from getting inadvertantly cleared + # after our echo commands + ::VIM::command 'redraw' + while (highlight = args.shift) and (text = args.shift) do + text = VIM::escape_for_single_quotes text + ::VIM::command "echohl #{highlight}" + ::VIM::command "echon '#{text}'" + end + ::VIM::command 'echohl None' + end + end # class Prompt +end # module CommandT diff --git a/.vim/bundle/command-t/ruby/command-t/ruby_compat.h b/.vim/bundle/command-t/ruby/command-t/ruby_compat.h new file mode 100644 index 0000000..e7960a2 --- /dev/null +++ b/.vim/bundle/command-t/ruby/command-t/ruby_compat.h @@ -0,0 +1,49 @@ +// Copyright 2010 Wincent Colaiuta. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#include + +// for compatibility with older versions of Ruby which don't declare RSTRING_PTR +#ifndef RSTRING_PTR +#define RSTRING_PTR(s) (RSTRING(s)->ptr) +#endif + +// for compatibility with older versions of Ruby which don't declare RSTRING_LEN +#ifndef RSTRING_LEN +#define RSTRING_LEN(s) (RSTRING(s)->len) +#endif + +// for compatibility with older versions of Ruby which don't declare RARRAY_PTR +#ifndef RARRAY_PTR +#define RARRAY_PTR(a) (RARRAY(a)->ptr) +#endif + +// for compatibility with older versions of Ruby which don't declare RARRAY_LEN +#ifndef RARRAY_LEN +#define RARRAY_LEN(a) (RARRAY(a)->len) +#endif + +// for compatibility with older versions of Ruby which don't declare RFLOAT_VALUE +#ifndef RFLOAT_VALUE +#define RFLOAT_VALUE(f) (RFLOAT(f)->value) +#endif diff --git a/.vim/bundle/command-t/ruby/command-t/scanner.rb b/.vim/bundle/command-t/ruby/command-t/scanner.rb new file mode 100644 index 0000000..9565f3a --- /dev/null +++ b/.vim/bundle/command-t/ruby/command-t/scanner.rb @@ -0,0 +1,93 @@ +# Copyright 2010 Wincent Colaiuta. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +require 'command-t/vim' + +module CommandT + # Reads the current directory recursively for the paths to all regular files. + class Scanner + class FileLimitExceeded < ::RuntimeError; end + + def initialize path = Dir.pwd, options = {} + @path = path + @max_depth = options[:max_depth] || 15 + @max_files = options[:max_files] || 10_000 + @scan_dot_directories = options[:scan_dot_directories] || false + end + + def paths + return @paths unless @paths.nil? + begin + @paths = [] + @depth = 0 + @files = 0 + @prefix_len = @path.chomp('/').length + add_paths_for_directory @path, @paths + rescue FileLimitExceeded + end + @paths + end + + def flush + @paths = nil + end + + def path= str + if @path != str + @path = str + flush + end + end + + private + + def path_excluded? path + # first strip common prefix (@path) from path to match VIM's behavior + path = path[(@prefix_len + 1)..-1] + path = VIM::escape_for_single_quotes path + ::VIM::evaluate("empty(expand(fnameescape('#{path}')))").to_i == 1 + end + + def add_paths_for_directory dir, accumulator + Dir.foreach(dir) do |entry| + next if ['.', '..'].include?(entry) + path = File.join(dir, entry) + unless path_excluded?(path) + if File.file?(path) + @files += 1 + raise FileLimitExceeded if @files > @max_files + accumulator << path[@prefix_len + 1..-1] + elsif File.directory?(path) + next if @depth >= @max_depth + next if (entry.match(/\A\./) && !@scan_dot_directories) + @depth += 1 + add_paths_for_directory path, accumulator + @depth -= 1 + end + end + end + rescue Errno::EACCES + # skip over directories for which we don't have access + end + end # class Scanner +end # module CommandT diff --git a/.vim/bundle/command-t/ruby/command-t/settings.rb b/.vim/bundle/command-t/ruby/command-t/settings.rb new file mode 100644 index 0000000..c15016a --- /dev/null +++ b/.vim/bundle/command-t/ruby/command-t/settings.rb @@ -0,0 +1,77 @@ +# Copyright 2010 Wincent Colaiuta. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +module CommandT + # Convenience class for saving and restoring global settings. + class Settings + def initialize + save + end + + def save + @timeoutlen = get_number 'timeoutlen' + @report = get_number 'report' + @sidescroll = get_number 'sidescroll' + @sidescrolloff = get_number 'sidescrolloff' + @timeout = get_bool 'timeout' + @equalalways = get_bool 'equalalways' + @hlsearch = get_bool 'hlsearch' + @insertmode = get_bool 'insertmode' + @showcmd = get_bool 'showcmd' + end + + def restore + set_number 'timeoutlen', @timeoutlen + set_number 'report', @report + set_number 'sidescroll', @sidescroll + set_number 'sidescrolloff', @sidescrolloff + set_bool 'timeout', @timeout + set_bool 'equalalways', @equalalways + set_bool 'hlsearch', @hlsearch + set_bool 'insertmode', @insertmode + set_bool 'showcmd', @showcmd + end + + private + + def get_number setting + ::VIM::evaluate("&#{setting}").to_i + end + + def get_bool setting + ::VIM::evaluate("&#{setting}").to_i == 1 + end + + def set_number setting, value + ::VIM::set_option "#{setting}=#{value}" + end + + def set_bool setting, value + if value + ::VIM::set_option setting + else + ::VIM::set_option "no#{setting}" + end + end + end # class Settings +end # module CommandT diff --git a/.vim/bundle/command-t/ruby/command-t/stub.rb b/.vim/bundle/command-t/ruby/command-t/stub.rb new file mode 100644 index 0000000..775bffa --- /dev/null +++ b/.vim/bundle/command-t/ruby/command-t/stub.rb @@ -0,0 +1,46 @@ +# Copyright 2010 Wincent Colaiuta. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +module CommandT + class Stub + @@load_error = ['command-t.vim could not load the C extension', + 'Please see INSTALLATION and TROUBLE-SHOOTING in the help', + 'For more information type: :help command-t'] + + def show + warn *@@load_error + end + + def flush + warn *@@load_error + end + + private + + def warn *msg + ::VIM::command 'echohl WarningMsg' + msg.each { |m| ::VIM::command "echo '#{m}'" } + ::VIM::command 'echohl none' + end + end # class Stub +end # module CommandT diff --git a/.vim/bundle/command-t/ruby/command-t/vim.rb b/.vim/bundle/command-t/ruby/command-t/vim.rb new file mode 100644 index 0000000..b4e40fc --- /dev/null +++ b/.vim/bundle/command-t/ruby/command-t/vim.rb @@ -0,0 +1,43 @@ +# Copyright 2010 Wincent Colaiuta. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +require 'command-t/vim/screen' +require 'command-t/vim/window' + +module CommandT + module VIM + def self.has_syntax? + ::VIM::evaluate('has("syntax")').to_i != 0 + end + + def self.pwd + ::VIM::evaluate 'getcwd()' + end + + # Escape a string for safe inclusion in a Vim single-quoted string + # (single quotes escaped by doubling, everything else is literal) + def self.escape_for_single_quotes str + str.gsub "'", "''" + end + end # module VIM +end # module CommandT diff --git a/.vim/bundle/command-t/ruby/command-t/vim/screen.rb b/.vim/bundle/command-t/ruby/command-t/vim/screen.rb new file mode 100644 index 0000000..fb7ba33 --- /dev/null +++ b/.vim/bundle/command-t/ruby/command-t/vim/screen.rb @@ -0,0 +1,32 @@ +# Copyright 2010 Wincent Colaiuta. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +module CommandT + module VIM + module Screen + def self.lines + ::VIM::evaluate('&lines').to_i + end + end # module Screen + end # module VIM +end # module CommandT diff --git a/.vim/bundle/command-t/ruby/command-t/vim/window.rb b/.vim/bundle/command-t/ruby/command-t/vim/window.rb new file mode 100644 index 0000000..1e53d56 --- /dev/null +++ b/.vim/bundle/command-t/ruby/command-t/vim/window.rb @@ -0,0 +1,38 @@ +# Copyright 2010 Wincent Colaiuta. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +module CommandT + module VIM + class Window + def self.select window + return true if $curwin == window + initial = $curwin + while true do + ::VIM::command 'wincmd w' # cycle through windows + return true if $curwin == window # have selected desired window + return false if $curwin == initial # have already looped through all + end + end + end # class Window + end # module VIM +end # module CommandT diff --git a/.vim/bundle/command-t/spec/command-t/finder_spec.rb b/.vim/bundle/command-t/spec/command-t/finder_spec.rb new file mode 100644 index 0000000..c002283 --- /dev/null +++ b/.vim/bundle/command-t/spec/command-t/finder_spec.rb @@ -0,0 +1,80 @@ +# Copyright 2010 Wincent Colaiuta. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +require File.expand_path('../spec_helper', File.dirname(__FILE__)) +require 'command-t/finder' + +module VIM; end + +describe CommandT::Finder do + before :all do + @finder = CommandT::Finder.new File.join(File.dirname(__FILE__), '..', + '..', 'fixtures') + @all_fixtures = %w( + bar/abc + bar/xyz + baz + bing + foo/alpha/t1 + foo/alpha/t2 + foo/beta + ) + end + + before do + # scanner will call VIM's expand() function for exclusion filtering + stub(::VIM).evaluate(/expand\(.+\)/) { '0' } + end + + describe 'sorted_matches_for method' do + it 'should return an empty array when no matches' do + @finder.sorted_matches_for('kung foo fighting').should == [] + end + + it 'should return all files when query string is empty' do + @finder.sorted_matches_for('').should == @all_fixtures + end + + it 'should return files in alphabetical order when query string is empty' do + results = @finder.sorted_matches_for('') + results.should == results.sort + end + + it 'should return matching files in score order' do + @finder.sorted_matches_for('ba'). + should == %w(baz bar/abc bar/xyz foo/beta) + @finder.sorted_matches_for('a'). + should == %w(baz bar/abc bar/xyz foo/alpha/t1 foo/alpha/t2 foo/beta) + end + + it 'should obey the :limit option for empty search strings' do + @finder.sorted_matches_for('', :limit => 2). + should == %w(bar/abc bar/xyz) + end + + it 'should obey the :limit option for non-empty search strings' do + @finder.sorted_matches_for('a', :limit => 3). + should == %w(baz bar/abc bar/xyz) + end + end +end diff --git a/.vim/bundle/command-t/spec/command-t/match_spec.rb b/.vim/bundle/command-t/spec/command-t/match_spec.rb new file mode 100644 index 0000000..39cb51e --- /dev/null +++ b/.vim/bundle/command-t/spec/command-t/match_spec.rb @@ -0,0 +1,236 @@ +# Copyright 2010 Wincent Colaiuta. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +require File.expand_path('../spec_helper', File.dirname(__FILE__)) +require 'command-t/ext' + +describe CommandT::Match do + def match_for path, pattern + CommandT::Match.new path, pattern + end + + it 'requires pattern to be lowercase' do + # this is an optimization: we ask our caller (the Matcher class) to + # downcase once before calling us, rather than downcase repeatedly + # during looping, recursion, and initialization of thousands of Match + # instances + match_for('foo', 'Foo').matches?.should == false + end + + describe '#matches?' do + it 'returns false for non-matches' do + match_for('foo', 'bar').matches?.should == false + end + + it 'returns true for matches' do + match_for('foo', 'foo').matches?.should == true + end + + it 'returns true for empty search strings' do + match_for('foo', '').matches?.should == true + end + + it 'returns false for overlength matches' do + match_for('foo', 'foo...').matches?.should == false + end + end + + describe 'score method' do + it 'assigns a score of 1.0 for empty search string' do + match_for('foo', '').score.should == 1.0 + end + + it 'assigns a score of zero for a non-match' do + match_for('foo', 'bar').score.should == 0.0 + end + + it 'assigns a score of zero for an overlength match' do + match_for('foo', 'foo...').score.should == 0.0 + end + + it 'assigns perfect matches a score of one' do + match_for('foo', 'foo').score.should == 1.0 + end + + it 'assigns perfect but incomplete matches a score of less than one' do + match_for('foo', 'f').score.should < 1.0 + end + + it 'prioritizes matches with more matching characters' do + few_matches = match_for('foobar', 'fb') + many_matches = match_for('foobar', 'fbar') + many_matches.score.should > few_matches.score + end + + it 'prioritizes shorter paths over longer ones' do + short_path = match_for('article.rb', 'art') + long_path = match_for('articles_controller_spec.rb', 'art') + short_path.score.should > long_path.score + end + + it 'prioritizes matches after "/"' do + normal_match = match_for('fooobar', 'b') + special_match = match_for('foo/bar', 'b') + special_match.score.should > normal_match.score + + # note that / beats _ + normal_match = match_for('foo_bar', 'b') + special_match = match_for('foo/bar', 'b') + special_match.score.should > normal_match.score + + # / also beats - + normal_match = match_for('foo-bar', 'b') + special_match = match_for('foo/bar', 'b') + special_match.score.should > normal_match.score + + # and numbers + normal_match = match_for('foo9bar', 'b') + special_match = match_for('foo/bar', 'b') + special_match.score.should > normal_match.score + + # and periods + normal_match = match_for('foo.bar', 'b') + special_match = match_for('foo/bar', 'b') + special_match.score.should > normal_match.score + + # and spaces + normal_match = match_for('foo bar', 'b') + special_match = match_for('foo/bar', 'b') + special_match.score.should > normal_match.score + end + + it 'prioritizes matches after "-"' do + normal_match = match_for('fooobar', 'b') + special_match = match_for('foo-bar', 'b') + special_match.score.should > normal_match.score + + # - also beats . + normal_match = match_for('foo.bar', 'b') + special_match = match_for('foo-bar', 'b') + special_match.score.should > normal_match.score + end + + it 'prioritizes matches after "_"' do + normal_match = match_for('fooobar', 'b') + special_match = match_for('foo_bar', 'b') + special_match.score.should > normal_match.score + + # _ also beats . + normal_match = match_for('foo.bar', 'b') + special_match = match_for('foo_bar', 'b') + special_match.score.should > normal_match.score + end + + it 'prioritizes matches after " "' do + normal_match = match_for('fooobar', 'b') + special_match = match_for('foo bar', 'b') + special_match.score.should > normal_match.score + + # " " also beats . + normal_match = match_for('foo.bar', 'b') + special_match = match_for('foo bar', 'b') + special_match.score.should > normal_match.score + end + + it 'prioritizes matches after numbers' do + normal_match = match_for('fooobar', 'b') + special_match = match_for('foo9bar', 'b') + special_match.score.should > normal_match.score + + # numbers also beat . + normal_match = match_for('foo.bar', 'b') + special_match = match_for('foo9bar', 'b') + special_match.score.should > normal_match.score + end + + it 'prioritizes matches after periods' do + normal_match = match_for('fooobar', 'b') + special_match = match_for('foo.bar', 'b') + special_match.score.should > normal_match.score + end + + it 'prioritizes matching capitals following lowercase' do + normal_match = match_for('foobar', 'b') + special_match = match_for('fooBar', 'b') + special_match.score.should > normal_match.score + end + + it 'prioritizes matches earlier in the string' do + early_match = match_for('**b*****', 'b') + late_match = match_for('******b*', 'b') + early_match.score.should > late_match.score + end + + it 'prioritizes matches closer to previous matches' do + early_match = match_for('**bc****', 'bc') + late_match = match_for('**b***c*', 'bc') + early_match.score.should > late_match.score + end + + it 'scores alternative matches of same path differently' do + # given path: app/controllers/articles_controller.rb + left_to_right_match = match_for('a**/****r******/**t*c***_*on*******.**', 'artcon') + best_match = match_for('***/***********/art*****_con*******.**', 'artcon') + best_match.score.should > left_to_right_match.score + end + + it 'returns the best possible score among alternatives' do + # given path: app/controllers/articles_controller.rb + best_match = match_for('***/***********/art*****_con*******.**', 'artcon') + chosen_match = match_for('app/controllers/articles_controller.rb', 'artcon') + chosen_match.score.should == best_match.score + end + + it 'provides intuitive results for "artcon" and "articles_controller"' do + low = match_for('app/controllers/heartbeat_controller.rb', 'artcon') + high = match_for('app/controllers/articles_controller.rb', 'artcon') + high.score.should > low.score + end + + it 'provides intuitive results for "aca" and "a/c/articles_controller"' do + low = match_for 'app/controllers/heartbeat_controller.rb', 'aca' + high = match_for 'app/controllers/articles_controller.rb', 'aca' + best_match = match_for 'a**/c**********/a******************.**', 'aca' + high.score.should > low.score + high.score.should == best_match.score + end + + it 'provides intuitive results for "d" and "doc/command-t.txt"' do + low = match_for 'TODO', 'd' + high = match_for 'doc/command-t.txt', 'd' + high.score.should > low.score + end + + it 'provides intuitive results for "do" and "doc/command-t.txt"' do + low = match_for 'TODO', 'do' + high = match_for 'doc/command-t.txt', 'do' + high.score.should > low.score + end + end + + describe 'to_s method' do + it 'returns the entire matched string' do + match_for('abc', 'abc').to_s.should == 'abc' + end + end +end diff --git a/.vim/bundle/command-t/spec/command-t/matcher_spec.rb b/.vim/bundle/command-t/spec/command-t/matcher_spec.rb new file mode 100644 index 0000000..074c815 --- /dev/null +++ b/.vim/bundle/command-t/spec/command-t/matcher_spec.rb @@ -0,0 +1,76 @@ +# Copyright 2010 Wincent Colaiuta. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +require File.expand_path('../spec_helper', File.dirname(__FILE__)) +require 'command-t/scanner' +require 'command-t/ext' + +describe CommandT::Matcher do + describe 'initialization' do + it 'should raise an ArgumentError if passed nil' do + lambda { CommandT::Matcher.new nil }. + should raise_error(ArgumentError) + end + end + + describe '#matches_for' do + before do + @scanner = Object.new + end + + it 'raises an ArgumentError if passed nil' do + @matcher = CommandT::Matcher.new @scanner + lambda { @matcher.matches_for(nil) }. + should raise_error(ArgumentError) + end + + it 'returns empty array when source array empty' do + stub(@scanner).paths { [] } + @no_paths = CommandT::Matcher.new @scanner + @no_paths.matches_for('foo').should == [] + @no_paths.matches_for('').should == [] + end + + it 'returns empty array when no matches' do + stub(@scanner).paths { ['foo/bar', 'foo/baz', 'bing'] } + @no_matches = CommandT::Matcher.new @scanner + @no_matches.matches_for('xyz').should == [] + end + + it 'returns matching paths' do + stub(@scanner).paths { ['foo/bar', 'foo/baz', 'bing'] } + @foo_paths = CommandT::Matcher.new @scanner + matches = @foo_paths.matches_for('z') + matches.map { |m| m.to_s }.should == ['foo/baz'] + matches = @foo_paths.matches_for('bg') + matches.map { |m| m.to_s }.should == ['bing'] + end + + it 'performs case-insensitive matching' do + stub(@scanner).paths { ['Foo'] } + @path = CommandT::Matcher.new @scanner + matches = @path.matches_for('f') + matches.map { |m| m.to_s }.should == ['Foo'] + end + end +end diff --git a/.vim/bundle/command-t/spec/command-t/scanner_spec.rb b/.vim/bundle/command-t/spec/command-t/scanner_spec.rb new file mode 100644 index 0000000..d1da248 --- /dev/null +++ b/.vim/bundle/command-t/spec/command-t/scanner_spec.rb @@ -0,0 +1,82 @@ +# Copyright 2010 Wincent Colaiuta. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +require File.expand_path('../spec_helper', File.dirname(__FILE__)) +require 'command-t/scanner' + +module VIM; end + +describe CommandT::Scanner do + before do + @dir = File.join(File.dirname(__FILE__), '..', '..', 'fixtures') + @all_fixtures = \ + %w(bar/abc bar/xyz baz bing foo/alpha/t1 foo/alpha/t2 foo/beta) + @scanner = CommandT::Scanner.new @dir + + # scanner will call VIM's expand() function for exclusion filtering + stub(::VIM).evaluate(/expand\(.+\)/) { '0' } + end + + describe 'paths method' do + it 'should return a list of regular files' do + @scanner.paths.should =~ @all_fixtures + end + end + + describe 'flush method' do + it 'should force a rescan on next call to paths method' do + first = @scanner.paths + @scanner.flush + @scanner.paths.object_id.should_not == first.object_id + end + end + + describe 'path= method' do + it 'should allow repeated applications of scanner at different paths' do + @scanner.paths.should =~ @all_fixtures + + # drill down 1 level + @scanner.path = File.join(@dir, 'foo') + @scanner.paths.should =~ %w(alpha/t1 alpha/t2 beta) + + # and another + @scanner.path = File.join(@dir, 'foo', 'alpha') + @scanner.paths.should =~ %w(t1 t2) + end + end + + describe "'wildignore' exclusion" do + it "should call on VIM's expand() function for pattern filtering" do + @scanner = CommandT::Scanner.new @dir + mock(::VIM).evaluate(/expand\(.+\)/).times(10) + @scanner.paths + end + end + + describe ':max_depth option' do + it 'should not descend below "max_depth" levels' do + @scanner = CommandT::Scanner.new @dir, :max_depth => 1 + @scanner.paths.should =~ %w(bar/abc bar/xyz baz bing foo/beta) + end + end +end diff --git a/.vim/bundle/command-t/spec/spec_helper.rb b/.vim/bundle/command-t/spec/spec_helper.rb new file mode 100644 index 0000000..f0831c2 --- /dev/null +++ b/.vim/bundle/command-t/spec/spec_helper.rb @@ -0,0 +1,38 @@ +# Copyright 2010 Wincent Colaiuta. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +if !Object.const_defined?('Bundler') + require 'rubygems' + require 'bundler' + Bundler.setup +end +require 'rspec' + +lib = File.expand_path('../ruby', File.dirname(__FILE__)) +unless $LOAD_PATH.include? lib + $LOAD_PATH.unshift lib +end + +RSpec.configure do |config| + config.mock_framework = :rr +end diff --git a/.vim/bundle/command-t/spec/vim_formatter.rb b/.vim/bundle/command-t/spec/vim_formatter.rb new file mode 100644 index 0000000..6ad902f --- /dev/null +++ b/.vim/bundle/command-t/spec/vim_formatter.rb @@ -0,0 +1,41 @@ +require 'spec/runner/formatter/base_text_formatter' +require 'pathname' + +# Format spec results for display in the Vim quickfix window +# Use this custom formatter like this: +# spec -r spec/vim_formatter.rb -f Spec::Runner::Formatter::VimFormatter spec +module Spec + module Runner + module Formatter + class VimFormatter < BaseTextFormatter + + # TODO: handle pending issues + # TODO: vim-side function for printing progress + def dump_failure counter, failure + path = failure.exception.backtrace.find do |frame| + frame =~ %r{\bspec/.*_spec\.rb:\d+\z} + end + message = failure.exception.message.gsub("\n", ' ') + @output.puts "#{relativize_path(path)}: #{message}" if path + end + + def dump_pending; end + + def dump_summary duration, example_count, failure_count, pending_count + end + + private + + def relativize_path path + @wd ||= Pathname.new Dir.getwd + begin + return Pathname.new(path).relative_path_from(@wd) + rescue ArgumentError + # raised unless both paths relative, or both absolute + return path + end + end + end # class VimFormatter + end # module Formatter + end # module Runner +end # module Spec diff --git a/.vim/bundle/nerdcommenter/.gitignore b/.vim/bundle/nerdcommenter/.gitignore new file mode 100644 index 0000000..3698c0e --- /dev/null +++ b/.vim/bundle/nerdcommenter/.gitignore @@ -0,0 +1,3 @@ +*~ +*.swp +tags diff --git a/.vim/bundle/nerdcommenter/Rakefile b/.vim/bundle/nerdcommenter/Rakefile new file mode 100644 index 0000000..c7bf9e6 --- /dev/null +++ b/.vim/bundle/nerdcommenter/Rakefile @@ -0,0 +1,76 @@ +# written by travis jeffery +# contributions by scrooloose + +require 'rake' +require 'find' +require 'pathname' + +IGNORE = [/\.gitignore$/, /Rakefile$/] + +files = `git ls-files`.split("\n") +files.reject! { |f| IGNORE.any? { |re| f.match(re) } } + +desc 'Zip up the project files' +task :zip do + zip_name = File.basename(File.dirname(__FILE__)) + zip_name.gsub!(/ /, '_') + zip_name = "#{zip_name}.zip" + + if File.exist?(zip_name) + abort("Zip file #{zip_name} already exists. Remove it first.") + end + + puts "Creating zip file: #{zip_name}" + system("zip #{zip_name} #{files.join(" ")}") +end + +desc 'Install plugin and documentation' +task :install do + vimfiles = if ENV['VIMFILES'] + ENV['VIMFILES'] + elsif RUBY_PLATFORM =~ /(win|w)32$/ + File.expand_path("~/vimfiles") + else + File.expand_path("~/.vim") + end + files.each do |file| + target_file = File.join(vimfiles, file) + FileUtils.mkdir_p File.dirname(target_file) + FileUtils.cp file, target_file + + puts "Installed #{file} to #{target_file}" + end + +end + +desc 'Pulls from origin' +task :pull do + puts "Updating local repo..." + system("cd " << Dir.new(File.dirname(__FILE__)).path << " && git pull") +end + +desc 'Calls pull task and then install task' +task :update => ['pull', 'install'] do + puts "Update of vim script complete." +end + +desc 'Uninstall plugin and documentation' +task :uninstall do + vimfiles = if ENV['VIMFILES'] + ENV['VIMFILES'] + elsif RUBY_PLATFORM =~ /(win|w)32$/ + File.expand_path("~/vimfiles") + else + File.expand_path("~/.vim") + end + files.each do |file| + target_file = File.join(vimfiles, file) + FileUtils.rm target_file + + puts "Uninstalled #{target_file}" + end + +end + +task :default => ['update'] + diff --git a/.vim/bundle/nerdcommenter/doc/NERD_commenter.txt b/.vim/bundle/nerdcommenter/doc/NERD_commenter.txt new file mode 100644 index 0000000..d7493b1 --- /dev/null +++ b/.vim/bundle/nerdcommenter/doc/NERD_commenter.txt @@ -0,0 +1,979 @@ +*NERD_commenter.txt* Plugin for commenting code + + + NERD COMMENTER REFERENCE MANUAL~ + + + + + +============================================================================== +CONTENTS *NERDCommenterContents* + + 1.Intro...................................|NERDCommenter| + 2.Installation............................|NERDComInstallation| + 3.Functionality provided..................|NERDComFunctionality| + 3.1 Functionality Summary.............|NERDComFunctionalitySummary| + 3.2 Functionality Details.............|NERDComFunctionalityDetails| + 3.2.1 Comment map.................|NERDComComment| + 3.2.2 Nested comment map..........|NERDComNestedComment| + 3.2.3 Toggle comment map..........|NERDComToggleComment| + 3.2.4 Minimal comment map.........|NERDComMinimalComment| + 3.2.5 Invert comment map..........|NERDComInvertComment| + 3.2.6 Sexy comment map............|NERDComSexyComment| + 3.2.7 Yank comment map............|NERDComYankComment| + 3.2.8 Comment to EOL map..........|NERDComEOLComment| + 3.2.9 Append com to line map......|NERDComAppendComment| + 3.2.10 Insert comment map.........|NERDComInsertComment| + 3.2.11 Use alternate delims map...|NERDComAltDelim| + 3.2.12 Comment aligned maps.......|NERDComAlignedComment| + 3.2.13 Uncomment line map.........|NERDComUncommentLine| + 3.4 Sexy Comments.....................|NERDComSexyComments| + 3.5 The NERDComment function..........|NERDComNERDComment| + 4.Options.................................|NERDComOptions| + 4.1 Options summary...................|NERDComOptionsSummary| + 4.2 Options details...................|NERDComOptionsDetails| + 4.3 Default delimiter Options.........|NERDComDefaultDelims| + 5. Customising key mappings...............|NERDComMappings| + 6. Issues with the script.................|NERDComIssues| + 6.1 Delimiter detection heuristics....|NERDComHeuristics| + 6.2 Nesting issues....................|NERDComNesting| + 7.About.. ............................|NERDComAbout| + 8.Changelog...............................|NERDComChangelog| + 9.Credits.................................|NERDComCredits| + 10.License................................|NERDComLicense| + +============================================================================== +1. Intro *NERDCommenter* + +The NERD commenter provides many different commenting operations and styles +which are invoked via key mappings and a menu. These operations are available +for most filetypes. + +There are also options that allow to tweak the commenting engine to your +taste. + +============================================================================== +2. Installation *NERDComInstallation* + +The NERD Commenter requires Vim 7 or higher. + +Extract the plugin files in your ~/.vim (*nix) or ~/vimfiles (Windows). You +should have 2 files: > + plugin/NERD_commenter.vim + doc/NERD_commenter.txt +< +Next, to finish installing the help file run: > + :helptags ~/.vim/doc +< +See |add-local-help| for more details. + +Make sure that you have filetype plugins enabled, as the script makes use of +|'commentstring'| where possible (which is usually set in a filetype plugin). +See |filetype-plugin-on| for details, but basically, stick this in your vimrc > + filetype plugin on +< + +============================================================================== +3. Functionality provided *NERDComFunctionality* + +------------------------------------------------------------------------------ +3.1 Functionality summary *NERDComFunctionalitySummary* + +The following key mappings are provided by default (there is also a menu +with items corresponding to all the mappings below): + +[count]cc |NERDComComment| +Comment out the current line or text selected in visual mode. + + +[count]cn |NERDComNestedComment| +Same as cc but forces nesting. + + +[count]c |NERDComToggleComment| +Toggles the comment state of the selected line(s). If the topmost selected +line is commented, all selected lines are uncommented and vice versa. + + +[count]cm |NERDComMinimalComment| +Comments the given lines using only one set of multipart delimiters. + + +[count]ci |NERDComInvertComment| +Toggles the comment state of the selected line(s) individually. + + +[count]cs |NERDComSexyComment| +Comments out the selected lines ``sexily'' + + +[count]cy |NERDComYankComment| +Same as cc except that the commented line(s) are yanked first. + + +c$ |NERDComEOLComment| +Comments the current line from the cursor to the end of line. + + +cA |NERDComAppendComment| +Adds comment delimiters to the end of line and goes into insert mode between +them. + + +|NERDComInsertComment| +Adds comment delimiters at the current cursor position and inserts between. +Disabled by default. + + +ca |NERDComAltDelim| +Switches to the alternative set of delimiters. + + +[count]cl +[count]cb |NERDComAlignedComment| +Same as |NERDComComment| except that the delimiters are aligned down the +left side (cl) or both sides (cb). + + +[count]cu |NERDComUncommentLine| +Uncomments the selected line(s). + +------------------------------------------------------------------------------ +3.2 Functionality details *NERDComFunctionalityDetails* + +------------------------------------------------------------------------------ +3.2.1 Comment map *NERDComComment* + +Default mapping: [count]cc +Mapped to: NERDCommenterComment +Applicable modes: normal visual visual-line visual-block. + + +Comments out the current line. If multiple lines are selected in visual-line +mode, they are all commented out. If some text is selected in visual or +visual-block mode then the script will try to comment out the exact text that +is selected using multi-part delimiters if they are available. + +If a [count] is given in normal mode, the mapping works as though that many +lines were selected in visual-line mode. + +------------------------------------------------------------------------------ +3.2.2 Nested comment map *NERDComNestedComment* + +Default mapping: [count]cn +Mapped to: NERDCommenterNest +Applicable modes: normal visual visual-line visual-block. + +Performs nested commenting. Works the same as cc except that if a line +is already commented then it will be commented again. + +If |'NERDUsePlaceHolders'| is set then the previous comment delimiters will +be replaced by place-holder delimiters if needed. Otherwise the nested +comment will only be added if the current commenting delimiters have no right +delimiter (to avoid syntax errors) + +If a [count] is given in normal mode, the mapping works as though that many +lines were selected in visual-line mode. + +Related options: +|'NERDDefaultNesting'| + +------------------------------------------------------------------------------ +3.2.3 Toggle comment map *NERDComToggleComment* + +Default mapping: [count]c +Mapped to: NERDCommenterToggle +Applicable modes: normal visual-line. + +Toggles commenting of the lines selected. The behaviour of this mapping +depends on whether the first line selected is commented or not. If so, all +selected lines are uncommented and vice versa. + +With this mapping, a line is only considered to be commented if it starts with +a left delimiter. + +If a [count] is given in normal mode, the mapping works as though that many +lines were selected in visual-line mode. + +------------------------------------------------------------------------------ +3.2.4 Minimal comment map *NERDComMinimalComment* + +Default mapping: [count]cm +Mapped to: NERDCommenterMinimal +Applicable modes: normal visual-line. + +Comments the selected lines using one set of multipart delimiters if possible. + +For example: if you are programming in c and you select 5 lines and press +cm then a '/*' will be placed at the start of the top line and a '*/' +will be placed at the end of the last line. + +Sets of multipart comment delimiters that are between the top and bottom +selected lines are replaced with place holders (see |'NERDLPlace'|) if +|'NERDUsePlaceHolders'| is set for the current filetype. If it is not, then +the comment will be aborted if place holders are required to prevent illegal +syntax. + +If a [count] is given in normal mode, the mapping works as though that many +lines were selected in visual-line mode. + +------------------------------------------------------------------------------ +3.2.5 Invert comment map *NERDComInvertComment* + +Default mapping: ci +Mapped to: NERDCommenterInvert +Applicable modes: normal visual-line. + +Inverts the commented state of each selected line. If the a selected line is +commented then it is uncommented and vice versa. Each line is examined and +commented/uncommented individually. + +With this mapping, a line is only considered to be commented if it starts with +a left delimiter. + +If a [count] is given in normal mode, the mapping works as though that many +lines were selected in visual-line mode. + +------------------------------------------------------------------------------ +3.2.6 Sexy comment map *NERDComSexyComment* + +Default mapping: [count]cs +Mapped to: NERDCommenterSexy +Applicable modes: normal, visual-line. + +Comments the selected line(s) ``sexily''... see |NERDComSexyComments| for +a description of what sexy comments are. Can only be done on filetypes for +which there is at least one set of multipart comment delimiters specified. + +Sexy comments cannot be nested and lines inside a sexy comment cannot be +commented again. + +If a [count] is given in normal mode, the mapping works as though that many +lines were selected in visual-line mode. + +Related options: +|'NERDCompactSexyComs'| + +------------------------------------------------------------------------------ +3.2.7 Yank comment map *NERDComYankComment* + +Default mapping: [count]cy +Mapped to: NERDCommenterYank +Applicable modes: normal visual visual-line visual-block. + +Same as cc except that it yanks the line(s) that are commented first. + +------------------------------------------------------------------------------ +3.2.8 Comment to EOL map *NERDComEOLComment* + +Default mapping: c$ +Mapped to: NERDCommenterToEOL +Applicable modes: normal. + +Comments the current line from the current cursor position up to the end of +the line. + +------------------------------------------------------------------------------ +3.2.9 Append com to line map *NERDComAppendComment* + +Default mapping: cA +Mapped to: NERDCommenterAppend +Applicable modes: normal. + +Appends comment delimiters to the end of the current line and goes +to insert mode between the new delimiters. + +------------------------------------------------------------------------------ +3.2.10 Insert comment map *NERDComInsertComment* + +Default mapping: disabled by default. +Map it to: NERDCommenterInInsert +Applicable modes: insert. + +Adds comment delimiters at the current cursor position and inserts +between them. + +NOTE: prior to version 2.1.17 this was mapped to ctrl-c. To restore this +mapping add > + let NERDComInsertMap='' +< +to your vimrc. + +------------------------------------------------------------------------------ +3.2.11 Use alternate delims map *NERDComAltDelim* + +Default mapping: ca +Mapped to: NERDCommenterAltDelims +Applicable modes: normal. + +Changes to the alternative commenting style if one is available. For example, +if the user is editing a c++ file using // comments and they hit ca +then they will be switched over to /**/ comments. + +See also |NERDComDefaultDelims| + +------------------------------------------------------------------------------ +3.2.12 Comment aligned maps *NERDComAlignedComment* + +Default mappings: [count]cl [count]cb +Mapped to: NERDCommenterAlignLeft + NERDCommenterAlignBoth +Applicable modes: normal visual-line. + +Same as cc except that the comment delimiters are aligned on the left +side or both sides respectively. These comments are always nested if the +line(s) are already commented. + +If a [count] is given in normal mode, the mapping works as though that many +lines were selected in visual-line mode. + +------------------------------------------------------------------------------ +3.2.13 Uncomment line map *NERDComUncommentLine* + +Default mapping: [count]cu +Mapped to: NERDCommenterUncomment +Applicable modes: normal visual visual-line visual-block. + +Uncomments the current line. If multiple lines are selected in +visual mode then they are all uncommented. + +When uncommenting, if the line contains multiple sets of delimiters then the +``outtermost'' pair of delimiters will be removed. + +The script uses a set of heurisics to distinguish ``real'' delimiters from +``fake'' ones when uncommenting. See |NERDComIssues| for details. + +If a [count] is given in normal mode, the mapping works as though that many +lines were selected in visual-line mode. + +Related options: +|'NERDRemoveAltComs'| +|'NERDRemoveExtraSpaces'| + +------------------------------------------------------------------------------ +3.3 Sexy Comments *NERDComSexyComments* +These are comments that use one set of multipart comment delimiters as well as +one other marker symbol. For example: > + /* + * This is a c style sexy comment + * So there! + */ + + /* This is a c style sexy comment + * So there! + * But this one is ``compact'' style */ +< +Here the multipart delimiters are /* and */ and the marker is *. + +------------------------------------------------------------------------------ +3.4 The NERDComment function *NERDComNERDComment* + +All of the NERD commenter mappings and menu items invoke a single function +which delegates the commenting work to other functions. This function is +public and has the prototype: > + function! NERDComment(isVisual, type) +< +The arguments to this function are simple: + - isVisual: if you wish to do any kind of visual comment then set this to + 1 and the function will use the '< and '> marks to find the comment + boundries. If set to 0 then the function will operate on the current + line. + - type: is used to specify what type of commenting operation is to be + performed, and it can be one of the following: "sexy", "invert", + "minimal", "toggle", "alignLeft", "alignBoth", "norm", "nested", + "toEOL", "append", "insert", "uncomment", "yank" + +For example, if you typed > + :call NERDComment(1, 'sexy') +< +then the script would do a sexy comment on the last visual selection. + + +============================================================================== +4. Options *NERDComOptions* + +------------------------------------------------------------------------------ +4.1 Options summary *NERDComOptionsSummary* + +|'loaded_nerd_comments'| Turns off the script. +|'NERDAllowAnyVisualDelims'| Allows multipart alternative delims to + be used when commenting in + visual/visual-block mode. +|'NERDBlockComIgnoreEmpty'| Forces right delims to be placed when + doing visual-block comments. +|'NERDCommentWholeLinesInVMode'| Changes behaviour of visual comments. +|'NERDCreateDefaultMappings'| Turn the default mappings on/off. +|'NERDDefaultNesting'| Tells the script to use nested comments + by default. +|'NERDMenuMode'| Specifies how the NERD commenter menu + will appear (if at all). +|'NERDLPlace'| Specifies what to use as the left + delimiter placeholder when nesting + comments. +|'NERDUsePlaceHolders'| Specifies which filetypes may use + placeholders when nesting comments. +|'NERDRemoveAltComs'| Tells the script whether to remove + alternative comment delimiters when + uncommenting. +|'NERDRemoveExtraSpaces'| Tells the script to always remove the + extra spaces when uncommenting + (regardless of whether NERDSpaceDelims + is set) +|'NERDRPlace'| Specifies what to use as the right + delimiter placeholder when nesting + comments. +|'NERDSpaceDelims'| Specifies whether to add extra spaces + around delimiters when commenting, and + whether to remove them when + uncommenting. +|'NERDCompactSexyComs'| Specifies whether to use the compact + style sexy comments. + +------------------------------------------------------------------------------ +4.3 Options details *NERDComOptionsDetails* + +To enable any of the below options you should put the given line in your +~/.vimrc + + *'loaded_nerd_comments'* +If this script is driving you insane you can turn it off by setting this +option > + let loaded_nerd_comments=1 +< +------------------------------------------------------------------------------ + *'NERDAllowAnyVisualDelims'* +Values: 0 or 1. +Default: 1. + +If set to 1 then, when doing a visual or visual-block comment (but not a +visual-line comment), the script will choose the right delimiters to use for +the comment. This means either using the current delimiters if they are +multipart or using the alternative delimiters if THEY are multipart. For +example if we are editing the following java code: > + float foo = 1221; + float bar = 324; + System.out.println(foo * bar); +< +If we are using // comments and select the "foo" and "bar" in visual-block +mode, as shown left below (where '|'s are used to represent the visual-block +boundary), and comment it then the script will use the alternative delims as +shown on the right: > + + float |foo| = 1221; float /*foo*/ = 1221; + float |bar| = 324; float /*bar*/ = 324; + System.out.println(foo * bar); System.out.println(foo * bar); +< +------------------------------------------------------------------------------ + *'NERDBlockComIgnoreEmpty'* +Values: 0 or 1. +Default: 1. + +This option affects visual-block mode commenting. If this option is turned +on, lines that begin outside the right boundary of the selection block will be +ignored. + +For example, if you are commenting this chunk of c code in visual-block mode +(where the '|'s are used to represent the visual-block boundary) > + #include + #include + #include + |int| main(){ + | | printf("SUCK THIS\n"); + | | while(1){ + | | fork(); + | | } + |} | +< +If NERDBlockComIgnoreEmpty=0 then this code will become: > + #include + #include + #include + /*int*/ main(){ + /* */ printf("SUCK THIS\n"); + /* */ while(1){ + /* */ fork(); + /* */ } + /*} */ +< +Otherwise, the code block would become: > + #include + #include + #include + /*int*/ main(){ + printf("SUCK THIS\n"); + while(1){ + fork(); + } + /*} */ +< +------------------------------------------------------------------------------ + *'NERDCommentWholeLinesInVMode'* +Values: 0, 1 or 2. +Default: 0. + +By default the script tries to comment out exactly what is selected in visual +mode (v). For example if you select and comment the following c code (using | +to represent the visual boundary): > + in|t foo = 3; + int bar =| 9; + int baz = foo + bar; +< +This will result in: > + in/*t foo = 3;*/ + /*int bar =*/ 9; + int baz = foo + bar; +< +But some people prefer it if the whole lines are commented like: > + /*int foo = 3;*/ + /*int bar = 9;*/ + int baz = foo + bar; +< +If you prefer the second option then stick this line in your vimrc: > + let NERDCommentWholeLinesInVMode=1 +< + +If the filetype you are editing only has no multipart delimiters (for example +a shell script) and you hadnt set this option then the above would become > + in#t foo = 3; + #int bar = 9; +< +(where # is the comment delimiter) as this is the closest the script can +come to commenting out exactly what was selected. If you prefer for whole +lines to be commented out when there is no multipart delimiters but the EXACT +text that was selected to be commented out if there IS multipart delimiters +then stick the following line in your vimrc: > + let NERDCommentWholeLinesInVMode=2 +< + +Note that this option does not affect the behaviour of commenting in +|visual-block| mode. + +------------------------------------------------------------------------------ + *'NERDCreateDefaultMappings'* +Values: 0 or 1. +Default: 1. + +If set to 0, none of the default mappings will be created. + +See also |NERDComMappings|. + +------------------------------------------------------------------------------ + *'NERDRemoveAltComs'* +Values: 0 or 1. +Default: 1. + +When uncommenting a line (for a filetype with an alternative commenting style) +this option tells the script whether to look for, and remove, comment +delimiters of the alternative style. + +For example, if you are editing a c++ file using // style comments and you go +cu on this line: > + /* This is a c++ comment baby! */ +< +It will not be uncommented if the NERDRemoveAltComs is set to 0. + +------------------------------------------------------------------------------ + *'NERDRemoveExtraSpaces'* +Values: 0 or 1. +Default: 1. + +By default, the NERD commenter will remove spaces around comment delimiters if +either: +1. |'NERDSpaceDelims'| is set to 1. +2. NERDRemoveExtraSpaces is set to 1. + +This means that if we have the following lines in a c code file: > + /* int foo = 5; */ + /* int bar = 10; */ + int baz = foo + bar +< +If either of the above conditions hold then if these lines are uncommented +they will become: > + int foo = 5; + int bar = 10; + int baz = foo + bar +< +Otherwise they would become: > + int foo = 5; + int bar = 10; + int baz = foo + bar +< +If you want the spaces to be removed only if |'NERDSpaceDelims'| is set then +set NERDRemoveExtraSpaces to 0. + +------------------------------------------------------------------------------ + *'NERDLPlace'* + *'NERDRPlace'* +Values: arbitrary string. +Default: + NERDLPlace: "[>" + NERDRPlace: "<]" + +These options are used to control the strings used as place-holder delimiters. +Place holder delimiters are used when performing nested commenting when the +filetype supports commenting styles with both left and right delimiters. +To set these options use lines like: > + let NERDLPlace="FOO" + let NERDRPlace="BAR" +< +Following the above example, if we have line of c code: > + /* int horse */ +< +and we comment it with cn it will be changed to: > + /*FOO int horse BAR*/ +< +When we uncomment this line it will go back to what it was. + +------------------------------------------------------------------------------ + *'NERDMenuMode'* +Values: 0, 1, 2, 3. +Default: 3 + +This option can take 4 values: + "0": Turns the menu off. + "1": Turns the 'comment' menu on with no menu shortcut. + "2": Turns the 'comment 'menu on with -c as the shortcut. + "3": Turns the 'Plugin -> comment' menu on with -c as the shortcut. + +------------------------------------------------------------------------------ + *'NERDUsePlaceHolders'* +Values: 0 or 1. +Default 1. + +This option is used to specify whether place-holder delimiters should be used +when creating a nested comment. + +------------------------------------------------------------------------------ + *'NERDSpaceDelims'* +Values: 0 or 1. +Default 0. + +Some people prefer a space after the left delimiter and before the right +delimiter like this: > + /* int foo=2; */ +< +as opposed to this: > + /*int foo=2;*/ +< +If you want spaces to be added then set NERDSpaceDelims to 1 in your vimrc. + +See also |'NERDRemoveExtraSpaces'|. + +------------------------------------------------------------------------------ + *'NERDCompactSexyComs'* +Values: 0 or 1. +Default 0. + +Some people may want their sexy comments to be like this: > + /* Hi There! + * This is a sexy comment + * in c */ +< +As opposed to like this: > + /* + * Hi There! + * This is a sexy comment + * in c + */ +< +If this option is set to 1 then the top style will be used. + +------------------------------------------------------------------------------ + *'NERDDefaultNesting'* +Values: 0 or 1. +Default 1. + +When this option is set to 1, comments are nested automatically. That is, if +you hit cc on a line that is already commented it will be commented +again. + +------------------------------------------------------------------------------ +3.3 Default delimiter customisation *NERDComDefaultDelims* + +If you want the NERD commenter to use the alternative delimiters for a +specific filetype by default then put a line of this form into your vimrc: > + let NERD__alt_style=1 +< +Example: java uses // style comments by default, but you want it to default to +/* */ style comments instead. You would put this line in your vimrc: > + let NERD_java_alt_style=1 +< + +See |NERDComAltDelim| for switching commenting styles at runtime. + +============================================================================== +5. Key mapping customisation *NERDComMappings* + +To change a mapping just map another key combo to the internal mapping. +For example, to remap the |NERDComComment| mapping to ",omg" you would put +this line in your vimrc: > + map ,omg NERDCommenterComment +< +This will stop the corresponding default mappings from being created. + +See the help for the mapping in question to see which mapping to +map to. + +See also |'NERDCreateDefaultMappings'|. + +============================================================================== +6. Issues with the script *NERDComIssues* + + +------------------------------------------------------------------------------ +6.1 Delimiter detection heuristics *NERDComHeuristics* + +Heuristics are used to distinguish the real comment delimiters + +Because we have comment mappings that place delimiters in the middle of lines, +removing comment delimiters is a bit tricky. This is because if comment +delimiters appear in a line doesnt mean they really ARE delimiters. For +example, Java uses // comments but the line > + System.out.println("//"); +< +clearly contains no real comment delimiters. + +To distinguish between ``real'' comment delimiters and ``fake'' ones we use a +set of heuristics. For example, one such heuristic states that any comment +delimiter that has an odd number of non-escaped " characters both preceding +and following it on the line is not a comment because it is probably part of a +string. These heuristics, while usually pretty accurate, will not work for all +cases. + +------------------------------------------------------------------------------ +6.2 Nesting issues *NERDComNesting* + +If we have some line of code like this: > + /*int foo */ = /*5 + 9;*/ +< +This will not be uncommented legally. The NERD commenter will remove the +"outter most" delimiters so the line will become: > + int foo */ = /*5 + 9; +< +which almost certainly will not be what you want. Nested sets of comments will +uncomment fine though. Eg: > + /*int/* foo =*/ 5 + 9;*/ +< +will become: > + int/* foo =*/ 5 + 9; +< +(Note that in the above examples I have deliberately not used place holders +for simplicity) + +============================================================================== +7. About *NERDComAbout* + +The author of the NERD commenter is Martyzillatron --- the half robot, half +dinosaur bastard son of Megatron and Godzilla. He enjoys destroying +metropolises and eating tourist busses. + +Drop him a line at martin_grenfell at msn.com. He would love to hear from you. +its a lonely life being the worlds premier terror machine. How would you feel +if your face looked like a toaster and a t-rex put together? :( + +The latest stable versions can be found at + http://www.vim.org/scripts/script.php?script_id=1218 + +The latest dev versions are on github + http://github.com/scrooloose/nerdcommenter + +============================================================================== +8. Changelog *NERDComChangelog* + +2.2.2 + - remove the NERDShutup option and the message is suppresses, this makes + the plugin silently rely on &commentstring for unknown filetypes. + - add support for dhcpd, limits, ntp, resolv, rgb, sysctl, udevconf and + udevrules. Thanks to Thilo Six. + - match filetypes case insensitively + - add support for mp (metapost), thanks to Andrey Skvortsov. + - add support for htmlcheetah, thanks to Simon Hengel. + - add support for javacc, thanks to Matt Tolton. + - make <%# %> the default delims for eruby, thanks to tpope. + - add support for javascript.jquery, thanks to Ivan Devat. + - add support for cucumber and pdf. Fix sass and railslog delims, + thanks to tpope + +2.2.1 + - add support for newlisp and clojure, thanks to Matthew Lee Hinman. + - fix automake comments, thanks to Elias Pipping + - make haml comments default to -# with / as the alternative delimiter, + thanks to tpope + - add support for actionscript and processing thanks to Edwin Benavides + - add support for ps1 (powershell), thanks to Jason Mills + - add support for hostsaccess, thanks to Thomas Rowe + - add support for CVScommit + - add support for asciidoc, git and gitrebase. Thanks to Simon Ruderich. + - use # for gitcommit comments, thanks to Simon Ruderich. + - add support for mako and genshi, thanks to Keitheis. + - add support for conkyrc, thanks to David + - add support for SVNannotate, thanks to Miguel Jaque Barbero. + - add support for sieve, thanks to Stefan Walk + - add support for objj, thanks to Adam Thorsen. + +2.2.0 + - rewrote the mappings system to be more "standard". + - removed all the mapping options. Now, mappings to mappings are + used + - see :help NERDComMappings, and :help NERDCreateDefaultMappings for + more info + - remove "prepend comments" and "right aligned comments". + - add support for applescript, calbire, man, SVNcommit, potwiki, txt2tags and SVNinfo. + Thanks to nicothakis, timberke, sgronblo, mntnoe, Bernhard Grotz, John + O'Shea, François and Giacomo Mariani respectively. + - bugfix for haskell delimiters. Thanks to mntnoe. +2.1.18 + - add support for llvm. Thanks to nicothakis. + - add support for xquery. Thanks to Phillip Kovalev. +2.1.17 + - fixed haskell delimiters (hackily). Thanks to Elias Pipping. + - add support for mailcap. Thanks to Pascal Brueckner. + - add support for stata. Thanks to Jerónimo Carballo. + - applied a patch from ewfalor to fix an error in the help file with the + NERDMapleader doc + - disable the insert mode ctrl-c mapping by default, see :help + NERDComInsertComment if you wish to restore it + +============================================================================== +9. Credits *NERDComCredits* + +Thanks to the follow people for suggestions and patches: + +Nick Brettell +Matthew Hawkins +Mathieu Clabaut +Greg Searle +Nguyen +Litchi +Jorge Scandaliaris +Shufeng Zheng +Martin Stubenschrott +Markus Erlmann +Brent Rice +Richard Willis +Igor Prischepoff +Harry +David Bourgeois +Eike Von Seggern +Torsten Blix +Alexander Bosecke +Stefano Zacchiroli +Norick Chen +Joseph Barker +Gary Church +Tim Carey-Smith +Markus Klinik +Anders +Seth Mason +James Hales +Heptite +Cheng Fang +Yongwei Wu +David Miani +Jeremy Hinegardner +Marco +Ingo Karkat +Zhang Shuhan +tpope +Ben Schmidt +David Fishburn +Erik Falor +JaGoTerr +Elias Pipping +mntnoe +Mark S. + + +Thanks to the following people for sending me new filetypes to support: + +The hackers The filetypes~ +Sam R verilog +Jonathan Derque context, plaintext and mail +Vigil fetchmail +Michael Brunner kconfig +Antono Vasiljev netdict +Melissa Reid omlet +Ilia N Ternovich quickfix +John O'Shea RTF, SVNcommitlog and vcscommit, SVNCommit +Anders occam +Mark Woodward csv +fREW gentoo-package-mask, + gentoo-package-keywords, + gentoo-package-use, and vo_base +Alexey verilog_systemverilog, systemverilog +Lizendir fstab +Michael Böhler autoit, autohotkey and docbk +Aaron Small cmake +Ramiro htmldjango and django +Stefano Zacchiroli debcontrol, debchangelog, mkd +Alex Tarkovsky ebuild and eclass +Jorge Rodrigues gams +Rainer Müller Objective C +Jason Mills Groovy, ps1 +Normandie Azucena vera +Florian Apolloner ldif +David Fishburn lookupfile +Niels Aan de Brugh rst +Don Hatlestad ahk +Christophe Benz Desktop and xsd +Eyolf Østrem lilypond, bbx and lytex +Ingo Karkat dosbatch +Nicolas Weber markdown, objcpp +tinoucas gentoo-conf-d +Greg Weber D, haml +Bruce Sherrod velocity +timberke cobol, calibre +Aaron Schaefer factor +Mr X asterisk, mplayerconf +Kuchma Michael plsql +Brett Warneke spectre +Pipp lhaskell +Renald Buter scala +Vladimir Lomov asymptote +Marco mrxvtrc, aap +nicothakis SVNAnnotate, CVSAnnotate, SVKAnnotate, + SVNdiff, gitAnnotate, gitdiff, dtrace + llvm, applescript +Chen Xing Wikipedia +Jacobo Diaz dakota, patran +Li Jin gentoo-env-d, gentoo-init-d, + gentoo-make-conf, grub, modconf, sudoers +SpookeyPeanut rib +Greg Jandl pyrex/cython +Christophe Benz services, gitcommit +A Pontus vimperator +Stromnov slice, bzr +Martin Kustermann pamconf +Indriði Einarsson mason +Chris map +Krzysztof A. Adamski group +Pascal Brueckner mailcap +Jerónimo Carballo stata +Phillip Kovalev xquery +Bernhard Grotz potwiki +sgronblo man +François txt2tags +Giacomo Mariani SVNinfo +Matthew Lee Hinman newlisp, clojure +Elias Pipping automake +Edwin Benavides actionscript, processing +Thomas Rowe hostsaccess +Simon Ruderich asciidoc, git, gitcommit, gitrebase +Keitheis mako, genshi +David conkyrc +Miguel Jaque Barbero SVNannotate +Stefan Walk sieve +Adam Thorsen objj +Thilo Six dhcpd, limits, ntp, resolv, rgb, sysctl, + udevconf, udevrules +Andrey Skvortsov mp +Simon Hengel htmlcheetah +Matt Tolton javacc +Ivan Devat javascript.jquery +tpope cucumber,pdf +============================================================================== +10. License *NERDComLicense* + +The NERD commenter is released under the wtfpl. +See http://sam.zoy.org/wtfpl/COPYING. diff --git a/.vim/bundle/nerdcommenter/plugin/NERD_commenter.vim b/.vim/bundle/nerdcommenter/plugin/NERD_commenter.vim new file mode 100644 index 0000000..c61524b --- /dev/null +++ b/.vim/bundle/nerdcommenter/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: 30th March, 2008 +" 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: Placeoholders 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 = bottomBound - (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/bundle/sparkup/.gitignore b/.vim/bundle/sparkup/.gitignore new file mode 100644 index 0000000..2626505 --- /dev/null +++ b/.vim/bundle/sparkup/.gitignore @@ -0,0 +1,14 @@ +.DS_Store +.project +doc +distribution/ +.sourcescribe_index +*.swp +*.swo +*.pyc +cscope.out +*~ + +# Distribution files +# */sparkup +# */sparkup.py diff --git a/.vim/bundle/sparkup/Makefile b/.vim/bundle/sparkup/Makefile new file mode 100644 index 0000000..33f64e8 --- /dev/null +++ b/.vim/bundle/sparkup/Makefile @@ -0,0 +1,39 @@ +SPARKUP_PY=sparkup +VERSION=`date '+%Y%m%d'` +README=README.md + +.PHONY: all textmate vim textmate-dist vim-dist plugins plugins-pre generic all-dist +all: plugins + +plugins-pre: + mkdir -p distribution + +plugins: plugins-pre all-dist + +textmate-dist: textmate + cd TextMate && zip -9r ../distribution/sparkup-textmate-${VERSION}.zip . && cd .. + +vim-dist: vim + cd vim && zip -9r ../distribution/sparkup-vim-${VERSION}.zip . && cd .. + +generic-dist: generic + cd generic && zip -9r ../distribution/sparkup-generic-${VERSION}.zip . && cd .. + +all-dist: + zip -9r distribution/sparkup-${VERSION}.zip generic vim textmate README.md -x */sparkup-readme.txt + cp distribution/sparkup-${VERSION}.zip distribution/sparkup-latest.zip + +generic: + cat sparkup.py > generic/sparkup + chmod +x generic/sparkup + #cp ${README} generic/sparkup-readme.txt + +textmate: + mkdir -p TextMate/Sparkup.tmbundle/Support + cp ${SPARKUP_PY} TextMate/Sparkup.tmbundle/Support/sparkup.py + #cp ${README} TextMate/sparkup-readme.txt + +vim: + mkdir -p vim/ftplugin/html + cp ${SPARKUP_PY} vim/ftplugin/html/sparkup.py + #cp ${README} vim/sparkup-readme.txt diff --git a/.vim/bundle/sparkup/README.md b/.vim/bundle/sparkup/README.md new file mode 100644 index 0000000..f52a282 --- /dev/null +++ b/.vim/bundle/sparkup/README.md @@ -0,0 +1,130 @@ +Sparkup +======= + +**Sparkup lets you write HTML code faster.** Don't believe us? +[See it in action!](http://www.youtube.com/watch?v=Jw3jipcenKc) + +You can write HTML in a CSS-like syntax, and have Sparkup handle the expansion to full HTML +code. It is meant to help you write long HTML blocks in your text editor by letting you +type less characters than needed. + +Sparkup is written in Python, and requires Python 2.5 or newer (2.5 is preinstalled in +Mac OS X Leopard). Sparkup also offers intregration into common text editors. Support for VIM +and TextMate are currently included. + +A short screencast is available here: +[http://www.youtube.com/watch?v=Jw3jipcenKc](http://www.youtube.com/watch?v=Jw3jipcenKc) + +Usage and installation +---------------------- +You may download Sparkup from Github. [Download the latest version here](http://github.com/rstacruz/sparkup/downloads). + + - **TextMate**: Simply double-click on the `Sparkup.tmbundle` package in Finder. This + will install it automatically. In TextMate, open an HTML file (orset the document type to + HTML) type in something (e.g., `#header > h1`), then press `Ctrl` + `E`. Pressing `Tab` + will cycle through empty elements. + + - **VIM**: See the `vim/README.txt` file for details. + + - **Others/command line use**: You may put `sparkup` in your `$PATH` somewhere. You may then + invoke it by typing `echo "(input here)" | sparkup`, or `sparkup --help` for a list of commands. + +Credits +------- + +Sparkup is written by Rico Sta. Cruz and is released under the MIT license. + +This project is inspired by [Zen Coding](http://code.google.com/p/zen-coding/) of +[Vadim Makeev](http://pepelsbey.net). The Zen HTML syntax is forward-compatible with Sparkup +(anything that Zen HTML can parse, Sparkup can too). + +The following people have contributed code to the project: + + - Guillermo O. Freschi (Tordek @ github) + Bugfixes to the parsing system + + - Eric Van Dewoestine (ervandew @ github) + Improvements to the VIM plugin + +Examples +-------- + +**`div`** expands to: +
+ +**`div#header`** expands to: + + +**`div.align-left#header`** expands to: + + +**`div#header + div#footer`** expands to: + + + +**`#menu > ul`** expands to: + + +**`#menu > h3 + ul`** expands to: + + +**`#header > h1{Welcome to our site}`** expands to: + + +**`a[href=index.html]{Home}`** expands to: + Home + +**`ul > li*3`** expands to: +
    +
  • +
  • +
  • +
+ +**`ul > li.item-$*3`** expands to: +
    +
  • +
  • +
  • +
+ +**`ul > li.item-$*3 > strong`** expands to: +
    +
  • +
  • +
  • +
+ +**`table > tr*2 > td.name + td*3`** expands to: + + + + + + + + + + + + + +
+ +**`#header > ul > li < p{Footer}`** expands to: + + + + diff --git a/.vim/bundle/sparkup/ftplugin/html/sparkup.py b/.vim/bundle/sparkup/ftplugin/html/sparkup.py new file mode 100755 index 0000000..50de2a8 --- /dev/null +++ b/.vim/bundle/sparkup/ftplugin/html/sparkup.py @@ -0,0 +1,1087 @@ +#!/usr/bin/env python +# -*- 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/bundle/sparkup/ftplugin/html/sparkup.vim b/.vim/bundle/sparkup/ftplugin/html/sparkup.vim new file mode 100644 index 0000000..80be270 --- /dev/null +++ b/.vim/bundle/sparkup/ftplugin/html/sparkup.vim @@ -0,0 +1,74 @@ +" 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. + +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/bundle/sparkup/mit-license.txt b/.vim/bundle/sparkup/mit-license.txt new file mode 100644 index 0000000..292d6b2 --- /dev/null +++ b/.vim/bundle/sparkup/mit-license.txt @@ -0,0 +1,22 @@ +Copyright (c) 2009, Rico Sta. Cruz. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/.vim/bundle/sparkup/sparkup b/.vim/bundle/sparkup/sparkup new file mode 100755 index 0000000..50de2a8 --- /dev/null +++ b/.vim/bundle/sparkup/sparkup @@ -0,0 +1,1087 @@ +#!/usr/bin/env python +# -*- 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/bundle/sparkup/sparkup-unittest.py b/.vim/bundle/sparkup/sparkup-unittest.py new file mode 100755 index 0000000..a27b7f7 --- /dev/null +++ b/.vim/bundle/sparkup/sparkup-unittest.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +import sys +import sparkup + +class SparkupTest: + options = { + 'textmate': True, + 'no-last-newline': True, + 'post-tag-guides': True, + } + options = { + 'default': {'textmate': True, 'no-last-newline': True, 'post-tag-guides': True}, + 'guides': {'textmate': True, 'no-last-newline': True, 'post-tag-guides': True, 'start-guide-format': 'Begin %s'} + } + cases = { + 'Simple test': { + 'options': 'default', + 'input': 'div', + 'output': '
$1
$0' + }, + 'Class test': { + 'input': 'div.lol', + 'output': '
$1
$0' + }, + 'ID and class test': { + 'input': 'div.class#id', + 'output': '
$1
$0' + }, + 'ID and class test 2': { + 'input': 'div#id.class', + 'output': '
$1
$0' + }, + 'Attributes test': { + 'input': 'div#id.class[style=color:blue]', + 'output': '
$1
$0' + }, + 'Multiple attributes test': { + 'input': 'div[align=center][style=color:blue][rel=none]', + 'output': '
$1
$0' + }, + 'Multiple class test': { + 'input': 'div.c1.c2.c3', + 'output': '
$1
$0' + }, + 'Shortcut test': { + 'input': 'input:button', + 'output': '$0' + }, + 'Shortcut synonym test': { + 'input': 'button', + 'output': '$0' + }, + 'Child test': { + 'input': 'div>ul>li', + 'output': "
\n
    \n
  • $1
  • \n
\n
$0" + }, + 'Sibling test': { + 'input': 'div#x + ul+ h3.class', + 'output': '
$1
\n
    $2
\n

$3

$0' + }, + 'Child + sibling test': { + 'input': 'div > ul > li + span', + 'output': '
\n
    \n
  • $1
  • \n $2\n
\n
$0' + }, + 'Multiplier test 1': { + 'input': 'ul > li*3', + 'output': '
    \n
  • $1
  • \n
  • $2
  • \n
  • $3
  • \n
$0' + }, + 'Multiplier test 2': { + 'input': 'ul > li.item-$*3', + 'output': '
    \n
  • $1
  • \n
  • $2
  • \n
  • $3
  • \n
$0' + }, + 'Multiplier test 3': { + 'input': 'ul > li.item-$*3 > a', + 'output': '
$0' + }, + 'Ampersand test': { + 'input': 'td > tr.row-$*3 > td.cell-&*2', + 'output': '\n \n $1\n $2\n \n \n $3\n $4\n \n \n $5\n $6\n \n$0' + }, + 'Menu test': { + 'input': 'ul#menu > li*3 > a > span', + 'output': '$0' + }, + 'Back test': { + 'input': 'ul#menu > li*3 > a < < div', + 'output': '\n
$7
$0' + }, + 'Expand test': { + 'input': 'p#menu > table+ + ul', + 'output': '
    $2
\n

$0' + }, + 'Text with dot test': { + 'input': 'p { text.com }', + 'output': '

text.com

$0' + }, + 'Attribute with dot test': { + 'input': 'p [attrib=text.com]', + 'output': '

$1

$0' + }, + # Add: text test, broken test, multi-attribute tests, indentation test, start and end comments test + } + def run(self): + """Run Forrest run!""" + + print "Test results:" + for name, case in self.cases.iteritems(): + try: options_key = case['options'] + except: options_key = 'default' + + try: options = self.options[options_key] + except: options = self.options['default'] + + # Output buffer + r = sparkup.Router() + input = case['input'] + output = r.start(options=options, str=input, ret=True) + del r + + # Did it work? + result = output == case['output'] + if result: result_str = " OK " + else: result_str = "FAIL" + + print " - %-30s [%s]" % (name, result_str) + if not result: + print "= %s" % input.replace("\n", "\n= ") + print "Actual output (condensed):" + print " | '%s'" % output.replace("\n", r"\n").replace('"', '\"') + print "Actual output:" + print " | %s" % output.replace("\n", "\n | ") + print "Expected:" + print " | %s" % case['output'].replace("\n", "\ n| ") + +if __name__ == '__main__': + s = SparkupTest() + s.run() diff --git a/.vim/bundle/sparkup/sparkup.py b/.vim/bundle/sparkup/sparkup.py new file mode 120000 index 0000000..14b201c --- /dev/null +++ b/.vim/bundle/sparkup/sparkup.py @@ -0,0 +1 @@ +sparkup \ No newline at end of file diff --git a/.vim/bundle/sparkup/vim/README.txt b/.vim/bundle/sparkup/vim/README.txt new file mode 100644 index 0000000..b74460f --- /dev/null +++ b/.vim/bundle/sparkup/vim/README.txt @@ -0,0 +1,23 @@ +Installation +------------ + + Copy the contents of vim/ftplugin/ to your ~/.vim/ftplugin directory. + + (Assuming your current dir is sparkup/vim/) + $ cp -R ftplugin ~/.vim/ + +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. diff --git a/.vim/bundle/vim-coffee-script/ftdetect/coffee.vim b/.vim/bundle/vim-coffee-script/ftdetect/coffee.vim new file mode 100644 index 0000000..e1c1314 --- /dev/null +++ b/.vim/bundle/vim-coffee-script/ftdetect/coffee.vim @@ -0,0 +1,7 @@ +" Language: CoffeeScript +" Maintainer: Mick Koch +" URL: http://github.com/kchmck/vim-coffee-script +" License: WTFPL + +autocmd BufNewFile,BufRead *.coffee set filetype=coffee +autocmd BufNewFile,BufRead *Cakefile set filetype=coffee diff --git a/.vim/bundle/vim-coffee-script/ftplugin/coffee.vim b/.vim/bundle/vim-coffee-script/ftplugin/coffee.vim new file mode 100644 index 0000000..4e53c17 --- /dev/null +++ b/.vim/bundle/vim-coffee-script/ftplugin/coffee.vim @@ -0,0 +1,14 @@ +" Language: CoffeeScript +" Maintainer: Mick Koch +" URL: http://github.com/kchmck/vim-coffee-script +" License: WTFPL + +if exists("b:did_ftplugin") + finish +endif + +let b:did_ftplugin = 1 + +setlocal formatoptions-=t formatoptions+=croql +setlocal comments=s:###,m:\ ,e:###,:# +setlocal commentstring=#\ %s diff --git a/.vim/bundle/vim-coffee-script/indent/coffee.vim b/.vim/bundle/vim-coffee-script/indent/coffee.vim new file mode 100644 index 0000000..796ad04 --- /dev/null +++ b/.vim/bundle/vim-coffee-script/indent/coffee.vim @@ -0,0 +1,157 @@ +" Language: CoffeeScript +" Maintainer: Mick Koch +" URL: http://github.com/kchmck/vim-coffee-script +" License: WTFPL + +if exists("b:did_indent") + finish +endif + +let b:did_indent = 1 + +setlocal autoindent +setlocal indentexpr=GetCoffeeIndent(v:lnum) +" Make sure GetCoffeeIndent is run when these are typed so they can be outdented +setlocal indentkeys+=0],0),=else,=when,=catch,=finally + +" Only define the function once +if exists("*GetCoffeeIndent") + finish +endif + +" Join a list of regexps as branches +function! s:RegexpJoin(regexps) + return join(a:regexps, '\|') +endfunction + +" Create a regexp group from a list of regexps +function! s:RegexpGroup(...) + return '\%(' . s:RegexpJoin(a:000) . '\)' +endfunction + +" Outdent certain keywords and brackets +let s:outdent = '^' +\ . s:RegexpGroup('else', 'when', 'catch', 'finally', +\ ']', '}', ')') + +" Indent after certain keywords +let s:indent_after_keywords = '^' +\ . s:RegexpGroup('if', 'unless', 'else', 'for', +\ 'while', 'until', 'loop', 'switch', +\ 'when', 'try', 'catch', 'finally', +\ 'class') +\ . '\>' + +" Indent after brackets, functions, and assignments +let s:indent_after_literals = s:RegexpGroup('\[', '{', '(', '->', '=>', +\ ':', '=') +\ . '$' + +" Combine the two regexps above +let s:indent_after = s:RegexpJoin([s:indent_after_keywords, +\ s:indent_after_literals]) + +" Indent after certain keywords used in multi-line assignments +let s:assignment_keywords = s:RegexpGroup(':', '=') +\ . '\s*\<' +\ . s:RegexpGroup('if', 'unless', 'for', 'while', +\ 'until', 'switch', 'try', 'class') +\ . '\>' + +" Outdent after certain keywords +let s:outdent_after = '^' +\ . s:RegexpGroup('return', 'break', 'continue', 'throw') +\ . '\>' + +" Don't outdent if the line contains one of these keywords (for cases like +" 'return if a is b', 'break unless a', etc.) +let s:dont_outdent_after = '\<' . s:RegexpGroup('if', 'unless') . '\>' + +" Check for a single-line statement (e.g., 'if a then b'), which doesn't need an +" indent afterwards +function! s:IsSingleLineStatement(line) + " The 'then' keyword is usually a good hint + return a:line =~ '\' +endfunction + +" Check for a single-line 'else' statement (e.g., 'else return a' but +" not 'else if a'), which doesn't need an indent afterwards +function! s:IsSingleLineElse(line) + " Check if the line actually starts with 'else', then if the line contains + " anything other than 'else', then finally if the line is actually an 'else' + " statement rather than an 'else if' statement + return a:line =~ '^else\>' && a:line !~ '^else$' && a:line !~ '^else if\>' +endfunction + +" Check if a 'when' statement is the first in a 'switch' block by searching the +" previous line for the 'switch' keyword. The first 'when' shouldn't be +" outdented +function! s:IsFirstWhen(curline, prevline) + return a:curline =~ '^when\>' && a:prevline =~ '\' +endfunction + +" Check for a multi-line assignment like +" a: if b +" c +" else +" d +function! s:IsMultiLineAssignment(line) + return a:line =~ s:assignment_keywords +endfunction + +function! s:ShouldOutdent(curline, prevline) + return !s:IsSingleLineStatement(a:prevline) + \ && !s:IsFirstWhen(a:curline, a:prevline) + \ && a:prevline !~ s:outdent_after + \ && a:curline =~ s:outdent +endfunction + +function! s:ShouldIndentAfter(prevline) + return !s:IsSingleLineStatement(a:prevline) + \ && !s:IsSingleLineElse(a:prevline) + \ && (a:prevline =~ s:indent_after + \ || s:IsMultiLineAssignment(a:prevline)) +endfunction + +function! s:ShouldOutdentAfter(prevline) + return (a:prevline !~ s:dont_outdent_after + \ || s:IsSingleLineStatement(a:prevline)) + \ && a:prevline =~ s:outdent_after +endfunction + +function! GetCoffeeIndent(curlinenum) + " Find a non-blank line above the current line + let prevlinenum = prevnonblank(a:curlinenum - 1) + + " No indenting is needed at the start of a file + if prevlinenum == 0 + return 0 + endif + + let curindent = indent(a:curlinenum) + let previndent = indent(prevlinenum) + + " Strip off leading whitespace + let curline = getline(a:curlinenum)[curindent : -1] + let prevline = getline(prevlinenum)[previndent : -1] + + if s:ShouldOutdent(curline, prevline) + " Is the line already outdented? + if curindent < previndent + return curindent + else + return curindent - &shiftwidth + endif + endif + + if s:ShouldIndentAfter(prevline) + return previndent + &shiftwidth + endif + + if s:ShouldOutdentAfter(prevline) + return previndent - &shiftwidth + endif + + " No indenting or outdenting is needed + return curindent +endfunction diff --git a/.vim/bundle/vim-coffee-script/readme.md b/.vim/bundle/vim-coffee-script/readme.md new file mode 100644 index 0000000..a38224b --- /dev/null +++ b/.vim/bundle/vim-coffee-script/readme.md @@ -0,0 +1,77 @@ +This project adds [CoffeeScript] support to the vim editor. Currently, it +supports [almost][todo] all of CoffeeScript 0.9.2's syntax and indentation style. + +![Screenshot][screenshot] + +[CoffeeScript]: http://coffeescript.org +[todo]: http://github.com/kchmck/vim-coffee-script/blob/master/todo.md +[screenshot]: http://i.imgur.com/xbto8.png + +### Installing and using + +1. Install [pathogen] into `~/.vim/autoload/` and add the following line to your + `~/.vimrc`: + + call pathogen#runtime_append_all_bundles() + + Be aware that it must be added before any `filetype plugin indent on` + lines according to the install page: + + > Note that you need to invoke the pathogen functions before invoking + > "filetype plugin indent on" if you want it to load ftdetect files. On + > Debian (and probably other distros), the system vimrc does this early on, + > so you actually need to "filetype off" before "filetype plugin indent on" + > to force reloading. + +[pathogen]: http://vim.org/scripts/script.php?script_id=2332 + +2. Create, and change into, the `~/.vim/bundle/` directory: + + $ mkdir -p ~/.vim/bundle + $ cd ~/.vim/bundle + +3. Make a clone of the `vim-coffee-script` repository: + + $ git clone git://github.com/kchmck/vim-coffee-script.git + [...] + $ ls + vim-coffee-script/ + +Thatʼs it. Pathogen should handle the rest. Opening a file with a `.coffee` +extension or a `Cakefile` will load all the CoffeeScript stuff. + +### Updating + +1. Change into the `~/.vim/bundle/vim-coffee-script/` directory: + + $ cd ~/.vim/bundle/vim-coffee-script + +2. Pull in the latest changes: + + $ git pull + +Everything will then be brought up to date! + +### Customizing + +Some of the possibly unwanted syntax highlighting elements can be disabled +in the following ways. + +#### Disable trailing whitespace error highlighting + +If having trailing whitespace highlighted as an error is a bit much, the +following line can be added to your `~/.vimrc` to disable it: + + let coffee_no_trailing_space_error = 1 + +#### Disable trailing semicolon error highlighting + +Likewise for the highlighting of trailing semicolons: + + let coffee_no_trailing_semicolon_error = 1 + +#### Disable future/reserved words error highlighting + +The same for reserved words: + + let coffee_no_reserved_words_error = 1 diff --git a/.vim/bundle/vim-coffee-script/syntax/coffee.vim b/.vim/bundle/vim-coffee-script/syntax/coffee.vim new file mode 100644 index 0000000..ea8606a --- /dev/null +++ b/.vim/bundle/vim-coffee-script/syntax/coffee.vim @@ -0,0 +1,161 @@ +" Language: CoffeeScript +" Maintainer: Mick Koch +" URL: http://github.com/kchmck/vim-coffee-script +" License: WTFPL + +if exists("b:current_syntax") + finish +endif + +if version < 600 + syntax clear +endif + +let b:current_syntax = "coffee" + +syntax sync minlines=100 + +" CoffeeScript allows dollar signs in identifiers +setlocal isident+=$ + +syntax match coffeeStatement /\<\%(return\|break\|continue\|throw\)\>/ +highlight default link coffeeStatement Statement + +syntax match coffeeRepeat /\<\%(for\|while\|until\|loop\)\>/ +highlight default link coffeeRepeat Repeat + +syntax match coffeeConditional /\<\%(if\|else\|unless\|switch\|when\|then\)\>/ +highlight default link coffeeConditional Conditional + +syntax match coffeeException /\<\%(try\|catch\|finally\)\>/ +highlight default link coffeeException Exception + +syntax match coffeeOperator /\<\%(instanceof\|typeof\|delete\)\>/ +highlight default link coffeeOperator Operator + +syntax match coffeeKeyword /\<\%(new\|in\|of\|by\|where\|and\|or\|not\|is\|isnt\|class\|extends\|super\|all\)\>/ +highlight default link coffeeKeyword Keyword + +syntax match coffeeBoolean /\<\%(\%(true\|on\|yes\|false\|off\|no\)\)\>/ +highlight default link coffeeBoolean Boolean + +syntax match coffeeGlobal /\<\%(null\|undefined\)\>/ +highlight default link coffeeGlobal Type + +syntax cluster coffeeReserved contains=coffeeStatement,coffeeRepeat, +\ coffeeConditional,coffeeException, +\ coffeeOperator,coffeeKeyword, +\ coffeeBoolean,coffeeGlobal + +syntax match coffeeAssignmentMod /\%(\s\+\zs\%(and\|or\)\|\W\{,3}\)\ze=/ contained +highlight default link coffeeAssignmentMod SpecialChar + +syntax match coffeeAssignmentChar /:\|=/ contained +highlight default link coffeeAssignmentChar SpecialChar + +syntax match coffeeVar /\<\%(this\|prototype\|arguments\)\>/ +" Matches @-variables like @abc +syntax match coffeeVar /@\%(\I\i*\)\?/ +highlight default link coffeeVar Type + +" Matches class-like names that start with a capital letter, like Array or +" Object +syntax match coffeeObject /\<\u\w*\>/ +highlight default link coffeeObject Structure + +" Matches constant-like names in SCREAMING_CAPS +syntax match coffeeConstant /\<\u[A-Z0-9_]\+\>/ +highlight default link coffeeConstant Constant + +syntax match coffeePrototype /::/ +highlight default link coffeePrototype SpecialChar + +syntax region coffeeString start=/"/ skip=/\\\\\|\\"/ end=/"/ contains=@coffeeInterpString +syntax region coffeeString start=/'/ skip=/\\\\\|\\'/ end=/'/ contains=@coffeeSimpleString +highlight default link coffeeString String + +" What can make up a variable name +syntax cluster coffeeIdentifier contains=coffeeVar,coffeeObject,coffeeConstant, +\ coffeePrototype + +syntax match coffeeAssignment /@\?\I\%(\i\|::\|\.\|\[.\+\]\|([^)]*)\)*\s*\%(::\@!\|\%(and\|or\|\|&&\|||\|?\|+\|-\|\/\|\*\|%\|<<\|>>\|>>>\|&\||\|\^\)==\@!>\@!\)/ +\ contains=@coffeeIdentifier,coffeeAssignmentMod, +\ coffeeAssignmentChar,coffeeBrackets, +\ coffeeParens +syntax match coffeeAssignment /\%("\|'\)[^'"]\+\%("\|'\)\s*:/ contains=coffeeString, +\ coffeeAssignmentChar +syntax match coffeeAssignment /\d*\%(\.\d\+\)\?\s*:/ contains=coffeeNumber,coffeeAssignmentChar +highlight default link coffeeAssignment Identifier + +syntax match coffeeFunction /->\|=>/ +highlight default link coffeeFunction Function + +syntax keyword coffeeTodo TODO FIXME XXX contained +highlight default link coffeeTodo Todo + +syntax match coffeeComment /#.*/ contains=@Spell,coffeeTodo +syntax match coffeeComment /####\@!\_.\{-}###/ contains=@Spell,coffeeTodo +highlight default link coffeeComment Comment + +syntax region coffeeEmbed start=/`/ end=/`/ +highlight default link coffeeEmbed Special + +" Matches numbers like -10, -10e8, -10E8, 10, 10e8, 10E8 +syntax match coffeeNumber /\<-\?\d\+\%([eE][+-]\?\d\+\)\?\>/ +" Matches hex numbers like 0xfff, 0x000 +syntax match coffeeNumber /\<0[xX]\x\+\>/ +highlight default link coffeeNumber Number + +" Matches floating-point numbers like -10.42e8, 10.42e-8 +syntax match coffeeFloat /-\?\d*\.\@ + c + } + └─ bracket should be put here + +- Should indent if the previous line ends, or the current line starts, with one + of these: + + + - * / % | & , . is isnt and or && || + +- Support `else unless` in indentation: + + unless a + b + else unless c + d diff --git a/.vim/filetype.vim b/.vim/filetype.vim index 24c0b9f..e62c4d3 100644 --- a/.vim/filetype.vim +++ b/.vim/filetype.vim @@ -16,6 +16,10 @@ augroup lilypond au! BufNewFile,BufRead *.ly,*.ily setf lilypond augroup END +au BufNewFile,BufRead motd.public,/tmp/motd.public.r.* setf motd + +au Filetype html,xml,xsl source ~/.vim/closetag.vim + au BufRead,BufNewFile *.go set filetype=go "Settings per filetype