command-t

This commit is contained in:
Barak Michener 2012-02-21 14:04:39 -08:00
parent e17a37c58d
commit 7a3c25fa03
55 changed files with 4 additions and 3640 deletions

3
.gitmodules vendored
View file

@ -34,3 +34,6 @@
[submodule ".vim/bundle/nerdcommenter"]
path = .vim/bundle/nerdcommenter
url = git://github.com/scrooloose/nerdcommenter.git
[submodule ".vim/bundle/command-t"]
path = .vim/bundle/command-t
url = git://git.wincent.com/command-t.git

1
.vim/bundle/command-t Submodule

@ -0,0 +1 @@
Subproject commit bcd391402144c80bae1d8a58a61b1bac0e0062a1

View file

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

View file

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

View file

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

View file

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

View file

@ -1,21 +0,0 @@
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

@ -1,22 +0,0 @@
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

@ -1,19 +0,0 @@
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

@ -1,68 +0,0 @@
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

@ -1,14 +0,0 @@
#!/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')

View file

@ -1,14 +0,0 @@
#!/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')

View file

@ -1,14 +0,0 @@
#!/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')

View file

@ -1,14 +0,0 @@
#!/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

@ -1,10 +0,0 @@
#!/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

View file

@ -1 +0,0 @@
tags

View file

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

View file

@ -1 +0,0 @@
.

View file

@ -1 +0,0 @@
.

View file

@ -1 +0,0 @@
.

View file

@ -1 +0,0 @@
.

View file

@ -1 +0,0 @@
.

View file

@ -1 +0,0 @@
.

View file

@ -1 +0,0 @@
.

View file

@ -1,25 +0,0 @@
#!/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

@ -1,151 +0,0 @@
" 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

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

View file

@ -1,181 +0,0 @@
SHELL = /bin/sh
#### Start of system configuration section. ####
srcdir = .
topdir = /usr/lib/ruby/1.8/x86_64-linux
hdrdir = $(topdir)
VPATH = $(srcdir):$(topdir):$(hdrdir)
exec_prefix = $(prefix)
prefix = $(DESTDIR)/usr
sharedstatedir = $(prefix)/com
mandir = $(prefix)/share/man
psdir = $(docdir)
oldincludedir = $(DESTDIR)/usr/include
localedir = $(datarootdir)/locale
bindir = $(exec_prefix)/bin
libexecdir = $(prefix)/lib/ruby1.8
sitedir = $(DESTDIR)/usr/local/lib/site_ruby
htmldir = $(docdir)
vendorarchdir = $(vendorlibdir)/$(sitearch)
includedir = $(prefix)/include
infodir = $(prefix)/share/info
vendorlibdir = $(vendordir)/$(ruby_version)
sysconfdir = $(DESTDIR)/etc
libdir = $(exec_prefix)/lib
sbindir = $(exec_prefix)/sbin
rubylibdir = $(libdir)/ruby/$(ruby_version)
docdir = $(datarootdir)/doc/$(PACKAGE)
dvidir = $(docdir)
vendordir = $(libdir)/ruby/vendor_ruby
datarootdir = $(prefix)/share
pdfdir = $(docdir)
archdir = $(rubylibdir)/$(arch)
sitearchdir = $(sitelibdir)/$(sitearch)
datadir = $(datarootdir)
localstatedir = $(DESTDIR)/var
sitelibdir = $(sitedir)/$(ruby_version)
CC = gcc
LIBRUBY = $(LIBRUBY_SO)
LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a
LIBRUBYARG_SHARED = -l$(RUBY_SO_NAME)
LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static
RUBY_EXTCONF_H =
CFLAGS = -fPIC -fno-strict-aliasing -g -g -O2 -fPIC $(cflags)
INCFLAGS = -I. -I$(topdir) -I$(hdrdir) -I$(srcdir)
DEFS =
CPPFLAGS = -DHAVE_RUBY_H $(DEFS) $(cppflags)
CXXFLAGS = $(CFLAGS)
ldflags = -L. -Wl,-Bsymbolic-functions -rdynamic -Wl,-export-dynamic
dldflags =
archflag =
DLDFLAGS = $(ldflags) $(dldflags) $(archflag)
LDSHARED = $(CC) -shared
AR = ar
EXEEXT =
RUBY_INSTALL_NAME = ruby1.8
RUBY_SO_NAME = ruby1.8
arch = x86_64-linux
sitearch = x86_64-linux
ruby_version = 1.8
ruby = /usr/bin/ruby1.8
RUBY = $(ruby)
RM = rm -f
MAKEDIRS = mkdir -p
INSTALL = /usr/bin/install -c
INSTALL_PROG = $(INSTALL) -m 0755
INSTALL_DATA = $(INSTALL) -m 644
COPY = cp
#### End of system configuration section. ####
preload =
libpath = . $(libdir)
LIBPATH = -L. -L$(libdir)
DEFFILE =
CLEANFILES = mkmf.log
DISTCLEANFILES =
extout =
extout_prefix =
target_prefix =
LOCAL_LIBS =
LIBS = $(LIBRUBYARG_SHARED) -lpthread -lrt -ldl -lcrypt -lm -lc
SRCS = ext.c match.c matcher.c
OBJS = ext.o match.o matcher.o
TARGET = ext
DLLIB = $(TARGET).so
EXTSTATIC =
STATIC_LIB =
BINDIR = $(bindir)
RUBYCOMMONDIR = $(sitedir)$(target_prefix)
RUBYLIBDIR = $(sitelibdir)$(target_prefix)
RUBYARCHDIR = $(sitearchdir)$(target_prefix)
TARGET_SO = $(DLLIB)
CLEANLIBS = $(TARGET).so $(TARGET).il? $(TARGET).tds $(TARGET).map
CLEANOBJS = *.o *.a *.s[ol] *.pdb *.exp *.bak
all: $(DLLIB)
static: $(STATIC_LIB)
clean:
@-$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES)
distclean: clean
@-$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log
@-$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES)
realclean: distclean
install: install-so install-rb
install-so: $(RUBYARCHDIR)
install-so: $(RUBYARCHDIR)/$(DLLIB)
$(RUBYARCHDIR)/$(DLLIB): $(DLLIB)
$(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR)
install-rb: pre-install-rb install-rb-default
install-rb-default: pre-install-rb-default
pre-install-rb: Makefile
pre-install-rb-default: Makefile
$(RUBYARCHDIR):
$(MAKEDIRS) $@
site-install: site-install-so site-install-rb
site-install-so: install-so
site-install-rb: install-rb
.SUFFIXES: .c .m .cc .cxx .cpp .C .o
.cc.o:
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
.cxx.o:
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
.cpp.o:
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
.C.o:
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
.c.o:
$(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) -c $<
$(DLLIB): $(OBJS) Makefile
@-$(RM) $@
$(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS)
###
# 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

@ -1,289 +0,0 @@
# 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

@ -1,24 +0,0 @@
# 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

@ -1,65 +0,0 @@
// 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

@ -1,36 +0,0 @@
// 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

@ -1,32 +0,0 @@
# 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

@ -1,51 +0,0 @@
# 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

@ -1,189 +0,0 @@
// 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

@ -1,29 +0,0 @@
// 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

@ -1,340 +0,0 @@
# 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

@ -1,164 +0,0 @@
// 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

@ -1,30 +0,0 @@
// 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

@ -1,10 +0,0 @@
have_header: checking for ruby.h... -------------------- yes
"gcc -E -I. -I/usr/lib/ruby/1.8/x86_64-linux -I. -fno-strict-aliasing -g -g -O2 -fPIC conftest.c -o conftest.i"
checked program was:
/* begin */
1: #include <ruby.h>
/* end */
--------------------

View file

@ -1,165 +0,0 @@
# 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

@ -1,49 +0,0 @@
// 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

@ -1,93 +0,0 @@
# 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

@ -1,77 +0,0 @@
# 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

@ -1,46 +0,0 @@
# 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

@ -1,43 +0,0 @@
# 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

@ -1,32 +0,0 @@
# 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

@ -1,38 +0,0 @@
# 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

@ -1,80 +0,0 @@
# 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

@ -1,236 +0,0 @@
# 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

@ -1,76 +0,0 @@
# 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

@ -1,82 +0,0 @@
# 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

@ -1,38 +0,0 @@
# 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

@ -1,41 +0,0 @@
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