Pathogen and new bundles

git-svn-id: http://photonzero.com/dotfiles/trunk@65 23f722f6-122a-0410-8cef-c75bd312dd78
This commit is contained in:
michener 2010-09-21 23:59:55 +00:00
parent 9b767aed56
commit 96a93bce9e
78 changed files with 10717 additions and 0 deletions

139
.vim/autoload/pathogen.vim Normal file
View file

@ -0,0 +1,139 @@
" pathogen.vim - path option manipulation
" Maintainer: Tim Pope <vimNOSPAM@tpope.org>
" 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,'\\\@<!\%(\\\\\)*\zs,')
return map(split,'substitute(v:val,''\\\([\\,]\)'',''\1'',"g")')
endfunction " }}}1
" Convert a list to a path.
function! pathogen#join(...) abort " {{{1
if type(a:1) == type(1) && a:1
let i = 1
let space = ' '
else
let i = 0
let space = ''
endif
let path = ""
while i < a:0
if type(a:000[i]) == type([])
let list = a:000[i]
let j = 0
while j < len(list)
let escaped = substitute(list[j],'[,'.space.']\|\\[\,'.space.']\@=','\\&','g')
let path .= ',' . escaped
let j += 1
endwhile
else
let path .= "," . a:000[i]
endif
let i += 1
endwhile
return substitute(path,'^,','','')
endfunction " }}}1
" Convert a list to a path with escaped spaces for 'path', 'tag', etc.
function! pathogen#legacyjoin(...) abort " {{{1
return call('pathogen#join',[1] + a:000)
endfunction " }}}1
" Remove duplicates from a list.
function! pathogen#uniq(list) abort " {{{1
let i = 0
let seen = {}
while i < len(a:list)
if has_key(seen,a:list[i])
call remove(a:list,i)
else
let seen[a:list[i]] = 1
let i += 1
endif
endwhile
return a:list
endfunction " }}}1
" Returns a hash indicating which filetype features are enabled.
function! pathogen#filetype() abort " {{{1
redir => 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 =~# '\<after$'
let list += pathogen#glob_directories(substitute(dir,'after$',name.sep.'*[^~]'.sep.'after','')) + [dir]
else
let list += [dir] + pathogen#glob_directories(dir.sep.name.sep.'*[^~]')
endif
endfor
let &rtp = pathogen#join(pathogen#uniq(list))
return 1
endfunction
" }}}1
" Invoke :helptags on all non-$VIM doc directories in runtimepath.
function! pathogen#helptags() " {{{1
for dir in pathogen#split(&rtp)
if dir[0 : strlen($VIM)-1] !=# $VIM && isdirectory(dir.'/doc') && (!filereadable(dir.'/doc/tags') || filewritable(dir.'/doc/tags'))
helptags `=dir.'/doc'`
endif
endfor
endfunction " }}}1
" vim:set ft=vim ts=8 sw=2 sts=2:

1
.vim/bundle/ack.vim/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
tags

View file

@ -0,0 +1,80 @@
# ack.vim #
This plugin is a front for the Perl module
[App::Ack](http://search.cpan.org/~petdance/ack/ack). Ack can be used as a
replacement for 99% of the uses of _grep_. This plugin will allow you to run
ack from vim, and shows the results in a split window.
The *Official Version* of this plugin is available at [vim.org](http://www.vim.org/scripts/script.php?script_id=2572).
## Installation ##
### Ack
You have to install [ack](http://search.cpan.org/~petdance/ack/ack), of course.
Install on Debian / Ubuntu with:
sudo apt-get install ack-grep
For Debian / Ubuntu you can add this line into your .vimrc:
let g:ackprg="ack-grep -H --nocolor --nogroup --column"
Install on Gentoo with:
sudo emerge ack
Install with MacPorts:
sudo port install p5-app-ack
Install with Gentoo Prefix
emerge ack
Otherwise, you are on your own.
### The Plugin
If you have [Rake](http://rake.rubyforge.org/) installed, you can just run: `rake install`.
Otherwise, the file ack.vim goes in ~/.vim/plugin, and the ack.txt file belongs in ~/.vim/doc. Be sure to run
:helptags ~/.vim/doc
afterwards.
## Usage ##
:Ack [options] {pattern} [{directory}]
Search recursively in {directory} (which defaults to the current directory) for the {pattern}.
Files containing the search term will be listed in the split window, along with
the line number of the occurrence, once for each occurrence. [Enter] on a line
in this window will open the file, and place the cursor on the matching line.
Just like where you use :grep, :grepadd, :lgrep, and :lgrepadd, you can use `:Ack`, `:AckAdd`, `:LAck`, and `:LAckAdd` respectively. (See `doc/ack.txt`, or install and `:h Ack` for more information.)
**From the [ack docs](http://search.cpan.org/~petdance/ack/ack)** (my favorite feature):
--type=TYPE, --type=noTYPE
Specify the types of files to include or exclude from a search. TYPE is a filetype, like perl or xml. --type=perl can also be specified as --perl, and --type=noperl can be done as --noperl.
If a file is of both type "foo" and "bar", specifying --foo and --nobar will exclude the file, because an exclusion takes precedence over an inclusion.
Type specifications can be repeated and are ORed together.
See ack --help=types for a list of valid types.
This Vim plugin is derived (and by derived, I mean copied, essentially) from
Antoine Imbert's blog post [Ack and Vim
Integration](http://blog.ant0ine.com/2007/03/ack_and_vim_integration.html) (in
particular, the function at the bottom of the post). I added a help file that
provides just enough reference to get you going. I also highly recommend you
check out the docs for the Perl script 'ack', for obvious reasons: [ack -
grep-like text finder](http://search.cpan.org/~petdance/ack/ack).

View file

@ -0,0 +1,23 @@
# Added by Josh Nichols, a.k.a. technicalpickles
require 'rake'
files = ['doc/ack.txt', 'plugin/ack.vim']
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 " Copied #{file} to #{target_file}"
end
end

View file

@ -0,0 +1,50 @@
*ack.txt* Plugin that integrates ack with Vim
==============================================================================
Author: Antoine Imbert <antoine.imbert+ackvim@gmail.com> *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. <Enter> 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.

View file

@ -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 <silent> <buffer> q :ccl<CR>"
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<bang>',<q-args>)
command! -bang -nargs=* -complete=file AckAdd call s:Ack('grepadd<bang>', <q-args>)
command! -bang -nargs=* -complete=file AckFromSearch call s:AckFromSearch('grep<bang>', <q-args>)
command! -bang -nargs=* -complete=file LAck call s:Ack('lgrep<bang>', <q-args>)
command! -bang -nargs=* -complete=file LAckAdd call s:Ack('lgrepadd<bang>', <q-args>)
command! -bang -nargs=* -complete=file AckFile call s:Ack('grep<bang> -g', <q-args>)

View file

@ -0,0 +1,2 @@
---
BUNDLE_BIN: bin

View file

@ -0,0 +1 @@
Sung Pae <sung@metablu.com>

View file

@ -0,0 +1 @@
--colour

View file

@ -0,0 +1,3 @@
gem 'rake'
gem 'rr'
gem 'rspec', '>= 2.0.0.beta.16'

View file

@ -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)

View file

@ -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.

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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]

View file

@ -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')

14
.vim/bundle/command-t/bin/ldiff Executable file
View file

@ -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')

14
.vim/bundle/command-t/bin/rake Executable file
View file

@ -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')

14
.vim/bundle/command-t/bin/rspec Executable file
View file

@ -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')

View file

@ -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

1
.vim/bundle/command-t/doc/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
tags

View file

@ -0,0 +1 @@
../README.txt

View file

@ -0,0 +1 @@
.

View file

@ -0,0 +1 @@
.

View file

@ -0,0 +1 @@
.

View file

@ -0,0 +1 @@
.

View file

@ -0,0 +1 @@
.

View file

@ -0,0 +1 @@
.

View file

@ -0,0 +1 @@
.

View file

@ -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

View file

@ -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 <SID>CommandTShow(<q-args>)
command CommandTFlush call <SID>CommandTFlush()
if !hasmapto('CommandT')
silent! nmap <unique> <silent> <Leader>t :CommandT<CR>
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

View file

@ -0,0 +1,6 @@
Makefile
*.o
*.log
ext.*
!ext.c
!ext.h

View file

@ -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 <silent> <buffer> #{key} " \
":call CommandT#{function}(#{param})<CR>"
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 "<Char-#{b}>", 'HandleKey', b
end
# "special" keys (overridable by settings)
{ 'Backspace' => '<BS>',
'Delete' => '<Del>',
'AcceptSelection' => '<CR>',
'AcceptSelectionSplit' => ['<C-CR>', '<C-s>'],
'AcceptSelectionTab' => '<C-t>',
'AcceptSelectionVSplit' => '<C-v>',
'ToggleFocus' => '<Tab>',
'Cancel' => ['<C-c>', '<Esc>'],
'SelectNext' => ['<C-n>', '<C-j>', '<Down>'],
'SelectPrev' => ['<C-p>', '<C-k>', '<Up>'],
'Clear' => '<C-u>',
'CursorLeft' => ['<Left>', '<C-h>'],
'CursorRight' => ['<Right>', '<C-l>'],
'CursorEnd' => '<C-e>',
'CursorStart' => '<C-a>' }.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 == '<Esc>' && (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

View file

@ -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

View file

@ -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);
}

View file

@ -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 <ruby.h>
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)

View file

@ -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')

View file

@ -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

View file

@ -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");
}

View file

@ -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 <ruby.h>
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);

View file

@ -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

View file

@ -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 <stdlib.h> /* for qsort() */
#include <string.h> /* 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;
}

View file

@ -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 <ruby.h>
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);

View file

@ -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

View file

@ -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 <ruby.h>
// 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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

3
.vim/bundle/nerdcommenter/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
*~
*.swp
tags

View file

@ -0,0 +1,76 @@
# written by travis jeffery <travisjeffery@gmail.com>
# contributions by scrooloose <github: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']

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

14
.vim/bundle/sparkup/.gitignore vendored Normal file
View file

@ -0,0 +1,14 @@
.DS_Store
.project
doc
distribution/
.sourcescribe_index
*.swp
*.swo
*.pyc
cscope.out
*~
# Distribution files
# */sparkup
# */sparkup.py

View file

@ -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

View file

@ -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></div>
**`div#header`** expands to:
<div id="header"></div>
**`div.align-left#header`** expands to:
<div id="header" class="align-left"></div>
**`div#header + div#footer`** expands to:
<div id="header"></div>
<div id="footer"></div>
**`#menu > ul`** expands to:
<div id="menu">
<ul></ul>
</div>
**`#menu > h3 + ul`** expands to:
<div id="menu">
<h3></h3>
<ul></ul>
</div>
**`#header > h1{Welcome to our site}`** expands to:
<div id="header">
<h1>Welcome to our site</h1>
</div>
**`a[href=index.html]{Home}`** expands to:
<a href="index.html">Home</a>
**`ul > li*3`** expands to:
<ul>
<li></li>
<li></li>
<li></li>
</ul>
**`ul > li.item-$*3`** expands to:
<ul>
<li class="item-1"></li>
<li class="item-2"></li>
<li class="item-3"></li>
</ul>
**`ul > li.item-$*3 > strong`** expands to:
<ul>
<li class="item-1"><strong></strong></li>
<li class="item-2"><strong></strong></li>
<li class="item-3"><strong></strong></li>
</ul>
**`table > tr*2 > td.name + td*3`** expands to:
<table>
<tr>
<td class="name"></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td class="name"></td>
<td></td>
<td></td>
<td></td>
</tr>
</table>
**`#header > ul > li < p{Footer}`** expands to:
<!-- The < symbol goes back up the parent; i.e., the opposite of >. -->
<div id="header">
<ul>
<li></li>
</ul>
<p>Footer</p>
</div>

File diff suppressed because it is too large Load diff

View file

@ -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: '<c-e>') -
" Mapping used to execute sparkup.
"
" g:sparkupNextMapping (Default: '<c-n>') -
" Mapping used to jump to the next empty tag/attribute.
if !exists('g:sparkupExecuteMapping')
let g:sparkupExecuteMapping = '<c-e>'
endif
if !exists('g:sparkupNextMapping')
let g:sparkupNextMapping = '<c-n>'
endif
exec 'nmap <buffer> ' . g:sparkupExecuteMapping . ' :call <SID>Sparkup()<cr>'
exec 'imap <buffer> ' . g:sparkupExecuteMapping . ' <c-g>u<Esc>:call <SID>Sparkup()<cr>'
exec 'nmap <buffer> ' . g:sparkupNextMapping . ' :call <SID>SparkupNext()<cr>'
exec 'imap <buffer> ' . g:sparkupNextMapping . ' <c-g>u<Esc>:call <SID>SparkupNext()<cr>'
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

View file

@ -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.

1087
.vim/bundle/sparkup/sparkup Executable file

File diff suppressed because it is too large Load diff

View file

@ -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': '<div>$1</div>$0'
},
'Class test': {
'input': 'div.lol',
'output': '<div class="lol">$1</div><!-- /.lol -->$0'
},
'ID and class test': {
'input': 'div.class#id',
'output': '<div class="class" id="id">$1</div><!-- /#id -->$0'
},
'ID and class test 2': {
'input': 'div#id.class',
'output': '<div class="class" id="id">$1</div><!-- /#id -->$0'
},
'Attributes test': {
'input': 'div#id.class[style=color:blue]',
'output': '<div style="color:blue" class="class" id="id">$1</div><!-- /#id -->$0'
},
'Multiple attributes test': {
'input': 'div[align=center][style=color:blue][rel=none]',
'output': '<div align="center" style="color:blue" rel="none">$1</div>$0'
},
'Multiple class test': {
'input': 'div.c1.c2.c3',
'output': '<div class="c1 c2 c3">$1</div><!-- /.c1.c2.c3 -->$0'
},
'Shortcut test': {
'input': 'input:button',
'output': '<input type="button" class="button" value="$1" name="$2" />$0'
},
'Shortcut synonym test': {
'input': 'button',
'output': '<input type="button" class="button" value="$1" name="$2" />$0'
},
'Child test': {
'input': 'div>ul>li',
'output': "<div>\n <ul>\n <li>$1</li>\n </ul>\n</div>$0"
},
'Sibling test': {
'input': 'div#x + ul+ h3.class',
'output': '<div id="x">$1</div><!-- /#x -->\n<ul>$2</ul>\n<h3 class="class">$3</h3>$0'
},
'Child + sibling test': {
'input': 'div > ul > li + span',
'output': '<div>\n <ul>\n <li>$1</li>\n <span>$2</span>\n </ul>\n</div>$0'
},
'Multiplier test 1': {
'input': 'ul > li*3',
'output': '<ul>\n <li>$1</li>\n <li>$2</li>\n <li>$3</li>\n</ul>$0'
},
'Multiplier test 2': {
'input': 'ul > li.item-$*3',
'output': '<ul>\n <li class="item-1">$1</li>\n <li class="item-2">$2</li>\n <li class="item-3">$3</li>\n</ul>$0'
},
'Multiplier test 3': {
'input': 'ul > li.item-$*3 > a',
'output': '<ul>\n <li class="item-1">\n <a href="$1">$2</a>\n </li>\n <li class="item-2">\n <a href="$3">$4</a>\n </li>\n <li class="item-3">\n <a href="$5">$6</a>\n </li>\n</ul>$0'
},
'Ampersand test': {
'input': 'td > tr.row-$*3 > td.cell-&*2',
'output': '<td>\n <tr class="row-1">\n <td class="cell-1">$1</td>\n <td class="cell-2">$2</td>\n </tr>\n <tr class="row-2">\n <td class="cell-3">$3</td>\n <td class="cell-4">$4</td>\n </tr>\n <tr class="row-3">\n <td class="cell-5">$5</td>\n <td class="cell-6">$6</td>\n </tr>\n</td>$0'
},
'Menu test': {
'input': 'ul#menu > li*3 > a > span',
'output': '<ul id="menu">\n <li>\n <a href="$1">\n <span>$2</span>\n </a>\n </li>\n <li>\n <a href="$3">\n <span>$4</span>\n </a>\n </li>\n <li>\n <a href="$5">\n <span>$6</span>\n </a>\n </li>\n</ul>$0'
},
'Back test': {
'input': 'ul#menu > li*3 > a < < div',
'output': '<ul id="menu">\n <li>\n <a href="$1">$2</a>\n </li>\n <li>\n <a href="$3">$4</a>\n </li>\n <li>\n <a href="$5">$6</a>\n </li>\n</ul>\n<div>$7</div>$0'
},
'Expand test': {
'input': 'p#menu > table+ + ul',
'output': '<p id="menu">\n <table cellspacing="0">\n <tr>\n <td>$1</td>\n </tr>\n </table>\n <ul>$2</ul>\n</p>$0'
},
'Text with dot test': {
'input': 'p { text.com }',
'output': '<p> text.com </p>$0'
},
'Attribute with dot test': {
'input': 'p [attrib=text.com]',
'output': '<p attrib="text.com">$1</p>$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()

View file

@ -0,0 +1 @@
sparkup

View file

@ -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: '<c-e>') -
Mapping used to execute sparkup.
g:sparkupNextMapping (Default: '<c-n>') -
Mapping used to jump to the next empty tag/attribute.

View file

@ -0,0 +1,7 @@
" Language: CoffeeScript
" Maintainer: Mick Koch <kchmck@gmail.com>
" URL: http://github.com/kchmck/vim-coffee-script
" License: WTFPL
autocmd BufNewFile,BufRead *.coffee set filetype=coffee
autocmd BufNewFile,BufRead *Cakefile set filetype=coffee

View file

@ -0,0 +1,14 @@
" Language: CoffeeScript
" Maintainer: Mick Koch <kchmck@gmail.com>
" 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

View file

@ -0,0 +1,157 @@
" Language: CoffeeScript
" Maintainer: Mick Koch <kchmck@gmail.com>
" 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 =~ '\<then\>'
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 =~ '\<switch\>'
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

View file

@ -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

View file

@ -0,0 +1,161 @@
" Language: CoffeeScript
" Maintainer: Mick Koch <kchmck@gmail.com>
" 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*\.\@<!\.\d\+\%([eE][+-]\?\d\+\)\?/
highlight default link coffeeFloat Float
syntax region coffeeInterpolation matchgroup=coffeeInterpDelim
\ start=/\#{/ end=/}/
\ contained contains=TOP
highlight default link coffeeInterpDelim Delimiter
syntax match coffeeEscape /\\\d\d\d\|\\x\x\{2\}\|\\u\x\{4\}\|\\./ contained
highlight default link coffeeEscape SpecialChar
syntax cluster coffeeSimpleString contains=@Spell,coffeeEscape
syntax cluster coffeeInterpString contains=@coffeeSimpleString,
\ coffeeInterpolation
syntax region coffeeRegExp start=/)\@<!\%(\%((\s*\|=\s\+\)\@<=\/\|\s\zs\/\s\@!\)/
\ end=/\/[gimy]\{,4}/ oneline
\ contains=@coffeeInterpString
highlight default link coffeeRegExp String
syntax region coffeeHeredoc start=/"""/ end=/"""/ contains=@coffeeInterpString
syntax region coffeeHeredoc start=/'''/ end=/'''/ contains=@coffeeSimpleString
highlight default link coffeeHeredoc String
syntax region coffeeCurlies start=/{/ end=/}/ contains=TOP
syntax region coffeeBrackets start=/\[/ end=/\]/ contains=TOP,coffeeAssignment
syntax match coffeeParens /(.*)/ contains=TOP,coffeeAssignment
" Displays an error for trailing whitespace
if !exists("coffee_no_trailing_space_error")
syntax match coffeeSpaceError /\s\+$/ display
highlight default link coffeeSpaceError Error
endif
" Displays an error for trailing semicolons
if !exists("coffee_no_trailing_semicolon_error")
syntax match coffeeSemicolonError /;$/ display
highlight default link coffeeSemicolonError Error
endif
" Displays an error for reserved words
if !exists("coffee_no_reserved_words_error")
syntax keyword coffeeReservedError case default do function var void with const
\ let enum export import native __hasProp
\ __extends __slice
highlight default link coffeeReservedError Error
endif
" Reserved words can be used as dot-properties
syntax match coffeeDot /\.\@<!\.\i\+/ transparent
\ contains=ALLBUT,@coffeeReserved,
\ coffeeReservedError

View file

@ -0,0 +1,35 @@
# To do for full support
- Destructuring assignments like:
[a, b] = c
{a, b} = c
└──┴─ these should be highlighted as identifiers
- Assignments inside brackets (sounds simple enough):
a[b -= c] = d
this should still be highlighted correctly:
a[b[c]] = d
- Smart, lookback outdenting for cases like:
a = {
b: ->
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

View file

@ -16,6 +16,10 @@ augroup lilypond
au! BufNewFile,BufRead *.ly,*.ily setf lilypond au! BufNewFile,BufRead *.ly,*.ily setf lilypond
augroup END 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 au BufRead,BufNewFile *.go set filetype=go
"Settings per filetype "Settings per filetype