1 # Copyright 2010-2011 Wincent Colaiuta. All rights reserved.
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions are met:
6 # 1. Redistributions of source code must retain the above copyright notice,
7 # this list of conditions and the following disclaimer.
8 # 2. Redistributions in binary form must reproduce the above copyright notice,
9 # this list of conditions and the following disclaimer in the documentation
10 # and/or other materials provided with the distribution.
12 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
13 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15 # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
16 # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
17 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
18 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
19 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
20 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
21 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
22 # POSSIBILITY OF SUCH DAMAGE.
25 require 'command-t/settings'
29 @
@selection_marker = '> '
30 @
@marker_length = @
@selection_marker.length
31 @
@unselected_marker = ' ' * @
@marker_length
34 def initialize options
= {}
35 @prompt = options
[:prompt]
36 @reverse_list = options
[:match_window_reverse]
38 # save existing window dimensions so we can restore them later
40 (0..(::VIM::Window.count
- 1)).each
do |i
|
41 window
= OpenStruct
.new
:index => i
, :height => ::VIM::Window[i
].height
45 # global settings (must manually save and restore)
46 @settings = Settings
.new
47 ::VIM::set_option 'timeout' # ensure mappings timeout
48 ::VIM::set_option 'timeoutlen=0' # respond immediately to mappings
49 ::VIM::set_option 'nohlsearch' # don't highlight search strings
50 ::VIM::set_option 'noinsertmode' # don't make Insert mode the default
51 ::VIM::set_option 'noshowcmd' # don't show command info on last line
52 ::VIM::set_option 'report=9999' # don't show "X lines changed" reports
53 ::VIM::set_option 'sidescroll=0' # don't sidescroll in jumps
54 ::VIM::set_option 'sidescrolloff=0' # don't sidescroll automatically
55 ::VIM::set_option 'noequalalways' # don't auto-balance window sizes
58 split_location
= options
[:match_window_at_top] ? 'topleft' : 'botright'
59 if @
@buffer # still have buffer from last time
60 ::VIM::command "silent! #{split_location} #{@@buffer.number}sbuffer
"
61 raise "Can
't re-open GoToFile buffer" unless $curbuf.number == @@buffer.number
63 else # creating match window for first time and set it up
64 split_command = "silent! #{split_location} 1split GoToFile
"
67 'setlocal bufhidden=unload', # unload buf when no longer displayed
68 'setlocal buftype=nofile', # buffer is not related to any file
69 'setlocal nomodifiable', # prevent manual edits
70 'setlocal noswapfile', # don't create a swapfile
71 'setlocal nowrap', # don't soft-wrap
72 'setlocal nonumber', # don't show line numbers
73 'setlocal nolist', # don't use List mode (visible tabs etc)
74 'setlocal foldcolumn=0', # don't show a fold column at side
75 'setlocal foldlevel=99', # don't fold anything
76 'setlocal nocursorline', # don't highlight line cursor is on
77 'setlocal nospell', # spell-checking off
78 'setlocal nobuflisted', # don't show up in the buffer list
79 'setlocal textwidth=0' # don't hard-wrap (break long lines)
80 ].each { |command| ::VIM::command command }
82 # sanity check: make sure the buffer really was created
83 raise "Can
't find GoToFile buffer" unless $curbuf.name.match /GoToFile\z/
89 ::VIM::command "syntax match CommandTSelection \"^#{@@selection_marker}.\\+$
\""
90 ::VIM::command 'syntax match CommandTNoEntries "^
-- NO MATCHES
--$
"'
91 ::VIM::command 'syntax match CommandTNoEntries "^
-- NO SUCH FILE OR DIRECTORY
--$
"'
92 ::VIM::command 'highlight link CommandTSelection Visual'
93 ::VIM::command 'highlight link CommandTNoEntries Error'
94 ::VIM::evaluate 'clearmatches()'
97 @cursor_highlight = get_cursor_highlight
101 # perform cleanup using an autocmd to ensure we don't get caught out
102 # by some unexpected means of dismissing or leaving the Command-T window
103 # (eg. <C-W q>, <C-W k> etc)
104 ::VIM::command 'autocmd! * <buffer
>'
105 ::VIM::command 'autocmd BufLeave
<buffer
> ruby
$command_t.leave
'
106 ::VIM::command 'autocmd BufUnload
<buffer
> ruby
$command_t.unload
'
115 # Workaround for upstream bug in Vim 7.3 on some platforms
117 # On some platforms, $curbuf.number always returns 0. One workaround is
118 # to build Vim with --disable-largefile, but as this is producing lots of
119 # support requests, implement the following fallback to the buffer name
120 # instead, at least until upstream gets fixed.
122 # For more details, see: https://wincent.com/issues/1617
123 if $curbuf.number == 0
124 # use bwipeout as bunload fails if passed the name of a hidden buffer
125 ::VIM::command 'bwipeout! GoToFile
'
128 ::VIM::command "bunload! #{@@buffer.number}"
138 restore_window_dimensions
153 if @selection < @matches.length
- 1
155 print_match(@selection - 1) # redraw old selection (removes marker)
156 print_match(@selection) # redraw new selection (adds marker)
157 move_cursor_to_selected_line
159 # (possibly) loop or scroll
166 print_match(@selection +
1) # redraw old selection (removes marker)
167 print_match(@selection) # redraw new selection (adds marker)
168 move_cursor_to_selected_line
170 # (possibly) loop or scroll
175 matches
= matches
.reverse
if @reverse_list
176 if matches !
= @matches
178 @selection = @reverse_list ? @matches.length
- 1 : 0
180 move_cursor_to_selected_line
188 ::VIM::command 'highlight link CommandTSelection Search'
197 ::VIM::command 'highlight link CommandTSelection Visual'
203 # is this a new search or the continuation of a previous one?
205 if @last_key_time.nil? or @last_key_time < (now
- 0.5)
212 # see if there's anything up ahead that matches
213 @matches.each_with_index
do |match
, idx
|
214 if match
[0, @find_string.length
].casecmp(@find_string) == 0
215 old_selection
= @selection
217 print_match(old_selection
) # redraw old selection (removes marker)
218 print_match(@selection) # redraw new selection (adds marker)
224 # Returns the currently selected item as a String.
229 def print_no_such_file_or_directory
230 print_error
'NO SUCH FILE OR DIRECTORY'
235 def move_cursor_to_selected_line
236 # on some non-GUI terminals, the cursor doesn't hide properly
237 # so we move the cursor to prevent it from blinking away in the
238 # upper-left corner in a distracting fashion
239 @window.cursor
= [@selection +
1, 0]
243 return unless VIM
::Window.select(@window)
247 @
@buffer[1] = "-- #{msg} --"
251 def restore_window_dimensions
252 # sort from tallest to shortest
253 @windows.sort!
{ |a
, b
| b
.height
<=> a
.height
}
255 # starting with the tallest ensures that there are no constraints
256 # preventing windows on the side of vertical splits from regaining
257 # their original full size
259 # beware: window may be nil
260 window
= ::VIM::Window[w
.index
]
261 window
.height
= w
.height
if window
265 def match_text_for_idx idx
266 match
= truncated_match
@matches[idx
]
268 prefix
= @
@selection_marker
269 suffix
= padding_for_selected_match match
271 prefix
= @
@unselected_marker
274 prefix + match + suffix
277 # Print just the specified match.
279 return unless VIM
::Window.select(@window)
281 @
@buffer[idx +
1] = match_text_for_idx idx
287 match_count
= @matches.length
289 print_error
'NO MATCHES'
291 return unless VIM
::Window.select(@window)
295 @window_width = @window.width
# update cached value
296 max_lines
= VIM
::Screen.lines
- 5
297 max_lines
= 1 if max_lines
< 0
298 actual_lines
= match_count
> max_lines
? max_lines
: match_count
299 @window.height
= actual_lines
300 (1..actual_lines
).each
do |line
|
302 if @
@buffer.count
>= line
303 @
@buffer[line
] = match_text_for_idx idx
305 @
@buffer.append line
- 1, match_text_for_idx(idx
)
312 # Prepare padding for match text (trailing spaces) so that selection
313 # highlighting extends all the way to the right edge of the window.
314 def padding_for_selected_match str
316 if len
>= @window_width - @
@marker_length
319 ' ' * (@window_width - @
@marker_length - len
)
323 # Convert "really/long/path" into "really...path" based on available
325 def truncated_match str
327 available_width
= @window_width - @
@marker_length
328 return str
if len
<= available_width
329 left
= (available_width
/ 2) - 1
330 right
= (available_width
/ 2) - 2 +
(available_width
% 2)
331 str
[0, left
] +
'...' + str
[-right
, right
]
335 # range = % (whole buffer)
336 # action = d (delete)
337 # register = _ (black hole register, don't record deleted text)
338 ::VIM::command 'silent %d _'
341 def get_cursor_highlight
342 # as :highlight returns nothing and only prints,
343 # must redirect its output to a variable
344 ::VIM::command 'silent redir => g:command_t_cursor_highlight'
346 # force 0 verbosity to ensure origin information isn't printed as well
347 ::VIM::command 'silent! 0verbose highlight Cursor
'
348 ::VIM::command 'silent redir END
'
350 # there are 3 possible formats to check for, each needing to be
351 # transformed in a certain way in order to reapply the highlight:
352 # Cursor xxx guifg=bg guibg=fg -> :hi! Cursor guifg
=bg guibg
=fg
353 # Cursor xxx links to SomethingElse -> :hi! link Cursor SomethingElse
354 # Cursor xxx cleared -> :hi! clear Cursor
355 highlight
= ::VIM::evaluate 'g:command_t_cursor_highlight'
356 if highlight
=~
/^Cursor\s+xxx\s+links to (\w+)/
357 "link Cursor #{$~[1]}"
358 elsif highlight
=~
/^Cursor\s+xxx\s+cleared/
360 elsif highlight
=~
/Cursor\s+xxx\s+(.+)/
362 else # likely cause E411 Cursor highlight group not found
369 ::VIM::command 'highlight Cursor NONE'
375 ::VIM::command "highlight #{@cursor_highlight}"
380 ::VIM::command 'setlocal nomodifiable'
384 ::VIM::command 'setlocal modifiable'