diff options
Diffstat (limited to 'vim/tmp/command_t/ruby/command-t/controller.rb')
| -rw-r--r-- | vim/tmp/command_t/ruby/command-t/controller.rb | 317 |
1 files changed, 317 insertions, 0 deletions
diff --git a/vim/tmp/command_t/ruby/command-t/controller.rb b/vim/tmp/command_t/ruby/command-t/controller.rb new file mode 100644 index 0000000..29e61b6 --- /dev/null +++ b/vim/tmp/command_t/ruby/command-t/controller.rb @@ -0,0 +1,317 @@ +# Copyright 2010-2011 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/buffer_finder' +require 'command-t/finder/file_finder' +require 'command-t/match_window' +require 'command-t/prompt' +require 'command-t/vim/path_utilities' + +module CommandT + class Controller + include VIM::PathUtilities + + def initialize + @prompt = Prompt.new + @buffer_finder = CommandT::BufferFinder.new + set_up_file_finder + set_up_max_height + end + + def show_buffer_finder + @path = VIM::pwd + @active_finder = @buffer_finder + show + end + + def show_file_finder + # optional parameter will be desired starting directory, or "" + @path = File.expand_path(::VIM::evaluate('a:arg'), VIM::pwd) + @file_finder.path = @path + @active_finder = @file_finder + show + 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 + if @initial_buffer.number == 0 + # upstream bug: buffer number misreported as 0 + # see: https://wincent.com/issues/1617 + ::VIM::command "silent b #{@initial_buffer.name}" + else + ::VIM::command "silent b #{@initial_buffer.number}" + end + end + end + + def flush + set_up_max_height + set_up_file_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 + @focus = @focus == @prompt ? @match_window : @prompt + @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 + + def leave + @match_window.leave + end + + def unload + @match_window.unload + end + + private + + def show + @initial_window = $curwin + @initial_buffer = $curbuf + @match_window = MatchWindow.new \ + :prompt => @prompt, + :match_window_at_top => get_bool('g:CommandTMatchWindowAtTop'), + :match_window_reverse => get_bool('g:CommandTMatchWindowReverse') + @focus = @prompt + @prompt.focus + register_for_key_presses + clear # clears prompt and lists matches + end + + def set_up_max_height + @max_height = get_number('g:CommandTMaxHeight') || 0 + end + + def set_up_file_finder + @file_finder = CommandT::FileFinder.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 = relative_path_under_working_directory selection + 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 = @active_finder.sorted_matches_for @prompt.abbrev, :limit => match_limit + @match_window.matches = matches + end + end # class Controller +end # module commandT |