command-t 1.6.1 → 1.7

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.
@@ -1,4 +1,4 @@
1
- # Copyright 2010-2013 Wincent Colaiuta. All rights reserved.
1
+ # Copyright 2010-2014 Wincent Colaiuta. All rights reserved.
2
2
  #
3
3
  # Redistribution and use in source and binary forms, with or without
4
4
  # modification, are permitted provided that the following conditions are met:
@@ -47,17 +47,16 @@ module CommandT
47
47
  :width => ::VIM::Window[i].width)
48
48
  end
49
49
 
50
- # global settings (must manually save and restore)
51
- @settings = Settings.new
52
- ::VIM::set_option 'timeout' # ensure mappings timeout
53
- ::VIM::set_option 'timeoutlen=0' # respond immediately to mappings
54
- ::VIM::set_option 'nohlsearch' # don't highlight search strings
55
- ::VIM::set_option 'noinsertmode' # don't make Insert mode the default
56
- ::VIM::set_option 'noshowcmd' # don't show command info on last line
57
- ::VIM::set_option 'report=9999' # don't show "X lines changed" reports
58
- ::VIM::set_option 'sidescroll=0' # don't sidescroll in jumps
59
- ::VIM::set_option 'sidescrolloff=0' # don't sidescroll automatically
60
- ::VIM::set_option 'noequalalways' # don't auto-balance window sizes
50
+ set 'timeout', true # ensure mappings timeout
51
+ set 'hlsearch', false # don't highlight search strings
52
+ set 'insertmode', false # don't make Insert mode the default
53
+ set 'showcmd', false # don't show command info on last line
54
+ set 'equalalways', false # don't auto-balance window sizes
55
+ set 'timeoutlen', 0 # respond immediately to mappings
56
+ set 'report', 9999 # don't show "X lines changed" reports
57
+ set 'sidescroll', 0 # don't sidescroll in jumps
58
+ set 'sidescrolloff', 0 # don't sidescroll automatically
59
+ set 'updatetime', options[:debounce_interval]
61
60
 
62
61
  # show match window
63
62
  split_location = options[:match_window_at_top] ? 'topleft' : 'botright'
@@ -66,29 +65,26 @@ module CommandT
66
65
  raise "Can't re-open GoToFile buffer" unless $curbuf.number == @@buffer.number
67
66
  $curwin.height = 1
68
67
  else # creating match window for first time and set it up
69
- split_command = "silent! #{split_location} 1split GoToFile"
70
- [
71
- split_command,
72
- 'setlocal bufhidden=unload', # unload buf when no longer displayed
73
- 'setlocal buftype=nofile', # buffer is not related to any file
74
- 'setlocal nomodifiable', # prevent manual edits
75
- 'setlocal noswapfile', # don't create a swapfile
76
- 'setlocal nowrap', # don't soft-wrap
77
- 'setlocal nonumber', # don't show line numbers
78
- 'setlocal nolist', # don't use List mode (visible tabs etc)
79
- 'setlocal foldcolumn=0', # don't show a fold column at side
80
- 'setlocal foldlevel=99', # don't fold anything
81
- 'setlocal nocursorline', # don't highlight line cursor is on
82
- 'setlocal nospell', # spell-checking off
83
- 'setlocal nobuflisted', # don't show up in the buffer list
84
- 'setlocal textwidth=0' # don't hard-wrap (break long lines)
85
- ].each { |command| ::VIM::command command }
68
+ ::VIM::command "silent! #{split_location} 1split GoToFile"
69
+ set 'bufhidden', 'unload' # unload buf when no longer displayed
70
+ set 'buftype', 'nofile' # buffer is not related to any file
71
+ set 'modifiable', false # prevent manual edits
72
+ set 'swapfile', false # don't create a swapfile
73
+ set 'wrap', false # don't soft-wrap
74
+ set 'number', false # don't show line numbers
75
+ set 'list', false # don't use List mode (visible tabs etc)
76
+ set 'foldcolumn', 0 # don't show a fold column at side
77
+ set 'foldlevel', 99 # don't fold anything
78
+ set 'cursorline', false # don't highlight line cursor is on
79
+ set 'spell', false # spell-checking off
80
+ set 'buflisted', false # don't show up in the buffer list
81
+ set 'textwidth', 0 # don't hard-wrap (break long lines)
86
82
 
87
83
  # don't show the color column
88
- ::VIM::command 'setlocal colorcolumn=0' if VIM::exists?('+colorcolumn')
84
+ set 'colorcolumn', 0 if VIM::exists?('+colorcolumn')
89
85
 
90
86
  # don't show relative line numbers
91
- ::VIM::command 'setlocal norelativenumber' if VIM::exists?('+relativenumber')
87
+ set 'relativenumber', false if VIM::exists?('+relativenumber')
92
88
 
93
89
  # sanity check: make sure the buffer really was created
94
90
  raise "Can't find GoToFile buffer" unless $curbuf.name.match /GoToFile\z/
@@ -100,11 +96,11 @@ module CommandT
100
96
  ::VIM::command "syntax match CommandTSelection \"^#{SELECTION_MARKER}.\\+$\""
101
97
  ::VIM::command 'syntax match CommandTNoEntries "^-- NO MATCHES --$"'
102
98
  ::VIM::command 'syntax match CommandTNoEntries "^-- NO SUCH FILE OR DIRECTORY --$"'
103
- ::VIM::command 'setlocal synmaxcol=9999'
99
+ set 'synmaxcol', 9999
104
100
 
105
101
  if VIM::has_conceal?
106
- ::VIM::command 'setlocal conceallevel=2'
107
- ::VIM::command 'setlocal concealcursor=nvic'
102
+ set 'conceallevel', 2
103
+ set 'concealcursor', 'nvic'
108
104
  ::VIM::command 'syntax region CommandTCharMatched ' \
109
105
  "matchgroup=CommandTCharMatched start=+#{MH_START}+ " \
110
106
  "matchgroup=CommandTCharMatchedEnd end=+#{MH_END}+ concealends"
@@ -115,7 +111,6 @@ module CommandT
115
111
 
116
112
  ::VIM::command "highlight link CommandTSelection #{@highlight_color}"
117
113
  ::VIM::command 'highlight link CommandTNoEntries Error'
118
- ::VIM::evaluate 'clearmatches()'
119
114
 
120
115
  # hide cursor
121
116
  @cursor_highlight = get_cursor_highlight
@@ -266,6 +261,11 @@ module CommandT
266
261
 
267
262
  private
268
263
 
264
+ def set(setting, value)
265
+ @settings ||= Settings.new
266
+ @settings.set(setting, value)
267
+ end
268
+
269
269
  def move_cursor_to_selected_line
270
270
  # on some non-GUI terminals, the cursor doesn't hide properly
271
271
  # so we move the cursor to prevent it from blinking away in the
@@ -436,11 +436,11 @@ module CommandT
436
436
  end
437
437
 
438
438
  def lock
439
- ::VIM::command 'setlocal nomodifiable'
439
+ set 'modifiable', false
440
440
  end
441
441
 
442
442
  def unlock
443
- ::VIM::command 'setlocal modifiable'
443
+ set 'modifiable', true
444
444
  end
445
445
  end
446
446
  end
@@ -1,4 +1,4 @@
1
- # Copyright 2010-2013 Wincent Colaiuta. All rights reserved.
1
+ # Copyright 2010-2014 Wincent Colaiuta. All rights reserved.
2
2
  #
3
3
  # Redistribution and use in source and binary forms, with or without
4
4
  # modification, are permitted provided that the following conditions are met:
@@ -26,11 +26,15 @@ require 'command-t/scanner'
26
26
 
27
27
  module CommandT
28
28
  # Reads the current directory recursively for the paths to all regular files.
29
+ #
30
+ # This is an abstract superclass; the real work is done by subclasses which
31
+ # obtain file listings via different strategies (for examples, see the
32
+ # RubyFileScanner and FindFileScanner subclasses).
29
33
  class FileScanner < Scanner
30
34
  class FileLimitExceeded < ::RuntimeError; end
31
35
  attr_accessor :path
32
36
 
33
- def initialize path = Dir.pwd, options = {}
37
+ def initialize(path = Dir.pwd, options = {})
34
38
  @paths = {}
35
39
  @paths_keys = []
36
40
  @path = path
@@ -43,20 +47,11 @@ module CommandT
43
47
  end
44
48
 
45
49
  def paths
46
- return @paths[@path] if @paths.has_key?(@path)
47
- begin
50
+ @paths[@path] || begin
48
51
  ensure_cache_under_limit
49
- @paths[@path] = []
50
- @depth = 0
51
- @files = 0
52
- @prefix_len = @path.chomp('/').length
53
- set_wild_ignore(@wild_ignore)
54
- add_paths_for_directory @path, @paths[@path]
55
- rescue FileLimitExceeded
56
- ensure
57
- set_wild_ignore(@base_wild_ignore)
52
+ @prefix_len = @path.chomp('/').length
53
+ nil
58
54
  end
59
- @paths[@path]
60
55
  end
61
56
 
62
57
  def flush
@@ -74,45 +69,15 @@ module CommandT
74
69
  @paths_keys << @path
75
70
  end
76
71
 
77
- def path_excluded? path
72
+ def path_excluded?(path)
78
73
  # first strip common prefix (@path) from path to match VIM's behavior
79
74
  path = path[(@prefix_len + 1)..-1]
80
75
  path = VIM::escape_for_single_quotes path
81
76
  ::VIM::evaluate("empty(expand(fnameescape('#{path}')))").to_i == 1
82
77
  end
83
78
 
84
- def looped_symlink? path
85
- if File.symlink?(path)
86
- target = File.expand_path(File.readlink(path), File.dirname(path))
87
- target.include?(@path) || @path.include?(target)
88
- end
89
- end
90
-
91
79
  def set_wild_ignore(ignore)
92
80
  ::VIM::command("set wildignore=#{ignore}") if @wild_ignore
93
81
  end
94
-
95
- def add_paths_for_directory dir, accumulator
96
- Dir.foreach(dir) do |entry|
97
- next if ['.', '..'].include?(entry)
98
- path = File.join(dir, entry)
99
- unless path_excluded?(path)
100
- if File.file?(path)
101
- @files += 1
102
- raise FileLimitExceeded if @files > @max_files
103
- accumulator << path[@prefix_len + 1..-1]
104
- elsif File.directory?(path)
105
- next if @depth >= @max_depth
106
- next if (entry.match(/\A\./) && !@scan_dot_directories)
107
- next if looped_symlink?(path)
108
- @depth += 1
109
- add_paths_for_directory path, accumulator
110
- @depth -= 1
111
- end
112
- end
113
- end
114
- rescue Errno::EACCES
115
- # skip over directories for which we don't have access
116
- end
117
82
  end # class FileScanner
118
83
  end # module CommandT
@@ -0,0 +1,77 @@
1
+ # Copyright 2014 Wincent Colaiuta. All rights reserved.
2
+ #
3
+ # Redistribution and use in source and binary forms, with or without
4
+ # modification, are permitted provided that the following conditions are met:
5
+ #
6
+ # 1. Redistributions of source code must retain the above copyright notice,
7
+ # this list of conditions and the following disclaimer.
8
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
9
+ # this list of conditions and the following disclaimer in the documentation
10
+ # and/or other materials provided with the distribution.
11
+ #
12
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
13
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
16
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
17
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
18
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
19
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
20
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
21
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
22
+ # POSSIBILITY OF SUCH DAMAGE.
23
+
24
+ require 'open3'
25
+ require 'command-t/vim'
26
+ require 'command-t/vim/path_utilities'
27
+ require 'command-t/scanner/file_scanner'
28
+
29
+ module CommandT
30
+ class FileScanner
31
+ # A FileScanner which shells out to the `find` executable in order to scan.
32
+ class FindFileScanner < FileScanner
33
+ include VIM::PathUtilities
34
+
35
+ def paths
36
+ super || begin
37
+ set_wild_ignore(@wild_ignore)
38
+
39
+ # temporarily set field separator to NUL byte; this setting is
40
+ # respected by both `readlines` and `chomp!` below, and makes it easier
41
+ # to parse the output of `find -print0`
42
+ separator = $/
43
+ $/ = "\x00"
44
+
45
+ unless @scan_dot_directories
46
+ dot_directory_filter = [
47
+ '-not', '-path', "#{@path}/.*/*", # top-level dot dir
48
+ '-and', '-not', '-path', "#{@path}/*/.*/*" # lower-level dot dir
49
+ ]
50
+ end
51
+
52
+ Open3.popen3(*([
53
+ 'find', '-L', # follow symlinks
54
+ @path, # anchor search here
55
+ '-maxdepth', @max_depth.to_s, # limit depth of DFS
56
+ '-type', 'f', # only show regular files (not dirs etc)
57
+ dot_directory_filter, # possibly skip out dot directories
58
+ '-print0' # NUL-terminate results
59
+ ].flatten.compact)) do |stdin, stdout, stderr|
60
+ counter = 1
61
+ paths = []
62
+ stdout.readlines.each do |line|
63
+ next if path_excluded?(line.chomp!)
64
+ paths << line[@prefix_len + 1..-1]
65
+ break if (counter += 1) > @max_files
66
+ end
67
+ @paths[@path] = paths
68
+ end
69
+ ensure
70
+ $/ = separator
71
+ set_wild_ignore(@base_wild_ignore)
72
+ end
73
+ @paths[@path]
74
+ end
75
+ end # class FindFileScanner
76
+ end # class FileScanner
77
+ end # module CommandT
@@ -0,0 +1,78 @@
1
+ # Copyright 2010-2014 Wincent Colaiuta. All rights reserved.
2
+ #
3
+ # Redistribution and use in source and binary forms, with or without
4
+ # modification, are permitted provided that the following conditions are met:
5
+ #
6
+ # 1. Redistributions of source code must retain the above copyright notice,
7
+ # this list of conditions and the following disclaimer.
8
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
9
+ # this list of conditions and the following disclaimer in the documentation
10
+ # and/or other materials provided with the distribution.
11
+ #
12
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
13
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
16
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
17
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
18
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
19
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
20
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
21
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
22
+ # POSSIBILITY OF SUCH DAMAGE.
23
+
24
+ require 'command-t/vim'
25
+ require 'command-t/scanner/file_scanner'
26
+
27
+ module CommandT
28
+ class FileScanner
29
+ # Pure Ruby implementation of a file scanner.
30
+ class RubyFileScanner < FileScanner
31
+ def paths
32
+ super || begin
33
+ @paths[@path] = []
34
+ @depth = 0
35
+ @files = 0
36
+ set_wild_ignore(@wild_ignore)
37
+ add_paths_for_directory @path, @paths[@path]
38
+ rescue FileLimitExceeded
39
+ ensure
40
+ set_wild_ignore(@base_wild_ignore)
41
+ end
42
+ @paths[@path]
43
+ end
44
+
45
+ private
46
+
47
+ def looped_symlink? path
48
+ if File.symlink?(path)
49
+ target = File.expand_path(File.readlink(path), File.dirname(path))
50
+ target.include?(@path) || @path.include?(target)
51
+ end
52
+ end
53
+
54
+ def add_paths_for_directory dir, accumulator
55
+ Dir.foreach(dir) do |entry|
56
+ next if ['.', '..'].include?(entry)
57
+ path = File.join(dir, entry)
58
+ unless path_excluded?(path)
59
+ if File.file?(path)
60
+ @files += 1
61
+ raise FileLimitExceeded if @files > @max_files
62
+ accumulator << path[@prefix_len + 1..-1]
63
+ elsif File.directory?(path)
64
+ next if @depth >= @max_depth
65
+ next if (entry.match(/\A\./) && !@scan_dot_directories)
66
+ next if looped_symlink?(path)
67
+ @depth += 1
68
+ add_paths_for_directory path, accumulator
69
+ @depth -= 1
70
+ end
71
+ end
72
+ end
73
+ rescue Errno::EACCES
74
+ # skip over directories for which we don't have access
75
+ end
76
+ end # class RubyFileScanner
77
+ end # class FileScanner
78
+ end # module CommandT
@@ -0,0 +1,79 @@
1
+ # Copyright 2014 Wincent Colaiuta. All rights reserved.
2
+ #
3
+ # Redistribution and use in source and binary forms, with or without
4
+ # modification, are permitted provided that the following conditions are met:
5
+ #
6
+ # 1. Redistributions of source code must retain the above copyright notice,
7
+ # this list of conditions and the following disclaimer.
8
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
9
+ # this list of conditions and the following disclaimer in the documentation
10
+ # and/or other materials provided with the distribution.
11
+ #
12
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
13
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
16
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
17
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
18
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
19
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
20
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
21
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
22
+ # POSSIBILITY OF SUCH DAMAGE.
23
+
24
+ require 'json'
25
+ require 'socket'
26
+ require 'command-t/vim'
27
+ require 'command-t/vim/path_utilities'
28
+ require 'command-t/scanner/file_scanner'
29
+ require 'command-t/scanner/file_scanner/find_file_scanner'
30
+
31
+ module CommandT
32
+ class FileScanner
33
+ # A FileScanner which delegates the heavy lifting to Watchman
34
+ # (https://github.com/facebook/watchman); useful for very large hierarchies.
35
+ #
36
+ # Inherits from FindFileScanner so that it can fall back to it in the event
37
+ # that Watchman isn't available or able to fulfil the request.
38
+ class WatchmanFileScanner < FindFileScanner
39
+ # Exception raised when Watchman is unavailable or unable to process the
40
+ # requested path.
41
+ class WatchmanUnavailable < RuntimeError; end
42
+
43
+ def paths
44
+ @paths[@path] ||= begin
45
+ ensure_cache_under_limit
46
+ sockname = JSON[%x{watchman get-sockname}]['sockname']
47
+ raise WatchmanUnavailable unless $?.exitstatus.zero?
48
+ socket = UNIXSocket.open(sockname) do |s|
49
+ root = File.realpath(File.expand_path(@path))
50
+ s.puts JSON.generate(['watch-list'])
51
+ if !JSON[s.gets]['roots'].include?(root)
52
+ # this path isn't being watched yet; try to set up watch
53
+ s.puts JSON.generate(['watch', root])
54
+
55
+ # root_restrict_files setting may prevent Watchman from working
56
+ raise WatchmanUnavailable if JSON[s.gets].has_key?('error')
57
+ end
58
+
59
+ s.puts JSON.generate(['query', root, {
60
+ 'expression' => ['type', 'f'],
61
+ 'fields' => ['name'],
62
+ }])
63
+ paths = JSON[s.gets]
64
+
65
+ # could return error if watch is removed
66
+ raise WatchmanUnavailable if paths.has_key?('error')
67
+
68
+ @paths[@path] = paths['files']
69
+ end
70
+ end
71
+
72
+ @paths[@path]
73
+ rescue Errno::ENOENT, WatchmanUnavailable
74
+ # watchman executable not present, or unable to fulfil request
75
+ super
76
+ end
77
+ end # class WatchmanFileScanner
78
+ end # class FileScanner
79
+ end # module CommandT