Pathogen and new bundles

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

View file

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

View file

@ -0,0 +1,289 @@
# Copyright 2010 Wincent Colaiuta. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
require 'command-t/finder'
require 'command-t/match_window'
require 'command-t/prompt'
module CommandT
class Controller
def initialize
@prompt = Prompt.new
set_up_max_height
set_up_finder
end
def show
# optional parameter will be desired starting directory, or ""
@path = File.expand_path(::VIM::evaluate('a:arg'), VIM::pwd)
@finder.path = @path
@initial_window = $curwin
@initial_buffer = $curbuf
@match_window = MatchWindow.new \
:prompt => @prompt,
:match_window_at_top => get_bool('g:CommandTMatchWindowAtTop')
@focus = @prompt
@prompt.focus
register_for_key_presses
clear # clears prompt and list matches
rescue Errno::ENOENT
# probably a problem with the optional parameter
@match_window.print_no_such_file_or_directory
end
def hide
@match_window.close
if VIM::Window.select @initial_window
::VIM::command "silent b #{@initial_buffer.number}"
end
end
def flush
set_up_max_height
set_up_finder
end
def handle_key
key = ::VIM::evaluate('a:arg').to_i.chr
if @focus == @prompt
@prompt.add! key
list_matches
else
@match_window.find key
end
end
def backspace
if @focus == @prompt
@prompt.backspace!
list_matches
end
end
def delete
if @focus == @prompt
@prompt.delete!
list_matches
end
end
def accept_selection options = {}
selection = @match_window.selection
hide
open_selection(selection, options) unless selection.nil?
end
def toggle_focus
@focus.unfocus # old focus
if @focus == @prompt
@focus = @match_window
else
@focus = @prompt
end
@focus.focus # new focus
end
def cancel
hide
end
def select_next
@match_window.select_next
end
def select_prev
@match_window.select_prev
end
def clear
@prompt.clear!
list_matches
end
def cursor_left
@prompt.cursor_left if @focus == @prompt
end
def cursor_right
@prompt.cursor_right if @focus == @prompt
end
def cursor_end
@prompt.cursor_end if @focus == @prompt
end
def cursor_start
@prompt.cursor_start if @focus == @prompt
end
private
def set_up_max_height
@max_height = get_number('g:CommandTMaxHeight') || 0
end
def set_up_finder
@finder = CommandT::Finder.new nil,
:max_files => get_number('g:CommandTMaxFiles'),
:max_depth => get_number('g:CommandTMaxDepth'),
:always_show_dot_files => get_bool('g:CommandTAlwaysShowDotFiles'),
:never_show_dot_files => get_bool('g:CommandTNeverShowDotFiles'),
:scan_dot_directories => get_bool('g:CommandTScanDotDirectories')
end
def exists? name
::VIM::evaluate("exists(\"#{name}\")").to_i != 0
end
def get_number name
exists?(name) ? ::VIM::evaluate("#{name}").to_i : nil
end
def get_bool name
exists?(name) ? ::VIM::evaluate("#{name}").to_i != 0 : nil
end
def get_string name
exists?(name) ? ::VIM::evaluate("#{name}").to_s : nil
end
# expect a string or a list of strings
def get_list_or_string name
return nil unless exists?(name)
list_or_string = ::VIM::evaluate("#{name}")
if list_or_string.kind_of?(Array)
list_or_string.map { |item| item.to_s }
else
list_or_string.to_s
end
end
# Backslash-escape space, \, |, %, #, "
def sanitize_path_string str
# for details on escaping command-line mode arguments see: :h :
# (that is, help on ":") in the Vim documentation.
str.gsub(/[ \\|%#"]/, '\\\\\0')
end
def default_open_command
if !get_bool('&hidden') && get_bool('&modified')
'sp'
else
'e'
end
end
def ensure_appropriate_window_selection
# normally we try to open the selection in the current window, but there
# is one exception:
#
# - we don't touch any "unlisted" buffer with buftype "nofile" (such as
# NERDTree or MiniBufExplorer); this is to avoid things like the "Not
# enough room" error which occurs when trying to open in a split in a
# shallow (potentially 1-line) buffer like MiniBufExplorer is current
#
# Other "unlisted" buffers, such as those with buftype "help" are treated
# normally.
initial = $curwin
while true do
break unless ::VIM::evaluate('&buflisted').to_i == 0 &&
::VIM::evaluate('&buftype').to_s == 'nofile'
::VIM::command 'wincmd w' # try next window
break if $curwin == initial # have already tried all
end
end
def open_selection selection, options = {}
command = options[:command] || default_open_command
selection = File.expand_path selection, @path
selection = sanitize_path_string selection
ensure_appropriate_window_selection
::VIM::command "silent #{command} #{selection}"
end
def map key, function, param = nil
::VIM::command "noremap <silent> <buffer> #{key} " \
":call CommandT#{function}(#{param})<CR>"
end
def xterm?
!!(::VIM::evaluate('&term') =~ /\Axterm/)
end
def vt100?
!!(::VIM::evaluate('&term') =~ /\Avt100/)
end
def register_for_key_presses
# "normal" keys (interpreted literally)
numbers = ('0'..'9').to_a.join
lowercase = ('a'..'z').to_a.join
uppercase = lowercase.upcase
punctuation = '<>`@#~!"$%&/()=+*-_.,;:?\\\'{}[] ' # and space
(numbers + lowercase + uppercase + punctuation).each_byte do |b|
map "<Char-#{b}>", 'HandleKey', b
end
# "special" keys (overridable by settings)
{ 'Backspace' => '<BS>',
'Delete' => '<Del>',
'AcceptSelection' => '<CR>',
'AcceptSelectionSplit' => ['<C-CR>', '<C-s>'],
'AcceptSelectionTab' => '<C-t>',
'AcceptSelectionVSplit' => '<C-v>',
'ToggleFocus' => '<Tab>',
'Cancel' => ['<C-c>', '<Esc>'],
'SelectNext' => ['<C-n>', '<C-j>', '<Down>'],
'SelectPrev' => ['<C-p>', '<C-k>', '<Up>'],
'Clear' => '<C-u>',
'CursorLeft' => ['<Left>', '<C-h>'],
'CursorRight' => ['<Right>', '<C-l>'],
'CursorEnd' => '<C-e>',
'CursorStart' => '<C-a>' }.each do |key, value|
if override = get_list_or_string("g:CommandT#{key}Map")
[override].flatten.each do |mapping|
map mapping, key
end
else
[value].flatten.each do |mapping|
map mapping, key unless mapping == '<Esc>' && (xterm? || vt100?)
end
end
end
end
# Returns the desired maximum number of matches, based on available
# vertical space and the g:CommandTMaxHeight option.
def match_limit
limit = VIM::Screen.lines - 5
limit = 1 if limit < 0
limit = [limit, @max_height].min if @max_height > 0
limit
end
def list_matches
matches = @finder.sorted_matches_for @prompt.abbrev, :limit => match_limit
@match_window.matches = matches
end
end # class Controller
end # module commandT

View file

@ -0,0 +1,24 @@
# Copyright 2010 Wincent Colaiuta. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
CFLAGS += -std=c99 -Wall -Wextra -Wno-unused-parameter

View file

@ -0,0 +1,65 @@
// Copyright 2010 Wincent Colaiuta. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include "match.h"
#include "matcher.h"
VALUE mCommandT = 0; // module CommandT
VALUE cCommandTMatch = 0; // class CommandT::Match
VALUE cCommandTMatcher = 0; // class CommandT::Matcher
VALUE CommandT_option_from_hash(const char *option, VALUE hash)
{
if (NIL_P(hash))
return Qnil;
VALUE key = ID2SYM(rb_intern(option));
if (rb_funcall(hash, rb_intern("has_key?"), 1, key) == Qtrue)
return rb_hash_aref(hash, key);
else
return Qnil;
}
void Init_ext()
{
// module CommandT
mCommandT = rb_define_module("CommandT");
// class CommandT::Match
cCommandTMatch = rb_define_class_under(mCommandT, "Match", rb_cObject);
// methods
rb_define_method(cCommandTMatch, "initialize", CommandTMatch_initialize, -1);
rb_define_method(cCommandTMatch, "matches?", CommandTMatch_matches, 0);
rb_define_method(cCommandTMatch, "to_s", CommandTMatch_to_s, 0);
// attributes
rb_define_attr(cCommandTMatch, "score", Qtrue, Qfalse); // reader: true, writer: false
// class CommandT::Matcher
cCommandTMatcher = rb_define_class_under(mCommandT, "Matcher", rb_cObject);
// methods
rb_define_method(cCommandTMatcher, "initialize", CommandTMatcher_initialize, -1);
rb_define_method(cCommandTMatcher, "sorted_matches_for", CommandTMatcher_sorted_matchers_for, 2);
rb_define_method(cCommandTMatcher, "matches_for", CommandTMatcher_matches_for, 1);
}

View file

@ -0,0 +1,36 @@
// Copyright 2010 Wincent Colaiuta. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include <ruby.h>
extern VALUE mCommandT; // module CommandT
extern VALUE cCommandTMatch; // class CommandT::Match
extern VALUE cCommandTMatcher; // class CommandT::Matcher
// Encapsulates common pattern of checking for an option in an optional
// options hash. The hash itself may be nil, but an exception will be
// raised if it is not nil and not a hash.
VALUE CommandT_option_from_hash(const char *option, VALUE hash);
// Debugging macro.
#define ruby_inspect(obj) rb_funcall(rb_mKernel, rb_intern("p"), 1, obj)

View file

@ -0,0 +1,32 @@
# Copyright 2010 Wincent Colaiuta. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
require 'mkmf'
def missing item
puts "couldn't find #{item} (required)"
exit 1
end
have_header('ruby.h') or missing('ruby.h')
create_makefile('ext')

View file

@ -0,0 +1,51 @@
# Copyright 2010 Wincent Colaiuta. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
require 'command-t/ext' # CommandT::Matcher
require 'command-t/scanner'
module CommandT
# Encapsulates a Scanner instance (which builds up a list of available files
# in a directory) and a Matcher instance (which selects from that list based
# on a search string).
class Finder
def initialize path = Dir.pwd, options = {}
@scanner = Scanner.new path, options
@matcher = Matcher.new @scanner, options
end
# Options:
# :limit (integer): limit the number of returned matches
def sorted_matches_for str, options = {}
@matcher.sorted_matches_for str, options
end
def flush
@scanner.flush
end
def path= path
@scanner.path = path
end
end # class Finder
end # CommandT

View file

@ -0,0 +1,189 @@
// Copyright 2010 Wincent Colaiuta. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include "match.h"
#include "ext.h"
#include "ruby_compat.h"
// use a struct to make passing params during recursion easier
typedef struct
{
char *str_p; // pointer to string to be searched
long str_len; // length of same
char *abbrev_p; // pointer to search string (abbreviation)
long abbrev_len; // length of same
double max_score_per_char;
int dot_file; // boolean: true if str is a dot-file
int always_show_dot_files; // boolean
int never_show_dot_files; // boolean
} matchinfo_t;
double recursive_match(matchinfo_t *m, // sharable meta-data
long str_idx, // where in the path string to start
long abbrev_idx, // where in the search string to start
long last_idx, // location of last matched character
double score) // cumulative score so far
{
double seen_score = 0; // remember best score seen via recursion
int dot_file_match = 0; // true if abbrev matches a dot-file
int dot_search = 0; // true if searching for a dot
for (long i = abbrev_idx; i < m->abbrev_len; i++)
{
char c = m->abbrev_p[i];
if (c == '.')
dot_search = 1;
int found = 0;
for (long j = str_idx; j < m->str_len; j++, str_idx++)
{
char d = m->str_p[j];
if (d == '.')
{
if (j == 0 || m->str_p[j - 1] == '/')
{
m->dot_file = 1; // this is a dot-file
if (dot_search) // and we are searching for a dot
dot_file_match = 1; // so this must be a match
}
}
else if (d >= 'A' && d <= 'Z')
d += 'a' - 'A'; // add 32 to downcase
if (c == d)
{
found = 1;
dot_search = 0;
// calculate score
double score_for_char = m->max_score_per_char;
long distance = j - last_idx;
if (distance > 1)
{
double factor = 1.0;
char last = m->str_p[j - 1];
char curr = m->str_p[j]; // case matters, so get again
if (last == '/')
factor = 0.9;
else if (last == '-' ||
last == '_' ||
last == ' ' ||
(last >= '0' && last <= '9'))
factor = 0.8;
else if (last >= 'a' && last <= 'z' &&
curr >= 'A' && curr <= 'Z')
factor = 0.8;
else if (last == '.')
factor = 0.7;
else
// if no "special" chars behind char, factor diminishes
// as distance from last matched char increases
factor = (1.0 / distance) * 0.75;
score_for_char *= factor;
}
if (++j < m->str_len)
{
// bump cursor one char to the right and
// use recursion to try and find a better match
double sub_score = recursive_match(m, j, i, last_idx, score);
if (sub_score > seen_score)
seen_score = sub_score;
}
score += score_for_char;
last_idx = str_idx++;
break;
}
}
if (!found)
return 0.0;
}
if (m->dot_file)
{
if (m->never_show_dot_files ||
(!dot_file_match && !m->always_show_dot_files))
return 0.0;
}
return (score > seen_score) ? score : seen_score;
}
// Match.new abbrev, string, options = {}
VALUE CommandTMatch_initialize(int argc, VALUE *argv, VALUE self)
{
// process arguments: 2 mandatory, 1 optional
VALUE str, abbrev, options;
if (rb_scan_args(argc, argv, "21", &str, &abbrev, &options) == 2)
options = Qnil;
str = StringValue(str);
abbrev = StringValue(abbrev); // already downcased by caller
// check optional options hash for overrides
VALUE always_show_dot_files = CommandT_option_from_hash("always_show_dot_files", options);
VALUE never_show_dot_files = CommandT_option_from_hash("never_show_dot_files", options);
matchinfo_t m;
m.str_p = RSTRING_PTR(str);
m.str_len = RSTRING_LEN(str);
m.abbrev_p = RSTRING_PTR(abbrev);
m.abbrev_len = RSTRING_LEN(abbrev);
m.max_score_per_char = (1.0 / m.str_len + 1.0 / m.abbrev_len) / 2;
m.dot_file = 0;
m.always_show_dot_files = always_show_dot_files == Qtrue;
m.never_show_dot_files = never_show_dot_files == Qtrue;
// calculate score
double score = 1.0;
if (m.abbrev_len == 0) // special case for zero-length search string
{
// filter out dot files
if (!m.always_show_dot_files)
{
for (long i = 0; i < m.str_len; i++)
{
char c = m.str_p[i];
if (c == '.' && (i == 0 || m.str_p[i - 1] == '/'))
{
score = 0.0;
break;
}
}
}
}
else // normal case
score = recursive_match(&m, 0, 0, 0, 0.0);
// clean-up and final book-keeping
rb_iv_set(self, "@score", rb_float_new(score));
rb_iv_set(self, "@str", str);
return Qnil;
}
VALUE CommandTMatch_matches(VALUE self)
{
double score = NUM2DBL(rb_iv_get(self, "@score"));
return score > 0 ? Qtrue : Qfalse;
}
VALUE CommandTMatch_to_s(VALUE self)
{
return rb_iv_get(self, "@str");
}

View file

@ -0,0 +1,29 @@
// Copyright 2010 Wincent Colaiuta. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include <ruby.h>
extern VALUE CommandTMatch_initialize(int argc, VALUE *argv, VALUE self);
extern VALUE CommandTMatch_matches(VALUE self);
extern VALUE CommandTMatch_score(VALUE self);
extern VALUE CommandTMatch_to_s(VALUE self);

View file

@ -0,0 +1,340 @@
# Copyright 2010 Wincent Colaiuta. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
require 'ostruct'
require 'command-t/settings'
module CommandT
class MatchWindow
@@selection_marker = '> '
@@marker_length = @@selection_marker.length
@@unselected_marker = ' ' * @@marker_length
def initialize options = {}
@prompt = options[:prompt]
# save existing window dimensions so we can restore them later
@windows = []
(0..(::VIM::Window.count - 1)).each do |i|
window = OpenStruct.new :index => i, :height => ::VIM::Window[i].height
@windows << window
end
# global settings (must manually save and restore)
@settings = Settings.new
::VIM::set_option 'timeout' # ensure mappings timeout
::VIM::set_option 'timeoutlen=0' # respond immediately to mappings
::VIM::set_option 'nohlsearch' # don't highlight search strings
::VIM::set_option 'noinsertmode' # don't make Insert mode the default
::VIM::set_option 'noshowcmd' # don't show command info on last line
::VIM::set_option 'report=9999' # don't show "X lines changed" reports
::VIM::set_option 'sidescroll=0' # don't sidescroll in jumps
::VIM::set_option 'sidescrolloff=0' # don't sidescroll automatically
::VIM::set_option 'noequalalways' # don't auto-balance window sizes
# create match window and set it up
split_location = options[:match_window_at_top] ? 'topleft' : 'botright'
split_command = "silent! #{split_location} 1split GoToFile"
[
split_command,
'setlocal bufhidden=delete', # delete buf when no longer displayed
'setlocal buftype=nofile', # buffer is not related to any file
'setlocal nomodifiable', # prevent manual edits
'setlocal noswapfile', # don't create a swapfile
'setlocal nowrap', # don't soft-wrap
'setlocal nonumber', # don't show line numbers
'setlocal nolist', # don't use List mode (visible tabs etc)
'setlocal foldcolumn=0', # don't show a fold column at side
'setlocal foldlevel=99', # don't fold anything
'setlocal nocursorline', # don't highlight line cursor is on
'setlocal nospell', # spell-checking off
'setlocal nobuflisted', # don't show up in the buffer list
'setlocal textwidth=0' # don't hard-wrap (break long lines)
].each { |command| ::VIM::command command }
# sanity check: make sure the buffer really was created
raise "Can't find buffer" unless $curbuf.name.match /GoToFile/
# syntax coloring
if VIM::has_syntax?
::VIM::command "syntax match CommandTSelection \"^#{@@selection_marker}.\\+$\""
::VIM::command 'syntax match CommandTNoEntries "^-- NO MATCHES --$"'
::VIM::command 'syntax match CommandTNoEntries "^-- NO SUCH FILE OR DIRECTORY --$"'
::VIM::command 'highlight link CommandTSelection Visual'
::VIM::command 'highlight link CommandTNoEntries Error'
::VIM::evaluate 'clearmatches()'
# hide cursor
@cursor_highlight = get_cursor_highlight
hide_cursor
end
@has_focus = false
@selection = nil
@abbrev = ''
@window = $curwin
@buffer = $curbuf
end
def close
::VIM::command "bwipeout! #{@buffer.number}"
restore_window_dimensions
@settings.restore
@prompt.dispose
show_cursor
end
def add! char
@abbrev += char
end
def backspace!
@abbrev.chop!
end
def select_next
if @selection < @matches.length - 1
@selection += 1
print_match(@selection - 1) # redraw old selection (removes marker)
print_match(@selection) # redraw new selection (adds marker)
else
# (possibly) loop or scroll
end
end
def select_prev
if @selection > 0
@selection -= 1
print_match(@selection + 1) # redraw old selection (removes marker)
print_match(@selection) # redraw new selection (adds marker)
else
# (possibly) loop or scroll
end
end
def matches= matches
if matches != @matches
@matches = matches
@selection = 0
print_matches
end
end
def focus
unless @has_focus
@has_focus = true
if VIM::has_syntax?
::VIM::command 'highlight link CommandTSelection Search'
end
end
end
def unfocus
if @has_focus
@has_focus = false
if VIM::has_syntax?
::VIM::command 'highlight link CommandTSelection Visual'
end
end
end
def find char
# is this a new search or the continuation of a previous one?
now = Time.now
if @last_key_time.nil? or @last_key_time < (now - 0.5)
@find_string = char
else
@find_string += char
end
@last_key_time = now
# see if there's anything up ahead that matches
@matches.each_with_index do |match, idx|
if match[0, @find_string.length].casecmp(@find_string) == 0
old_selection = @selection
@selection = idx
print_match(old_selection) # redraw old selection (removes marker)
print_match(@selection) # redraw new selection (adds marker)
break
end
end
end
# Returns the currently selected item as a String.
def selection
@matches[@selection]
end
def print_no_such_file_or_directory
print_error 'NO SUCH FILE OR DIRECTORY'
end
private
def print_error msg
return unless VIM::Window.select(@window)
unlock
clear
@window.height = 1
@buffer[1] = "-- #{msg} --"
lock
end
def restore_window_dimensions
# sort from tallest to shortest
@windows.sort! { |a, b| b.height <=> a.height }
# starting with the tallest ensures that there are no constraints
# preventing windows on the side of vertical splits from regaining
# their original full size
@windows.each do |w|
# beware: window may be nil
window = ::VIM::Window[w.index]
window.height = w.height if window
end
end
def match_text_for_idx idx
match = truncated_match @matches[idx]
if idx == @selection
prefix = @@selection_marker
suffix = padding_for_selected_match match
else
prefix = @@unselected_marker
suffix = ''
end
prefix + match + suffix
end
# Print just the specified match.
def print_match idx
return unless VIM::Window.select(@window)
unlock
@buffer[idx + 1] = match_text_for_idx idx
lock
end
# Print all matches.
def print_matches
match_count = @matches.length
if match_count == 0
print_error 'NO MATCHES'
else
return unless VIM::Window.select(@window)
unlock
clear
actual_lines = 1
@window_width = @window.width # update cached value
max_lines = VIM::Screen.lines - 5
max_lines = 1 if max_lines < 0
actual_lines = match_count > max_lines ? max_lines : match_count
@window.height = actual_lines
(1..actual_lines).each do |line|
idx = line - 1
if @buffer.count >= line
@buffer[line] = match_text_for_idx idx
else
@buffer.append line - 1, match_text_for_idx(idx)
end
end
lock
end
end
# Prepare padding for match text (trailing spaces) so that selection
# highlighting extends all the way to the right edge of the window.
def padding_for_selected_match str
len = str.length
if len >= @window_width - @@marker_length
''
else
' ' * (@window_width - @@marker_length - len)
end
end
# Convert "really/long/path" into "really...path" based on available
# window width.
def truncated_match str
len = str.length
available_width = @window_width - @@marker_length
return str if len <= available_width
left = (available_width / 2) - 1
right = (available_width / 2) - 2 + (available_width % 2)
str[0, left] + '...' + str[-right, right]
end
def clear
# range = % (whole buffer)
# action = d (delete)
# register = _ (black hole register, don't record deleted text)
::VIM::command 'silent %d _'
end
def get_cursor_highlight
# as :highlight returns nothing and only prints,
# must redirect its output to a variable
::VIM::command 'silent redir => g:command_t_cursor_highlight'
# force 0 verbosity to ensure origin information isn't printed as well
::VIM::command 'silent! 0verbose highlight Cursor'
::VIM::command 'silent redir END'
# there are 3 possible formats to check for, each needing to be
# transformed in a certain way in order to reapply the highlight:
# Cursor xxx guifg=bg guibg=fg -> :hi! Cursor guifg=bg guibg=fg
# Cursor xxx links to SomethingElse -> :hi! link Cursor SomethingElse
# Cursor xxx cleared -> :hi! clear Cursor
highlight = ::VIM::evaluate 'g:command_t_cursor_highlight'
if highlight =~ /^Cursor\s+xxx\s+links to (\w+)/
"link Cursor #{$~[1]}"
elsif highlight =~ /^Cursor\s+xxx\s+cleared/
'clear Cursor'
elsif highlight =~ /Cursor\s+xxx\s+(.+)/
"Cursor #{$~[1]}"
else # likely cause E411 Cursor highlight group not found
nil
end
end
def hide_cursor
if @cursor_highlight
::VIM::command 'highlight Cursor NONE'
end
end
def show_cursor
if @cursor_highlight
::VIM::command "highlight #{@cursor_highlight}"
end
end
def lock
::VIM::command 'setlocal nomodifiable'
end
def unlock
::VIM::command 'setlocal modifiable'
end
end
end

View file

@ -0,0 +1,164 @@
// Copyright 2010 Wincent Colaiuta. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include <stdlib.h> /* for qsort() */
#include <string.h> /* for strcmp() */
#include "matcher.h"
#include "ext.h"
#include "ruby_compat.h"
// comparison function for use with qsort
int comp_alpha(const void *a, const void *b)
{
VALUE a_val = *(VALUE *)a;
VALUE b_val = *(VALUE *)b;
ID to_s = rb_intern("to_s");
VALUE a_str = rb_funcall(a_val, to_s, 0);
VALUE b_str = rb_funcall(b_val, to_s, 0);
char *a_p = RSTRING_PTR(a_str);
long a_len = RSTRING_LEN(a_str);
char *b_p = RSTRING_PTR(b_str);
long b_len = RSTRING_LEN(b_str);
int order = 0;
if (a_len > b_len)
{
order = strncmp(a_p, b_p, b_len);
if (order == 0)
order = 1; // shorter string (b) wins
}
else if (a_len < b_len)
{
order = strncmp(a_p, b_p, a_len);
if (order == 0)
order = -1; // shorter string (a) wins
}
else
order = strncmp(a_p, b_p, a_len);
return order;
}
// comparison function for use with qsort
int comp_score(const void *a, const void *b)
{
VALUE a_val = *(VALUE *)a;
VALUE b_val = *(VALUE *)b;
ID score = rb_intern("score");
double a_score = RFLOAT_VALUE(rb_funcall(a_val, score, 0));
double b_score = RFLOAT_VALUE(rb_funcall(b_val, score, 0));
if (a_score > b_score)
return -1; // a scores higher, a should appear sooner
else if (a_score < b_score)
return 1; // b scores higher, a should appear later
else
return comp_alpha(a, b);
}
VALUE CommandTMatcher_initialize(int argc, VALUE *argv, VALUE self)
{
// process arguments: 1 mandatory, 1 optional
VALUE scanner, options;
if (rb_scan_args(argc, argv, "11", &scanner, &options) == 1)
options = Qnil;
if (NIL_P(scanner))
rb_raise(rb_eArgError, "nil scanner");
rb_iv_set(self, "@scanner", scanner);
// check optional options hash for overrides
VALUE always_show_dot_files = CommandT_option_from_hash("always_show_dot_files", options);
if (always_show_dot_files != Qtrue)
always_show_dot_files = Qfalse;
VALUE never_show_dot_files = CommandT_option_from_hash("never_show_dot_files", options);
if (never_show_dot_files != Qtrue)
never_show_dot_files = Qfalse;
rb_iv_set(self, "@always_show_dot_files", always_show_dot_files);
rb_iv_set(self, "@never_show_dot_files", never_show_dot_files);
return Qnil;
}
VALUE CommandTMatcher_sorted_matchers_for(VALUE self, VALUE abbrev, VALUE options)
{
// process optional options hash
VALUE limit_option = CommandT_option_from_hash("limit", options);
// get unsorted matches
VALUE matches = CommandTMatcher_matches_for(self, abbrev);
abbrev = StringValue(abbrev);
if (RSTRING_LEN(abbrev) == 0 ||
(RSTRING_LEN(abbrev) == 1 && RSTRING_PTR(abbrev)[0] == '.'))
// alphabetic order if search string is only "" or "."
qsort(RARRAY_PTR(matches), RARRAY_LEN(matches), sizeof(VALUE), comp_alpha);
else
// for all other non-empty search strings, sort by score
qsort(RARRAY_PTR(matches), RARRAY_LEN(matches), sizeof(VALUE), comp_score);
// apply optional limit option
long limit = NIL_P(limit_option) ? 0 : NUM2LONG(limit_option);
if (limit == 0 || RARRAY_LEN(matches)< limit)
limit = RARRAY_LEN(matches);
// will return an array of strings, not an array of Match objects
for (long i = 0; i < limit; i++)
{
VALUE str = rb_funcall(RARRAY_PTR(matches)[i], rb_intern("to_s"), 0);
RARRAY_PTR(matches)[i] = str;
}
// trim off any items beyond the limit
if (limit < RARRAY_LEN(matches))
(void)rb_funcall(matches, rb_intern("slice!"), 2, LONG2NUM(limit),
LONG2NUM(RARRAY_LEN(matches) - limit));
return matches;
}
VALUE CommandTMatcher_matches_for(VALUE self, VALUE abbrev)
{
if (NIL_P(abbrev))
rb_raise(rb_eArgError, "nil abbrev");
VALUE matches = rb_ary_new();
VALUE scanner = rb_iv_get(self, "@scanner");
VALUE always_show_dot_files = rb_iv_get(self, "@always_show_dot_files");
VALUE never_show_dot_files = rb_iv_get(self, "@never_show_dot_files");
VALUE options = Qnil;
if (always_show_dot_files == Qtrue)
{
options = rb_hash_new();
rb_hash_aset(options, ID2SYM(rb_intern("always_show_dot_files")), always_show_dot_files);
}
else if (never_show_dot_files == Qtrue)
{
options = rb_hash_new();
rb_hash_aset(options, ID2SYM(rb_intern("never_show_dot_files")), never_show_dot_files);
}
abbrev = rb_funcall(abbrev, rb_intern("downcase"), 0);
VALUE paths = rb_funcall(scanner, rb_intern("paths"), 0);
for (long i = 0, max = RARRAY_LEN(paths); i < max; i++)
{
VALUE path = RARRAY_PTR(paths)[i];
VALUE match = rb_funcall(cCommandTMatch, rb_intern("new"), 3, path, abbrev, options);
if (rb_funcall(match, rb_intern("matches?"), 0) == Qtrue)
rb_funcall(matches, rb_intern("push"), 1, match);
}
return matches;
}

View file

@ -0,0 +1,30 @@
// Copyright 2010 Wincent Colaiuta. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include <ruby.h>
extern VALUE CommandTMatcher_initialize(int argc, VALUE *argv, VALUE self);
extern VALUE CommandTMatcher_sorted_matchers_for(VALUE self, VALUE abbrev, VALUE options);
// most likely the function will be subsumed by the sorted_matcher_for function
extern VALUE CommandTMatcher_matches_for(VALUE self, VALUE abbrev);

View file

@ -0,0 +1,165 @@
# Copyright 2010 Wincent Colaiuta. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
module CommandT
# Abuse the status line as a prompt.
class Prompt
attr_accessor :abbrev
def initialize
@abbrev = '' # abbreviation entered so far
@col = 0 # cursor position
@has_focus = false
end
# Erase whatever is displayed in the prompt line,
# effectively disposing of the prompt
def dispose
::VIM::command 'echo'
::VIM::command 'redraw'
end
# Clear any entered text.
def clear!
@abbrev = ''
@col = 0
redraw
end
# Insert a character at (before) the current cursor position.
def add! char
left, cursor, right = abbrev_segments
@abbrev = left + char + cursor + right
@col += 1
redraw
end
# Delete a character to the left of the current cursor position.
def backspace!
if @col > 0
left, cursor, right = abbrev_segments
@abbrev = left.chop! + cursor + right
@col -= 1
redraw
end
end
# Delete a character at the current cursor position.
def delete!
if @col < @abbrev.length
left, cursor, right = abbrev_segments
@abbrev = left + right
redraw
end
end
def cursor_left
if @col > 0
@col -= 1
redraw
end
end
def cursor_right
if @col < @abbrev.length
@col += 1
redraw
end
end
def cursor_end
if @col < @abbrev.length
@col = @abbrev.length
redraw
end
end
def cursor_start
if @col != 0
@col = 0
redraw
end
end
def redraw
if @has_focus
prompt_highlight = 'Comment'
normal_highlight = 'None'
cursor_highlight = 'Underlined'
else
prompt_highlight = 'NonText'
normal_highlight = 'NonText'
cursor_highlight = 'NonText'
end
left, cursor, right = abbrev_segments
components = [prompt_highlight, '>>', 'None', ' ']
components += [normal_highlight, left] unless left.empty?
components += [cursor_highlight, cursor] unless cursor.empty?
components += [normal_highlight, right] unless right.empty?
components += [cursor_highlight, ' '] if cursor.empty?
set_status *components
end
def focus
unless @has_focus
@has_focus = true
redraw
end
end
def unfocus
if @has_focus
@has_focus = false
redraw
end
end
private
# Returns the @abbrev string divided up into three sections, any of
# which may actually be zero width, depending on the location of the
# cursor:
# - left segment (to left of cursor)
# - cursor segment (character at cursor)
# - right segment (to right of cursor)
def abbrev_segments
left = @abbrev[0, @col]
cursor = @abbrev[@col, 1]
right = @abbrev[(@col + 1)..-1] || ''
[left, cursor, right]
end
def set_status *args
# see ':help :echo' for why forcing a redraw here helps
# prevent the status line from getting inadvertantly cleared
# after our echo commands
::VIM::command 'redraw'
while (highlight = args.shift) and (text = args.shift) do
text = VIM::escape_for_single_quotes text
::VIM::command "echohl #{highlight}"
::VIM::command "echon '#{text}'"
end
::VIM::command 'echohl None'
end
end # class Prompt
end # module CommandT

View file

@ -0,0 +1,49 @@
// Copyright 2010 Wincent Colaiuta. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include <ruby.h>
// for compatibility with older versions of Ruby which don't declare RSTRING_PTR
#ifndef RSTRING_PTR
#define RSTRING_PTR(s) (RSTRING(s)->ptr)
#endif
// for compatibility with older versions of Ruby which don't declare RSTRING_LEN
#ifndef RSTRING_LEN
#define RSTRING_LEN(s) (RSTRING(s)->len)
#endif
// for compatibility with older versions of Ruby which don't declare RARRAY_PTR
#ifndef RARRAY_PTR
#define RARRAY_PTR(a) (RARRAY(a)->ptr)
#endif
// for compatibility with older versions of Ruby which don't declare RARRAY_LEN
#ifndef RARRAY_LEN
#define RARRAY_LEN(a) (RARRAY(a)->len)
#endif
// for compatibility with older versions of Ruby which don't declare RFLOAT_VALUE
#ifndef RFLOAT_VALUE
#define RFLOAT_VALUE(f) (RFLOAT(f)->value)
#endif

View file

@ -0,0 +1,93 @@
# Copyright 2010 Wincent Colaiuta. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
require 'command-t/vim'
module CommandT
# Reads the current directory recursively for the paths to all regular files.
class Scanner
class FileLimitExceeded < ::RuntimeError; end
def initialize path = Dir.pwd, options = {}
@path = path
@max_depth = options[:max_depth] || 15
@max_files = options[:max_files] || 10_000
@scan_dot_directories = options[:scan_dot_directories] || false
end
def paths
return @paths unless @paths.nil?
begin
@paths = []
@depth = 0
@files = 0
@prefix_len = @path.chomp('/').length
add_paths_for_directory @path, @paths
rescue FileLimitExceeded
end
@paths
end
def flush
@paths = nil
end
def path= str
if @path != str
@path = str
flush
end
end
private
def path_excluded? path
# first strip common prefix (@path) from path to match VIM's behavior
path = path[(@prefix_len + 1)..-1]
path = VIM::escape_for_single_quotes path
::VIM::evaluate("empty(expand(fnameescape('#{path}')))").to_i == 1
end
def add_paths_for_directory dir, accumulator
Dir.foreach(dir) do |entry|
next if ['.', '..'].include?(entry)
path = File.join(dir, entry)
unless path_excluded?(path)
if File.file?(path)
@files += 1
raise FileLimitExceeded if @files > @max_files
accumulator << path[@prefix_len + 1..-1]
elsif File.directory?(path)
next if @depth >= @max_depth
next if (entry.match(/\A\./) && !@scan_dot_directories)
@depth += 1
add_paths_for_directory path, accumulator
@depth -= 1
end
end
end
rescue Errno::EACCES
# skip over directories for which we don't have access
end
end # class Scanner
end # module CommandT

View file

@ -0,0 +1,77 @@
# Copyright 2010 Wincent Colaiuta. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
module CommandT
# Convenience class for saving and restoring global settings.
class Settings
def initialize
save
end
def save
@timeoutlen = get_number 'timeoutlen'
@report = get_number 'report'
@sidescroll = get_number 'sidescroll'
@sidescrolloff = get_number 'sidescrolloff'
@timeout = get_bool 'timeout'
@equalalways = get_bool 'equalalways'
@hlsearch = get_bool 'hlsearch'
@insertmode = get_bool 'insertmode'
@showcmd = get_bool 'showcmd'
end
def restore
set_number 'timeoutlen', @timeoutlen
set_number 'report', @report
set_number 'sidescroll', @sidescroll
set_number 'sidescrolloff', @sidescrolloff
set_bool 'timeout', @timeout
set_bool 'equalalways', @equalalways
set_bool 'hlsearch', @hlsearch
set_bool 'insertmode', @insertmode
set_bool 'showcmd', @showcmd
end
private
def get_number setting
::VIM::evaluate("&#{setting}").to_i
end
def get_bool setting
::VIM::evaluate("&#{setting}").to_i == 1
end
def set_number setting, value
::VIM::set_option "#{setting}=#{value}"
end
def set_bool setting, value
if value
::VIM::set_option setting
else
::VIM::set_option "no#{setting}"
end
end
end # class Settings
end # module CommandT

View file

@ -0,0 +1,46 @@
# Copyright 2010 Wincent Colaiuta. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
module CommandT
class Stub
@@load_error = ['command-t.vim could not load the C extension',
'Please see INSTALLATION and TROUBLE-SHOOTING in the help',
'For more information type: :help command-t']
def show
warn *@@load_error
end
def flush
warn *@@load_error
end
private
def warn *msg
::VIM::command 'echohl WarningMsg'
msg.each { |m| ::VIM::command "echo '#{m}'" }
::VIM::command 'echohl none'
end
end # class Stub
end # module CommandT

View file

@ -0,0 +1,43 @@
# Copyright 2010 Wincent Colaiuta. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
require 'command-t/vim/screen'
require 'command-t/vim/window'
module CommandT
module VIM
def self.has_syntax?
::VIM::evaluate('has("syntax")').to_i != 0
end
def self.pwd
::VIM::evaluate 'getcwd()'
end
# Escape a string for safe inclusion in a Vim single-quoted string
# (single quotes escaped by doubling, everything else is literal)
def self.escape_for_single_quotes str
str.gsub "'", "''"
end
end # module VIM
end # module CommandT

View file

@ -0,0 +1,32 @@
# Copyright 2010 Wincent Colaiuta. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
module CommandT
module VIM
module Screen
def self.lines
::VIM::evaluate('&lines').to_i
end
end # module Screen
end # module VIM
end # module CommandT

View file

@ -0,0 +1,38 @@
# Copyright 2010 Wincent Colaiuta. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
module CommandT
module VIM
class Window
def self.select window
return true if $curwin == window
initial = $curwin
while true do
::VIM::command 'wincmd w' # cycle through windows
return true if $curwin == window # have selected desired window
return false if $curwin == initial # have already looped through all
end
end
end # class Window
end # module VIM
end # module CommandT