utils 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +68 -0
- data/VERSION +1 -0
- data/bin/chroot-exec +12 -0
- data/bin/chroot-libs +18 -0
- data/bin/classify +37 -0
- data/bin/discover +137 -0
- data/bin/edit +74 -0
- data/bin/errf +32 -0
- data/bin/git-empty +8 -0
- data/bin/myex +90 -0
- data/bin/number_files +26 -0
- data/bin/same_files +37 -0
- data/bin/search +205 -0
- data/bin/sedit +3 -0
- data/bin/sshscreen +68 -0
- data/bin/term +21 -0
- data/bin/unquarantine_apps +8 -0
- data/bin/untest +17 -0
- data/bin/utils-install-config +10 -0
- data/bin/vacuum_firefox_sqlite +22 -0
- data/bin/xmp +74 -0
- data/lib/utils.rb +8 -0
- data/lib/utils/config.rb +23 -0
- data/lib/utils/config/gdb/asm +179 -0
- data/lib/utils/config/gdb/ruby +528 -0
- data/lib/utils/config/gdbinit +8 -0
- data/lib/utils/config/irbrc +455 -0
- data/lib/utils/config/rdebugrc +2 -0
- data/lib/utils/config/screenrc +143 -0
- data/lib/utils/config/vim/autoload/Align.vim +1029 -0
- data/lib/utils/config/vim/autoload/AlignMaps.vim +330 -0
- data/lib/utils/config/vim/autoload/rails.vim +4744 -0
- data/lib/utils/config/vim/autoload/rubycomplete.vim +801 -0
- data/lib/utils/config/vim/autoload/sqlcomplete.vim +741 -0
- data/lib/utils/config/vim/autoload/vimball.vim +750 -0
- data/lib/utils/config/vim/colors/flori.vim +113 -0
- data/lib/utils/config/vim/compiler/eruby.vim +40 -0
- data/lib/utils/config/vim/compiler/ruby.vim +67 -0
- data/lib/utils/config/vim/compiler/rubyunit.vim +34 -0
- data/lib/utils/config/vim/ftdetect/ragel.vim +2 -0
- data/lib/utils/config/vim/ftdetect/ruby.vim +17 -0
- data/lib/utils/config/vim/ftplugin/eruby.vim +100 -0
- data/lib/utils/config/vim/ftplugin/ruby.vim +260 -0
- data/lib/utils/config/vim/ftplugin/xml.vim +941 -0
- data/lib/utils/config/vim/indent/IndentAnything_html.vim +35 -0
- data/lib/utils/config/vim/indent/eruby.vim +77 -0
- data/lib/utils/config/vim/indent/javascript.vim +116 -0
- data/lib/utils/config/vim/indent/ruby.vim +377 -0
- data/lib/utils/config/vim/plugin/AlignMapsPlugin.vim +242 -0
- data/lib/utils/config/vim/plugin/AlignPlugin.vim +41 -0
- data/lib/utils/config/vim/plugin/Decho.vim +592 -0
- data/lib/utils/config/vim/plugin/IndentAnything.vim +675 -0
- data/lib/utils/config/vim/plugin/bufexplorer.vim +1144 -0
- data/lib/utils/config/vim/plugin/cecutil.vim +482 -0
- data/lib/utils/config/vim/plugin/fugitive.vim +1703 -0
- data/lib/utils/config/vim/plugin/lusty-explorer.vim +1509 -0
- data/lib/utils/config/vim/plugin/rails.vim +340 -0
- data/lib/utils/config/vim/plugin/rubyextra.vim +193 -0
- data/lib/utils/config/vim/plugin/surround.vim +628 -0
- data/lib/utils/config/vim/plugin/taglist.vim +4546 -0
- data/lib/utils/config/vim/plugin/test/IndentAnything/test.js +131 -0
- data/lib/utils/config/vim/plugin/vimballPlugin.vim +40 -0
- data/lib/utils/config/vim/syntax/Decho.vim +101 -0
- data/lib/utils/config/vim/syntax/eruby.vim +73 -0
- data/lib/utils/config/vim/syntax/javascript.vim +246 -0
- data/lib/utils/config/vim/syntax/ragel.vim +165 -0
- data/lib/utils/config/vim/syntax/ruby.vim +367 -0
- data/lib/utils/config/vimrc +461 -0
- data/lib/utils/file.rb +49 -0
- data/lib/utils/find.rb +54 -0
- data/lib/utils/md5.rb +23 -0
- data/lib/utils/patterns.rb +34 -0
- data/lib/utils/version.rb +8 -0
- data/utils.gemspec +33 -0
- metadata +183 -0
@@ -0,0 +1,1509 @@
|
|
1
|
+
" Copyright: Copyright (C) 2007-2010 Stephen Bach
|
2
|
+
" Permission is hereby granted to use and distribute this code,
|
3
|
+
" with or without modifications, provided that this copyright
|
4
|
+
" notice is copied with it. Like anything else that's free,
|
5
|
+
" lusty-explorer.vim is provided *as is* and comes with no
|
6
|
+
" warranty of any kind, either expressed or implied. In no
|
7
|
+
" event will the copyright holder be liable for any damages
|
8
|
+
" resulting from the use of this software.
|
9
|
+
"
|
10
|
+
" Name Of File: lusty-explorer.vim
|
11
|
+
" Description: Dynamic Filesystem and Buffer Explorer Vim Plugin
|
12
|
+
" Maintainers: Stephen Bach <this-file@sjbach.com>
|
13
|
+
" Matt Tolton <matt-lusty-explorer@tolton.com>
|
14
|
+
" Contributors: Raimon Grau, Sergey Popov, Yuichi Tateno, Bernhard Walle,
|
15
|
+
" Rajendra Badapanda, cho45, Simo Salminen, Sami Samhuri,
|
16
|
+
" Matt Tolton, Björn Winckler, sowill
|
17
|
+
"
|
18
|
+
" Release Date: March 3, 2010
|
19
|
+
" Version: 2.1.3
|
20
|
+
" Inspired by Viewglob, Emacs, and by Jeff Lanzarotta's Buffer
|
21
|
+
" Explorer plugin.
|
22
|
+
"
|
23
|
+
" Usage: To launch the explorers:
|
24
|
+
"
|
25
|
+
" <Leader>lf - Opens the filesystem explorer.
|
26
|
+
" <Leader>lr - Opens the filesystem explorer from the parent
|
27
|
+
" directory of the current file.
|
28
|
+
" <Leader>lb - Opens the buffer explorer.
|
29
|
+
"
|
30
|
+
" You can also use the commands:
|
31
|
+
"
|
32
|
+
" ":FilesystemExplorer"
|
33
|
+
" ":FilesystemExplorerFromHere"
|
34
|
+
" ":BufferExplorer"
|
35
|
+
"
|
36
|
+
" (Personally, I map these to ,f and ,r and ,b)
|
37
|
+
"
|
38
|
+
" The interface is intuitive. When one of the explorers is
|
39
|
+
" launched, a new window appears at bottom presenting a list of
|
40
|
+
" files/dirs or buffers, and in the status bar is a prompt:
|
41
|
+
"
|
42
|
+
" >>
|
43
|
+
"
|
44
|
+
" As you type, the list updates for possible matches using a
|
45
|
+
" fuzzy matching algorithm. Special keys include:
|
46
|
+
"
|
47
|
+
" <Enter> open the selected match
|
48
|
+
" <Tab> open the selected match
|
49
|
+
" <Esc> cancel
|
50
|
+
" <C-c> cancel
|
51
|
+
" <C-g> cancel
|
52
|
+
"
|
53
|
+
" <C-t> open the selected match in a new tab
|
54
|
+
" <C-n> select the next match
|
55
|
+
" <C-p> select the previous match
|
56
|
+
" <C-w> ascend one directory at prompt
|
57
|
+
" <C-u> clear the prompt
|
58
|
+
"
|
59
|
+
" Additional shortcuts for the filesystem explorer:
|
60
|
+
"
|
61
|
+
" <C-r> refresh directory contents
|
62
|
+
" <C-a> open all files in the current list
|
63
|
+
" <C-e> create a new file with the given name
|
64
|
+
"
|
65
|
+
" Buffer Explorer:
|
66
|
+
" - The currently active buffer is highlighted.
|
67
|
+
" - Buffers are listed without path unless needed to differentiate buffers of
|
68
|
+
" the same name.
|
69
|
+
"
|
70
|
+
" Filesystem Explorer:
|
71
|
+
" - Directory contents are memoized.
|
72
|
+
" - You can recurse into and out of directories by typing the directory name
|
73
|
+
" and a slash, e.g. "stuff/" or "../".
|
74
|
+
" - Variable expansion, e.g. "$D" -> "/long/dir/path/".
|
75
|
+
" - Tilde (~) expansion, e.g. "~/" -> "/home/steve/".
|
76
|
+
" - Dotfiles are hidden by default, but are shown if the current search term
|
77
|
+
" begins with a '.'. To show these file at all times, set this option:
|
78
|
+
"
|
79
|
+
" let g:LustyExplorerAlwaysShowDotFiles = 1
|
80
|
+
"
|
81
|
+
" You can prevent certain files from appearing in the directory listings with
|
82
|
+
" the following variable:
|
83
|
+
"
|
84
|
+
" set wildignore=*.o,*.fasl,CVS
|
85
|
+
"
|
86
|
+
" The above example will mask all object files, compiled lisp files, and
|
87
|
+
" files/directories named CVS from appearing in the filesystem explorer.
|
88
|
+
" Note that they can still be opened by being named explicitly.
|
89
|
+
"
|
90
|
+
" See :help 'wildignore' for more information.
|
91
|
+
"
|
92
|
+
"
|
93
|
+
" Install Details:
|
94
|
+
"
|
95
|
+
" Copy this file into your $HOME/.vim/plugin directory so that it will be
|
96
|
+
" sourced on startup automatically.
|
97
|
+
"
|
98
|
+
" Note! This plugin requires Vim be compiled with Ruby interpretation. If you
|
99
|
+
" don't know if your build of Vim has this functionality, you can check by
|
100
|
+
" running "vim --version" from the command line and looking for "+ruby".
|
101
|
+
" Alternatively, just try sourcing this script.
|
102
|
+
"
|
103
|
+
" If your version of Vim does not have "+ruby" but you would still like to
|
104
|
+
" use this plugin, you can fix it. See the "Check for Ruby functionality"
|
105
|
+
" comment below for instructions.
|
106
|
+
"
|
107
|
+
" If you are using the same Vim configuration and plugins for multiple
|
108
|
+
" machines, some of which have Ruby and some of which don't, you may want to
|
109
|
+
" turn off the "Sorry, LustyExplorer requires ruby" warning. You can do so
|
110
|
+
" like this (in .vimrc):
|
111
|
+
"
|
112
|
+
" let g:LustyExplorerSuppressRubyWarning = 1
|
113
|
+
"
|
114
|
+
" GetLatestVimScripts: 1890 1 :AutoInstall: lusty-explorer.vim
|
115
|
+
"
|
116
|
+
" TODO:
|
117
|
+
" - when an edited file is in nowrap mode and the explorer is called while the
|
118
|
+
" current window is scrolled to the right, name truncation occurs.
|
119
|
+
" - bug: NO ENTRIES is not red when input is a space
|
120
|
+
" - happens because LustyExpMatch declares after LustyExpNoEntries.
|
121
|
+
" - if new_hash == previous_hash, don't bother 'repainting'.
|
122
|
+
|
123
|
+
" Exit quickly when already loaded.
|
124
|
+
if exists("g:loaded_lustyexplorer")
|
125
|
+
finish
|
126
|
+
endif
|
127
|
+
|
128
|
+
if exists("g:FuzzyFinderMode.TextMate")
|
129
|
+
echohl WarningMsg
|
130
|
+
echo "Warning: LustyExplorer detects the presence of fuzzyfinder_textmate;"
|
131
|
+
echo "that plugin sometimes interacts poorly with other Ruby plugins."
|
132
|
+
echohl none
|
133
|
+
endif
|
134
|
+
|
135
|
+
" Check for Ruby functionality.
|
136
|
+
if !has("ruby") || version < 700
|
137
|
+
if !exists("g:LustyExplorerSuppressRubyWarning") ||
|
138
|
+
\ g:LustyExplorerSuppressRubyWarning == "0"
|
139
|
+
if !exists("g:LustyJugglerSuppressRubyWarning") ||
|
140
|
+
\ g:LustyJugglerSuppressRubyWarning == "0"
|
141
|
+
echohl ErrorMsg
|
142
|
+
echon "Sorry, LustyExplorer requires ruby. "
|
143
|
+
echon "Here are some tips for adding it:\n"
|
144
|
+
|
145
|
+
echo "Debian / Ubuntu:"
|
146
|
+
echo " # apt-get install vim-ruby\n"
|
147
|
+
|
148
|
+
echo "Fedora:"
|
149
|
+
echo " # yum install vim-enhanced\n"
|
150
|
+
|
151
|
+
echo "Gentoo:"
|
152
|
+
echo " # USE=\"ruby\" emerge vim\n"
|
153
|
+
|
154
|
+
echo "FreeBSD:"
|
155
|
+
echo " # pkg_add -r vim+ruby\n"
|
156
|
+
|
157
|
+
echo "Windows:"
|
158
|
+
echo " 1. Download and install Ruby from here:"
|
159
|
+
echo " http://www.ruby-lang.org/"
|
160
|
+
echo " 2. Install a Vim binary with Ruby support:"
|
161
|
+
echo " http://segfault.hasno.info/vim/gvim72.zip\n"
|
162
|
+
|
163
|
+
echo "Manually (including Cygwin):"
|
164
|
+
echo " 1. Install Ruby."
|
165
|
+
echo " 2. Download the Vim source package (say, vim-7.0.tar.bz2)"
|
166
|
+
echo " 3. Build and install:"
|
167
|
+
echo " # tar -xvjf vim-7.0.tar.bz2"
|
168
|
+
echo " # ./configure --enable-rubyinterp"
|
169
|
+
echo " # make && make install"
|
170
|
+
|
171
|
+
echo "(If you just wish to stifle this message, set the following option:"
|
172
|
+
echo " let g:LustyJugglerSuppressRubyWarning = 1)"
|
173
|
+
echohl none
|
174
|
+
endif
|
175
|
+
endif
|
176
|
+
finish
|
177
|
+
endif
|
178
|
+
|
179
|
+
let g:loaded_lustyexplorer = "yep"
|
180
|
+
|
181
|
+
" Commands.
|
182
|
+
command BufferExplorer :call <SID>BufferExplorerStart()
|
183
|
+
command FilesystemExplorer :call <SID>FilesystemExplorerStart()
|
184
|
+
command FilesystemExplorerFromHere :call <SID>FilesystemExplorerStartFromHere()
|
185
|
+
|
186
|
+
" Default mappings.
|
187
|
+
nmap <silent> <Leader>lf :FilesystemExplorer<CR>
|
188
|
+
nmap <silent> <Leader>lr :FilesystemExplorerFromHere<CR>
|
189
|
+
nmap <silent> <Leader>lb :BufferExplorer<CR>
|
190
|
+
|
191
|
+
" Old mappings (from DynamicExplorer).
|
192
|
+
nmap <silent> <Leader>df :FilesystemExplorer<CR>
|
193
|
+
nmap <silent> <Leader>db :BufferExplorer<CR>
|
194
|
+
|
195
|
+
" Vim-to-ruby function calls.
|
196
|
+
function! s:FilesystemExplorerStart()
|
197
|
+
ruby $filesystem_explorer.run_from_wd
|
198
|
+
endfunction
|
199
|
+
|
200
|
+
function! s:FilesystemExplorerStartFromHere()
|
201
|
+
ruby $filesystem_explorer.run_from_here
|
202
|
+
endfunction
|
203
|
+
|
204
|
+
function! s:BufferExplorerStart()
|
205
|
+
ruby $buffer_explorer.run
|
206
|
+
endfunction
|
207
|
+
|
208
|
+
function! FilesystemExplorerCancel()
|
209
|
+
ruby $filesystem_explorer.cancel
|
210
|
+
endfunction
|
211
|
+
|
212
|
+
function! BufferExplorerCancel()
|
213
|
+
ruby $buffer_explorer.cancel
|
214
|
+
endfunction
|
215
|
+
|
216
|
+
function! FilesystemExplorerKeyPressed(code_arg)
|
217
|
+
ruby $filesystem_explorer.key_pressed
|
218
|
+
endfunction
|
219
|
+
|
220
|
+
function! BufferExplorerKeyPressed(code_arg)
|
221
|
+
ruby $buffer_explorer.key_pressed
|
222
|
+
endfunction
|
223
|
+
|
224
|
+
" Setup the autocommands that handle buffer MRU ordering.
|
225
|
+
"augroup LustyExplorer
|
226
|
+
" autocmd!
|
227
|
+
" autocmd BufEnter * ruby Window.buffer_stack.push
|
228
|
+
" autocmd BufDelete * ruby Window.buffer_stack.pop
|
229
|
+
" autocmd BufWipeout * ruby Window.buffer_stack.pop
|
230
|
+
"augroup End
|
231
|
+
|
232
|
+
ruby << EOF
|
233
|
+
require 'pathname'
|
234
|
+
# Needed for String#each_char in Ruby 1.8 on some platforms
|
235
|
+
require 'jcode' unless "".respond_to? :each_char
|
236
|
+
|
237
|
+
$PROFILING = false
|
238
|
+
|
239
|
+
if $PROFILING
|
240
|
+
require 'rubygems'
|
241
|
+
require 'ruby-prof'
|
242
|
+
end
|
243
|
+
|
244
|
+
class String
|
245
|
+
def ends_with?(s)
|
246
|
+
tail = self[-s.length, s.length]
|
247
|
+
tail == s
|
248
|
+
end
|
249
|
+
|
250
|
+
def starts_with?(s)
|
251
|
+
head = self[0, s.length]
|
252
|
+
head == s
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
class IO
|
257
|
+
def ready_for_read?
|
258
|
+
result = IO.select([self], nil, nil, 0)
|
259
|
+
result && (result.first.first == self)
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
class File
|
264
|
+
def self.simplify_path(s)
|
265
|
+
begin
|
266
|
+
if s[0] == '~'[0]
|
267
|
+
s = File.expand_path(s.sub(/\/.*/,'')) + \
|
268
|
+
s.sub(/^[^\/]+/,'')
|
269
|
+
end
|
270
|
+
|
271
|
+
if s.ends_with?(File::SEPARATOR)
|
272
|
+
File.expand_path(s) + File::SEPARATOR
|
273
|
+
else
|
274
|
+
File.expand_path(File.dirname(s)) + File::SEPARATOR + File.basename(s)
|
275
|
+
end
|
276
|
+
rescue ArgumentError
|
277
|
+
s
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
module VIM
|
283
|
+
def self.zero?(var)
|
284
|
+
# In Vim 7.2 and older, VIM::evaluate returns Strings for boolean
|
285
|
+
# expressions; in later versions, Fixnums.
|
286
|
+
case var
|
287
|
+
when String
|
288
|
+
var == "0"
|
289
|
+
when Fixnum
|
290
|
+
var == 0
|
291
|
+
else
|
292
|
+
assert(false, "unexpected type: #{var.class}")
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
def self.nonzero?(var)
|
297
|
+
not(self.zero? var)
|
298
|
+
end
|
299
|
+
|
300
|
+
def self.has_syntax?
|
301
|
+
VIM::nonzero? eva('has("syntax")')
|
302
|
+
end
|
303
|
+
|
304
|
+
def self.columns
|
305
|
+
eva("&columns").to_i
|
306
|
+
end
|
307
|
+
|
308
|
+
def self.lines
|
309
|
+
eva("&lines").to_i
|
310
|
+
end
|
311
|
+
|
312
|
+
def self.getcwd
|
313
|
+
eva("getcwd()")
|
314
|
+
end
|
315
|
+
|
316
|
+
def self.single_quote_escape(s)
|
317
|
+
# Everything in a Vim single quoted string is literal, except single quotes.
|
318
|
+
# Single quotes are escaped by doubling them.
|
319
|
+
s.gsub("'", "''")
|
320
|
+
end
|
321
|
+
|
322
|
+
def self.filename_escape(s)
|
323
|
+
# Escape slashes, open square braces, spaces, sharps, and double quotes.
|
324
|
+
s.gsub(/\\/, '\\\\\\').gsub(/[\[ #"]/, '\\\\\0')
|
325
|
+
end
|
326
|
+
|
327
|
+
def self.regex_escape(s)
|
328
|
+
s.gsub(/[\]\[.~"^$\\*]/,'\\\\\0')
|
329
|
+
end
|
330
|
+
|
331
|
+
class Buffer
|
332
|
+
def modified?
|
333
|
+
VIM::nonzero? eva("getbufvar(#{number()}, '&modified')")
|
334
|
+
end
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
def lusty_option_set?(opt_name)
|
339
|
+
opt_name = "g:LustyExplorer" + opt_name
|
340
|
+
VIM::nonzero? eva("exists('#{opt_name}') && #{opt_name} != '0'")
|
341
|
+
end
|
342
|
+
|
343
|
+
# Port of Ryan McGeary's LiquidMetal fuzzy matching algorithm found at:
|
344
|
+
# http://github.com/rmm5t/liquidmetal/tree/master.
|
345
|
+
class LiquidMetal
|
346
|
+
@@SCORE_NO_MATCH = 0.0
|
347
|
+
@@SCORE_MATCH = 1.0
|
348
|
+
@@SCORE_TRAILING = 0.8
|
349
|
+
@@SCORE_TRAILING_BUT_STARTED = 0.90
|
350
|
+
@@SCORE_BUFFER = 0.85
|
351
|
+
|
352
|
+
def self.score(string, abbrev)
|
353
|
+
|
354
|
+
return @@SCORE_TRAILING if abbrev.empty?
|
355
|
+
return @@SCORE_NO_MATCH if abbrev.length > string.length
|
356
|
+
|
357
|
+
scores = buildScoreArray(string, abbrev)
|
358
|
+
|
359
|
+
sum = scores.inject { |a, b| a + b }
|
360
|
+
|
361
|
+
return sum / scores.length;
|
362
|
+
end
|
363
|
+
|
364
|
+
def self.buildScoreArray(string, abbrev)
|
365
|
+
scores = Array.new(string.length)
|
366
|
+
lower = string.downcase()
|
367
|
+
|
368
|
+
lastIndex = -1
|
369
|
+
started = false
|
370
|
+
|
371
|
+
abbrev.downcase().each_char do |c|
|
372
|
+
index = lower.index(c, lastIndex + 1)
|
373
|
+
return scores.fill(@@SCORE_NO_MATCH, 0..-1) if index.nil?
|
374
|
+
started = true if index == 0
|
375
|
+
|
376
|
+
if index > 0 and " \t/._-".include?(string[index - 1])
|
377
|
+
scores[index - 1] = @@SCORE_MATCH
|
378
|
+
scores.fill(@@SCORE_BUFFER, (lastIndex + 1)...(index - 1))
|
379
|
+
elsif string[index] >= "A"[0] and string[index] <= "Z"[0]
|
380
|
+
scores.fill(@@SCORE_BUFFER, (lastIndex + 1)...index)
|
381
|
+
else
|
382
|
+
scores.fill(@@SCORE_NO_MATCH, (lastIndex + 1)...index)
|
383
|
+
end
|
384
|
+
|
385
|
+
scores[index] = @@SCORE_MATCH
|
386
|
+
lastIndex = index
|
387
|
+
end
|
388
|
+
|
389
|
+
trailing_score = started ? @@SCORE_TRAILING_BUT_STARTED : @@SCORE_TRAILING
|
390
|
+
scores.fill(trailing_score, lastIndex + 1)
|
391
|
+
return scores
|
392
|
+
end
|
393
|
+
end
|
394
|
+
|
395
|
+
# Used in FilesystemExplorer
|
396
|
+
class Entry
|
397
|
+
attr_accessor :name, :current_score
|
398
|
+
def initialize(name)
|
399
|
+
@name = name
|
400
|
+
@current_score = 0.0
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|
404
|
+
# Used in BufferExplorer
|
405
|
+
class BufferEntry < Entry
|
406
|
+
attr_accessor :full_name, :vim_buffer
|
407
|
+
def initialize(vim_buffer)
|
408
|
+
@full_name = vim_buffer.name
|
409
|
+
@vim_buffer = vim_buffer
|
410
|
+
@name = "::UNSET::"
|
411
|
+
@current_score = 0.0
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
415
|
+
class LustyExplorer
|
416
|
+
public
|
417
|
+
def initialize
|
418
|
+
@settings = SavedSettings.new
|
419
|
+
@displayer = Displayer.new title()
|
420
|
+
@prompt = nil
|
421
|
+
@ordered_matching_entries = []
|
422
|
+
@running = false
|
423
|
+
end
|
424
|
+
|
425
|
+
def run
|
426
|
+
return if @running
|
427
|
+
|
428
|
+
if $PROFILING
|
429
|
+
RubyProf.measure_mode = RubyProf::WALL_TIME
|
430
|
+
end
|
431
|
+
|
432
|
+
@settings.save
|
433
|
+
@running = true
|
434
|
+
@calling_window = $curwin
|
435
|
+
@saved_alternate_bufnum = if VIM::nonzero? eva("expand('#') == ''")
|
436
|
+
nil
|
437
|
+
else
|
438
|
+
eva("bufnr(expand('#'))")
|
439
|
+
end
|
440
|
+
@selected_index = 0
|
441
|
+
create_explorer_window()
|
442
|
+
refresh(:full)
|
443
|
+
end
|
444
|
+
|
445
|
+
def key_pressed()
|
446
|
+
# Grab argument from the Vim function.
|
447
|
+
i = eva("a:code_arg").to_i
|
448
|
+
refresh_mode = :full
|
449
|
+
|
450
|
+
case i
|
451
|
+
when 32..126 # Printable characters
|
452
|
+
c = i.chr
|
453
|
+
@prompt.add! c
|
454
|
+
@selected_index = 0
|
455
|
+
when 8 # Backspace/Del/C-h
|
456
|
+
@prompt.backspace!
|
457
|
+
@selected_index = 0
|
458
|
+
when 9, 13 # Tab and Enter
|
459
|
+
choose(:current_tab)
|
460
|
+
@selected_index = 0
|
461
|
+
when 23 # C-w (delete 1 dir backward)
|
462
|
+
@prompt.up_one_dir!
|
463
|
+
@selected_index = 0
|
464
|
+
when 14 # C-n (select next)
|
465
|
+
@selected_index = \
|
466
|
+
(@selected_index + 1) % @ordered_matching_entries.size
|
467
|
+
refresh_mode = :no_recompute
|
468
|
+
when 16 # C-p (select previous)
|
469
|
+
@selected_index = \
|
470
|
+
(@selected_index - 1) % @ordered_matching_entries.size
|
471
|
+
refresh_mode = :no_recompute
|
472
|
+
when 20 # C-t choose in new tab
|
473
|
+
choose(:new_tab)
|
474
|
+
@selected_index = 0
|
475
|
+
when 21 # C-u clear prompt
|
476
|
+
@prompt.clear!
|
477
|
+
@selected_index = 0
|
478
|
+
end
|
479
|
+
|
480
|
+
refresh(refresh_mode)
|
481
|
+
end
|
482
|
+
|
483
|
+
def cancel
|
484
|
+
if @running
|
485
|
+
cleanup()
|
486
|
+
# fix alternate file
|
487
|
+
if @saved_alternate_bufnum
|
488
|
+
cur = $curbuf
|
489
|
+
exe "silent b #{@saved_alternate_bufnum}"
|
490
|
+
exe "silent b #{cur.number}"
|
491
|
+
end
|
492
|
+
|
493
|
+
if $PROFILING
|
494
|
+
#outfile = File.new('rbprof.txt', 'a')
|
495
|
+
#RubyProf::CallTreePrinter.new(RubyProf.stop).print(outfile)
|
496
|
+
outfile = File.new('rbprof.html', 'a')
|
497
|
+
RubyProf::GraphHtmlPrinter.new(RubyProf.stop).print(outfile)
|
498
|
+
end
|
499
|
+
end
|
500
|
+
end
|
501
|
+
|
502
|
+
private
|
503
|
+
def refresh(mode)
|
504
|
+
return if not @running
|
505
|
+
|
506
|
+
if mode == :full
|
507
|
+
@ordered_matching_entries = compute_ordered_matching_entries()
|
508
|
+
end
|
509
|
+
|
510
|
+
on_refresh()
|
511
|
+
highlight_selected_index()
|
512
|
+
@displayer.print @ordered_matching_entries.map { |x| x.name }
|
513
|
+
@prompt.print
|
514
|
+
end
|
515
|
+
|
516
|
+
def create_explorer_window
|
517
|
+
|
518
|
+
@displayer.create
|
519
|
+
|
520
|
+
# Setup key mappings to reroute user input.
|
521
|
+
|
522
|
+
# Non-special printable characters.
|
523
|
+
printables = '/!"#$%&\'()*+,-.0123456789:<=>?#@"' \
|
524
|
+
'ABCDEFGHIJKLMNOPQRSTUVWXYZ' \
|
525
|
+
'[]^_`abcdefghijklmnopqrstuvwxyz{}~'
|
526
|
+
|
527
|
+
map_command = "noremap <silent> <buffer> "
|
528
|
+
|
529
|
+
printables.each_byte do |b|
|
530
|
+
exe "#{map_command} <Char-#{b}> :call #{self.class}KeyPressed(#{b})<CR>"
|
531
|
+
end
|
532
|
+
|
533
|
+
# Special characters
|
534
|
+
exe "#{map_command} <Tab> :call #{self.class}KeyPressed(9)<CR>"
|
535
|
+
exe "#{map_command} <Bslash> :call #{self.class}KeyPressed(92)<CR>"
|
536
|
+
exe "#{map_command} <Space> :call #{self.class}KeyPressed(32)<CR>"
|
537
|
+
exe "#{map_command} \026| :call #{self.class}KeyPressed(124)<CR>"
|
538
|
+
|
539
|
+
exe "#{map_command} <BS> :call #{self.class}KeyPressed(8)<CR>"
|
540
|
+
exe "#{map_command} <Del> :call #{self.class}KeyPressed(8)<CR>"
|
541
|
+
exe "#{map_command} <C-h> :call #{self.class}KeyPressed(8)<CR>"
|
542
|
+
|
543
|
+
exe "#{map_command} <CR> :call #{self.class}KeyPressed(13)<CR>"
|
544
|
+
exe "#{map_command} <S-CR> :call #{self.class}KeyPressed(10)<CR>"
|
545
|
+
exe "#{map_command} <C-a> :call #{self.class}KeyPressed(1)<CR>"
|
546
|
+
|
547
|
+
exe "#{map_command} <Esc> :call #{self.class}Cancel()<CR>"
|
548
|
+
exe "#{map_command} <C-c> :call #{self.class}Cancel()<CR>"
|
549
|
+
exe "#{map_command} <C-g> :call #{self.class}Cancel()<CR>"
|
550
|
+
|
551
|
+
exe "#{map_command} <C-w> :call #{self.class}KeyPressed(23)<CR>"
|
552
|
+
exe "#{map_command} <C-n> :call #{self.class}KeyPressed(14)<CR>"
|
553
|
+
exe "#{map_command} <C-p> :call #{self.class}KeyPressed(16)<CR>"
|
554
|
+
exe "#{map_command} <C-t> :call #{self.class}KeyPressed(20)<CR>"
|
555
|
+
exe "#{map_command} <C-e> :call #{self.class}KeyPressed(5)<CR>"
|
556
|
+
exe "#{map_command} <C-r> :call #{self.class}KeyPressed(18)<CR>"
|
557
|
+
exe "#{map_command} <C-u> :call #{self.class}KeyPressed(21)<CR>"
|
558
|
+
end
|
559
|
+
|
560
|
+
def highlight_selected_index
|
561
|
+
return unless VIM::has_syntax?
|
562
|
+
|
563
|
+
entry = @ordered_matching_entries[@selected_index]
|
564
|
+
return if entry.nil?
|
565
|
+
|
566
|
+
exe "syn clear LustyExpSelected"
|
567
|
+
exe "syn match LustyExpSelected " \
|
568
|
+
"\"#{Displayer.vim_match_string(entry.name, false)}\" "
|
569
|
+
end
|
570
|
+
|
571
|
+
def compute_ordered_matching_entries
|
572
|
+
abbrev = current_abbreviation()
|
573
|
+
unordered = matching_entries()
|
574
|
+
|
575
|
+
# Sort alphabetically if there's just a dot or we have no abbreviation,
|
576
|
+
# otherwise it just looks weird.
|
577
|
+
if abbrev.length == 0 or abbrev == '.'
|
578
|
+
unordered.sort! { |x, y| x.name <=> y.name }
|
579
|
+
else
|
580
|
+
# Sort by score.
|
581
|
+
unordered.sort! { |x, y| y.current_score <=> x.current_score }
|
582
|
+
end
|
583
|
+
end
|
584
|
+
|
585
|
+
def matching_entries
|
586
|
+
all_entries().select { |x|
|
587
|
+
x.current_score = LiquidMetal.score(x.name, current_abbreviation())
|
588
|
+
x.current_score != 0.0
|
589
|
+
}
|
590
|
+
end
|
591
|
+
|
592
|
+
def choose(open_mode)
|
593
|
+
entry = @ordered_matching_entries[@selected_index]
|
594
|
+
return if entry.nil?
|
595
|
+
@selected_index = 0
|
596
|
+
open_entry(entry, open_mode)
|
597
|
+
end
|
598
|
+
|
599
|
+
def cleanup
|
600
|
+
@displayer.close
|
601
|
+
Window.select @calling_window
|
602
|
+
@settings.restore
|
603
|
+
@running = false
|
604
|
+
msg ""
|
605
|
+
assert(@calling_window == $curwin)
|
606
|
+
end
|
607
|
+
end
|
608
|
+
|
609
|
+
|
610
|
+
class BufferExplorer < LustyExplorer
|
611
|
+
public
|
612
|
+
def initialize
|
613
|
+
super
|
614
|
+
@prompt = Prompt.new
|
615
|
+
@buffer_entries = []
|
616
|
+
end
|
617
|
+
|
618
|
+
def run
|
619
|
+
unless @running
|
620
|
+
@prompt.clear!
|
621
|
+
@curbuf_at_start = VIM::Buffer.current
|
622
|
+
fill_buffer_entries()
|
623
|
+
super
|
624
|
+
end
|
625
|
+
end
|
626
|
+
|
627
|
+
private
|
628
|
+
def title
|
629
|
+
'[LustyExplorer-Buffers]'
|
630
|
+
end
|
631
|
+
|
632
|
+
def curbuf_match_string
|
633
|
+
curbuf = @buffer_entries.find { |x| x.vim_buffer == @curbuf_at_start }
|
634
|
+
if curbuf
|
635
|
+
Displayer.vim_match_string(curbuf.name, @prompt.insensitive?)
|
636
|
+
else
|
637
|
+
""
|
638
|
+
end
|
639
|
+
end
|
640
|
+
|
641
|
+
def on_refresh
|
642
|
+
# Highlighting for the current buffer name.
|
643
|
+
if VIM::has_syntax?
|
644
|
+
exe 'syn clear LustyExpCurrentBuffer'
|
645
|
+
exe "syn match LustyExpCurrentBuffer \"#{curbuf_match_string()}\" " \
|
646
|
+
'contains=LustyExpModified'
|
647
|
+
end
|
648
|
+
end
|
649
|
+
|
650
|
+
def common_prefix(entries)
|
651
|
+
prefix = entries[0].full_name
|
652
|
+
entries.each do |entry|
|
653
|
+
full_name = entry.full_name
|
654
|
+
for i in 0...prefix.length
|
655
|
+
if full_name.length <= i or prefix[i] != full_name[i]
|
656
|
+
prefix = prefix[0...i]
|
657
|
+
prefix = prefix[0..(prefix.rindex('/') or -1)]
|
658
|
+
break
|
659
|
+
end
|
660
|
+
end
|
661
|
+
end
|
662
|
+
return prefix
|
663
|
+
end
|
664
|
+
|
665
|
+
def fill_buffer_entries
|
666
|
+
@buffer_entries.clear
|
667
|
+
(0..VIM::Buffer.count-1).each do |i|
|
668
|
+
@buffer_entries << BufferEntry.new(VIM::Buffer[i])
|
669
|
+
end
|
670
|
+
|
671
|
+
# Shorten each buffer name by removing all path elements which are not
|
672
|
+
# needed to differentiate a given name from other names. This usually
|
673
|
+
# results in only the basename shown, but if several buffers of the
|
674
|
+
# same basename are opened, there will be more.
|
675
|
+
|
676
|
+
# Group the buffers by common basename
|
677
|
+
common_base = Hash.new { |hash, k| hash[k] = [] }
|
678
|
+
@buffer_entries.each do |entry|
|
679
|
+
if entry.full_name
|
680
|
+
basename = Pathname.new(entry.full_name).basename.to_s
|
681
|
+
common_base[basename] << entry
|
682
|
+
end
|
683
|
+
end
|
684
|
+
|
685
|
+
# Determine the longest common prefix for each basename group.
|
686
|
+
basename_to_prefix = {}
|
687
|
+
common_base.each do |base, entries|
|
688
|
+
if entries.length > 1
|
689
|
+
basename_to_prefix[base] = common_prefix(entries)
|
690
|
+
end
|
691
|
+
end
|
692
|
+
|
693
|
+
# Compute shortened buffer names by removing prefix, if possible.
|
694
|
+
@buffer_entries.each do |entry|
|
695
|
+
full_name = entry.full_name
|
696
|
+
|
697
|
+
short_name = if full_name.nil?
|
698
|
+
'[No Name]'
|
699
|
+
elsif full_name.starts_with?("scp://")
|
700
|
+
full_name
|
701
|
+
else
|
702
|
+
base = Pathname.new(full_name).basename.to_s
|
703
|
+
prefix = basename_to_prefix[base]
|
704
|
+
|
705
|
+
prefix ? full_name[prefix.length..-1] \
|
706
|
+
: base
|
707
|
+
end
|
708
|
+
|
709
|
+
# Disabled: show buffer number next to name
|
710
|
+
#short_name += ' ' + buffer.number.to_s
|
711
|
+
|
712
|
+
# Show modification indicator
|
713
|
+
short_name += entry.vim_buffer.modified? ? " [+]" : ""
|
714
|
+
|
715
|
+
entry.name = short_name
|
716
|
+
end
|
717
|
+
end
|
718
|
+
|
719
|
+
def current_abbreviation
|
720
|
+
@prompt.input
|
721
|
+
end
|
722
|
+
|
723
|
+
def all_entries
|
724
|
+
@buffer_entries
|
725
|
+
end
|
726
|
+
|
727
|
+
def open_entry(entry, open_mode)
|
728
|
+
cleanup()
|
729
|
+
assert($curwin == @calling_window)
|
730
|
+
|
731
|
+
number = entry.vim_buffer.number
|
732
|
+
assert(number)
|
733
|
+
|
734
|
+
cmd = case open_mode
|
735
|
+
when :current_tab
|
736
|
+
"b"
|
737
|
+
when :new_tab
|
738
|
+
# For some reason just using tabe or e gives an error when
|
739
|
+
# the alternate-file isn't set.
|
740
|
+
"tab split | b"
|
741
|
+
else
|
742
|
+
assert(false, "bad open mode")
|
743
|
+
end
|
744
|
+
|
745
|
+
exe "silent #{cmd} #{number}"
|
746
|
+
end
|
747
|
+
end
|
748
|
+
|
749
|
+
def time
|
750
|
+
if $PROFILING
|
751
|
+
RubyProf.resume
|
752
|
+
end
|
753
|
+
begin
|
754
|
+
yield
|
755
|
+
rescue Exception => e
|
756
|
+
puts e
|
757
|
+
puts e.backtrace
|
758
|
+
end
|
759
|
+
if $PROFILING
|
760
|
+
RubyProf.pause
|
761
|
+
end
|
762
|
+
end
|
763
|
+
|
764
|
+
class FilesystemExplorer < LustyExplorer
|
765
|
+
public
|
766
|
+
def initialize
|
767
|
+
super
|
768
|
+
@prompt = FilesystemPrompt.new
|
769
|
+
@memoized_entries = {}
|
770
|
+
end
|
771
|
+
|
772
|
+
def run
|
773
|
+
FileMasks.create_glob_masks()
|
774
|
+
@vim_swaps = VimSwaps.new
|
775
|
+
super
|
776
|
+
end
|
777
|
+
|
778
|
+
def run_from_here
|
779
|
+
start_path = if $curbuf.name.nil?
|
780
|
+
VIM::getcwd()
|
781
|
+
else
|
782
|
+
eva("expand('%:p:h')")
|
783
|
+
end
|
784
|
+
|
785
|
+
@prompt.set!(start_path + File::SEPARATOR)
|
786
|
+
run()
|
787
|
+
end
|
788
|
+
|
789
|
+
def run_from_wd
|
790
|
+
@prompt.set!(VIM::getcwd() + File::SEPARATOR)
|
791
|
+
run()
|
792
|
+
end
|
793
|
+
|
794
|
+
def key_pressed()
|
795
|
+
time do
|
796
|
+
i = eva("a:code_arg").to_i
|
797
|
+
|
798
|
+
case i
|
799
|
+
when 1, 10 # <C-a>, <Shift-Enter>
|
800
|
+
cleanup()
|
801
|
+
# Open all non-directories currently in view.
|
802
|
+
@ordered_matching_entries.each do |e|
|
803
|
+
path_str = \
|
804
|
+
if @prompt.at_dir?
|
805
|
+
@prompt.input + e.name
|
806
|
+
else
|
807
|
+
@prompt.dirname + File::SEPARATOR + e.name
|
808
|
+
end
|
809
|
+
|
810
|
+
load_file(path_str, :current_tab) unless File.directory?(path_str)
|
811
|
+
end
|
812
|
+
when 5 # <C-e> edit file, create it if necessary
|
813
|
+
if not @prompt.at_dir?
|
814
|
+
cleanup()
|
815
|
+
# Force a reread of this directory so that the new file will
|
816
|
+
# show up (as long as it is saved before the next run).
|
817
|
+
@memoized_entries.delete(view_path())
|
818
|
+
load_file(@prompt.input, :current_tab)
|
819
|
+
end
|
820
|
+
when 18 # <C-r> refresh
|
821
|
+
@memoized_entries.delete(view_path())
|
822
|
+
refresh(:full)
|
823
|
+
else
|
824
|
+
super
|
825
|
+
end
|
826
|
+
end
|
827
|
+
end
|
828
|
+
|
829
|
+
private
|
830
|
+
def title
|
831
|
+
'[LustyExplorer-Files]'
|
832
|
+
end
|
833
|
+
|
834
|
+
def on_refresh
|
835
|
+
if VIM::has_syntax?
|
836
|
+
exe 'syn clear LustyExpFileWithSwap'
|
837
|
+
|
838
|
+
view = view_path()
|
839
|
+
@vim_swaps.file_names.each do |file_with_swap|
|
840
|
+
if file_with_swap.dirname == view
|
841
|
+
base = file_with_swap.basename
|
842
|
+
match_str = Displayer.vim_match_string(base.to_s, false)
|
843
|
+
exe "syn match LustyExpFileWithSwap \"#{match_str}\""
|
844
|
+
end
|
845
|
+
end
|
846
|
+
end
|
847
|
+
|
848
|
+
# TODO: restore highlighting for open buffers?
|
849
|
+
end
|
850
|
+
|
851
|
+
def current_abbreviation
|
852
|
+
if @prompt.at_dir?
|
853
|
+
""
|
854
|
+
else
|
855
|
+
File.basename(@prompt.input)
|
856
|
+
end
|
857
|
+
end
|
858
|
+
|
859
|
+
def view_path
|
860
|
+
input = @prompt.input
|
861
|
+
|
862
|
+
path = \
|
863
|
+
if @prompt.at_dir? and \
|
864
|
+
input.length > 1 # Not root
|
865
|
+
# The last element in the path is a directory + '/' and we want to
|
866
|
+
# see what's in it instead of what's in its parent directory.
|
867
|
+
|
868
|
+
Pathname.new(input[0..-2]) # Canonicalize by removing trailing '/'
|
869
|
+
else
|
870
|
+
Pathname.new(input).dirname
|
871
|
+
end
|
872
|
+
|
873
|
+
return path
|
874
|
+
end
|
875
|
+
|
876
|
+
def all_entries
|
877
|
+
view = view_path()
|
878
|
+
|
879
|
+
if not view.exist?
|
880
|
+
return []
|
881
|
+
elsif not view.readable?
|
882
|
+
# TODO: show "-- PERMISSION DENIED --"
|
883
|
+
return []
|
884
|
+
end
|
885
|
+
|
886
|
+
unless @memoized_entries.has_key?(view)
|
887
|
+
# Generate an array of the files
|
888
|
+
entries = []
|
889
|
+
view.each_entry do |file|
|
890
|
+
name = file.basename.to_s
|
891
|
+
next if name == "." # Skip pwd
|
892
|
+
next if name == ".." and lusty_option_set?("AlwaysShowDotFiles")
|
893
|
+
|
894
|
+
# Hide masked files.
|
895
|
+
next if FileMasks.masked?(name)
|
896
|
+
|
897
|
+
if (view + file).directory?
|
898
|
+
# ^^ bug in Pathname.each_entry -- block variable has no dir.
|
899
|
+
name += File::SEPARATOR
|
900
|
+
end
|
901
|
+
entries << Entry.new(name)
|
902
|
+
end
|
903
|
+
@memoized_entries[view] = entries
|
904
|
+
end
|
905
|
+
|
906
|
+
all = @memoized_entries[view]
|
907
|
+
|
908
|
+
if lusty_option_set?("AlwaysShowDotFiles") or \
|
909
|
+
current_abbreviation()[0] == '.'[0]
|
910
|
+
all
|
911
|
+
else
|
912
|
+
# Filter out dotfiles if the current abbreviation doesn't start with
|
913
|
+
# '.'.
|
914
|
+
all.select { |x| x.name[0] != '.'[0] }
|
915
|
+
end
|
916
|
+
end
|
917
|
+
|
918
|
+
def open_entry(entry, open_mode)
|
919
|
+
path = view_path() + entry.name
|
920
|
+
|
921
|
+
if File.directory?(path)
|
922
|
+
# Recurse into the directory instead of opening it.
|
923
|
+
@prompt.set!(path.to_s)
|
924
|
+
elsif entry.name.include?(File::SEPARATOR)
|
925
|
+
# Don't open a fake file/buffer with "/" in its name.
|
926
|
+
return
|
927
|
+
else
|
928
|
+
cleanup()
|
929
|
+
load_file(path.to_s, open_mode)
|
930
|
+
end
|
931
|
+
end
|
932
|
+
|
933
|
+
def load_file(path_str, open_mode)
|
934
|
+
assert($curwin == @calling_window)
|
935
|
+
# Escape for Vim and remove leading ./ for files in pwd.
|
936
|
+
escaped = VIM::filename_escape(path_str).sub(/^\.\//,"")
|
937
|
+
sanitized = eva "fnamemodify('#{escaped}', ':.')"
|
938
|
+
cmd = case open_mode
|
939
|
+
when :current_tab
|
940
|
+
"e"
|
941
|
+
when :new_tab
|
942
|
+
"tabe"
|
943
|
+
else
|
944
|
+
assert(false, "bad open mode")
|
945
|
+
end
|
946
|
+
|
947
|
+
exe "silent #{cmd} #{sanitized}"
|
948
|
+
end
|
949
|
+
end
|
950
|
+
|
951
|
+
|
952
|
+
class Prompt
|
953
|
+
private
|
954
|
+
@@PROMPT = ">> "
|
955
|
+
|
956
|
+
public
|
957
|
+
def initialize
|
958
|
+
clear!
|
959
|
+
end
|
960
|
+
|
961
|
+
def clear!
|
962
|
+
@input = ""
|
963
|
+
end
|
964
|
+
|
965
|
+
def print
|
966
|
+
pretty_msg("Comment", @@PROMPT, "None", @input, "Underlined", " ")
|
967
|
+
end
|
968
|
+
|
969
|
+
def set!(s)
|
970
|
+
@input = s
|
971
|
+
end
|
972
|
+
|
973
|
+
def input
|
974
|
+
@input
|
975
|
+
end
|
976
|
+
|
977
|
+
def insensitive?
|
978
|
+
@input == @input.downcase
|
979
|
+
end
|
980
|
+
|
981
|
+
def ends_with?(c)
|
982
|
+
@input.ends_with? c
|
983
|
+
end
|
984
|
+
|
985
|
+
def add!(s)
|
986
|
+
@input += s
|
987
|
+
end
|
988
|
+
|
989
|
+
def backspace!
|
990
|
+
@input.chop!
|
991
|
+
end
|
992
|
+
|
993
|
+
def up_one_dir!
|
994
|
+
@input.chop!
|
995
|
+
while !@input.empty? and @input[-1] != '/'[0]
|
996
|
+
@input.chop!
|
997
|
+
end
|
998
|
+
end
|
999
|
+
end
|
1000
|
+
|
1001
|
+
class FilesystemPrompt < Prompt
|
1002
|
+
|
1003
|
+
def initialize
|
1004
|
+
super
|
1005
|
+
@memoized = nil
|
1006
|
+
@dirty = true
|
1007
|
+
end
|
1008
|
+
|
1009
|
+
def clear!
|
1010
|
+
@dirty = true
|
1011
|
+
super
|
1012
|
+
end
|
1013
|
+
|
1014
|
+
def set!(s)
|
1015
|
+
@dirty = true
|
1016
|
+
# On Windows, Vim will return paths with a '\' separator, but
|
1017
|
+
# we want to use '/'.
|
1018
|
+
super(s.gsub('\\', '/'))
|
1019
|
+
end
|
1020
|
+
|
1021
|
+
def backspace!
|
1022
|
+
@dirty = true
|
1023
|
+
super
|
1024
|
+
end
|
1025
|
+
|
1026
|
+
def up_one_dir!
|
1027
|
+
@dirty = true
|
1028
|
+
super
|
1029
|
+
end
|
1030
|
+
|
1031
|
+
def at_dir?
|
1032
|
+
# We have not typed anything yet or have just typed the final '/' on a
|
1033
|
+
# directory name in pwd. This check is interspersed throughout
|
1034
|
+
# FilesystemExplorer because of the conventions of basename and dirname.
|
1035
|
+
input().empty? or input().ends_with?(File::SEPARATOR)
|
1036
|
+
# Don't think the File.directory? call is necessary, but leaving this
|
1037
|
+
# here as a reminder.
|
1038
|
+
#(File.directory?(input()) and input().ends_with?(File::SEPARATOR))
|
1039
|
+
end
|
1040
|
+
|
1041
|
+
def insensitive?
|
1042
|
+
at_dir? or (basename() == basename().downcase)
|
1043
|
+
end
|
1044
|
+
|
1045
|
+
def add!(s)
|
1046
|
+
# Assumption: add!() will only receive enough chars at a time to complete
|
1047
|
+
# a single directory level, e.g. foo/, not foo/bar/
|
1048
|
+
|
1049
|
+
@input += s
|
1050
|
+
@dirty = true
|
1051
|
+
end
|
1052
|
+
|
1053
|
+
def input
|
1054
|
+
if @dirty
|
1055
|
+
@memoized = variable_expansion(File.simplify_path(@input))
|
1056
|
+
@dirty = false
|
1057
|
+
end
|
1058
|
+
|
1059
|
+
@memoized
|
1060
|
+
end
|
1061
|
+
|
1062
|
+
def basename
|
1063
|
+
File.basename input()
|
1064
|
+
end
|
1065
|
+
|
1066
|
+
def dirname
|
1067
|
+
File.dirname input()
|
1068
|
+
end
|
1069
|
+
|
1070
|
+
private
|
1071
|
+
def variable_expansion (input_str)
|
1072
|
+
# FIXME does this still work?
|
1073
|
+
strings = input_str.split('$', -1)
|
1074
|
+
return "" if strings.nil? or strings.length == 0
|
1075
|
+
|
1076
|
+
first = strings.shift
|
1077
|
+
|
1078
|
+
# Try to expand each instance of $<word>.
|
1079
|
+
strings.inject(first) { |str, s|
|
1080
|
+
if s =~ /^(\w+)/ and ENV[$1]
|
1081
|
+
str + s.sub($1, ENV[$1])
|
1082
|
+
else
|
1083
|
+
str + "$" + s
|
1084
|
+
end
|
1085
|
+
}
|
1086
|
+
end
|
1087
|
+
end
|
1088
|
+
|
1089
|
+
# Simplify switching between windows.
|
1090
|
+
class Window
|
1091
|
+
def Window.select(window)
|
1092
|
+
return true if window == $curwin
|
1093
|
+
|
1094
|
+
start = $curwin
|
1095
|
+
|
1096
|
+
# Try to select the given window.
|
1097
|
+
begin
|
1098
|
+
exe "wincmd w"
|
1099
|
+
end while ($curwin != window) and ($curwin != start)
|
1100
|
+
|
1101
|
+
if $curwin == window
|
1102
|
+
return true
|
1103
|
+
else
|
1104
|
+
# Failed -- re-select the starting window.
|
1105
|
+
exe("wincmd w") while $curwin != start
|
1106
|
+
pretty_msg("ErrorMsg", "Cannot find the correct window!")
|
1107
|
+
return false
|
1108
|
+
end
|
1109
|
+
end
|
1110
|
+
end
|
1111
|
+
|
1112
|
+
# Save and restore settings when creating the explorer buffer.
|
1113
|
+
class SavedSettings
|
1114
|
+
def initialize
|
1115
|
+
save()
|
1116
|
+
end
|
1117
|
+
|
1118
|
+
def save
|
1119
|
+
@timeoutlen = eva "&timeoutlen"
|
1120
|
+
|
1121
|
+
@splitbelow = VIM::nonzero? eva("&splitbelow")
|
1122
|
+
@insertmode = VIM::nonzero? eva("&insertmode")
|
1123
|
+
@showcmd = VIM::nonzero? eva("&showcmd")
|
1124
|
+
@list = VIM::nonzero? eva("&list")
|
1125
|
+
|
1126
|
+
@report = eva "&report"
|
1127
|
+
@sidescroll = eva "&sidescroll"
|
1128
|
+
@sidescrolloff = eva "&sidescrolloff"
|
1129
|
+
end
|
1130
|
+
|
1131
|
+
def restore
|
1132
|
+
set "timeoutlen=#{@timeoutlen}"
|
1133
|
+
|
1134
|
+
if @splitbelow
|
1135
|
+
set "splitbelow"
|
1136
|
+
else
|
1137
|
+
set "nosplitbelow"
|
1138
|
+
end
|
1139
|
+
|
1140
|
+
if @insertmode
|
1141
|
+
set "insertmode"
|
1142
|
+
else
|
1143
|
+
set "noinsertmode"
|
1144
|
+
end
|
1145
|
+
|
1146
|
+
if @showcmd
|
1147
|
+
set "showcmd"
|
1148
|
+
else
|
1149
|
+
set "noshowcmd"
|
1150
|
+
end
|
1151
|
+
|
1152
|
+
if @list
|
1153
|
+
set "list"
|
1154
|
+
else
|
1155
|
+
set "nolist"
|
1156
|
+
end
|
1157
|
+
|
1158
|
+
exe "set report=#{@report}"
|
1159
|
+
exe "set sidescroll=#{@sidescroll}"
|
1160
|
+
exe "set sidescrolloff=#{@sidescrolloff}"
|
1161
|
+
end
|
1162
|
+
end
|
1163
|
+
|
1164
|
+
# Manage the explorer buffer.
|
1165
|
+
class Displayer
|
1166
|
+
private
|
1167
|
+
@@COLUMN_SEPARATOR = " "
|
1168
|
+
@@NO_ENTRIES_STRING = "-- NO ENTRIES --"
|
1169
|
+
@@TRUNCATED_STRING = "-- TRUNCATED --"
|
1170
|
+
|
1171
|
+
public
|
1172
|
+
def Displayer.vim_match_string(s, case_insensitive)
|
1173
|
+
# Create a match regex string for the given s. This is for a Vim regex,
|
1174
|
+
# not for a Ruby regex.
|
1175
|
+
|
1176
|
+
str = '\%(^\|' + @@COLUMN_SEPARATOR + '\)' \
|
1177
|
+
'\zs' + VIM::regex_escape(s) + '\%( \[+\]\)\?' + '\ze' \
|
1178
|
+
'\%(\s*$\|' + @@COLUMN_SEPARATOR + '\)'
|
1179
|
+
|
1180
|
+
str += '\c' if case_insensitive
|
1181
|
+
|
1182
|
+
return str
|
1183
|
+
end
|
1184
|
+
|
1185
|
+
def initialize(title)
|
1186
|
+
@title = title
|
1187
|
+
@window = nil
|
1188
|
+
@buffer = nil
|
1189
|
+
end
|
1190
|
+
|
1191
|
+
def create
|
1192
|
+
# Make a window for the displayer and move there.
|
1193
|
+
exe "silent! botright split #{@title}"
|
1194
|
+
|
1195
|
+
@window = $curwin
|
1196
|
+
@buffer = $curbuf
|
1197
|
+
|
1198
|
+
# Displayer buffer is special.
|
1199
|
+
exe "setlocal bufhidden=delete"
|
1200
|
+
exe "setlocal buftype=nofile"
|
1201
|
+
exe "setlocal nomodifiable"
|
1202
|
+
exe "setlocal noswapfile"
|
1203
|
+
exe "setlocal nowrap"
|
1204
|
+
exe "setlocal nonumber"
|
1205
|
+
exe "setlocal foldcolumn=0"
|
1206
|
+
exe "setlocal nocursorline"
|
1207
|
+
exe "setlocal nospell"
|
1208
|
+
exe "setlocal nobuflisted"
|
1209
|
+
exe "setlocal textwidth=0"
|
1210
|
+
|
1211
|
+
# (Update SavedSettings if adding to below.)
|
1212
|
+
set "timeoutlen=0"
|
1213
|
+
set "noinsertmode"
|
1214
|
+
set "noshowcmd"
|
1215
|
+
set "nolist"
|
1216
|
+
set "report=9999"
|
1217
|
+
set "sidescroll=0"
|
1218
|
+
set "sidescrolloff=0"
|
1219
|
+
|
1220
|
+
# TODO -- cpoptions?
|
1221
|
+
|
1222
|
+
if VIM::has_syntax?
|
1223
|
+
exe 'syn match LustyExpSlash "/" contained'
|
1224
|
+
exe 'syn match LustyExpDir "\zs\%(\S\+ \)*\S\+/\ze" ' \
|
1225
|
+
'contains=LustyExpSlash'
|
1226
|
+
|
1227
|
+
exe 'syn match LustyExpModified " \[+\]"'
|
1228
|
+
|
1229
|
+
exe 'syn match LustyExpNoEntries "\%^\s*' \
|
1230
|
+
"#{@@NO_ENTRIES_STRING}" \
|
1231
|
+
'\s*\%$"'
|
1232
|
+
|
1233
|
+
exe 'syn match LustyExpTruncated "^\s*' \
|
1234
|
+
"#{@@TRUNCATED_STRING}" \
|
1235
|
+
'\s*$"'
|
1236
|
+
|
1237
|
+
exe 'highlight link LustyExpDir Directory'
|
1238
|
+
exe 'highlight link LustyExpSlash Function'
|
1239
|
+
exe 'highlight link LustyExpSelected Type'
|
1240
|
+
exe 'highlight link LustyExpModified Special'
|
1241
|
+
exe 'highlight link LustyExpCurrentBuffer Constant'
|
1242
|
+
exe 'highlight link LustyExpOpenedFile PreProc'
|
1243
|
+
exe 'highlight link LustyExpFileWithSwap WarningMsg'
|
1244
|
+
exe 'highlight link LustyExpNoEntries ErrorMsg'
|
1245
|
+
exe 'highlight link LustyExpTruncated Visual'
|
1246
|
+
end
|
1247
|
+
end
|
1248
|
+
|
1249
|
+
def print(strings)
|
1250
|
+
Window.select(@window) || return
|
1251
|
+
|
1252
|
+
if strings.empty?
|
1253
|
+
print_no_entries()
|
1254
|
+
return
|
1255
|
+
end
|
1256
|
+
|
1257
|
+
# Perhaps truncate the results to just over the upper bound of
|
1258
|
+
# displayable strings. This isn't exact, but it's close enough.
|
1259
|
+
max = VIM::lines * (VIM::columns / (1 + @@COLUMN_SEPARATOR.length))
|
1260
|
+
if strings.length > max
|
1261
|
+
strings.slice!(max, strings.length - max)
|
1262
|
+
end
|
1263
|
+
|
1264
|
+
# Get a high upper bound on the number of columns to display to optimize
|
1265
|
+
# the following algorithm a little.
|
1266
|
+
col_count = column_count_upper_bound(strings)
|
1267
|
+
|
1268
|
+
# Figure out the actual number of columns to use (yuck)
|
1269
|
+
cols = nil
|
1270
|
+
widths = nil
|
1271
|
+
while col_count > 1 do
|
1272
|
+
|
1273
|
+
cols = columnize(strings, col_count);
|
1274
|
+
|
1275
|
+
widths = cols.map { |col|
|
1276
|
+
col.max { |a, b| a.length <=> b.length }.length
|
1277
|
+
}
|
1278
|
+
|
1279
|
+
full_width = widths.inject { |sum, n| sum + n }
|
1280
|
+
full_width += @@COLUMN_SEPARATOR.length * (col_count - 1)
|
1281
|
+
|
1282
|
+
if full_width <= $curwin.width
|
1283
|
+
break
|
1284
|
+
end
|
1285
|
+
|
1286
|
+
col_count -= 1
|
1287
|
+
end
|
1288
|
+
|
1289
|
+
if col_count <= 1
|
1290
|
+
cols = [strings]
|
1291
|
+
widths = [0]
|
1292
|
+
end
|
1293
|
+
|
1294
|
+
print_columns(cols, widths)
|
1295
|
+
end
|
1296
|
+
|
1297
|
+
def close
|
1298
|
+
# Only wipe the buffer if we're *sure* it's the explorer.
|
1299
|
+
if Window.select @window and \
|
1300
|
+
$curbuf == @buffer and \
|
1301
|
+
$curbuf.name =~ /#{Regexp.escape(@title)}$/
|
1302
|
+
exe "bwipeout!"
|
1303
|
+
@window = nil
|
1304
|
+
@buffer = nil
|
1305
|
+
end
|
1306
|
+
end
|
1307
|
+
|
1308
|
+
private
|
1309
|
+
def print_columns(cols, widths)
|
1310
|
+
unlock_and_clear()
|
1311
|
+
|
1312
|
+
# Set the height to the height of the longest column.
|
1313
|
+
$curwin.height = cols.max { |a, b| a.length <=> b.length }.length
|
1314
|
+
|
1315
|
+
(0..$curwin.height-1).each do |i|
|
1316
|
+
|
1317
|
+
string = ""
|
1318
|
+
(0..cols.length-1).each do |j|
|
1319
|
+
break if cols[j][i].nil?
|
1320
|
+
string += cols[j][i]
|
1321
|
+
string += " " * [(widths[j] - cols[j][i].length), 0].max
|
1322
|
+
string += @@COLUMN_SEPARATOR
|
1323
|
+
end
|
1324
|
+
|
1325
|
+
# Stretch the line to the length of the window with whitespace so that
|
1326
|
+
# we can "hide" the cursor in the corner.
|
1327
|
+
string += " " * [($curwin.width - string.length), 0].max
|
1328
|
+
|
1329
|
+
$curwin.cursor = [i+1, 1]
|
1330
|
+
$curbuf.append(i, string)
|
1331
|
+
end
|
1332
|
+
|
1333
|
+
# Check for result truncation.
|
1334
|
+
if cols[0][$curwin.height]
|
1335
|
+
# Show a truncation indicator.
|
1336
|
+
$curbuf.delete($curbuf.count - 1)
|
1337
|
+
$curwin.cursor = [$curbuf.count, 1]
|
1338
|
+
$curbuf.append($curbuf.count - 1, \
|
1339
|
+
@@TRUNCATED_STRING.center($curwin.width, " "))
|
1340
|
+
end
|
1341
|
+
|
1342
|
+
# There's a blank line at the end of the buffer because of how
|
1343
|
+
# VIM::Buffer.append works.
|
1344
|
+
$curbuf.delete $curbuf.count
|
1345
|
+
lock()
|
1346
|
+
end
|
1347
|
+
|
1348
|
+
def print_no_entries
|
1349
|
+
unlock_and_clear()
|
1350
|
+
$curwin.height = 1
|
1351
|
+
|
1352
|
+
$curbuf[1] = @@NO_ENTRIES_STRING.center($curwin.width, " ")
|
1353
|
+
lock()
|
1354
|
+
end
|
1355
|
+
|
1356
|
+
def unlock_and_clear
|
1357
|
+
exe "setlocal modifiable"
|
1358
|
+
|
1359
|
+
# Clear the explorer (black hole register)
|
1360
|
+
exe "silent %d _"
|
1361
|
+
end
|
1362
|
+
|
1363
|
+
def lock
|
1364
|
+
exe "setlocal nomodifiable"
|
1365
|
+
|
1366
|
+
# Hide the cursor
|
1367
|
+
exe "normal! Gg$"
|
1368
|
+
end
|
1369
|
+
|
1370
|
+
# Get a starting upper bound on the number of columns
|
1371
|
+
def column_count_upper_bound(strings)
|
1372
|
+
column_count = 0
|
1373
|
+
length = 0
|
1374
|
+
|
1375
|
+
sorted_by_length = strings.sort {|x, y| x.length <=> y.length }
|
1376
|
+
|
1377
|
+
sorted_by_length.each do |e|
|
1378
|
+
length += e.length
|
1379
|
+
break unless length < $curwin.width
|
1380
|
+
|
1381
|
+
column_count += 1
|
1382
|
+
length += @@COLUMN_SEPARATOR.length
|
1383
|
+
end
|
1384
|
+
|
1385
|
+
return column_count
|
1386
|
+
end
|
1387
|
+
|
1388
|
+
def columnize(strings, n_cols)
|
1389
|
+
n_rows = (strings.length.to_f / n_cols).ceil
|
1390
|
+
|
1391
|
+
# Break the array into sub arrays representing columns
|
1392
|
+
cols = []
|
1393
|
+
0.step(strings.size-1, n_rows) do |i|
|
1394
|
+
cols << strings[i..(i + n_rows - 1)]
|
1395
|
+
end
|
1396
|
+
return cols
|
1397
|
+
end
|
1398
|
+
end
|
1399
|
+
|
1400
|
+
|
1401
|
+
class FileMasks
|
1402
|
+
private
|
1403
|
+
@@glob_masks = []
|
1404
|
+
|
1405
|
+
public
|
1406
|
+
def FileMasks.create_glob_masks
|
1407
|
+
@@glob_masks = \
|
1408
|
+
if VIM::nonzero? eva('exists("g:LustyExplorerFileMasks")')
|
1409
|
+
# Note: this variable deprecated.
|
1410
|
+
eva("g:LustyExplorerFileMasks").split(',')
|
1411
|
+
elsif VIM::nonzero? eva('exists("&wildignore")')
|
1412
|
+
eva("&wildignore").split(',')
|
1413
|
+
else
|
1414
|
+
[]
|
1415
|
+
end
|
1416
|
+
end
|
1417
|
+
|
1418
|
+
def FileMasks.masked?(str)
|
1419
|
+
@@glob_masks.each do |mask|
|
1420
|
+
return true if File.fnmatch(mask, str)
|
1421
|
+
end
|
1422
|
+
|
1423
|
+
return false
|
1424
|
+
end
|
1425
|
+
end
|
1426
|
+
|
1427
|
+
class VimSwaps
|
1428
|
+
def initialize
|
1429
|
+
if VIM::has_syntax?
|
1430
|
+
# FIXME: vvv disabled
|
1431
|
+
# @vim_r = IO.popen("vim -r 2>&1")
|
1432
|
+
# @files_with_swaps = nil
|
1433
|
+
@files_with_swaps = []
|
1434
|
+
else
|
1435
|
+
@files_with_swaps = []
|
1436
|
+
end
|
1437
|
+
end
|
1438
|
+
|
1439
|
+
def file_names
|
1440
|
+
if @files_with_swaps.nil?
|
1441
|
+
if @vim_r.ready_for_read?
|
1442
|
+
@files_with_swaps = []
|
1443
|
+
@vim_r.each_line do |line|
|
1444
|
+
if line =~ /^ +file name: (.*)$/
|
1445
|
+
file = $1.chomp
|
1446
|
+
@files_with_swaps << Pathname.new(File.simplify_path(file))
|
1447
|
+
end
|
1448
|
+
end
|
1449
|
+
else
|
1450
|
+
return []
|
1451
|
+
end
|
1452
|
+
end
|
1453
|
+
|
1454
|
+
@files_with_swaps
|
1455
|
+
end
|
1456
|
+
end
|
1457
|
+
|
1458
|
+
|
1459
|
+
def d(s)
|
1460
|
+
# (Debug print)
|
1461
|
+
$stderr.puts s
|
1462
|
+
end
|
1463
|
+
|
1464
|
+
# Simple mappings to decrease typing.
|
1465
|
+
def exe(s)
|
1466
|
+
VIM.command s
|
1467
|
+
end
|
1468
|
+
|
1469
|
+
def eva(s)
|
1470
|
+
VIM.evaluate s
|
1471
|
+
end
|
1472
|
+
|
1473
|
+
def set(s)
|
1474
|
+
VIM.set_option s
|
1475
|
+
end
|
1476
|
+
|
1477
|
+
def msg(s)
|
1478
|
+
VIM.message s
|
1479
|
+
end
|
1480
|
+
|
1481
|
+
def pretty_msg(*rest)
|
1482
|
+
return if rest.length == 0
|
1483
|
+
return if rest.length % 2 != 0
|
1484
|
+
|
1485
|
+
exe "redraw" # see :help echo-redraw
|
1486
|
+
i = 0
|
1487
|
+
while i < rest.length do
|
1488
|
+
exe "echohl #{rest[i]}"
|
1489
|
+
exe "echon '#{rest[i+1]}'"
|
1490
|
+
i += 2
|
1491
|
+
end
|
1492
|
+
|
1493
|
+
exe 'echohl None'
|
1494
|
+
end
|
1495
|
+
|
1496
|
+
class AssertionError < StandardError
|
1497
|
+
end
|
1498
|
+
|
1499
|
+
def assert(condition, message = 'assertion failure')
|
1500
|
+
raise AssertionError.new(message) unless condition
|
1501
|
+
end
|
1502
|
+
|
1503
|
+
|
1504
|
+
$buffer_explorer = BufferExplorer.new
|
1505
|
+
$filesystem_explorer = FilesystemExplorer.new
|
1506
|
+
|
1507
|
+
EOF
|
1508
|
+
|
1509
|
+
" vim: set sts=2 sw=2:
|