utils 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. data/Rakefile +68 -0
  2. data/VERSION +1 -0
  3. data/bin/chroot-exec +12 -0
  4. data/bin/chroot-libs +18 -0
  5. data/bin/classify +37 -0
  6. data/bin/discover +137 -0
  7. data/bin/edit +74 -0
  8. data/bin/errf +32 -0
  9. data/bin/git-empty +8 -0
  10. data/bin/myex +90 -0
  11. data/bin/number_files +26 -0
  12. data/bin/same_files +37 -0
  13. data/bin/search +205 -0
  14. data/bin/sedit +3 -0
  15. data/bin/sshscreen +68 -0
  16. data/bin/term +21 -0
  17. data/bin/unquarantine_apps +8 -0
  18. data/bin/untest +17 -0
  19. data/bin/utils-install-config +10 -0
  20. data/bin/vacuum_firefox_sqlite +22 -0
  21. data/bin/xmp +74 -0
  22. data/lib/utils.rb +8 -0
  23. data/lib/utils/config.rb +23 -0
  24. data/lib/utils/config/gdb/asm +179 -0
  25. data/lib/utils/config/gdb/ruby +528 -0
  26. data/lib/utils/config/gdbinit +8 -0
  27. data/lib/utils/config/irbrc +455 -0
  28. data/lib/utils/config/rdebugrc +2 -0
  29. data/lib/utils/config/screenrc +143 -0
  30. data/lib/utils/config/vim/autoload/Align.vim +1029 -0
  31. data/lib/utils/config/vim/autoload/AlignMaps.vim +330 -0
  32. data/lib/utils/config/vim/autoload/rails.vim +4744 -0
  33. data/lib/utils/config/vim/autoload/rubycomplete.vim +801 -0
  34. data/lib/utils/config/vim/autoload/sqlcomplete.vim +741 -0
  35. data/lib/utils/config/vim/autoload/vimball.vim +750 -0
  36. data/lib/utils/config/vim/colors/flori.vim +113 -0
  37. data/lib/utils/config/vim/compiler/eruby.vim +40 -0
  38. data/lib/utils/config/vim/compiler/ruby.vim +67 -0
  39. data/lib/utils/config/vim/compiler/rubyunit.vim +34 -0
  40. data/lib/utils/config/vim/ftdetect/ragel.vim +2 -0
  41. data/lib/utils/config/vim/ftdetect/ruby.vim +17 -0
  42. data/lib/utils/config/vim/ftplugin/eruby.vim +100 -0
  43. data/lib/utils/config/vim/ftplugin/ruby.vim +260 -0
  44. data/lib/utils/config/vim/ftplugin/xml.vim +941 -0
  45. data/lib/utils/config/vim/indent/IndentAnything_html.vim +35 -0
  46. data/lib/utils/config/vim/indent/eruby.vim +77 -0
  47. data/lib/utils/config/vim/indent/javascript.vim +116 -0
  48. data/lib/utils/config/vim/indent/ruby.vim +377 -0
  49. data/lib/utils/config/vim/plugin/AlignMapsPlugin.vim +242 -0
  50. data/lib/utils/config/vim/plugin/AlignPlugin.vim +41 -0
  51. data/lib/utils/config/vim/plugin/Decho.vim +592 -0
  52. data/lib/utils/config/vim/plugin/IndentAnything.vim +675 -0
  53. data/lib/utils/config/vim/plugin/bufexplorer.vim +1144 -0
  54. data/lib/utils/config/vim/plugin/cecutil.vim +482 -0
  55. data/lib/utils/config/vim/plugin/fugitive.vim +1703 -0
  56. data/lib/utils/config/vim/plugin/lusty-explorer.vim +1509 -0
  57. data/lib/utils/config/vim/plugin/rails.vim +340 -0
  58. data/lib/utils/config/vim/plugin/rubyextra.vim +193 -0
  59. data/lib/utils/config/vim/plugin/surround.vim +628 -0
  60. data/lib/utils/config/vim/plugin/taglist.vim +4546 -0
  61. data/lib/utils/config/vim/plugin/test/IndentAnything/test.js +131 -0
  62. data/lib/utils/config/vim/plugin/vimballPlugin.vim +40 -0
  63. data/lib/utils/config/vim/syntax/Decho.vim +101 -0
  64. data/lib/utils/config/vim/syntax/eruby.vim +73 -0
  65. data/lib/utils/config/vim/syntax/javascript.vim +246 -0
  66. data/lib/utils/config/vim/syntax/ragel.vim +165 -0
  67. data/lib/utils/config/vim/syntax/ruby.vim +367 -0
  68. data/lib/utils/config/vimrc +461 -0
  69. data/lib/utils/file.rb +49 -0
  70. data/lib/utils/find.rb +54 -0
  71. data/lib/utils/md5.rb +23 -0
  72. data/lib/utils/patterns.rb +34 -0
  73. data/lib/utils/version.rb +8 -0
  74. data/utils.gemspec +33 -0
  75. 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: