command-t 3.0.2 → 4.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.
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