command-t 3.0.2 → 4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +8 -2
  3. data/doc/command-t.txt +312 -147
  4. data/ruby/command-t.rb +13 -12
  5. data/ruby/command-t/controller.rb +86 -15
  6. data/ruby/command-t/depend +4 -0
  7. data/ruby/command-t/ext.h +9 -2
  8. data/ruby/command-t/extconf.rb +2 -2
  9. data/ruby/command-t/finder.rb +6 -2
  10. data/ruby/command-t/finder/buffer_finder.rb +3 -3
  11. data/ruby/command-t/finder/command_finder.rb +23 -0
  12. data/ruby/command-t/finder/file_finder.rb +3 -3
  13. data/ruby/command-t/finder/help_finder.rb +25 -0
  14. data/ruby/command-t/finder/history_finder.rb +27 -0
  15. data/ruby/command-t/finder/jump_finder.rb +3 -3
  16. data/ruby/command-t/finder/line_finder.rb +23 -0
  17. data/ruby/command-t/finder/mru_buffer_finder.rb +3 -3
  18. data/ruby/command-t/finder/tag_finder.rb +3 -3
  19. data/ruby/command-t/heap.c +146 -0
  20. data/ruby/command-t/heap.h +22 -0
  21. data/ruby/command-t/match.c +183 -116
  22. data/ruby/command-t/match.h +16 -10
  23. data/ruby/command-t/match_window.rb +10 -1
  24. data/ruby/command-t/matcher.c +203 -63
  25. data/ruby/command-t/metadata/fallback.rb +2 -2
  26. data/ruby/command-t/mru.rb +2 -2
  27. data/ruby/command-t/path_utilities.rb +2 -2
  28. data/ruby/command-t/progress_reporter.rb +38 -0
  29. data/ruby/command-t/prompt.rb +4 -4
  30. data/ruby/command-t/scanner.rb +22 -2
  31. data/ruby/command-t/scanner/buffer_scanner.rb +3 -3
  32. data/ruby/command-t/scanner/command_scanner.rb +33 -0
  33. data/ruby/command-t/scanner/file_scanner.rb +30 -6
  34. data/ruby/command-t/scanner/file_scanner/find_file_scanner.rb +12 -7
  35. data/ruby/command-t/scanner/file_scanner/git_file_scanner.rb +11 -8
  36. data/ruby/command-t/scanner/file_scanner/ruby_file_scanner.rb +7 -4
  37. data/ruby/command-t/scanner/file_scanner/watchman_file_scanner.rb +13 -5
  38. data/ruby/command-t/scanner/help_scanner.rb +40 -0
  39. data/ruby/command-t/scanner/history_scanner.rb +24 -0
  40. data/ruby/command-t/scanner/jump_scanner.rb +3 -3
  41. data/ruby/command-t/scanner/line_scanner.rb +45 -0
  42. data/ruby/command-t/scanner/mru_buffer_scanner.rb +3 -3
  43. data/ruby/command-t/scanner/tag_scanner.rb +3 -3
  44. data/ruby/command-t/scm_utilities.rb +2 -2
  45. data/ruby/command-t/settings.rb +2 -2
  46. data/ruby/command-t/stub.rb +7 -2
  47. data/ruby/command-t/util.rb +2 -2
  48. data/ruby/command-t/vim.rb +27 -2
  49. data/ruby/command-t/vim/screen.rb +3 -3
  50. data/ruby/command-t/vim/window.rb +3 -3
  51. data/ruby/command-t/watchman.c +1 -1
  52. metadata +13 -2
@@ -8,5 +8,5 @@ module CommandT
8
8
  EXPECTED_RUBY_VERSION = '[unknown]'
9
9
  EXPECTED_RUBY_PATCHLEVEL = '[unknown]'
10
10
  UNKNOWN = true
11
- end # module Metadata
12
- end # module CommandT
11
+ end
12
+ end
@@ -39,5 +39,5 @@ module CommandT
39
39
  stack.include?(buffer)
40
40
  end
41
41
  end
42
- end # module MRU
43
- end # module CommandT
42
+ end
43
+ end
@@ -13,5 +13,5 @@ module CommandT
13
13
  path.index(pwd) == 0 ? path[pwd.length..-1] : path
14
14
  end
15
15
 
16
- end # module PathUtilities
17
- end # module CommandT
16
+ end
17
+ end
@@ -0,0 +1,38 @@
1
+ # Copyright 2010-present Greg Hurrell. All rights reserved.
2
+ # Licensed under the terms of the BSD 2-clause license.
3
+
4
+ module CommandT
5
+ # Simple class for displaying scan progress to the user.
6
+ #
7
+ # The active scanner calls the `#update` method with a `count` to inform it of
8
+ # progress, the reporter updates the UI and then returns a suggested count at
9
+ # which to invoke `#update` again in the future (the suggested count is based
10
+ # on a heuristic that seeks to update the UI about 5 times per second).
11
+ class ProgressReporter
12
+ SPINNER = %w[^ > v <]
13
+
14
+ def initialize
15
+ @spinner ||= SPINNER.first
16
+ end
17
+
18
+ def update(count)
19
+ @spinner = SPINNER[(SPINNER.index(@spinner) + 1) % SPINNER.length]
20
+
21
+ ::VIM::command "echon '#{@spinner} #{count}'"
22
+ ::VIM::command 'redraw'
23
+
24
+ # Aim for 5 updates per second.
25
+ now = Time.now.to_f
26
+ if @last_time
27
+ time_diff = now - @last_time
28
+ count_diff = count - @last_count
29
+ next_count = count + ((0.2 / time_diff) * count_diff).to_i
30
+ else
31
+ next_count = count + 100
32
+ end
33
+ @last_time = now
34
+ @last_count = count
35
+ next_count
36
+ end
37
+ end
38
+ end
@@ -112,8 +112,6 @@ module CommandT
112
112
  end
113
113
  end
114
114
 
115
- private
116
-
117
115
  def redraw
118
116
  if @has_focus
119
117
  prompt_highlight = 'Comment'
@@ -133,6 +131,8 @@ module CommandT
133
131
  set_status *components
134
132
  end
135
133
 
134
+ private
135
+
136
136
  # Returns the @abbrev string divided up into three sections, any of
137
137
  # which may actually be zero width, depending on the location of the
138
138
  # cursor:
@@ -158,5 +158,5 @@ module CommandT
158
158
  end
159
159
  ::VIM::command 'echohl None'
160
160
  end
161
- end # class Prompt
162
- end # module CommandT
161
+ end
162
+ end
@@ -4,9 +4,29 @@
4
4
  module CommandT
5
5
  class Scanner
6
6
  autoload :BufferScanner, 'command-t/scanner/buffer_scanner'
7
+ autoload :CommandScanner, 'command-t/scanner/command_scanner'
7
8
  autoload :FileScanner, 'command-t/scanner/file_scanner'
9
+ autoload :HelpScanner, 'command-t/scanner/help_scanner'
10
+ autoload :HistoryScanner, 'command-t/scanner/history_scanner'
8
11
  autoload :JumpScanner, 'command-t/scanner/jump_scanner'
12
+ autoload :LineScanner, 'command-t/scanner/line_scanner'
9
13
  autoload :MRUBufferScanner, 'command-t/scanner/mru_buffer_scanner'
10
14
  autoload :TagScanner, 'command-t/scanner/tag_scanner'
11
- end # class Scanner
12
- end # module CommandT
15
+
16
+ # Subclasses implement this method to return the list of paths that should
17
+ # be searched.
18
+ #
19
+ # Note that as an optimization, the C extension will record the
20
+ # `Object#object_id` of the returned array and assumes it will not be
21
+ # mutated.
22
+ def paths
23
+ raise RuntimeError, 'Subclass responsibility'
24
+ end
25
+
26
+ private
27
+
28
+ def progress_reporter
29
+ @progress_reporter ||= ProgressReporter.new
30
+ end
31
+ end
32
+ end
@@ -15,6 +15,6 @@ module CommandT
15
15
  end
16
16
  end.compact
17
17
  end
18
- end # class BufferScanner
19
- end # class Scanner
20
- end # module CommandT
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,33 @@
1
+ # Copyright 2011-present Greg Hurrell. All rights reserved.
2
+ # Licensed under the terms of the BSD 2-clause license.
3
+
4
+ module CommandT
5
+ class Scanner
6
+ class CommandScanner < Scanner
7
+ def paths
8
+ @paths ||= paths!
9
+ end
10
+
11
+ private
12
+
13
+ def paths!
14
+ # Get user commands.
15
+ commands = VIM.capture('silent command').split("\n")[2..-1].map do |line|
16
+ line.sub(/\A.{4}(\S+).+/, '\1')
17
+ end
18
+
19
+ # Get built-in commands from `ex-cmd-index`.
20
+ ex_cmd_index = ::VIM.evaluate('expand(findfile("doc/index.txt", &runtimepath))')
21
+ if File.readable?(ex_cmd_index)
22
+ File.readlines(ex_cmd_index).each do |line|
23
+ if line =~ %r{\A\|:([^|]+)\|\s+}
24
+ commands << $~[1]
25
+ end
26
+ end
27
+ end
28
+
29
+ commands.uniq
30
+ end
31
+ end
32
+ end
33
+ end
@@ -22,7 +22,7 @@ module CommandT
22
22
  @paths_keys = []
23
23
  @path = path
24
24
  @max_depth = options[:max_depth] || 15
25
- @max_files = options[:max_files] || 30_000
25
+ @max_files = options[:max_files] || 100_000
26
26
  @max_caches = options[:max_caches] || 1
27
27
  @scan_dot_directories = options[:scan_dot_directories] || false
28
28
  @wild_ignore = options[:wild_ignore]
@@ -44,6 +44,26 @@ module CommandT
44
44
 
45
45
  private
46
46
 
47
+ def show_max_files_warning
48
+ unless VIM::get_bool('g:CommandTSuppressMaxFilesWarning', false)
49
+ ::VIM::command('redraw!')
50
+ ::VIM::command('echohl ErrorMsg')
51
+ warning =
52
+ "Warning: maximum file limit reached\n" +
53
+ "\n" +
54
+ "Increase it by setting a higher value in $MYVIMRC; eg:\n" +
55
+ " let g:CommandTMaxFiles=#{@max_files * 2}\n" +
56
+ "Or suppress this warning by setting:\n" +
57
+ " let g:CommandTSuppressMaxFilesWarning=1\n" +
58
+ "For best performance, consider using a fast scanner; see:\n" +
59
+ " :help g:CommandTFileScanner\n" +
60
+ "\n" +
61
+ "Press ENTER to continue."
62
+ ::VIM::evaluate(%{input("#{warning}")})
63
+ ::VIM::command('echohl None')
64
+ end
65
+ end
66
+
47
67
  def wild_ignore
48
68
  VIM::exists?('&wildignore') && ::VIM::evaluate('&wildignore').to_s
49
69
  end
@@ -71,13 +91,17 @@ module CommandT
71
91
  end
72
92
 
73
93
  def has_custom_wild_ignore?
74
- @wild_ignore && !@wild_ignore.empty?
94
+ !!@wild_ignore
75
95
  end
76
96
 
77
97
  # Used to skip expensive calls to `expand()` when there is no applicable
78
98
  # wildignore.
79
99
  def apply_wild_ignore?
80
- has_custom_wild_ignore? || @base_wild_ignore
100
+ if has_custom_wild_ignore?
101
+ !@wild_ignore.empty?
102
+ else
103
+ !!@base_wild_ignore
104
+ end
81
105
  end
82
106
 
83
107
  def set_wild_ignore(&block)
@@ -86,6 +110,6 @@ module CommandT
86
110
  ensure
87
111
  ::VIM::command("set wildignore=#{@base_wild_ignore}") if has_custom_wild_ignore?
88
112
  end
89
- end # class FileScanner
90
- end # class Scanner
91
- end # module CommandT
113
+ end
114
+ end
115
+ end
@@ -12,7 +12,7 @@ module CommandT
12
12
 
13
13
  def paths!
14
14
  # temporarily set field separator to NUL byte; this setting is
15
- # respected by both `readlines` and `chomp!` below, and makes it easier
15
+ # respected by both `each_line` and `chomp!` below, and makes it easier
16
16
  # to parse the output of `find -print0`
17
17
  separator = $/
18
18
  $/ = "\x00"
@@ -34,17 +34,22 @@ module CommandT
34
34
  '-print0' # NUL-terminate results
35
35
  ].flatten.compact)) do |stdin, stdout, stderr|
36
36
  counter = 1
37
- stdout.readlines.each do |line|
37
+ next_progress = progress_reporter.update(counter)
38
+ stdout.each_line do |line|
38
39
  next if path_excluded?(line.chomp!)
39
40
  paths << line[@prefix_len..-1]
40
- break if (counter += 1) > @max_files
41
+ next_progress = progress_reporter.update(counter) if counter == next_progress
42
+ if (counter += 1) > @max_files
43
+ show_max_files_warning
44
+ break
45
+ end
41
46
  end
42
47
  end
43
48
  paths
44
49
  ensure
45
50
  $/ = separator
46
51
  end
47
- end # class FindFileScanner
48
- end # class FileScanner
49
- end # class Scanner
50
- end # module CommandT
52
+ end
53
+ end
54
+ end
55
+ end
@@ -26,11 +26,14 @@ module CommandT
26
26
  end
27
27
  end
28
28
 
29
- all_files.
29
+ filtered = all_files.
30
30
  map { |path| path.chomp }.
31
- reject { |path| path_excluded?(path, 0) }.
32
- take(@max_files).
33
- to_a
31
+ reject { |path| path_excluded?(path, 0) }
32
+ truncated = filtered.take(@max_files)
33
+ if truncated.count < filtered.count
34
+ show_max_files_warning
35
+ end
36
+ truncated.to_a
34
37
  end
35
38
  rescue LsFilesError
36
39
  super
@@ -48,7 +51,7 @@ module CommandT
48
51
  raise LsFilesError if stderr && stderr.gets
49
52
  end
50
53
 
51
- end # class GitFileScanner
52
- end # class FileScanner
53
- end # class Scanner
54
- end # module CommandT
54
+ end
55
+ end
56
+ end
57
+ end
@@ -12,9 +12,11 @@ module CommandT
12
12
  accumulator = []
13
13
  @depth = 0
14
14
  @files = 0
15
+ @next_progress = progress_reporter.update(@files)
15
16
  add_paths_for_directory(@path, accumulator)
16
17
  accumulator
17
18
  rescue FileLimitExceeded
19
+ show_max_files_warning
18
20
  accumulator
19
21
  end
20
22
 
@@ -34,6 +36,7 @@ module CommandT
34
36
  unless path_excluded?(path)
35
37
  if File.file?(path)
36
38
  @files += 1
39
+ @next_progress = progress_reporter.update(@files) if @files == @next_progress
37
40
  raise FileLimitExceeded if @files > @max_files
38
41
  accumulator << path[@prefix_len..-1]
39
42
  elsif File.directory?(path)
@@ -51,7 +54,7 @@ module CommandT
51
54
  rescue ArgumentError
52
55
  # skip over bad file names
53
56
  end
54
- end # class RubyFileScanner
55
- end # class FileScanner
56
- end # class Scanner
57
- end # module CommandT
57
+ end
58
+ end
59
+ end
60
+ end
@@ -42,7 +42,15 @@ module CommandT
42
42
  paths = Watchman::Utils.query(query, socket)
43
43
 
44
44
  # could return error if watch is removed
45
- extract_value(paths, 'files')
45
+ extracted = extract_value(paths, 'files')
46
+ if (
47
+ apply_wild_ignore? &&
48
+ (regex = VIM::wildignore_to_regexp(@wild_ignore || @base_wild_ignore))
49
+ )
50
+ extracted.select { |path| path !~ regex }
51
+ else
52
+ extracted
53
+ end
46
54
  end
47
55
  rescue Errno::ENOENT, WatchmanError
48
56
  # watchman executable not present, or unable to fulfil request
@@ -61,7 +69,7 @@ module CommandT
61
69
  raise WatchmanError, 'get-sockname failed' if !$?.exitstatus.zero?
62
70
  raw_sockname
63
71
  end
64
- end # class WatchmanFileScanner
65
- end # class FileScanner
66
- end # class Scanner
67
- end # module CommandT
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,40 @@
1
+ # Copyright 2011-present Greg Hurrell. All rights reserved.
2
+ # Licensed under the terms of the BSD 2-clause license.
3
+
4
+ module CommandT
5
+ class Scanner
6
+ class HelpScanner < Scanner
7
+ def paths
8
+ @cached_tags ||= paths!
9
+ end
10
+
11
+ def flush
12
+ @cached_tags = nil
13
+ end
14
+
15
+ private
16
+
17
+ def paths!
18
+ # Vim doesn't provide an easy way to get a list of all help tags.
19
+ # `tagfiles()` only shows the tagfiles for the current buffer, so you
20
+ # need to already be in a buffer of `'buftype'` `help` for that to work.
21
+ # Likewise, `taglist()` only shows tags that apply to the current file
22
+ # type, and `:tag` has the same restriction.
23
+ #
24
+ # So, we look for a "doc/tags" file at every location in the
25
+ # `'runtimepath'` and try to manually parse it.
26
+ tags = []
27
+
28
+ ::VIM::evaluate('findfile("doc/tags", &runtimepath, -1)').each do |path|
29
+ if File.readable?(path)
30
+ File.readlines(path).each do |tag|
31
+ tags << tag.split.first if tag.split.first
32
+ end
33
+ end
34
+ end
35
+
36
+ tags
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,24 @@
1
+ # Copyright 2011-present Greg Hurrell. All rights reserved.
2
+ # Licensed under the terms of the BSD 2-clause license.
3
+
4
+ module CommandT
5
+ class Scanner
6
+ class HistoryScanner < Scanner
7
+ def initialize(history_command)
8
+ @history_command = history_command
9
+ end
10
+
11
+ def paths
12
+ @paths ||= paths!
13
+ end
14
+
15
+ private
16
+
17
+ def paths!
18
+ VIM.capture(@history_command).split("\n")[2..-1].map do |line|
19
+ line.sub(/\A>?\s*\d+\s*(.+)/, '\1').strip
20
+ end.uniq
21
+ end
22
+ end
23
+ end
24
+ end
@@ -27,6 +27,6 @@ module CommandT
27
27
  def jumps
28
28
  VIM::capture 'silent jumps'
29
29
  end
30
- end # class JumpScanner
31
- end # class Scanner
32
- end # module CommandT
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,45 @@
1
+ # Copyright 2011-present Greg Hurrell. All rights reserved.
2
+ # Licensed under the terms of the BSD 2-clause license.
3
+
4
+ module CommandT
5
+ class Scanner
6
+ class LineScanner < Scanner
7
+ def paths
8
+ @lines ||= paths!
9
+ end
10
+
11
+ private
12
+
13
+ def paths!
14
+ # $curbuf is the Command-T match listing; we actually want the last
15
+ # buffer, but passing `$`, `#`, `%` etc to `bufnr()` returns the wrong
16
+ # value.
17
+ number = ::VIM.evaluate("g:CommandTCurrentBuffer").to_i
18
+ return [] unless number > 0
19
+ buffer = nil
20
+ (0...(::VIM::Buffer.count)).each do |n|
21
+ buffer = ::VIM::Buffer[n]
22
+ if buffer_number(buffer) == number
23
+ break
24
+ else
25
+ buffer = nil
26
+ end
27
+ end
28
+ return [] unless buffer
29
+
30
+ (1..(buffer.length)).map do |n|
31
+ line = buffer[n]
32
+ unless line.match(/\A\s*\z/)
33
+ line.sub(/\A\s*/, '') + ':' + n.to_s
34
+ end
35
+ end.compact
36
+ end
37
+
38
+ def buffer_number(buffer)
39
+ buffer && buffer.number
40
+ rescue Vim::DeletedBufferError
41
+ # Beware of people manually deleting Command-T's hidden, unlisted buffer.
42
+ end
43
+ end
44
+ end
45
+ end