diff -Nru vim-command-t-4.0/autoload/commandt/isengard.vim vim-command-t-5.0.2-5-g7147ba9/autoload/commandt/isengard.vim --- vim-command-t-4.0/autoload/commandt/isengard.vim 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/autoload/commandt/isengard.vim 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,25 @@ +" Copyright 2010-present Greg Hurrell. All rights reserved. +" Licensed under the terms of the BSD 2-clause license. + +let s:script_directory=expand(':p:h') + +" Set up the new async implementation of the Command-T engine -- successor to +" "mirkwood" -- codenamed "isengard". +function! commandt#isengard#init() abort + let l:daemon_path=resolve(s:script_directory . '/../../ruby/command-t/bin/commandtd') + + let l:client_log_file=get(g:, 'CommandTClientLog', '') + let l:server_log_file=get(g:, 'CommandTServerLog', '') + if !empty(l:client_log_file) + call ch_logfile(l:client_log_file, 'w') + endif + if !empty(l:server_log_file) + let s:job=job_start([l:daemon_path, '--logfile=' . l:server_log_file, '--vim-pid=' . getpid()]) + else + let s:job=job_start([l:daemon_path, '--vim-pid=' . getpid()]) + endif + let s:channel=job_getchannel(s:job) + + call ch_evalraw(s:channel, json_encode({'cd': getcwd()}) . "\n") + let g:CommandTResult=ch_evalraw(s:channel, json_encode({'match': 'commandt'}) . "\n") +endfunction diff -Nru vim-command-t-4.0/autoload/commandt/mirkwood.vim vim-command-t-5.0.2-5-g7147ba9/autoload/commandt/mirkwood.vim --- vim-command-t-4.0/autoload/commandt/mirkwood.vim 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/autoload/commandt/mirkwood.vim 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,44 @@ +" Copyright 2010-present Greg Hurrell. All rights reserved. +" Licensed under the terms of the BSD 2-clause license. + +" Set up the original implementation Command-T engine, codenamed "mirkwood". +function! commandt#mirkwood#init() abort + command! CommandTBuffer call commandt#BufferFinder() + command! CommandTCommand call commandt#CommandFinder() + command! CommandTHelp call commandt#HelpFinder() + command! CommandTHistory call commandt#HistoryFinder() + command! CommandTJump call commandt#JumpFinder() + command! CommandTLine call commandt#LineFinder() + command! CommandTMRU call commandt#MRUFinder() + command! CommandTSearch call commandt#SearchFinder() + command! CommandTTag call commandt#TagFinder() + command! -nargs=? -complete=dir CommandT call commandt#FileFinder() + command! CommandTFlush call commandt#Flush() + command! CommandTLoad call commandt#Load() + + if !hasmapto('(CommandT)') && maparg('t', 'n') ==# '' + nmap t (CommandT) + endif + nnoremap (CommandT) :CommandT + + if !hasmapto('(CommandTBuffer)') && maparg('b', 'n') ==# '' + nmap b (CommandTBuffer) + endif + nnoremap (CommandTBuffer) :CommandTBuffer + + nnoremap (CommandTHelp) :CommandTHelp + nnoremap (CommandTHistory) :CommandTHistory + + if has('jumplist') + if !hasmapto('(CommandTJump)') && maparg('j', 'n') ==# '' + nmap j (CommandTJump) + endif + nnoremap (CommandTJump) :CommandTJump + endif + + nnoremap (CommandTCommand) :CommandTCommand + nnoremap (CommandTLine) :CommandTLine + nnoremap (CommandTMRU) :CommandTMRU + nnoremap (CommandTSearch) :CommandTSearch + nnoremap (CommandTTag) :CommandTTag +endfunction diff -Nru vim-command-t-4.0/autoload/commandt/private.vim vim-command-t-5.0.2-5-g7147ba9/autoload/commandt/private.vim --- vim-command-t-4.0/autoload/commandt/private.vim 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/autoload/commandt/private.vim 2017-11-17 03:46:11.000000000 +0000 @@ -41,6 +41,10 @@ ruby $command_t.refresh endfunction +function! commandt#private#RemoveBuffer() abort + ruby $command_t.remove_buffer +endfunction + function! commandt#private#ToggleFocus() abort ruby $command_t.toggle_focus endfunction diff -Nru vim-command-t-4.0/autoload/commandt.vim vim-command-t-5.0.2-5-g7147ba9/autoload/commandt.vim --- vim-command-t-4.0/autoload/commandt.vim 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/autoload/commandt.vim 2017-11-17 03:46:11.000000000 +0000 @@ -139,6 +139,51 @@ endif endfunction +" visible == exists, loaded, listed and not hidden +" (buffer is opened in a window - in current or another tab) +function! s:BufVisible(buffer) + " buffer is opened in current tab (quick check for current tab) + if bufwinnr('^' . a:buffer . '$') != -1 | return 1 | end + " buffer exists if it has been opened at least once (unless wiped) + if !bufexists(a:buffer) | return 0 | end + " buffer is not loaded when its last window is closed (`set nohidden` only) + if !bufloaded(a:buffer) | return 0 | end + " buffer is not listed when it's deleted + if !buflisted(a:buffer) | return 0 | end + + let bufno = bufnr(a:buffer) + let ls_buffers = '' + + redir => ls_buffers + silent ls + redir END + + " buffer is hidden when its last window is closed (`set hidden` only) + for line in split(ls_buffers, "\n") + let components = split(line) + if components[0] == bufno + return match(components[1], 'h') == -1 + endif + endfor + + return 1 +endfunction + +function! commandt#GotoOrOpen(command_and_args) abort + let l:command_and_args = split(a:command_and_args, '\v^\w+ \zs') + let l:command = l:command_and_args[0] + let l:file = l:command_and_args[1] + + " `bufwinnr()` doesn't see windows in other tabs, meaning we open them again + " instead of switching to the other tab; but `bufname()` sees hidden + " buffers, and if we try to open one of those, we get an unwanted split. + if s:BufVisible(l:file) + execute 'sbuffer ' . l:file + else + execute l:command . l:file + endif +endfunction + if !has('ruby') finish endif @@ -170,7 +215,12 @@ rescue LoadError load_path_modified = false ::VIM::evaluate('&runtimepath').to_s.split(',').each do |path| - lib = "#{path}/ruby" + ext = "#{path}/ruby/command-t/ext" + if !$LOAD_PATH.include?(ext) && File.exist?(ext) + $LOAD_PATH << ext + load_path_modified = true + end + lib = "#{path}/ruby/command-t/lib" if !$LOAD_PATH.include?(lib) && File.exist?(lib) $LOAD_PATH << lib load_path_modified = true diff -Nru vim-command-t-4.0/bin/benchmarks/matcher.rb vim-command-t-5.0.2-5-g7147ba9/bin/benchmarks/matcher.rb --- vim-command-t-4.0/bin/benchmarks/matcher.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/bin/benchmarks/matcher.rb 2017-11-17 03:46:11.000000000 +0000 @@ -3,8 +3,10 @@ # Copyright 2013-present Greg Hurrell. All rights reserved. # Licensed under the terms of the BSD 2-clause license. -lib = File.expand_path('../../ruby', File.dirname(__FILE__)) -$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) +%w[ext lib].each do |dir| + path = File.expand_path("../../ruby/command-t/#{dir}", File.dirname(__FILE__)) + $LOAD_PATH.unshift(path) unless $LOAD_PATH.include?(path) +end require 'command-t/ext' require 'command-t/util' @@ -71,7 +73,7 @@ end rank = 1 - table = table.map.with_index do |row, i| + table = table.map do |row| count = 0 rank = table.map.with_index do |(diff, abs, sig), i| if abs == row[ABSOLUTE] diff -Nru vim-command-t-4.0/CODE_OF_CONDUCT.md vim-command-t-5.0.2-5-g7147ba9/CODE_OF_CONDUCT.md --- vim-command-t-4.0/CODE_OF_CONDUCT.md 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/CODE_OF_CONDUCT.md 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,46 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at greg@hurrell.net. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff -Nru vim-command-t-4.0/command-t.gemspec vim-command-t-5.0.2-5-g7147ba9/command-t.gemspec --- vim-command-t-4.0/command-t.gemspec 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/command-t.gemspec 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -Gem::Specification.new do |s| - s.name = 'command-t' - - # see note in the Rakefile about how intermediate version numbers - # can break RubyGems - s.version = `git describe --abbrev=0`.chomp - - s.authors = ['Greg Hurrell'] - s.email = 'greg@hurrell.net' - - s.files = - ['README.md', 'LICENSE', 'Gemfile', 'Rakefile'] + - `git ls-files -z ruby doc`.split("\x0") - - s.license = 'BSD' - s.require_path = 'ruby' - s.extensions = 'ruby/command-t/extconf.rb' - - s.executables = [] - - s.has_rdoc = false - s.homepage = 'https://github.com/wincent/command-t' - - s.summary = 'The Command-T plug-in for VIM.' - - s.description = <<-EOS - Command-T provides a fast, intuitive mechanism for opening files with a - minimal number of keystrokes. Its full functionality is only available when - installed as a Vim plug-in, but it is also made available as a RubyGem so - that other applications can make use of its searching algorithm. - EOS -end diff -Nru vim-command-t-4.0/CONTRIBUTING.md vim-command-t-5.0.2-5-g7147ba9/CONTRIBUTING.md --- vim-command-t-4.0/CONTRIBUTING.md 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/CONTRIBUTING.md 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,5 @@ +# Contributing + +Patches are welcome via the usual mechanisms (pull requests, email, posting to the project issue tracker etc). + +For more details, see the "command-t-development" section in [the documentation](https://github.com/wincent/command-t/blob/master/doc/command-t.txt). diff -Nru vim-command-t-4.0/debian/changelog vim-command-t-5.0.2-5-g7147ba9/debian/changelog --- vim-command-t-4.0/debian/changelog 2018-03-01 09:36:29.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/debian/changelog 2018-03-06 10:48:39.000000000 +0000 @@ -1,14 +1,20 @@ -vim-command-t (4.0-4build2) bionic; urgency=high +vim-command-t (5.0.2-5-g7147ba9-1) unstable; urgency=medium - * No change rebuild against ruby-defaults without ruby2.3 support. + * Add .gitignore for byproducts of package building + * Install **/*.rb (and ext.so) by using cp --parents + * Install command-t.yaml with install -D + * Specify upstream/debian branch names + * Update README.Source with pointers to gbp documentation and examples + * Update reason test suite is ignored + * Limit gbp-dch to commits that touch the debian directory + * Rebase patches + * Order file list for vam registry deterministically. + Thanks to Chris Lamb (Closes: #862553) + * Correctly escape $1 in get-orig-source make rule + * Update changelog for release + * New upstream release - -- Dimitri John Ledkov Thu, 01 Mar 2018 09:36:29 +0000 - -vim-command-t (4.0-4build1) bionic; urgency=medium - - * No-change rebuild for ruby2.5 update. - - -- Matthias Klose Thu, 01 Feb 2018 19:14:36 +0000 + -- Sam Morris Tue, 06 Mar 2018 10:48:39 +0000 vim-command-t (4.0-4) unstable; urgency=medium diff -Nru vim-command-t-4.0/debian/control vim-command-t-5.0.2-5-g7147ba9/debian/control --- vim-command-t-4.0/debian/control 2018-03-01 09:36:29.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/debian/control 2017-06-22 14:53:04.000000000 +0000 @@ -1,6 +1,5 @@ Source: vim-command-t -Maintainer: Ubuntu Developers -XSBC-Original-Maintainer: Sam Morris +Maintainer: Sam Morris Section: editors Priority: optional Build-Depends: diff -Nru vim-command-t-4.0/debian/dirs vim-command-t-5.0.2-5-g7147ba9/debian/dirs --- vim-command-t-4.0/debian/dirs 2016-12-09 22:26:54.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/debian/dirs 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -usr/lib/vim-command-t/doc -usr/share/vim/registry diff -Nru vim-command-t-4.0/debian/gbp.conf vim-command-t-5.0.2-5-g7147ba9/debian/gbp.conf --- vim-command-t-4.0/debian/gbp.conf 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/debian/gbp.conf 2017-06-22 14:30:41.000000000 +0000 @@ -0,0 +1,7 @@ +[DEFAULT] +# defaults to 'upstream' +upstream-branch = upstream/latest +# defaults to 'master' +debian-branch = debian/sid +# causes upstream history to be merged into upstream/latest branch +upstream-vcs-tag = %(version)s diff -Nru vim-command-t-4.0/debian/install vim-command-t-5.0.2-5-g7147ba9/debian/install --- vim-command-t-4.0/debian/install 2016-12-09 22:26:54.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/debian/install 2017-06-22 14:53:04.000000000 +0000 @@ -1,19 +1,3 @@ -#!/bin/bash - -set -eu - -cat <<- EOF - autoload /usr/lib/vim-command-t/ - plugin /usr/lib/vim-command-t/ - doc/*.txt /usr/lib/vim-command-t/doc/ - ruby/command-t/ext.so /usr/lib/vim-command-t/ruby/command-t/ -EOF - -# Our goal is to install all the ruby files that we can find within the ruby -# directory, to the same relative path underneath /usr/lib/vim-command-t. -mapfile -t rb < <(find ruby -name '*.rb') -for f in "${rb[@]}"; do - IFS=/ read -a components <<< "$f" - n=$((${#components[@]} - 1)) - (IFS=/; echo "$f" "/usr/lib/vim-command-t/${components[*]:0:$n}") -done +autoload /usr/lib/vim-command-t/ +plugin /usr/lib/vim-command-t/ +doc/*.txt /usr/lib/vim-command-t/doc/ diff -Nru vim-command-t-4.0/debian/patches/link-as-needed.patch vim-command-t-5.0.2-5-g7147ba9/debian/patches/link-as-needed.patch --- vim-command-t-4.0/debian/patches/link-as-needed.patch 2016-12-09 23:36:43.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/debian/patches/link-as-needed.patch 2018-03-06 10:48:39.000000000 +0000 @@ -7,7 +7,7 @@ 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile -index 8e8f95f..9515980 100644 +index fbc877c..70380f2 100644 --- a/Rakefile +++ b/Rakefile @@ -84,7 +84,7 @@ task :make do diff -Nru vim-command-t-4.0/debian/patches/make-verbose.patch vim-command-t-5.0.2-5-g7147ba9/debian/patches/make-verbose.patch --- vim-command-t-4.0/debian/patches/make-verbose.patch 2016-12-09 23:36:43.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/debian/patches/make-verbose.patch 2018-03-06 10:48:39.000000000 +0000 @@ -7,7 +7,7 @@ 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile -index 54c242f..8e8f95f 100644 +index a38bfcb..fbc877c 100644 --- a/Rakefile +++ b/Rakefile @@ -84,7 +84,7 @@ task :make do diff -Nru vim-command-t-4.0/debian/patches/relax-ruby-version-check vim-command-t-5.0.2-5-g7147ba9/debian/patches/relax-ruby-version-check --- vim-command-t-4.0/debian/patches/relax-ruby-version-check 2016-12-09 23:38:28.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/debian/patches/relax-ruby-version-check 2018-03-06 10:48:39.000000000 +0000 @@ -9,10 +9,10 @@ 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/autoload/commandt.vim b/autoload/commandt.vim -index 7513f55..a03a2a1 100644 +index 1c65748..5e1ca61 100644 --- a/autoload/commandt.vim +++ b/autoload/commandt.vim -@@ -154,19 +154,8 @@ ruby << EOF +@@ -199,19 +199,8 @@ ruby << EOF # require Ruby files begin require 'command-t' diff -Nru vim-command-t-4.0/debian/README.source vim-command-t-5.0.2-5-g7147ba9/debian/README.source --- vim-command-t-4.0/debian/README.source 2016-12-09 23:38:28.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/debian/README.source 2018-03-06 10:48:39.000000000 +0000 @@ -1,11 +1,18 @@ command-t source package notes ============================== -I'm maintaining the package using git-buildpackage. Source packages are -generated with: +I'm maintaining the package using git-buildpackage, using [Upstream tarballs +and linked upstream +history](file:///usr/share/doc/git-buildpackage/manual-html/gbp.import.html#GBP.IMPORT.UPSTREAM.GIT.TARBALL>). - $ gbp dch --release - $ gbp buildpackage --git-debian-branch=debian/sid --git-pristine-tar --git-tag +Source packages are generated with: + + $ gbp dch --release debian/ + $ gbp buildpackage --git-pristine-tar --git-tag + +A new upstream release can be imported with: + + $ gbp import-orig --uscan get-orig-source --------------- diff -Nru vim-command-t-4.0/debian/rules vim-command-t-5.0.2-5-g7147ba9/debian/rules --- vim-command-t-4.0/debian/rules 2016-12-09 23:38:28.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/debian/rules 2018-03-06 10:48:39.000000000 +0000 @@ -15,18 +15,18 @@ # thereby causing `bundle exec` to complain that Debian-packaged gems are missing. rm -rf .bundle ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS))) -# Test suite doesn't currently pass, and upstream says that it's a maintenance -# burden, so ignore failures. +# Test suite doesn't currently pass; see debian/TODO for details. -rake spec endif override_dh_install: dh_install - cp debian/command-t.yaml.in debian/vim-command-t/usr/share/vim/registry/command-t.yaml + find ruby '(' -name '*.rb' -o -name '*.so' ')' -exec cp --parents {} debian/vim-command-t/usr/lib/vim-command-t ';' + install -T -D -m 0644 debian/command-t.yaml.in debian/vim-command-t/usr/share/vim/registry/command-t.yaml cd debian/vim-command-t/usr/lib/vim-command-t && \ - find -type f | sed 's,^\./, - ,' >> ../../share/vim/registry/command-t.yaml + find -type f | LC_ALL=C sort | sed 's,^\./, - ,' >> ../../share/vim/registry/command-t.yaml -get-orig-source: VERSION := $(shell dpkg-parsechangelog -S Version | perl -pe 's/(.*)-/$1/') +get-orig-source: VERSION := $(shell dpkg-parsechangelog -S Version | perl -pe 's/(.*)-/$$1/') get-orig-source: set -eu; \ d=$(shell mktemp -d); \ diff -Nru vim-command-t-4.0/debian/TODO vim-command-t-5.0.2-5-g7147ba9/debian/TODO --- vim-command-t-4.0/debian/TODO 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/debian/TODO 2017-06-22 14:30:41.000000000 +0000 @@ -0,0 +1,202 @@ +Get test suite passing. As of 5.0, fails with: + + 1) CommandT::Controller accept selection opens relative paths inside the working directory + Failure/Error: stub(finder).path = anything + + NoMethodError: + undefined method `stub' for # + # ./spec/command-t/controller_spec.rb:62:in `stub_finder' + # ./spec/command-t/controller_spec.rb:12:in `block (3 levels) in ' + + 2) CommandT::Controller accept selection opens absolute paths outside the working directory + Failure/Error: stub(finder).path = anything + + NoMethodError: + undefined method `stub' for # + # ./spec/command-t/controller_spec.rb:62:in `stub_finder' + # ./spec/command-t/controller_spec.rb:12:in `block (3 levels) in ' + + 3) CommandT::Controller accept selection does not get confused by common directory prefixes + Failure/Error: stub(finder).path = anything + + NoMethodError: + undefined method `stub' for # + # ./spec/command-t/controller_spec.rb:62:in `stub_finder' + # ./spec/command-t/controller_spec.rb:12:in `block (3 levels) in ' + + 4) CommandT::Controller accept selection does not enter an infinite loop when toggling focus + Failure/Error: stub(finder).path = anything + + NoMethodError: + undefined method `stub' for # + # ./spec/command-t/controller_spec.rb:62:in `stub_finder' + # ./spec/command-t/controller_spec.rb:12:in `block (3 levels) in ' + + 5) CommandT::Finder::BufferFinder sorted_matches_for method returns an empty array when no matches + Failure/Error: any_instance_of(CommandT::Scanner::BufferScanner, :paths => @paths) + + NoMethodError: + undefined method `any_instance_of' for # + Did you mean? an_instance_of + + # ./spec/command-t/finder/buffer_finder_spec.rb:9:in `block (2 levels) in ' + + 6) CommandT::Finder::BufferFinder sorted_matches_for method returns all files when query string is empty + Failure/Error: any_instance_of(CommandT::Scanner::BufferScanner, :paths => @paths) + + NoMethodError: + undefined method `any_instance_of' for # + Did you mean? an_instance_of + # ./spec/command-t/finder/buffer_finder_spec.rb:9:in `block (2 levels) in ' + + 7) CommandT::Finder::BufferFinder sorted_matches_for method returns files in alphabetical order when query string is empty + Failure/Error: any_instance_of(CommandT::Scanner::BufferScanner, :paths => @paths) + + NoMethodError: + undefined method `any_instance_of' for # + Did you mean? an_instance_of + # ./spec/command-t/finder/buffer_finder_spec.rb:9:in `block (2 levels) in ' + + 8) CommandT::Finder::BufferFinder sorted_matches_for method returns matching files in score order + Failure/Error: any_instance_of(CommandT::Scanner::BufferScanner, :paths => @paths) + + NoMethodError: + undefined method `any_instance_of' for # + Did you mean? an_instance_of + # ./spec/command-t/finder/buffer_finder_spec.rb:9:in `block (2 levels) in ' + + 9) CommandT::Finder::BufferFinder sorted_matches_for method returns matching dot files even when search term does not include a dot + Failure/Error: any_instance_of(CommandT::Scanner::BufferScanner, :paths => @paths) + + NoMethodError: + undefined method `any_instance_of' for # + Did you mean? an_instance_of + # ./spec/command-t/finder/buffer_finder_spec.rb:9:in `block (2 levels) in ' + + 10) CommandT::Finder::BufferFinder sorted_matches_for method returns matching files inside dot directories even when search term does not include a dot + Failure/Error: any_instance_of(CommandT::Scanner::BufferScanner, :paths => @paths) + + NoMethodError: + undefined method `any_instance_of' for # + Did you mean? an_instance_of + # ./spec/command-t/finder/buffer_finder_spec.rb:9:in `block (2 levels) in ' + + 11) CommandT::Finder::BufferFinder sorted_matches_for method does not consult the 'wildignore' setting + Failure/Error: any_instance_of(CommandT::Scanner::BufferScanner, :paths => @paths) + + NoMethodError: + undefined method `any_instance_of' for # + Did you mean? an_instance_of + # ./spec/command-t/finder/buffer_finder_spec.rb:9:in `block (2 levels) in ' + + 12) CommandT::Finder::BufferFinder sorted_matches_for method obeys the :limit option for empty search strings + Failure/Error: any_instance_of(CommandT::Scanner::BufferScanner, :paths => @paths) + + NoMethodError: + undefined method `any_instance_of' for # + Did you mean? an_instance_of + # ./spec/command-t/finder/buffer_finder_spec.rb:9:in `block (2 levels) in ' + + 13) CommandT::Finder::BufferFinder sorted_matches_for method obeys the :limit option for non-empty search strings + Failure/Error: any_instance_of(CommandT::Scanner::BufferScanner, :paths => @paths) + + NoMethodError: + undefined method `any_instance_of' for # + Did you mean? an_instance_of + # ./spec/command-t/finder/buffer_finder_spec.rb:9:in `block (2 levels) in ' + + 14) CommandT::Finder::FileFinder sorted_matches_for method returns an empty array when no matches + Failure/Error: stub(::VIM).evaluate(/expand/) { 0 } + + NoMethodError: + undefined method `stub' for # + # ./spec/command-t/finder/file_finder_spec.rb:22:in `block (2 levels) in ' + + 15) CommandT::Finder::FileFinder sorted_matches_for method returns all files when query string is empty + Failure/Error: stub(::VIM).evaluate(/expand/) { 0 } + + NoMethodError: + undefined method `stub' for # + # ./spec/command-t/finder/file_finder_spec.rb:22:in `block (2 levels) in ' + + 16) CommandT::Finder::FileFinder sorted_matches_for method returns files in alphabetical order when query string is empty + Failure/Error: stub(::VIM).evaluate(/expand/) { 0 } + + NoMethodError: + undefined method `stub' for # + # ./spec/command-t/finder/file_finder_spec.rb:22:in `block (2 levels) in ' + + 17) CommandT::Finder::FileFinder sorted_matches_for method returns matching files in score order + Failure/Error: stub(::VIM).evaluate(/expand/) { 0 } + + NoMethodError: + undefined method `stub' for # + # ./spec/command-t/finder/file_finder_spec.rb:22:in `block (2 levels) in ' + + 18) CommandT::Finder::FileFinder sorted_matches_for method obeys the :limit option for empty search strings + Failure/Error: stub(::VIM).evaluate(/expand/) { 0 } + + NoMethodError: + undefined method `stub' for # + # ./spec/command-t/finder/file_finder_spec.rb:22:in `block (2 levels) in ' + + 19) CommandT::Finder::FileFinder sorted_matches_for method obeys the :limit option for non-empty search strings + Failure/Error: stub(::VIM).evaluate(/expand/) { 0 } + + NoMethodError: + undefined method `stub' for # + # ./spec/command-t/finder/file_finder_spec.rb:22:in `block (2 levels) in ' + + 20) CommandT::Scanner::BufferScanner paths method returns a list of regular files + Failure/Error: stub(@scanner).relative_path_under_working_directory(is_a(String)) { |arg| arg } + + NoMethodError: + undefined method `stub' for # + # ./spec/command-t/scanner/buffer_scanner_spec.rb:17:in `block (2 levels) in ' + + 21) CommandT::Scanner::FileScanner::RubyFileScanner paths method returns a list of regular files + Failure/Error: stub(::VIM).evaluate(/exists/) { 1 } + + NoMethodError: + undefined method `stub' for # + # ./spec/command-t/scanner/file_scanner/ruby_file_scanner_spec.rb:14:in `block (2 levels) in ' + + 22) CommandT::Scanner::FileScanner::RubyFileScanner path= method allows repeated applications of scanner at different paths + Failure/Error: stub(::VIM).evaluate(/exists/) { 1 } + + NoMethodError: + undefined method `stub' for # + # ./spec/command-t/scanner/file_scanner/ruby_file_scanner_spec.rb:14:in `block (2 levels) in ' + + 23) CommandT::Scanner::FileScanner::RubyFileScanner 'wildignore' exclusion when there is a 'wildignore' setting in effect filters out matching files + Failure/Error: stub(::VIM).evaluate(/exists/) { 1 } + + NoMethodError: + undefined method `stub' for # + # ./spec/command-t/scanner/file_scanner/ruby_file_scanner_spec.rb:14:in `block (2 levels) in ' + + 24) CommandT::Scanner::FileScanner::RubyFileScanner 'wildignore' exclusion when there is no 'wildignore' setting in effect does nothing + Failure/Error: stub(::VIM).evaluate(/exists/) { 1 } + + NoMethodError: + undefined method `stub' for # + # ./spec/command-t/scanner/file_scanner/ruby_file_scanner_spec.rb:14:in `block (2 levels) in ' + + 25) CommandT::Scanner::FileScanner::RubyFileScanner :max_depth option does not descend below "max_depth" levels + Failure/Error: stub(::VIM).evaluate(/exists/) { 1 } + + NoMethodError: + undefined method `stub' for # + # ./spec/command-t/scanner/file_scanner/ruby_file_scanner_spec.rb:14:in `block (2 levels) in ' + + 26) CommandT::Scanner::FileScanner::WatchmanFileScanner when an error occurs falls back to the FindFileScanner + Failure/Error: + stub(scanner).get_raw_sockname do + raise described_class::WatchmanError + end + + NoMethodError: + undefined method `stub' for # + # ./spec/command-t/scanner/file_scanner/watchman_file_scanner_spec.rb:11:in `block (3 levels) in ' + +Perhaps due to the test suite requiring a newer rspec than 3.5 (in sid at time of writing). diff -Nru vim-command-t-4.0/doc/command-t.txt vim-command-t-5.0.2-5-g7147ba9/doc/command-t.txt --- vim-command-t-4.0/doc/command-t.txt 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/doc/command-t.txt 2017-11-17 03:46:11.000000000 +0000 @@ -72,7 +72,7 @@ version of OS X at the time of writing, Mavericks, does). All recent versions of MacVim come with Ruby support; it is available from: - http://github.com/b4winckler/macvim/downloads + http://macvim-dev.github.io/macvim/ For Windows users, the Vim 7.2 executable available from www.vim.org does include Ruby support, and is recommended over version 7.3 (which links against @@ -246,7 +246,7 @@ NeoBundle 'wincent/command-t', { \ 'build_commands': ['make', 'ruby'], \ 'build': { - \ 'unix': 'cd ruby/command-t && { make clean; ruby extconf.rb && make }' + \ 'unix': 'cd ruby/command-t/ext/command-t && { make clean; ruby extconf.rb && make }' \ } \ } call neobundle#end() @@ -279,7 +279,7 @@ Command-T: call plug#begin() - Plugin 'wincent/command-t' + Plug 'wincent/command-t' call plug#end() To actually install the plug-in run `:PlugInstall` from inside Vim. After @@ -289,7 +289,7 @@ call plug#begin() Plug 'wincent/command-t', { - \ 'do': 'cd ruby/command-t && ruby extconf.rb && make' + \ 'do': 'cd ruby/command-t/ext/command-t && ruby extconf.rb && make' \ } call plug#end() @@ -307,10 +307,10 @@ `~/.vim/plugged/Command-T/`. Wherever the Command-T files were installed, you can build the extension by -changing to the `ruby/command-t` subdirectory and running a couple of commands -as follows: +changing to the `ruby/command-t/ext/command-t` subdirectory and running a +couple of commands as follows: - cd ~/.vim/bundle/command-t/ruby/command-t + cd ~/.vim/bundle/command-t/ruby/command-t/ext/command-t ruby extconf.rb make @@ -347,7 +347,7 @@ system Ruby is 2.0 but MacVim still links against the older 1.8.7 Ruby that is also bundled with the system; in this case the build command becomes: - cd ~/.vim/bundle/command-t/ruby/command-t + cd ~/.vim/bundle/command-t/ruby/command-t/ext/command-t /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby extconf.rb make @@ -506,6 +506,7 @@ open the selected file in a new split window open the selected file in a new vertical split window open the selected file in a new tab + delete the selected buffer select next file in the file listing select next file in the file listing select next file in the file listing @@ -612,6 +613,19 @@ mapping). This command may be useful for people wishing to extend Command-T by "monkey patching" its functionality. + *:CommandTOpen* +|:CommandTOpen| The default command used by the various "AcceptSelection" + settings (|g:CommandTAcceptSelectionCommand|, + |g:CommandTAcceptSelectionTabCommand|, + |g:CommandTAcceptSelectionSplitCommand|, and + |g:CommandTAcceptSelectionVSplitCommand|) to open the + selected item. Implements smart "goto or open" logic that + will try to focus an existing, previously opened instance of + the selected item if possible, and only open a new tab or + split as a last resort. To work most usefully, should be + used with Vim's |'switchbuf'| setting set to "usetab". + + MAPPINGS *command-t-mappings* @@ -632,9 +646,9 @@ Note that Command-T won't overwrite a pre-existing mapping so if you prefer to define different mappings use lines like these in your |.vimrc|: - nnoremap t (CommandT) - nnoremap b (CommandTBuffer) - nnoremap j (CommandTJump) + nmap t (CommandT) + nmap b (CommandTBuffer) + nmap j (CommandTJump) Replacing "t", "b" or "j" with your mapping of choice. @@ -679,7 +693,7 @@ Set up a mapping for any of these like so: - nnoremap h (CommandTHelp) + nmap h (CommandTHelp) When the Command-T window is active a number of other additional mappings become available for doing things like moving between and selecting matches. @@ -799,6 +813,11 @@ If set to 1, Command-T will scan submodules (recursively) when using the "git" file scanner (see |g:CommandTFileScanner|). + *g:CommandTGitIncludeUntracked* + |g:CommandTGitIncludeUntracked| boolean (default: 0) + + If set to 1, Command-T will include untracked files when using the "git" + file scanner (see: |g:CommandTFileScanner|). *g:CommandTSCMDirectories* |g:CommandTSCMDirectories| string (default: '.git,.hg,.svn,.bzr,_darcs') @@ -935,62 +954,56 @@ If unset (which is the default), the value of the Vim |'smartcase'| setting will be used instead. - *g:CommandTAcceptSelectionCommand* - |g:CommandTAcceptSelectionCommand| string (default: 'e') + *g:CommandTAcceptSelectionCommand* + |g:CommandTAcceptSelectionCommand| string (default: 'CommandTOpen e') The Vim command that will be used to open a selection from the match listing (via |g:CommandTAcceptSelectionMap|). - For an example of how this can be used to apply arbitrarily complex - logic, see the example in |g:CommandTAcceptSelectionTabCommand| below. + See also, |:CommandTOpen|. - *g:CommandTAcceptSelectionTabCommand* - |g:CommandTAcceptSelectionTabCommand| string (default: 'tabe') + *g:CommandTAcceptSelectionTabCommand* + |g:CommandTAcceptSelectionTabCommand| string (default: 'CommandTOpen tabe') The Vim command that will be used to open a selection from the match - listing in a new tab (via |g:CommandTAcceptSelectionSplitMap|). - - For example, this can be used to switch to an existing buffer (rather - than opening a duplicate buffer with the selection in a new tab) with - configuration such as the following: - - set switchbuf=usetab + listing in a new tab (via |g:CommandTAcceptSelectionTabMap|). - function! GotoOrOpen(...) - for file in a:000 - if bufwinnr(file) != -1 - exec "sb " . file - else - exec "tabe " . file - endif - endfor - endfunction - - command! -nargs=+ GotoOrOpen call GotoOrOpen("") - - let g:CommandTAcceptSelectionTabCommand = 'GotoOrOpen' - - For a slightly more comprehensive example, see: https://wt.pe/e + See also, |:CommandTOpen|. *g:CommandTAcceptSelectionSplitCommand* - |g:CommandTAcceptSelectionSplitCommand| string (default: 'sp') + |g:CommandTAcceptSelectionSplitCommand| string (default: 'CommandTOpen sp') The Vim command that will be used to open a selection from the match - listing in a split (via |g:CommandTAcceptSelectionVSplitMap|). + listing in a split (via |g:CommandTAcceptSelectionSplitMap|). - For an example of how this can be used to apply arbitrarily complex - logic, see the example in |g:CommandTAcceptSelectionTabCommand| above. + See also, |:CommandTOpen|. - *g:CommandTAcceptSelectionVsplitCommand* - string (default: 'vs') + *g:CommandTAcceptSelectionVsplitCommand* + string (default: 'CommandTOpen vs') |g:CommandTAcceptSelectionVSplitCommand| The Vim command that will be used to open a selection from the match listing in a vertical split (via |g:CommandTAcceptSelectionVSplitMap|). - For an example of how this can be used to apply arbitrarily complex - logic, see the example in |g:CommandTAcceptSelectionTabCommand| above. + See also, |:CommandTOpen|. + *g:CommandTWindowFilter* + string (default: '!&buflisted && &buftype == "nofile"') + |g:CommandTWindowFilter| + + An expression that will be used to filter out windows that Command-T + should avoid using to open the selected file. The expression should + evaluate to a boolean (0 or 1). + + The default expression skips windows containing unlisted buffers that are + not backed by files (examples of such files include NERDTree windows). As + an example of the kind of custom expression you may wish to supply, if + you are using NERDTree to hijack |netrw| windows ('NERDTreeHijackNetrw') + and you want to make sure that Command-T does not skip over those, you + could use: +> + let g:CommandTWindowFilter='!&buflisted && &buftype == "nofile" && !exists("w:netrw_liststyle")" +< *g:CommandTEncoding* |g:CommandTEncoding| string (default: none) @@ -1126,25 +1139,6 @@ |g:CommandTWildIgnore| setting to apply an override that takes effect only during Command-T searches. - Note that there are some differences among file scanners - (see |g:CommandTFileScanner|) with respect to 'wildignore' handling: - - - The default "ruby" scanner explores the filesystem recursively using a - depth-first search, and any directory (or subdirectory) which matches - the 'wildignore' pattern is not explored. So, if your 'wildignore' - contains "*/node_modules" then that entire sub-hierarchy will be - ignored. - - - The "git" and "find" scanners apply 'wildignore' filtering only after - completing their scans. - - - The "watchman" scanner is intended for use with massive hierarchies - where speed is of the utmost import, so it doesn't make use of Vim's - very slow 'wildignore' filtering at all. Instead, it constructs a - regular expression on the fly based on 'wildignore' and/or - |g:CommandTWildIgnore| and uses that. To suppress this behavior, set - |g:CommandTWildIgnore| to an empty string. - INTEGRATION AND EXTENSIBILITY *command-t-integration-and-extensibility* @@ -1163,7 +1157,7 @@ an |autocommand| or apply custom configuration. For example of an |ftplugin| that sets a custom 'statusline' for the -Command-T match listing buffer, see: https://wt.pe/f +Command-T match listing buffer, see: https://rfr.to/f *command-t-load* *commandt#Load* @@ -1211,7 +1205,7 @@ autocmd User CommandTWillShowMatchListing call CustomWillShow() autocmd! User CommandTDidHideMatchListing autocmd User CommandTDidHideMatchListing call CustomDidHide() - +< FAQ *command-t-faq* @@ -1318,9 +1312,7 @@ tree with a tool like the `find` executable may take literally minutes with a cold cache. Once the cache is warm, the same `find` run may take only a second or two. Command-T provides a "find" scanner to leverage this performance, but -there is still massive overhead in passing the results through Vim internal -functions that apply 'wildignore' settings and such, so for truly immense -repos the "watchman" scanner is the tool of choice. +for truly immense repos the "watchman" scanner is the tool of choice. This scanner delegates the task of finding files to Facebook's `watchman` tool (https://github.com/facebook/watchman), which can return results for a 500,000 @@ -1403,37 +1395,44 @@ AUTHORS *command-t-authors* Command-T is written and maintained by Greg Hurrell . -Other contributors that have submitted patches include (in alphabetical -order, via `git shortlog -s | cut -f 2-3 | column -c 72`): +Other contributors that have submitted patches include, in alphabetical order: - Abhinav Gupta Nicolas Alpi + Abhinav Gupta Nicholas T. + Adrian Keet Nicolas Alpi Aleksandrs Ļedovskis Nikolai Aleksandrovich Pavlov - Andy Waite Nilo César Teixeira - Anthony Panozzo Noon Silk - Artem Nezvigin Ole Petter Bang - Ben Boeckel Patrick Hayes - Daniel Burgess Paul Jolly - Daniel Hahler Pavel Sergeev - David Szotten Rainux Luo - Emily Strickland Richard Feldman - Felix Tjandrawibawa Roland Puntaier - Gary Bernhardt Ross Lagerwall - Greg Hurrell Sam Morris - Ivan Ukhov Scott Bronson - Jeff Kreeftmeijer Seth Fowler - Jerome Castaneda Sherzod Gapirov - Joe Lencioni Shlomi Fish - KJ Tsanaktsidis Steven Moazami + Alexey Terekhov Nilo César Teixeira + Andy Waite Noon Silk + Anthony Panozzo Ole Petter Bang + Artem Nezvigin Patrick Hayes + Ben Boeckel Paul Jolly + Daniel Burgess Pavel Sergeev + Daniel Hahler Rainux Luo + David Szotten Richard Feldman + Douglas Drumond Roland Puntaier + Emily Strickland Ross Lagerwall + Felix Tjandrawibawa Sam Morris + Gary Bernhardt Scott Bronson + Henric Trotzig Seth Fowler + Ivan Ukhov Sherzod Gapirov + Jakob Pfender Shlomi Fish + Jeff Kreeftmeijer Stefan Schmidt + Jerome Castaneda Stephen Gelman + Joe Lencioni Steven Moazami + KJ Tsanaktsidis Steven Stallion Kevin Webster Sung Pae Kien Nguyen Duc Thomas Pelletier Lucas de Vries Ton van den Heuvel Marcus Brito Victor Hugo Borja Marian Schubert Vlad Seghete Matthew Todd Vít Ondruch - Mike Lundy Woody Peterson - Nadav Samet Yan Pritzker - Nate Kane Zak Johnson - Nicholas T. + Max Timkovich Woody Peterson + Mike Lundy Yan Pritzker + Nadav Samet Zak Johnson + Nate Kane + +This list produced with: + + :read !git shortlog -s | grep -v 'Greg Hurrell' | cut -f 2-3 | column -c 72 | expand | sed -e 's/^/ /' Additionally, Hanson Wang, Jacek Wysocki and Yiding Jia wrote patches which were not directly included but which served as a model for changes that did @@ -1521,6 +1520,12 @@ https://github.com/JazzCore/ctrlp-cmatcher +commandt.score ~ + +Command-T's match-scoring algorithm wrapped in a Python extension: + + https://pypi.python.org/pypi/commandt.score + LICENSE *command-t-license* @@ -1549,7 +1554,55 @@ HISTORY *command-t-history* -4.0 (16 May 2016) +master (not yet released) ~ + +- Fix unlisted buffers showing up in |:CommandTBuffer| listing on Neovim. +- Fix edge cases with opening selections in tabs (#315). + +5.0.2 (7 September 2017) ~ + +- Fix a RangeError on 64-bit Windows (#304, patch from Adrian Keet). +- Fix issue switching back to previously opened file in another tab (#306). +- Fix inability to open some help targets with |:CommandTHelp| (#307). +- Similar to #307, make |:CommandTCommand| work with commands containing + special characters. +- Again similar to #307, prevent special characters in tags from being escaped + when using |:CommandTTag|. + +5.0.1 (18 August 2017) ~ + +- Fixed inability to open a top-level file with a name matching a previously + opened file (#295). +- Fixed a related issue where previously opened file would cause a file to be + opened directly rather than in the desired split/tab (#298). +- Tweaked mapping behavior to better match what other readline-ish + implementations do, especially with respect to moving past punctuation + (#301). + +5.0 (6 June 2017) ~ + +- Command-T now uses |:map-|, when available, when setting up mappings. +- 'wildignore' filtering is now always performed by producing an equivalent + regular expression and applying that; previously this only happened with + the "watchman" file scanner (includes a bug fix from Henric Trotzig). +- Fixed mis-memoization of |:CommandTHelp| and |:CommandTJump| finders + (whichever one you used first would be used for both). +- Added mapping () to delete a buffer from the buffer list (patch from + Max Timkovich). +- Added |g:CommandTGitIncludeUntracked| option (patch from Steven Stallion). +- Added |:CommandTOpen|, which implements smart "goto or open" functionality, + and adjust |g:CommandTAcceptSelectionCommand|, + |g:CommandTAcceptSelectionTabCommand|, + |g:CommandTAcceptSelectionSplitCommand|, and + |g:CommandTAcceptSelectionVSplitCommand| to use it by default. Their default + values have been changed from "e", "tabe", "sp" and "vs" to "CommandTOpen + e", "CommandTOpen tabe", "CommandTOpen sp" and "CommandTOpen vs", + respectively. Use with |'switchbuf'| set to "usetab" for maximum effect. +- Added |g:CommandTWindowFilter| for customizing the filtering expression that + is used to determine which windows Command-T should not open selected + files in. + +4.0 (16 May 2016) ~ - A non-leading dot in the search query can now match against dot-files and "dot-directories" in non-leading path components. @@ -1574,22 +1627,22 @@ - Make it possible to completely disable |'wildignore'|-based filtering by setting |g:CommandTWildIgnore| to an empty string. - The "watchman" file scanner now respects |'wildignore'| and - |g:CommandTWildIgnore| by construcing an equivalent regular expression and + |g:CommandTWildIgnore| by constructing an equivalent regular expression and using that for filtering. - Show a warning when hitting |g:CommandTMaxFiles|, and add a corresponding |g:CommandTSuppressMaxFilesWarning| setting to suppress the warning. -3.0.2 (9 February 2016) +3.0.2 (9 February 2016) ~ - Minimize flicker on opening and closing the match listing in MacVim. - Add |CommandTWillShowMatchListing| and |CommandTDidHideMatchListing| "User" autocommands. -3.0.1 (25 January 2016) +3.0.1 (25 January 2016) ~ - restore compatibility with Ruby 1.8.7. -3.0 (19 January 2016) +3.0 (19 January 2016) ~ - change |g:CommandTIgnoreSpaces| default value to 1. - change |g:CommandTMatchWindowReverse| default value to 1. @@ -1597,7 +1650,7 @@ - try harder to avoid scrolling other buffer when showing or hiding the match listing -2.0 (28 December 2015) +2.0 (28 December 2015) ~ - add |:CommandTIgnoreSpaces| option (patch from KJ Tsanaktsidis) - make Command-T resilient to people deleting its hidden, unlisted buffer @@ -1645,17 +1698,17 @@ (patch from Jerome Castaneda) - add |g:CommandTCursorColor| option - expose mappings for |:CommandT| and |:CommandTBuffer| using `` - mappings |(CommandT)| and |(CommandT)| + mappings |(CommandT)| and |(CommandTBuffer)| - add `j` mapping to |:CommandTJump|, via |(CommandTJump)| (defined only if no pre-existing mapping exists) -1.13 (29 April 2015) +1.13 (29 April 2015) ~ - avoid "W10: Warning: Changing a readonly file" when starting Vim in read-only mode (ie. as `view` or with the `-R` option) - fix infinite loop on || (regression introduced in 1.12) -1.12 (9 April 2015) +1.12 (9 April 2015) ~ - add |:CommandTLoad| command - fix rare failure to restore cursor color after closing Command-T (patch from @@ -1674,25 +1727,25 @@ - fix for not falling back to "find"-based scanner when a Watchman-related error occurs -1.11.4 (4 November 2014) +1.11.4 (4 November 2014) ~ - fix infinite loop on Windows when |g:CommandTTraverseSCM| is set to a value other than "pwd" (bug present since 1.11) - handle unwanted split edgecase when |'hidden'| is set, the current buffer is modified, and it is visible in more than one window -1.11.3 (10 October 2014) +1.11.3 (10 October 2014) ~ - ignore impromperly encoded filenames (patch from Sherzod Gapirov) - fix failure to update path when using |:cd| in conjunction with |g:CommandTTraverseSCM| set to "pwd" (bug present since 1.11.2) -1.11.2 (2 September 2014) +1.11.2 (2 September 2014) ~ - fix error while using Command-T outside of an SCM repo (bug present since 1.11.1) -1.11.1 (29 August 2014) +1.11.1 (29 August 2014) ~ - compatibility fixes with Ruby 1.8.6 (patch from Emily Strickland) - compatibility fixes with Ruby 1.8.5 @@ -1701,7 +1754,7 @@ set to "pwd" (bug present since 1.11) - performance improvements -1.11 (15 August 2014) +1.11 (15 August 2014) ~ - improve edge-case handling in match results window code (patches from Richard Feldman) @@ -1712,7 +1765,7 @@ Osheroff) - add AppStream metadata (patch from Vít Ondruch) -1.10 (15 July 2014) +1.10 (15 July 2014) ~ - improve tag finder performance by caching tag lists (patch from Artem Nezvigin) @@ -1728,12 +1781,12 @@ - add |g:CommandTIgnoreCase| and |g:CommandTSmartCase| options, providing support for case-sensitive matching (based on patch from Jacek Wysocki) -1.9.1 (30 May 2014) +1.9.1 (30 May 2014) ~ - include the file in the release archive that was missing from the 1.9 release -1.9 (25 May 2014) +1.9 (25 May 2014) ~ - improved startup time using Vim's autload mechanism (patch from Ross Lagerwall) @@ -1745,13 +1798,13 @@ - tune memoization in match scoring algorithm, yielding a more than 10% speed boost -1.8 (31 March 2014) +1.8 (31 March 2014) ~ - taught Watchman file scanner to use the binary protocol instead of JSON, roughly doubling its speed - build changes to accommodate MinGW (patch from Roland Puntaier) -1.7 (9 March 2014) +1.7 (9 March 2014) ~ - added |g:CommandTInputDebounce|, which can be used to improve responsiveness in large file hierarchies (based on patch from Yiding Jia) @@ -1762,23 +1815,23 @@ - added |g:CommandTFileScanner|, which can be used to switch file scanners - fix processor count detection on some platforms (patch from Pavel Sergeev) -1.6.1 (22 December 2013) +1.6.1 (22 December 2013) ~ - defer processor count detection until runtime (makes it possible to sensibly build Command-T on one machine and use it on another) -1.6 (16 December 2013) +1.6 (16 December 2013) ~ - on systems with POSIX threads (such as OS X and Linux), Command-T will use threads to compute match results in parallel, resulting in a large speed boost that is especially noticeable when navigating large projects -1.5.1 (23 September 2013) +1.5.1 (23 September 2013) ~ - exclude large benchmark fixture file from source exports (patch from Vít Ondruch) -1.5 (18 September 2013) +1.5 (18 September 2013) ~ - don't scan "pathological" filesystem structures (ie. circular or self-referential symlinks; patch from Marcus Brito) @@ -1792,7 +1845,7 @@ hierarchies - added |g:CommandTWildIgnore| setting (patch from Paul Jolly) -1.4 (20 June 2012) +1.4 (20 June 2012) ~ - added |:CommandTTag| command (patches from Noon Silk) - turn off |'colorcolumn'| and |'relativenumber'| in the match window (patch @@ -1805,50 +1858,50 @@ - added the ability to flush the cache while the match window is open using -1.3.1 (18 December 2011) +1.3.1 (18 December 2011) ~ - fix jumplist navigation under Ruby 1.9.x (patch from Woody Peterson) -1.3 (27 November 2011) +1.3 (27 November 2011) ~ - added the option to maintain multiple caches when changing among directories; see the accompanying |g:CommandTMaxCachedDirectories| setting - added the ability to navigate using the Vim jumplist (patch from Marian Schubert) -1.2.1 (30 April 2011) +1.2.1 (30 April 2011) ~ - Remove duplicate copy of the documentation that was causing "Duplicate tag" errors - Mitigate issue with distracting blinking cursor in non-GUI versions of Vim (patch from Steven Moazami) -1.2 (30 April 2011) +1.2 (30 April 2011) ~ - added |g:CommandTMatchWindowReverse| option, to reverse the order of items in the match listing (patch from Steven Moazami) -1.1b2 (26 March 2011) +1.1b2 (26 March 2011) ~ - fix a glitch in the release process; the plugin itself is unchanged since 1.1b -1.1b (26 March 2011) +1.1b (26 March 2011) ~ - add |:CommandTBuffer| command for quickly selecting among open buffers -1.0.1 (5 January 2011) +1.0.1 (5 January 2011) ~ - work around bug when mapping |:CommandTFlush|, wherein the default mapping for |:CommandT| would not be set up - clean up when leaving the Command-T buffer via unexpected means (such as with or similar) -1.0 (26 November 2010) +1.0 (26 November 2010) ~ - make relative path simplification work on Windows -1.0b (5 November 2010) +1.0b (5 November 2010) ~ - work around platform-specific Vim 7.3 bug seen by some users (wherein Vim always falsely reports to Ruby that the buffer numbers is 0) @@ -1856,18 +1909,18 @@ throwing it away and recreating it each time Command-T is shown; this stops the buffer numbers from creeping up needlessly -0.9 (8 October 2010) +0.9 (8 October 2010) ~ - use relative paths when opening files inside the current working directory in order to keep buffer listings as brief as possible (patch from Matthew Todd) -0.8.1 (14 September 2010) +0.8.1 (14 September 2010) ~ - fix mapping issues for users who have set |'notimeout'| (patch from Sung Pae) -0.8 (19 August 2010) +0.8 (19 August 2010) ~ - overrides for the default mappings can now be lists of strings, allowing multiple mappings to be defined for any given action @@ -1881,13 +1934,13 @@ - move all Ruby files under the "command-t" subdirectory and avoid polluting the "Vim" module namespace -0.8b (11 July 2010) +0.8b (11 July 2010) ~ - large overhaul of the scoring algorithm to make the ordering of returned results more intuitive; given the scope of the changes and room for optimization of the new algorithm, this release is labelled as "beta" -0.7 (10 June 2010) +0.7 (10 June 2010) ~ - handle more |'wildignore'| patterns by delegating to Vim's own |expand()| function; with this change it is now viable to exclude patterns such as @@ -1896,18 +1949,18 @@ - always sort results alphabetically for empty search strings; this eliminates filesystem-specific variations (patch from Mike Lundy) -0.6 (28 April 2010) +0.6 (28 April 2010) ~ - |:CommandT| now accepts an optional parameter to specify the starting directory, temporarily overriding the usual default of Vim's |:pwd| - fix truncated paths when operating from root directory -0.5.1 (11 April 2010) +0.5.1 (11 April 2010) ~ - fix for Ruby 1.9 compatibility regression introduced in 0.5 - documentation enhancements, specifically targetted at Windows users -0.5 (3 April 2010) +0.5 (3 April 2010) ~ - |:CommandTFlush| now re-evaluates settings, allowing changes made via |let| to be picked up without having to restart Vim @@ -1916,13 +1969,13 @@ - provide settings for overriding default mappings - minor performance optimization -0.4 (27 March 2010) +0.4 (27 March 2010) ~ - add |g:CommandTMatchWindowAtTop| setting (patch from Zak Johnson) - documentation fixes and enhancements - internal refactoring and simplification -0.3 (24 March 2010) +0.3 (24 March 2010) ~ - add |g:CommandTMaxHeight| setting for controlling the maximum height of the match window (patch from Lucas de Vries) @@ -1934,7 +1987,7 @@ - open in split when opening normally would fail due to |'hidden'| and |'modified'| values -0.2 (23 March 2010) +0.2 (23 March 2010) ~ - compatibility fixes for compilation under Ruby 1.9 series - compatibility fixes for compilation under Ruby 1.8.5 @@ -1944,7 +1997,7 @@ - exclude paths based on |'wildignore'| setting rather than a hardcoded regular expression -0.1 (22 March 2010) +0.1 (22 March 2010) ~ - initial public release diff -Nru vim-command-t-4.0/plugin/command-t.vim vim-command-t-5.0.2-5-g7147ba9/plugin/command-t.vim --- vim-command-t-4.0/plugin/command-t.vim 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/plugin/command-t.vim 2017-11-17 03:46:11.000000000 +0000 @@ -6,41 +6,21 @@ endif let g:command_t_loaded = 1 -command! CommandTBuffer call commandt#BufferFinder() -command! CommandTCommand call commandt#CommandFinder() -command! CommandTHelp call commandt#HelpFinder() -command! CommandTHistory call commandt#HistoryFinder() -command! CommandTJump call commandt#JumpFinder() -command! CommandTLine call commandt#LineFinder() -command! CommandTMRU call commandt#MRUFinder() -command! CommandTSearch call commandt#SearchFinder() -command! CommandTTag call commandt#TagFinder() -command! -nargs=? -complete=dir CommandT call commandt#FileFinder() -command! CommandTFlush call commandt#Flush() -command! CommandTLoad call commandt#Load() +command! -nargs=+ CommandTOpen call commandt#GotoOrOpen() -if !hasmapto('(CommandT)') && maparg('t', 'n') ==# '' - nmap t (CommandT) +if empty(&switchbuf) + set switchbuf=usetab endif -nnoremap (CommandT) :CommandT -if !hasmapto('(CommandTBuffer)') && maparg('b', 'n') ==# '' - nmap b (CommandTBuffer) +" HACK: use both old and new during early development +if has('patch-7-4-1829') && get(g:, 'CommandTEngine', 'mirkwood') ==? 'isengard' + call commandt#isengard#init() endif -nnoremap (CommandTBuffer) :CommandTBuffer +call commandt#mirkwood#init() +finish -nnoremap (CommandTHelp) :CommandTHelp -nnoremap (CommandTHistory) :CommandTHistory - -if has('jumplist') - if !hasmapto('(CommandTJump)') && maparg('j', 'n') ==# '' - nmap j (CommandTJump) - endif - nnoremap (CommandTJump) :CommandTJump +if has('patch-7-4-1829') && get(g:, 'CommandTEngine', 'isengard') ==? 'isengard' + call commandt#isengard#init() +else + call commandt#mirkwood#init() endif - -nnoremap (CommandTCommand) :CommandTCommand -nnoremap (CommandTLine) :CommandTLine -nnoremap (CommandTMRU) :CommandTMRU -nnoremap (CommandTSearch) :CommandTSearch -nnoremap (CommandTTag) :CommandTTag diff -Nru vim-command-t-4.0/Rakefile vim-command-t-5.0.2-5-g7147ba9/Rakefile --- vim-command-t-4.0/Rakefile 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/Rakefile 2017-11-17 03:46:11.000000000 +0000 @@ -72,7 +72,7 @@ desc 'Clean compiled products' task :clean do - Dir.chdir 'ruby/command-t' do + Dir.chdir 'ruby/command-t/ext/command-t' do system 'make clean' if File.exists?('Makefile') system 'rm -f Makefile' end @@ -80,7 +80,7 @@ desc 'Compile extension' task :make do - Dir.chdir 'ruby/command-t' do + Dir.chdir 'ruby/command-t/ext/command-t' do ruby 'extconf.rb' system 'make clean' bail_on_failure @@ -171,10 +171,14 @@ desc 'Create the ruby gem package' task :gem => :check_tag do - sh "gem build command-t.gemspec" + Dir.chdir 'ruby/command-t' do + sh "gem build command-t.gemspec" + end end desc 'Push gem to Gemcutter ("gem push")' task :push => :gem do - sh "gem push command-t-#{rubygems_version}.gem" + Dir.chdir 'ruby/command-t' do + sh "gem push command-t-#{rubygems_version}.gem" + end end diff -Nru vim-command-t-4.0/README.md vim-command-t-5.0.2-5-g7147ba9/README.md --- vim-command-t-4.0/README.md 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/README.md 2017-11-17 03:46:11.000000000 +0000 @@ -1,6 +1,9 @@ -# Command-T +

+ + +

-![](https://raw.githubusercontent.com/wincent/command-t/media/command-t.gif) +# Command-T Command-T is a Vim plug-in that provides an extremely fast "fuzzy" mechanism for: diff -Nru vim-command-t-4.0/ruby/command-t/bin/commandtd vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/bin/commandtd --- vim-command-t-4.0/ruby/command-t/bin/commandtd 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/bin/commandtd 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,89 @@ +#!/usr/bin/env ruby + +ERR_CHANNEL = STDERR.dup +OUT_CHANNEL = STDOUT.dup + +STDERR.reopen('/dev/null', 'w') +STDOUT.reopen('/dev/null', 'w') + +require 'ostruct' + +OPTIONS = OpenStruct.new + +def log(msg) + if OPTIONS.logfile + File.open(OPTIONS.logfile, 'a') { |f| f.puts "#{Time.now}: #{msg}"} + end + nil +end + +require 'json' +require 'optparse' + +begin + OptionParser.new do |opts| + opts.on('--vim-pid=PID') # Ignore: included only to make `ps` output more useful. + opts.on('--logfile=NAME') do |logfile| + OPTIONS.logfile = logfile + end + end.parse! +rescue => e + log e +end + +begin + require 'command-t' + require 'command-t/ext' +rescue LoadError => e + load_path_modified = false + [ + File.expand_path('../ext', File.dirname(__FILE__)), + File.expand_path('../lib', File.dirname(__FILE__)) + ].each do |path| + if !$LOAD_PATH.include?(path) + $LOAD_PATH << path + load_path_modified = true + end + end + retry if load_path_modified + + # TODO: show error here instructing to run install script + log e + exit 1 +end + +def read + line = STDIN.readline.chomp + input = JSON[line] + log "read: #{line}" + input +rescue => e + log "read: #{e} reading line: #{line.inspect}" +end + +def write(payload) + json = payload.to_json + OUT_CHANNEL.puts json + OUT_CHANNEL.flush + log "wrote: #{json}" +end + +log "open for business running from #{__FILE__}" + +while true + log 'loop' + next unless input = read + if input['cd'] + Dir.chdir(input['cd']) + log "changed directory to #{input['cd']}" + write({'cd' => input['cd']}) + elsif input['match'] + threads = CommandT::Util.processor_count + scanner = OpenStruct.new(:paths => ['commandt/foo', 'commandt/bar']) + matcher = CommandT::Matcher.new(scanner) + results = matcher.sorted_matches_for(input['match'], :threads => threads) + write({'results' => results}) + else + write({'echo' => input}) + end +end diff -Nru vim-command-t-4.0/ruby/command-t/command-t.gemspec vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/command-t.gemspec --- vim-command-t-4.0/ruby/command-t/command-t.gemspec 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/command-t.gemspec 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,32 @@ +Gem::Specification.new do |s| + s.name = 'command-t' + + # see note in the Rakefile about how intermediate version numbers + # can break RubyGems + s.version = `git describe --abbrev=0`.chomp + + s.authors = ['Greg Hurrell'] + s.email = 'greg@hurrell.net' + + s.files = + ['../../README.md', '../../LICENSE', '../../Gemfile', '../../Rakefile'] + + `git ls-files -z ./bin ./ext ./lib ../../doc`.split("\x0") + + s.license = 'BSD' + s.require_paths = ['lib', 'ruby'] + s.extensions = 'ext/command-t/extconf.rb' + + s.executables = ['commandtd'] + + s.has_rdoc = false + s.homepage = 'https://github.com/wincent/command-t' + + s.summary = 'The Command-T plug-in for VIM.' + + s.description = <<-EOS + Command-T provides a fast, intuitive mechanism for opening files with a + minimal number of keystrokes. Its full functionality is only available when + installed as a Vim plug-in, but it is also made available as a RubyGem so + that other applications can make use of its searching algorithm. + EOS +end diff -Nru vim-command-t-4.0/ruby/command-t/controller.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/controller.rb --- vim-command-t-4.0/ruby/command-t/controller.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/controller.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,585 +0,0 @@ -# Copyright 2010-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -module CommandT - class Controller - include PathUtilities - include SCMUtilities - - # Wraps `method` in a `rescue` clause that attempts to print some useful - # information to the screen before re-raising any exception. Without this, - # most of the useful output is unhelpfully swallowed by Vim. - def self.guard(method) - class_eval <<-END - alias original_#{method} #{method} - def #{method}(*args, &block) - original_#{method}(*args, &block) - rescue Exception => e - backtrace = e.backtrace - trimmed = backtrace.take(backtrace.length - 2) - text = VIM::escape_for_single_quotes trimmed.join("\n") - ::VIM::command "echo '\#{text}'" - raise e - end - END - end - - def initialize - encoding = VIM::get_string('g:CommandTEncoding') - if encoding - begin - encoding = Encoding.find(encoding) - Encoding.default_external = encoding - Encoding.default_internal = encoding - rescue - end - end - end - - # For possible use in status lines. - def active_finder - @active_finder && @active_finder.class.name - end - - # For possible use in status lines. - def path - @path - end - - # For possible use in status lines. - def is_own_buffer(buffer_number) - @match_window && buffer_number == @match_window.buffer_number - end - - # For possible use in status lines. - def return_is_own_buffer(buffer_number) - if is_own_buffer(buffer_number) - ::VIM::command 'return 1' - else - ::VIM::command 'return 0' - end - end - - def show_buffer_finder - @path = VIM::pwd - @active_finder = buffer_finder - show - end - guard :show_buffer_finder - - def show_command_finder - @path = VIM::pwd - @active_finder = command_finder - show - end - guard :show_command_finder - - def show_help_finder - @path = VIM::pwd - @active_finder = help_finder - show - end - guard :show_help_finder - - def show_history_finder - @path = VIM::pwd - @active_finder = history_finder - show - end - guard :show_history_finder - - def show_jump_finder - @path = VIM::pwd - @active_finder = jump_finder - show - end - guard :show_jump_finder - - def show_line_finder - @path = VIM::pwd - @active_finder = line_finder - show - end - guard :show_line_finder - - def show_mru_finder - @path = VIM::pwd - @active_finder = mru_finder - show - end - guard :show_mru_finder - - def show_search_finder - @path = VIM::pwd - @active_finder = search_finder - show - end - guard :show_search_finder - - def show_tag_finder - @path = VIM::pwd - @active_finder = tag_finder - show - end - guard :show_tag_finder - - def show_file_finder - # optional parameter will be desired starting directory, or "" - - arg = ::VIM::evaluate('a:arg') - if arg && arg.size > 0 - @path = File.expand_path(arg, VIM::pwd) - else - traverse = VIM::get_string('g:CommandTTraverseSCM') || 'file' - case traverse - when 'file' - @path = nearest_ancestor(VIM::current_file_dir, scm_markers) || VIM::pwd - when 'dir' - @path = nearest_ancestor(VIM::pwd, scm_markers) || VIM::pwd - else - @path = VIM::pwd - end - end - - @active_finder = file_finder - file_finder.path = @path - show - rescue Errno::ENOENT - # probably a problem with the optional parameter - @match_window.print_no_such_file_or_directory - end - guard :show_file_finder - - def hide - @match_window.leave - if VIM::Window.select @initial_window - if @initial_buffer.number == 0 - # upstream bug: buffer number misreported as 0 - # see: https://wincent.com/issues/1617 - ::VIM::command "silent b #{@initial_buffer.name}" - else - ::VIM::command "silent b #{@initial_buffer.number}" - end - end - end - - # Take current matches and stick them in the quickfix window. - def quickfix - hide - - matches = @matches.map do |match| - "{ 'filename': '#{VIM::escape_for_single_quotes match}' }" - end.join(', ') - - ::VIM::command 'call setqflist([' + matches + '])' - ::VIM::command 'cope' - end - guard :quickfix - - def refresh - return unless @active_finder && @active_finder.respond_to?(:flush) - @active_finder.flush - list_matches! - end - guard :refresh - - def flush - @file_finder = nil - @max_height = nil - @min_height = nil - @prompt = nil - @tag_finder = nil - end - guard :flush - - def handle_key - key = ::VIM::evaluate('a:arg').to_i.chr - if @focus == prompt - prompt.add! key - update - else - @match_window.find key - end - end - guard :handle_key - - def backspace - if @focus == prompt - prompt.backspace! - update - end - end - guard :backspace - - def delete - if @focus == prompt - prompt.delete! - update - end - end - guard :delete - - def accept_selection(options = {}) - selection = @match_window.selection - hide - open_selection(selection, options) unless selection.nil? - end - guard :accept_selection - - def toggle_focus - @focus.unfocus # old focus - @focus = @focus == prompt ? @match_window : prompt - @focus.focus # new focus - end - guard :toggle_focus - - def cancel - hide - end - guard :cancel - - def select_next - @match_window.select_next - end - guard :select_next - - def select_prev - @match_window.select_prev - end - guard :select_prev - - def clear - prompt.clear! - list_matches! - end - guard :clear - - def clear_prev_word - prompt.clear_prev_word! - list_matches! - end - guard :clear_prev_word - - def cursor_left - prompt.cursor_left if @focus == prompt - end - guard :cursor_left - - def cursor_right - prompt.cursor_right if @focus == prompt - end - guard :cursor_right - - def cursor_end - prompt.cursor_end if @focus == prompt - end - guard :cursor_end - - def cursor_start - prompt.cursor_start if @focus == prompt - end - guard :cursor_start - - def leave - @match_window.leave - end - - def unload - @match_window.unload - end - - def list_matches(options = {}) - return unless @needs_update || options[:force] - - @matches = @active_finder.sorted_matches_for( - prompt.abbrev, - :case_sensitive => case_sensitive?, - :limit => match_limit, - :threads => CommandT::Util.processor_count, - :ignore_spaces => VIM::get_bool('g:CommandTIgnoreSpaces', true), - :recurse => VIM::get_bool('g:CommandTRecursiveMatch', true) - ) - @match_window.matches = @matches - - # Scanner may have overwritten prompt to show progress. - prompt.redraw - - @needs_update = false - end - guard :list_matches - - def tab_command - VIM::get_string('g:CommandTAcceptSelectionTabCommand') || 'tabe' - end - - def split_command - VIM::get_string('g:CommandTAcceptSelectionSplitCommand') || 'sp' - end - - def vsplit_command - VIM::get_string('g:CommandTAcceptSelectionVSplitCommand') || 'vs' - end - - private - - def update - if @debounce_interval > 0 - @needs_update = true - else - list_matches! - end - end - - def prompt - @prompt ||= Prompt.new( - :cursor_color => VIM::get_string('g:CommandTCursorColor') - ) - end - - def scm_markers - markers = VIM::get_string('g:CommandTSCMDirectories') - markers = markers && markers.split(/\s*,\s*/) - markers = %w[.git .hg .svn .bzr _darcs] unless markers && markers.any? - markers - end - - def list_matches! - list_matches(:force => true) - end - - def show - @initial_window = $curwin - @initial_buffer = $curbuf - @debounce_interval = VIM::get_number('g:CommandTInputDebounce') || 0 - @match_window = MatchWindow.new \ - :encoding => VIM::get_string('g:CommandTEncoding'), - :highlight_color => VIM::get_string('g:CommandTHighlightColor'), - :match_window_at_top => VIM::get_bool('g:CommandTMatchWindowAtTop'), - :match_window_reverse => VIM::get_bool('g:CommandTMatchWindowReverse', true), - :min_height => min_height, - :debounce_interval => @debounce_interval, - :prompt => prompt, - :name => "Command-T [#{@active_finder.name}]" - @focus = prompt - prompt.focus - register_for_key_presses - set_up_autocmds - clear # clears prompt and lists matches - end - - def max_height - @max_height ||= VIM::get_number('g:CommandTMaxHeight') || 15 - end - - def min_height - @min_height ||= begin - min_height = VIM::get_number('g:CommandTMinHeight') || 0 - min_height = max_height if max_height != 0 && min_height > max_height - min_height - end - end - - def case_sensitive? - if prompt.abbrev.match(/[A-Z]/) - if VIM::exists?('g:CommandTSmartCase') - smart_case = VIM::get_bool('g:CommandTSmartCase') - else - smart_case = VIM::get_bool('&smartcase') - end - - if smart_case - return true - end - end - - if VIM::exists?('g:CommandTIgnoreCase') - return !VIM::get_bool('g:CommandTIgnoreCase') - end - - false - end - - # Backslash-escape space, \, |, %, #, " - def sanitize_path_string(str) - # for details on escaping command-line mode arguments see: :h : - # (that is, help on ":") in the Vim documentation. - str.gsub(/[ \\|%#"]/, '\\\\\0') - end - - def current_buffer_visible_in_other_window - count = (0...::VIM::Window.count).to_a.inject(0) do |acc, i| - acc += 1 if ::VIM::Window[i].buffer.number == $curbuf.number - acc - end - count > 1 - end - - def default_open_command - if !VIM::get_bool('&modified') || - VIM::get_bool('&hidden') || - VIM::get_bool('&autowriteall') && !VIM::get_bool('&readonly') || - current_buffer_visible_in_other_window - VIM::get_string('g:CommandTAcceptSelectionCommand') || 'e' - else - 'sp' - end - end - - def ensure_appropriate_window_selection - # normally we try to open the selection in the current window, but there - # is one exception: - # - # - we don't touch any "unlisted" buffer with buftype "nofile" (such as - # NERDTree or MiniBufExplorer); this is to avoid things like the "Not - # enough room" error which occurs when trying to open in a split in a - # shallow (potentially 1-line) buffer like MiniBufExplorer is current - # - # Other "unlisted" buffers, such as those with buftype "help" are treated - # normally. - initial = $curwin - while true do - break unless ::VIM::evaluate('&buflisted').to_i == 0 && - ::VIM::evaluate('&buftype').to_s == 'nofile' - ::VIM::command 'wincmd w' # try next window - break if $curwin == initial # have already tried all - end - end - - def open_selection(selection, options = {}) - command = options[:command] || default_open_command - selection = File.expand_path selection, @path - selection = relative_path_under_working_directory selection - selection = sanitize_path_string selection - selection = File.join('.', selection) if selection =~ /^\+/ - ensure_appropriate_window_selection - - @active_finder.open_selection command, selection, options - end - - def map(key, function, param = nil) - ::VIM::command "noremap #{key} " \ - ":call commandt#private##{function}(#{param})" - end - - def term - @term ||= ::VIM::evaluate('&term') - end - - def register_for_key_presses - # "normal" keys (interpreted literally) - numbers = ('0'..'9').to_a.join - lowercase = ('a'..'z').to_a.join - uppercase = lowercase.upcase - punctuation = '<>`@#~!"$%^&/()=+*-_.,;:?\\|\'{}[]' - space = ' ' - (numbers + lowercase + uppercase + punctuation + space).each_byte do |b| - map "", 'HandleKey', b - end - - # "special" keys (overridable by settings) - { - 'AcceptSelection' => '', - 'AcceptSelectionSplit' => ['', ''], - 'AcceptSelectionTab' => '', - 'AcceptSelectionVSplit' => '', - 'Backspace' => '', - 'Cancel' => ['', ''], - 'Clear' => '', - 'ClearPrevWord' => '', - 'CursorEnd' => '', - 'CursorLeft' => ['', ''], - 'CursorRight' => ['', ''], - 'CursorStart' => '', - 'Delete' => '', - 'Quickfix' => '', - 'Refresh' => '', - 'SelectNext' => ['', '', ''], - 'SelectPrev' => ['', '', ''], - 'ToggleFocus' => '', - }.each do |key, value| - if override = VIM::get_list_or_string("g:CommandT#{key}Map") - Array(override).each do |mapping| - map mapping, key - end - else - Array(value).each do |mapping| - unless mapping == '' && term =~ /\A(rxvt|screen|vt100|xterm)/ - map mapping, key - end - end - end - end - end - - def set_up_autocmds - if @debounce_interval > 0 - ::VIM::command 'augroup CommandTController' - ::VIM::command 'autocmd!' - ::VIM::command 'autocmd CursorHold :call commandt#private#ListMatches()' - ::VIM::command 'augroup END' - end - end - - # Returns the desired maximum number of matches, based on available vertical - # space and the g:CommandTMaxHeight option. - # - # Note the "available" space is actually a theoretical upper bound; it takes - # into account screen dimensions but not things like existing splits which - # may reduce the amount of space in practice. - def match_limit - limit = [1, VIM::Screen.lines - 5].max - limit = [limit, max_height].min if max_height > 0 - limit - end - - def buffer_finder - @buffer_finder ||= CommandT::Finder::BufferFinder.new - end - - def command_finder - @command_finder ||= CommandT::Finder::CommandFinder.new - end - - def mru_finder - @mru_finder ||= CommandT::Finder::MRUBufferFinder.new - end - - def file_finder - @file_finder ||= CommandT::Finder::FileFinder.new nil, - :max_depth => VIM::get_number('g:CommandTMaxDepth'), - :max_files => VIM::get_number('g:CommandTMaxFiles'), - :max_caches => VIM::get_number('g:CommandTMaxCachedDirectories'), - :always_show_dot_files => VIM::get_bool('g:CommandTAlwaysShowDotFiles'), - :never_show_dot_files => VIM::get_bool('g:CommandTNeverShowDotFiles'), - :scan_dot_directories => VIM::get_bool('g:CommandTScanDotDirectories'), - :wild_ignore => VIM::get_string('g:CommandTWildIgnore'), - :scanner => VIM::get_string('g:CommandTFileScanner'), - :git_scan_submodules => VIM::get_bool('g:CommandTGitScanSubmodules') - end - - def help_finder - @jump_finder ||= CommandT::Finder::HelpFinder.new - end - - def history_finder - CommandT::Finder::HistoryFinder.new(:history_type => ':') - end - - def jump_finder - @jump_finder ||= CommandT::Finder::JumpFinder.new - end - - def line_finder - CommandT::Finder::LineFinder.new - end - - def search_finder - CommandT::Finder::HistoryFinder.new(:history_type => '/') - end - - def tag_finder - @tag_finder ||= CommandT::Finder::TagFinder.new \ - :include_filenames => VIM::get_bool('g:CommandTTagIncludeFilenames') - end - end -end diff -Nru vim-command-t-4.0/ruby/command-t/depend vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/depend --- vim-command-t-4.0/ruby/command-t/depend 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/depend 1970-01-01 00:00:00.000000000 +0000 @@ -1,8 +0,0 @@ -# Copyright 2010-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -CFLAGS += -Wall -Wextra -Wno-unused-parameter - -ifdef DEBUG -CFLAGS += -DDEBUG -endif diff -Nru vim-command-t-4.0/ruby/command-t/ext/command-t/depend vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/ext/command-t/depend --- vim-command-t-4.0/ruby/command-t/ext/command-t/depend 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/ext/command-t/depend 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,8 @@ +# Copyright 2010-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +CFLAGS += -Wall -Wextra -Wno-unused-parameter + +ifdef DEBUG +CFLAGS += -DDEBUG +endif diff -Nru vim-command-t-4.0/ruby/command-t/ext/command-t/ext.c vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/ext/command-t/ext.c --- vim-command-t-4.0/ruby/command-t/ext/command-t/ext.c 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/ext/command-t/ext.c 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,40 @@ +// Copyright 2010-present Greg Hurrell. All rights reserved. +// Licensed under the terms of the BSD 2-clause license. + +#include "matcher.h" +#include "watchman.h" + +VALUE mCommandT = 0; // module CommandT +VALUE cCommandTMatcher = 0; // class CommandT::Matcher +VALUE mCommandTWatchman = 0; // module CommandT::Watchman +VALUE mCommandTWatchmanUtils = 0; // module CommandT::Watchman::Utils + +VALUE CommandT_option_from_hash(const char *option, VALUE hash) { + VALUE key; + if (NIL_P(hash)) { + return Qnil; + } + key = ID2SYM(rb_intern(option)); + if (rb_funcall(hash, rb_intern("has_key?"), 1, key) == Qtrue) { + return rb_hash_aref(hash, key); + } else { + return Qnil; + } +} + +void Init_ext() { + // module CommandT + mCommandT = rb_define_module("CommandT"); + + // class CommandT::Matcher + cCommandTMatcher = rb_define_class_under(mCommandT, "Matcher", rb_cObject); + rb_define_method(cCommandTMatcher, "initialize", CommandTMatcher_initialize, -1); + rb_define_method(cCommandTMatcher, "sorted_matches_for", CommandTMatcher_sorted_matches_for, -1); + + // module CommandT::Watchman::Utils + mCommandTWatchman = rb_define_module_under(mCommandT, "Watchman"); + mCommandTWatchmanUtils = rb_define_module_under(mCommandTWatchman, "Utils"); + rb_define_singleton_method(mCommandTWatchmanUtils, "load", CommandTWatchmanUtils_load, 1); + rb_define_singleton_method(mCommandTWatchmanUtils, "dump", CommandTWatchmanUtils_dump, 1); + rb_define_singleton_method(mCommandTWatchmanUtils, "query", CommandTWatchmanUtils_query, 2); +} diff -Nru vim-command-t-4.0/ruby/command-t/ext/command-t/extconf.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/ext/command-t/extconf.rb --- vim-command-t-4.0/ruby/command-t/ext/command-t/extconf.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/ext/command-t/extconf.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,66 @@ +# Copyright 2010-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +require 'pathname' + +begin + require 'mkmf' +rescue LoadError + puts <<-DOC.gsub(/^\s+/, '') + Unable to require "mkmf"; you may need to install Ruby development tools + (depending on your system, a "ruby-dev"/"ruby-devel" package or similar). + [exiting] + DOC + exit 1 +end + +def header(item) + unless find_header(item) + puts "couldn't find #{item} (required)" + exit 1 + end +end + +# mandatory headers +header('float.h') +header('ruby.h') +header('stdlib.h') +header('string.h') + +# optional headers (for CommandT::Watchman::Utils) +if have_header('fcntl.h') && + have_header('stdint.h') && + have_header('sys/errno.h') && + have_header('sys/socket.h') + RbConfig::MAKEFILE_CONFIG['DEFS'] ||= '' + RbConfig::MAKEFILE_CONFIG['DEFS'] += ' -DWATCHMAN_BUILD' + + have_header('ruby/st.h') # >= 1.9; sets HAVE_RUBY_ST_H + have_header('st.h') # 1.8; sets HAVE_ST_H +end + +# optional +if RbConfig::CONFIG['THREAD_MODEL'] == 'pthread' + have_library('pthread', 'pthread_create') # sets HAVE_PTHREAD_H if found +end + +RbConfig::MAKEFILE_CONFIG['CC'] = ENV['CC'] if ENV['CC'] + +create_makefile('ext') + +# Create `metadata.rb`, which is used to diagnose installation problems. +basedir = Pathname.new(__FILE__).dirname +(basedir + 'metadata.rb').open('w') do |f| + f.puts <<-END.gsub(/^ /, '') + # This file was generated by #{(basedir + 'extconf.rb').to_s} + module CommandT + module Metadata + EXPECTED_RUBY_VERSION = #{RUBY_VERSION.inspect} + EXPECTED_RUBY_PATCHLEVEL = #{ + defined?(RUBY_PATCHLEVEL) ? RUBY_PATCHLEVEL.inspect : nil.inspect + } + UNKNOWN = false + end + end + END +end diff -Nru vim-command-t-4.0/ruby/command-t/ext/command-t/ext.h vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/ext/command-t/ext.h --- vim-command-t-4.0/ruby/command-t/ext/command-t/ext.h 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/ext/command-t/ext.h 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,24 @@ +// Copyright 2010-present Greg Hurrell. All rights reserved. +// Licensed under the terms of the BSD 2-clause license. + +#include + +extern VALUE mCommandT; // module CommandT +extern VALUE cCommandTMatcher; // class CommandT::Matcher +extern VALUE mCommandTWatchman; // module CommandT::Watchman +extern VALUE mCommandTWatchmanUtils; // module CommandT::Watchman::Utils + +// Encapsulates common pattern of checking for an option in an optional +// options hash. The hash itself may be nil, but an exception will be +// raised if it is not nil and not a hash. +VALUE CommandT_option_from_hash(const char *option, VALUE hash); + +// Debugging macros. +#define L(...) { \ + fprintf(stdout, __VA_ARGS__); \ + fflush(stdout); \ +} while (0) +#define RUBY_INSPECT(obj) do { \ + rb_funcall(rb_mKernel, rb_intern("p"), 1, obj); \ + fflush(stdout); \ +} while (0) diff -Nru vim-command-t-4.0/ruby/command-t/ext/command-t/.gitignore vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/ext/command-t/.gitignore --- vim-command-t-4.0/ruby/command-t/ext/command-t/.gitignore 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/ext/command-t/.gitignore 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,7 @@ +/ext.* +!/ext.c +!/ext.h +/*.log +/*.o +/Makefile +/metadata.rb diff -Nru vim-command-t-4.0/ruby/command-t/ext/command-t/heap.c vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/ext/command-t/heap.c --- vim-command-t-4.0/ruby/command-t/ext/command-t/heap.c 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/ext/command-t/heap.c 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,146 @@ +// Copyright 2016-present Greg Hurrell. All rights reserved. +// Licensed under the terms of the BSD 2-clause license. + +#include /* for free(), malloc(), NULL */ + +#include "heap.h" + +#define HEAP_PARENT(index) ((index - 1) / 2) +#define HEAP_LEFT(index) (2 * index + 1) +#define HEAP_RIGHT(index) (2 * index + 2) + +/** + * Returns a new heap, or NULL on failure. + */ +heap_t *heap_new(long capacity, heap_compare_entries comparator) { + heap_t *heap = malloc(sizeof(heap_t)); + if (!heap) { + return NULL; + } + heap->capacity = capacity; + heap->comparator = comparator; + heap->count = 0; + + heap->entries = malloc(capacity * sizeof(void *)); + if (!heap->entries) { + free(heap); + return NULL; + } + return heap; +} + +/** + * Frees a previously created heap. + */ +void heap_free(heap_t *heap) { + free(heap->entries); + free(heap); +} + +/** + * @internal + * + * Compare values at indices `a_idx` and `b_idx` using the heap's comparator + * function. + */ +int heap_compare(heap_t *heap, long a_idx, long b_idx) { + const void *a = heap->entries[a_idx]; + const void *b = heap->entries[b_idx]; + return heap->comparator(a, b); +} + +/** + * @internal + * + * Returns 1 if the heap property holds (ie. parent < child). + */ +int heap_property(heap_t *heap, long parent_idx, long child_idx) { + return heap_compare(heap, parent_idx, child_idx) > 0; +} + +/** + * @internal + * + * Swaps the values at indexes `a` and `b` within `heap`. + */ +void heap_swap(heap_t *heap, long a, long b) { + void *tmp = heap->entries[a]; + heap->entries[a] = heap->entries[b]; + heap->entries[b] = tmp; +} + +/** + * Inserts `value` into `heap`. + */ +void heap_insert(heap_t *heap, void *value) { + long idx, parent_idx; + + // If at capacity, ignore. + if (heap->count == heap->capacity) { + return; + } + + // Insert into first empty slot. + idx = heap->count; + heap->entries[idx] = value; + heap->count++; + + // Bubble upwards until heap property is restored. + parent_idx = HEAP_PARENT(idx); + while (idx && !heap_property(heap, parent_idx, idx)) { + heap_swap(heap, idx, parent_idx); + idx = parent_idx; + parent_idx = HEAP_PARENT(idx); + } +} + +/** + * @internal + * + * Restores the heap property starting at `idx`. + */ +void heap_heapify(heap_t *heap, long idx) { + long left_idx = HEAP_LEFT(idx); + long right_idx = HEAP_RIGHT(idx); + long smallest_idx = + right_idx < heap->count ? + + // Right (and therefore left) child exists. + (heap_compare(heap, left_idx, right_idx) > 0 ? left_idx : right_idx) : + + left_idx < heap->count ? + + // Only left child exists. + left_idx : + + // No children exist. + idx; + + if ( + smallest_idx != idx && + !heap_property(heap, idx, smallest_idx) + ) { + // Swap with smallest_idx child. + heap_swap(heap, idx, smallest_idx); + heap_heapify(heap, smallest_idx); + } +} + +/** + * Extracts the minimum value from `heap`. + */ +void *heap_extract(heap_t *heap) { + void *extracted = NULL; + if (heap->count) { + // Grab root value. + extracted = heap->entries[0]; + + // Move last item to root. + heap->entries[0] = heap->entries[heap->count - 1]; + heap->count--; + + // Restore heap property. + heap_heapify(heap, 0); + } + return extracted; +} diff -Nru vim-command-t-4.0/ruby/command-t/ext/command-t/heap.h vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/ext/command-t/heap.h --- vim-command-t-4.0/ruby/command-t/ext/command-t/heap.h 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/ext/command-t/heap.h 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,22 @@ +// Copyright 2016-present Greg Hurrell. All rights reserved. +// Licensed under the terms of the BSD 2-clause license. + +/** + * A fixed size min-heap implementation. + */ + +typedef int (*heap_compare_entries)(const void *a, const void *b); + +typedef struct { + long count; + long capacity; + void **entries; + heap_compare_entries comparator; +} heap_t; + +#define HEAP_PEEK(heap) (heap->entries[0]) + +heap_t *heap_new(long capacity, heap_compare_entries comparator); +void heap_free(heap_t *heap); +void heap_insert(heap_t *heap, void *value); +void *heap_extract(heap_t *heap); diff -Nru vim-command-t-4.0/ruby/command-t/ext/command-t/match.c vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/ext/command-t/match.c --- vim-command-t-4.0/ruby/command-t/ext/command-t/match.c 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/ext/command-t/match.c 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,243 @@ +// Copyright 2010-present Greg Hurrell. All rights reserved. +// Licensed under the terms of the BSD 2-clause license. + +#include /* for FLT_MAX */ +#include "match.h" +#include "ext.h" +#include "ruby_compat.h" + +#define UNSET_SCORE FLT_MAX + +// Use a struct to make passing params during recursion easier. +typedef struct { + char *haystack_p; // Pointer to the path string to be searched. + long haystack_len; // Length of same. + char *needle_p; // Pointer to search string (needle). + long needle_len; // Length of same. + long *rightmost_match_p; // Rightmost match for each char in needle. + float max_score_per_char; + int always_show_dot_files; // Boolean. + int never_show_dot_files; // Boolean. + int case_sensitive; // Boolean. + int recurse; // Boolean. + float *memo; // Memoization. +} matchinfo_t; + +float recursive_match( + matchinfo_t *m, // Sharable meta-data. + long haystack_idx, // Where in the path string to start. + long needle_idx, // Where in the needle string to start. + long last_idx, // Location of last matched character. + float score // Cumulative score so far. +) { + long distance, i, j; + float *memoized = NULL; + float score_for_char; + float seen_score = 0; + + // Iterate over needle. + for (i = needle_idx; i < m->needle_len; i++) { + // Iterate over (valid range of) haystack. + for (j = haystack_idx; j <= m->rightmost_match_p[i]; j++) { + char c, d; + + // Do we have a memoized result we can return? + memoized = &m->memo[j * m->needle_len + i]; + if (*memoized != UNSET_SCORE) { + return *memoized > seen_score ? *memoized : seen_score; + } + c = m->needle_p[i]; + d = m->haystack_p[j]; + if (d == '.') { + if (j == 0 || m->haystack_p[j - 1] == '/') { // This is a dot-file. + int dot_search = c == '.'; // Searching for a dot. + if ( + m->never_show_dot_files || + (!dot_search && !m->always_show_dot_files) + ) { + return *memoized = 0.0; + } + } + } else if (d >= 'A' && d <= 'Z' && !m->case_sensitive) { + d += 'a' - 'A'; // Add 32 to downcase. + } + + if (c == d) { + // Calculate score. + float sub_score = 0; + score_for_char = m->max_score_per_char; + distance = j - last_idx; + + if (distance > 1) { + float factor = 1.0; + char last = m->haystack_p[j - 1]; + char curr = m->haystack_p[j]; // Case matters, so get again. + if (last == '/') { + factor = 0.9; + } else if ( + last == '-' || + last == '_' || + last == ' ' || + (last >= '0' && last <= '9') + ) { + factor = 0.8; + } else if ( + last >= 'a' && last <= 'z' && + curr >= 'A' && curr <= 'Z' + ) { + factor = 0.8; + } else if (last == '.') { + factor = 0.7; + } else { + // If no "special" chars behind char, factor diminishes + // as distance from last matched char increases. + factor = (1.0 / distance) * 0.75; + } + score_for_char *= factor; + } + + if (j < m->rightmost_match_p[i] && m->recurse) { + sub_score = recursive_match(m, j + 1, i, last_idx, score); + if (sub_score > seen_score) { + seen_score = sub_score; + } + } + last_idx = j; + haystack_idx = last_idx + 1; + score += score_for_char; + *memoized = seen_score > score ? seen_score : score; + if (i == m->needle_len - 1) { + // Whole string matched. + return *memoized; + } + if (!m->recurse) { + break; + } + } + } + } + return *memoized = score; +} + +float calculate_match( + VALUE haystack, + VALUE needle, + VALUE case_sensitive, + VALUE always_show_dot_files, + VALUE never_show_dot_files, + VALUE recurse, + long needle_bitmask, + long *haystack_bitmask +) { + matchinfo_t m; + long i; + float score = 1.0; + int compute_bitmasks = *haystack_bitmask == UNSET_BITMASK; + m.haystack_p = RSTRING_PTR(haystack); + m.haystack_len = RSTRING_LEN(haystack); + m.needle_p = RSTRING_PTR(needle); + m.needle_len = RSTRING_LEN(needle); + m.rightmost_match_p = NULL; + m.max_score_per_char = (1.0 / m.haystack_len + 1.0 / m.needle_len) / 2; + m.always_show_dot_files = always_show_dot_files == Qtrue; + m.never_show_dot_files = never_show_dot_files == Qtrue; + m.case_sensitive = (int)case_sensitive; + m.recurse = recurse == Qtrue; + + // Special case for zero-length search string. + if (m.needle_len == 0) { + // Filter out dot files. + if (m.never_show_dot_files || !m.always_show_dot_files) { + for (i = 0; i < m.haystack_len; i++) { + char c = m.haystack_p[i]; + if (c == '.' && (i == 0 || m.haystack_p[i - 1] == '/')) { + return -1.0; + } + } + } + } else { + long haystack_limit; + long memo_size; + long needle_idx; + long mask; + long rightmost_match_p[m.needle_len]; + + if (*haystack_bitmask != UNSET_BITMASK) { + if ((needle_bitmask & *haystack_bitmask) != needle_bitmask) { + return 0.0; + } + } + + // Pre-scan string: + // - Bail if it can't match at all. + // - Record rightmost match for each character (prune search space). + // - Record bitmask for haystack to speed up future searches. + m.rightmost_match_p = rightmost_match_p; + needle_idx = m.needle_len - 1; + mask = 0; + for (i = m.haystack_len - 1; i >= 0; i--) { + char c = m.haystack_p[i]; + char lower = c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c; + if (!m.case_sensitive) { + c = lower; + } + if (compute_bitmasks) { + mask |= (1 << (lower - 'a')); + } + + if (needle_idx >= 0) { + char d = m.needle_p[needle_idx]; + if (c == d) { + rightmost_match_p[needle_idx] = i; + needle_idx--; + } + } + } + if (compute_bitmasks) { + *haystack_bitmask = mask; + } + if (needle_idx != -1) { + return 0.0; + } + + // Prepare for memoization. + haystack_limit = rightmost_match_p[m.needle_len - 1] + 1; + memo_size = m.needle_len * haystack_limit; + { + float memo[memo_size]; + for (i = 0; i < memo_size; i++) { + memo[i] = UNSET_SCORE; + } + m.memo = memo; + score = recursive_match(&m, 0, 0, 0, 0.0); + +#ifdef DEBUG + fprintf(stdout, " "); + for (i = 0; i < m.needle_len; i++) { + fprintf(stdout, " %c ", m.needle_p[i]); + } + fprintf(stdout, "\n"); + for (i = 0; i < memo_size; i++) { + char formatted[8]; + if (i % m.needle_len == 0) { + long haystack_idx = i / m.needle_len; + fprintf(stdout, "%c: ", m.haystack_p[haystack_idx]); + } + if (memo[i] == UNSET_SCORE) { + snprintf(formatted, sizeof(formatted), " - "); + } else { + snprintf(formatted, sizeof(formatted), " %-.4f", memo[i]); + } + fprintf(stdout, "%s", formatted); + if ((i + 1) % m.needle_len == 0) { + fprintf(stdout, "\n"); + } else { + fprintf(stdout, " "); + } + } + fprintf(stdout, "Final score: %f\n\n", score); +#endif + } + } + return score; +} diff -Nru vim-command-t-4.0/ruby/command-t/ext/command-t/matcher.c vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/ext/command-t/matcher.c --- vim-command-t-4.0/ruby/command-t/ext/command-t/matcher.c 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/ext/command-t/matcher.c 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,408 @@ +// Copyright 2010-present Greg Hurrell. All rights reserved. +// Licensed under the terms of the BSD 2-clause license. + +#include /* for qsort() */ +#include /* for strncmp() */ +#include "match.h" +#include "matcher.h" +#include "heap.h" +#include "ext.h" +#include "ruby_compat.h" + +// order matters; we want this to be evaluated only after ruby.h +#ifdef HAVE_PTHREAD_H +#include /* for pthread_create, pthread_join etc */ +#endif + +// Comparison function for use with qsort. +int cmp_alpha(const void *a, const void *b) { + match_t a_match = *(match_t *)a; + match_t b_match = *(match_t *)b; + VALUE a_str = a_match.path; + VALUE b_str = b_match.path; + char *a_p = RSTRING_PTR(a_str); + long a_len = RSTRING_LEN(a_str); + char *b_p = RSTRING_PTR(b_str); + long b_len = RSTRING_LEN(b_str); + int order = 0; + + if (a_len > b_len) { + order = strncmp(a_p, b_p, b_len); + if (order == 0) + order = 1; // shorter string (b) wins. + } else if (a_len < b_len) { + order = strncmp(a_p, b_p, a_len); + if (order == 0) + order = -1; // shorter string (a) wins. + } else { + order = strncmp(a_p, b_p, a_len); + } + + return order; +} + +// Comparison function for use with qsort. +int cmp_score(const void *a, const void *b) { + match_t a_match = *(match_t *)a; + match_t b_match = *(match_t *)b; + + if (a_match.score > b_match.score) { + return -1; // a scores higher, a should appear sooner. + } else if (a_match.score < b_match.score) { + return 1; // b scores higher, a should appear later. + } else { + return cmp_alpha(a, b); + } +} + +VALUE CommandTMatcher_initialize(int argc, VALUE *argv, VALUE self) { + VALUE always_show_dot_files; + VALUE never_show_dot_files; + VALUE options; + VALUE scanner; + + // Process arguments: 1 mandatory, 1 optional. + if (rb_scan_args(argc, argv, "11", &scanner, &options) == 1) { + options = Qnil; + } + if (NIL_P(scanner)) { + rb_raise(rb_eArgError, "nil scanner"); + } + + rb_iv_set(self, "@scanner", scanner); + + // Check optional options hash for overrides. + always_show_dot_files = CommandT_option_from_hash("always_show_dot_files", options); + never_show_dot_files = CommandT_option_from_hash("never_show_dot_files", options); + + rb_iv_set(self, "@always_show_dot_files", always_show_dot_files); + rb_iv_set(self, "@never_show_dot_files", never_show_dot_files); + + return Qnil; +} + +typedef struct { + long thread_count; + long thread_index; + long case_sensitive; + long limit; + match_t *matches; + long path_count; + VALUE haystacks; + VALUE needle; + VALUE last_needle; + VALUE always_show_dot_files; + VALUE never_show_dot_files; + VALUE recurse; + long needle_bitmask; +} thread_args_t; + +void *match_thread(void *thread_args) { + long i; + float score; + heap_t *heap = NULL; + thread_args_t *args = (thread_args_t *)thread_args; + + if (args->limit) { + // Reserve one extra slot so that we can do an insert-then-extract even + // when "full" (effectively allows use of min-heap to maintain a + // top-"limit" list of items). + heap = heap_new(args->limit + 1, cmp_score); + } + + for ( + i = args->thread_index; + i < args->path_count; + i += args->thread_count + ) { + args->matches[i].path = RARRAY_PTR(args->haystacks)[i]; + if (args->needle_bitmask == UNSET_BITMASK) { + args->matches[i].bitmask = UNSET_BITMASK; + } + if (!NIL_P(args->last_needle) && args->matches[i].score == 0.0) { + // Skip over this candidate because it didn't match last + // time and it can't match this time either. + continue; + } + args->matches[i].score = calculate_match( + args->matches[i].path, + args->needle, + args->case_sensitive, + args->always_show_dot_files, + args->never_show_dot_files, + args->recurse, + args->needle_bitmask, + &args->matches[i].bitmask + ); + if (args->matches[i].score == 0.0) { + continue; + } + if (heap) { + if (heap->count == args->limit) { + score = ((match_t *)HEAP_PEEK(heap))->score; + if (args->matches[i].score >= score) { + heap_insert(heap, &args->matches[i]); + (void)heap_extract(heap); + } + } else { + heap_insert(heap, &args->matches[i]); + } + } + } + + return heap; +} + +long calculate_bitmask(VALUE string) { + char *str = RSTRING_PTR(string); + long len = RSTRING_LEN(string); + long i; + long mask = 0; + for (i = 0; i < len; i++) { + if (str[i] >= 'a' && str[i] <= 'z') { + mask |= (1 << (str[i] - 'a')); + } else if (str[i] >= 'A' && str[i] <= 'Z') { + mask |= (1 << (str[i] - 'A')); + } + } + return mask; +} + +VALUE CommandTMatcher_sorted_matches_for(int argc, VALUE *argv, VALUE self) +{ + long i, j, limit, path_count, thread_count; +#ifdef HAVE_PTHREAD_H + long err; + pthread_t *threads; +#endif + long needle_bitmask = UNSET_BITMASK; + long heap_matches_count; + int use_heap; + int sort; + match_t *matches; + match_t *heap_matches = NULL; + heap_t *heap; + thread_args_t *thread_args; + VALUE always_show_dot_files; + VALUE case_sensitive; + VALUE recurse; + VALUE ignore_spaces; + VALUE limit_option; + VALUE last_needle; + VALUE needle; + VALUE never_show_dot_files; + VALUE new_paths_object_id; + VALUE options; + VALUE paths; + VALUE paths_object_id; + VALUE results; + VALUE scanner; + VALUE sort_option; + VALUE threads_option; + VALUE wrapped_matches; + + // Process arguments: 1 mandatory, 1 optional. + if (rb_scan_args(argc, argv, "11", &needle, &options) == 1) { + options = Qnil; + } + if (NIL_P(needle)) { + rb_raise(rb_eArgError, "nil needle"); + } + + // Check optional options hash for overrides. + case_sensitive = CommandT_option_from_hash("case_sensitive", options); + limit_option = CommandT_option_from_hash("limit", options); + threads_option = CommandT_option_from_hash("threads", options); + sort_option = CommandT_option_from_hash("sort", options); + ignore_spaces = CommandT_option_from_hash("ignore_spaces", options); + always_show_dot_files = rb_iv_get(self, "@always_show_dot_files"); + never_show_dot_files = rb_iv_get(self, "@never_show_dot_files"); + recurse = CommandT_option_from_hash("recurse", options); + + limit = NIL_P(limit_option) ? 15 : NUM2LONG(limit_option); + sort = NIL_P(sort_option) || sort_option == Qtrue; + use_heap = limit && sort; + heap_matches_count = 0; + + needle = StringValue(needle); + if (case_sensitive != Qtrue) { + needle = rb_funcall(needle, rb_intern("downcase"), 0); + } + + if (ignore_spaces == Qtrue) { + needle = rb_funcall(needle, rb_intern("delete"), 1, rb_str_new2(" ")); + } + + // Get unsorted matches. + scanner = rb_iv_get(self, "@scanner"); + paths = rb_funcall(scanner, rb_intern("paths"), 0); + path_count = RARRAY_LEN(paths); + + // Cached C data, not visible to Ruby layer. + paths_object_id = rb_ivar_get(self, rb_intern("paths_object_id")); + new_paths_object_id = rb_funcall(paths, rb_intern("object_id"), 0); + rb_ivar_set(self, rb_intern("paths_object_id"), new_paths_object_id); + last_needle = rb_ivar_get(self, rb_intern("last_needle")); + if ( + NIL_P(paths_object_id) || + rb_equal(new_paths_object_id, paths_object_id) != Qtrue + ) { + // `paths` changed, need to replace matches array. + paths_object_id = new_paths_object_id; + matches = malloc(path_count * sizeof(match_t)); + if (!matches) { + rb_raise(rb_eNoMemError, "memory allocation failed"); + } + wrapped_matches = Data_Wrap_Struct( + rb_cObject, + 0, + free, + matches + ); + rb_ivar_set(self, rb_intern("matches"), wrapped_matches); + last_needle = Qnil; + } else { + // Get existing array. + Data_Get_Struct( + rb_ivar_get(self, rb_intern("matches")), + match_t, + matches + ); + + // Will compare against previously computed haystack bitmasks. + needle_bitmask = calculate_bitmask(needle); + + // Check whether current search extends previous search; if so, we can + // skip all the non-matches from last time without looking at them. + if (rb_funcall(needle, rb_intern("start_with?"), 1, last_needle) != Qtrue) { + last_needle = Qnil; + } + } + + thread_count = NIL_P(threads_option) ? 1 : NUM2LONG(threads_option); + if (use_heap) { + heap_matches = malloc(thread_count * limit * sizeof(match_t)); + if (!heap_matches) { + rb_raise(rb_eNoMemError, "memory allocation failed"); + } + } + +#ifdef HAVE_PTHREAD_H +#define THREAD_THRESHOLD 1000 /* avoid the overhead of threading when search space is small */ + if (path_count < THREAD_THRESHOLD) { + thread_count = 1; + } + threads = malloc(sizeof(pthread_t) * thread_count); + if (!threads) + rb_raise(rb_eNoMemError, "memory allocation failed"); +#endif + + thread_args = malloc(sizeof(thread_args_t) * thread_count); + if (!thread_args) + rb_raise(rb_eNoMemError, "memory allocation failed"); + for (i = 0; i < thread_count; i++) { + thread_args[i].thread_count = thread_count; + thread_args[i].thread_index = i; + thread_args[i].case_sensitive = case_sensitive == Qtrue; + thread_args[i].matches = matches; + thread_args[i].limit = use_heap ? limit : 0; + thread_args[i].path_count = path_count; + thread_args[i].haystacks = paths; + thread_args[i].needle = needle; + thread_args[i].last_needle = last_needle; + thread_args[i].always_show_dot_files = always_show_dot_files; + thread_args[i].never_show_dot_files = never_show_dot_files; + thread_args[i].recurse = recurse; + thread_args[i].needle_bitmask = needle_bitmask; + +#ifdef HAVE_PTHREAD_H + if (i == thread_count - 1) { +#endif + // For the last "worker", we'll just use the main thread. + heap = match_thread(&thread_args[i]); + if (heap) { + for (j = 0; j < heap->count; j++) { + heap_matches[heap_matches_count++] = *(match_t *)heap->entries[j]; + } + heap_free(heap); + } +#ifdef HAVE_PTHREAD_H + } else { + err = pthread_create(&threads[i], NULL, match_thread, (void *)&thread_args[i]); + if (err != 0) { + rb_raise(rb_eSystemCallError, "pthread_create() failure (%d)", (int)err); + } + } +#endif + } + +#ifdef HAVE_PTHREAD_H + for (i = 0; i < thread_count - 1; i++) { + err = pthread_join(threads[i], (void **)&heap); + if (err != 0) { + rb_raise(rb_eSystemCallError, "pthread_join() failure (%d)", (int)err); + } + if (heap) { + for (j = 0; j < heap->count; j++) { + heap_matches[heap_matches_count++] = *(match_t *)heap->entries[j]; + } + heap_free(heap); + } + } + free(threads); +#endif + + if (sort) { + if ( + RSTRING_LEN(needle) == 0 || + (RSTRING_LEN(needle) == 1 && RSTRING_PTR(needle)[0] == '.') + ) { + // Alphabetic order if search string is only "" or "." + // TODO: make those semantics fully apply to heap case as well + // (they don't because the heap itself calls cmp_score, which means + // that the items which stay in the top [limit] may (will) be + // different). + qsort( + use_heap ? heap_matches : matches, + use_heap ? heap_matches_count : path_count, + sizeof(match_t), + cmp_alpha + ); + } else { + qsort( + use_heap ? heap_matches : matches, + use_heap ? heap_matches_count : path_count, + sizeof(match_t), + cmp_score + ); + } + } + + results = rb_ary_new(); + if (limit == 0) { + limit = path_count; + } + for ( + i = 0; + i < (use_heap ? heap_matches_count : path_count) && limit > 0; + i++ + ) { + if ((use_heap ? heap_matches : matches)[i].score > 0.0) { + rb_funcall( + results, + rb_intern("push"), + 1, + (use_heap ? heap_matches : matches)[i].path + ); + limit--; + } + } + + if (use_heap) { + free(heap_matches); + } + + // Save this state to potentially speed subsequent searches. + rb_ivar_set(self, rb_intern("last_needle"), needle); + return results; +} diff -Nru vim-command-t-4.0/ruby/command-t/ext/command-t/matcher.h vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/ext/command-t/matcher.h --- vim-command-t-4.0/ruby/command-t/ext/command-t/matcher.h 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/ext/command-t/matcher.h 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,7 @@ +// Copyright 2010-present Greg Hurrell. All rights reserved. +// Licensed under the terms of the BSD 2-clause license. + +#include + +extern VALUE CommandTMatcher_initialize(int argc, VALUE *argv, VALUE self); +extern VALUE CommandTMatcher_sorted_matches_for(int argc, VALUE *argv, VALUE self); diff -Nru vim-command-t-4.0/ruby/command-t/ext/command-t/match.h vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/ext/command-t/match.h --- vim-command-t-4.0/ruby/command-t/ext/command-t/match.h 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/ext/command-t/match.h 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,24 @@ +// Copyright 2010-present Greg Hurrell. All rights reserved. +// Licensed under the terms of the BSD 2-clause license. + +#include + +#define UNSET_BITMASK (-1) + +// Struct for representing an individual match. +typedef struct { + VALUE path; + long bitmask; + float score; +} match_t; + +extern float calculate_match( + VALUE str, + VALUE needle, + VALUE case_sensitive, + VALUE always_show_dot_files, + VALUE never_show_dot_files, + VALUE recurse, + long needle_bitmask, + long *haystack_bitmask +); diff -Nru vim-command-t-4.0/ruby/command-t/ext/command-t/ruby_compat.h vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/ext/command-t/ruby_compat.h --- vim-command-t-4.0/ruby/command-t/ext/command-t/ruby_compat.h 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/ext/command-t/ruby_compat.h 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,29 @@ +// Copyright 2010-present Greg Hurrell. All rights reserved. +// Licensed under the terms of the BSD 2-clause license. + +#include + +// for compatibility with older versions of Ruby which don't declare RSTRING_PTR +#ifndef RSTRING_PTR +#define RSTRING_PTR(s) (RSTRING(s)->ptr) +#endif + +// for compatibility with older versions of Ruby which don't declare RSTRING_LEN +#ifndef RSTRING_LEN +#define RSTRING_LEN(s) (RSTRING(s)->len) +#endif + +// for compatibility with older versions of Ruby which don't declare RARRAY_PTR +#ifndef RARRAY_PTR +#define RARRAY_PTR(a) (RARRAY(a)->ptr) +#endif + +// for compatibility with older versions of Ruby which don't declare RARRAY_LEN +#ifndef RARRAY_LEN +#define RARRAY_LEN(a) (RARRAY(a)->len) +#endif + +// for compatibility with older versions of Ruby which don't declare RFLOAT_VALUE +#ifndef RFLOAT_VALUE +#define RFLOAT_VALUE(f) (RFLOAT(f)->value) +#endif diff -Nru vim-command-t-4.0/ruby/command-t/ext/command-t/watchman.c vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/ext/command-t/watchman.c --- vim-command-t-4.0/ruby/command-t/ext/command-t/watchman.c 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/ext/command-t/watchman.c 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,660 @@ +// Copyright 2014-present Greg Hurrell. All rights reserved. +// Licensed under the terms of the BSD 2-clause license. + +#include "watchman.h" + +#ifdef WATCHMAN_BUILD + +#if defined(HAVE_RUBY_ST_H) +#include +#elif defined(HAVE_ST_H) +#include +#else +#error no st.h header found +#endif + +#include /* for uint8_t */ +#include /* for fcntl() */ +#include /* for errno */ +#include /* for recv(), MSG_PEEK */ + +typedef struct { + uint8_t *data; // payload + size_t cap; // total capacity + size_t len; // current length +} watchman_t; + +// Forward declarations: +VALUE watchman_load(char **ptr, char *end); +void watchman_dump(watchman_t *w, VALUE serializable); + +#define WATCHMAN_DEFAULT_STORAGE 4096 + +#define WATCHMAN_BINARY_MARKER "\x00\x01" +#define WATCHMAN_ARRAY_MARKER 0x00 +#define WATCHMAN_HASH_MARKER 0x01 +#define WATCHMAN_STRING_MARKER 0x02 +#define WATCHMAN_INT8_MARKER 0x03 +#define WATCHMAN_INT16_MARKER 0x04 +#define WATCHMAN_INT32_MARKER 0x05 +#define WATCHMAN_INT64_MARKER 0x06 +#define WATCHMAN_FLOAT_MARKER 0x07 +#define WATCHMAN_TRUE 0x08 +#define WATCHMAN_FALSE 0x09 +#define WATCHMAN_NIL 0x0a +#define WATCHMAN_TEMPLATE_MARKER 0x0b +#define WATCHMAN_SKIP_MARKER 0x0c + +#define WATCHMAN_HEADER \ + WATCHMAN_BINARY_MARKER \ + "\x06" \ + "\x00\x00\x00\x00\x00\x00\x00\x00" + +static const char watchman_array_marker = WATCHMAN_ARRAY_MARKER; +static const char watchman_hash_marker = WATCHMAN_HASH_MARKER; +static const char watchman_string_marker = WATCHMAN_STRING_MARKER; +static const char watchman_true = WATCHMAN_TRUE; +static const char watchman_false = WATCHMAN_FALSE; +static const char watchman_nil = WATCHMAN_NIL; + +/** + * Appends `len` bytes, starting at `data`, to the watchman_t struct `w` + * + * Will attempt to reallocate the underlying storage if it is not sufficient. + */ +void watchman_append(watchman_t *w, const char *data, size_t len) { + if (w->len + len > w->cap) { + w->cap += w->len + WATCHMAN_DEFAULT_STORAGE; + REALLOC_N(w->data, uint8_t, w->cap); + } + memcpy(w->data + w->len, data, len); + w->len += len; +} + +/** + * Allocate a new watchman_t struct + * + * The struct has a small amount of extra capacity preallocated, and a blank + * header that can be filled in later to describe the PDU. + */ +watchman_t *watchman_init() { + watchman_t *w = ALLOC(watchman_t); + w->cap = WATCHMAN_DEFAULT_STORAGE; + w->len = 0; + w->data = ALLOC_N(uint8_t, WATCHMAN_DEFAULT_STORAGE); + + watchman_append(w, WATCHMAN_HEADER, sizeof(WATCHMAN_HEADER) - 1); + return w; +} + +/** + * Free a watchman_t struct `w` that was previously allocated with + * `watchman_init` + */ +void watchman_free(watchman_t *w) { + xfree(w->data); + xfree(w); +} + +/** + * Encodes and appends the integer `num` to `w` + */ +void watchman_dump_int(watchman_t *w, int64_t num) { + char encoded[1 + sizeof(int64_t)]; + + if (num == (int8_t)num) { + encoded[0] = WATCHMAN_INT8_MARKER; + encoded[1] = (int8_t)num; + watchman_append(w, encoded, 1 + sizeof(int8_t)); + } else if (num == (int16_t)num) { + encoded[0] = WATCHMAN_INT16_MARKER; + *(int16_t *)(encoded + 1) = (int16_t)num; + watchman_append(w, encoded, 1 + sizeof(int16_t)); + } else if (num == (int32_t)num) { + encoded[0] = WATCHMAN_INT32_MARKER; + *(int32_t *)(encoded + 1) = (int32_t)num; + watchman_append(w, encoded, 1 + sizeof(int32_t)); + } else { + encoded[0] = WATCHMAN_INT64_MARKER; + *(int64_t *)(encoded + 1) = (int64_t)num; + watchman_append(w, encoded, 1 + sizeof(int64_t)); + } +} + +/** + * Encodes and appends the string `string` to `w` + */ +void watchman_dump_string(watchman_t *w, VALUE string) { + watchman_append(w, &watchman_string_marker, sizeof(watchman_string_marker)); + watchman_dump_int(w, RSTRING_LEN(string)); + watchman_append(w, RSTRING_PTR(string), RSTRING_LEN(string)); +} + +/** + * Encodes and appends the double `num` to `w` + */ +void watchman_dump_double(watchman_t *w, double num) { + char encoded[1 + sizeof(double)]; + encoded[0] = WATCHMAN_FLOAT_MARKER; + *(double *)(encoded + 1) = num; + watchman_append(w, encoded, sizeof(encoded)); +} + +/** + * Encodes and appends the array `array` to `w` + */ +void watchman_dump_array(watchman_t *w, VALUE array) { + long i; + watchman_append(w, &watchman_array_marker, sizeof(watchman_array_marker)); + watchman_dump_int(w, RARRAY_LEN(array)); + for (i = 0; i < RARRAY_LEN(array); i++) { + watchman_dump(w, rb_ary_entry(array, i)); + } +} + +/** + * Helper method that encodes and appends a key/value pair (`key`, `value`) from + * a hash to the watchman_t struct passed in via `data` + */ +int watchman_dump_hash_iterator(VALUE key, VALUE value, VALUE data) { + watchman_t *w = (watchman_t *)data; + watchman_dump_string(w, StringValue(key)); + watchman_dump(w, value); + return ST_CONTINUE; +} + +/** + * Encodes and appends the hash `hash` to `w` + */ +void watchman_dump_hash(watchman_t *w, VALUE hash) { + watchman_append(w, &watchman_hash_marker, sizeof(watchman_hash_marker)); + watchman_dump_int(w, RHASH_SIZE(hash)); + rb_hash_foreach(hash, watchman_dump_hash_iterator, (VALUE)w); +} + +/** + * Encodes and appends the serialized Ruby object `serializable` to `w` + * + * Examples of serializable objects include arrays, hashes, strings, numbers + * (integers, floats), booleans, and nil. + */ +void watchman_dump(watchman_t *w, VALUE serializable) { + switch (TYPE(serializable)) { + case T_ARRAY: + return watchman_dump_array(w, serializable); + case T_HASH: + return watchman_dump_hash(w, serializable); + case T_STRING: + return watchman_dump_string(w, serializable); + case T_FIXNUM: // up to 63 bits + return watchman_dump_int(w, FIX2LONG(serializable)); + case T_BIGNUM: + return watchman_dump_int(w, NUM2LL(serializable)); + case T_FLOAT: + return watchman_dump_double(w, NUM2DBL(serializable)); + case T_TRUE: + return watchman_append(w, &watchman_true, sizeof(watchman_true)); + case T_FALSE: + return watchman_append(w, &watchman_false, sizeof(watchman_false)); + case T_NIL: + return watchman_append(w, &watchman_nil, sizeof(watchman_nil)); + default: + rb_raise(rb_eTypeError, "unsupported type"); + } +} + +/** + * Extract and return the int encoded at `ptr` + * + * Moves `ptr` past the extracted int. + * + * Will raise an ArgumentError if extracting the int would take us beyond the + * end of the buffer indicated by `end`, or if there is no int encoded at `ptr`. + * + * @returns The extracted int + */ +int64_t watchman_load_int(char **ptr, char *end) { + char *val_ptr = *ptr + sizeof(int8_t); + int64_t val = 0; + + if (val_ptr >= end) { + rb_raise(rb_eArgError, "insufficient int storage"); + } + + switch (*ptr[0]) { + case WATCHMAN_INT8_MARKER: + if (val_ptr + sizeof(int8_t) > end) { + rb_raise(rb_eArgError, "overrun extracting int8_t"); + } + val = *(int8_t *)val_ptr; + *ptr = val_ptr + sizeof(int8_t); + break; + case WATCHMAN_INT16_MARKER: + if (val_ptr + sizeof(int16_t) > end) { + rb_raise(rb_eArgError, "overrun extracting int16_t"); + } + val = *(int16_t *)val_ptr; + *ptr = val_ptr + sizeof(int16_t); + break; + case WATCHMAN_INT32_MARKER: + if (val_ptr + sizeof(int32_t) > end) { + rb_raise(rb_eArgError, "overrun extracting int32_t"); + } + val = *(int32_t *)val_ptr; + *ptr = val_ptr + sizeof(int32_t); + break; + case WATCHMAN_INT64_MARKER: + if (val_ptr + sizeof(int64_t) > end) { + rb_raise(rb_eArgError, "overrun extracting int64_t"); + } + val = *(int64_t *)val_ptr; + *ptr = val_ptr + sizeof(int64_t); + break; + default: + rb_raise(rb_eArgError, "bad integer marker 0x%02x", (unsigned int)*ptr[0]); + break; + } + + return val; +} + +/** + * Reads and returns a string encoded in the Watchman binary protocol format, + * starting at `ptr` and finishing at or before `end` + */ +VALUE watchman_load_string(char **ptr, char *end) { + int64_t len; + VALUE string; + if (*ptr >= end) { + rb_raise(rb_eArgError, "unexpected end of input"); + } + + if (*ptr[0] != WATCHMAN_STRING_MARKER) { + rb_raise(rb_eArgError, "not a number"); + } + + *ptr += sizeof(int8_t); + if (*ptr >= end) { + rb_raise(rb_eArgError, "invalid string header"); + } + + len = watchman_load_int(ptr, end); + if (len == 0) { // special case for zero-length strings + return rb_str_new2(""); + } else if (*ptr + len > end) { + rb_raise(rb_eArgError, "insufficient string storage"); + } + + string = rb_str_new(*ptr, len); + *ptr += len; + return string; +} + +/** + * Reads and returns a double encoded in the Watchman binary protocol format, + * starting at `ptr` and finishing at or before `end` + */ +double watchman_load_double(char **ptr, char *end) { + double val; + *ptr += sizeof(int8_t); // caller has already verified the marker + if (*ptr + sizeof(double) > end) { + rb_raise(rb_eArgError, "insufficient double storage"); + } + val = *(double *)*ptr; + *ptr += sizeof(double); + return val; +} + +/** + * Helper method which returns length of the array encoded in the Watchman + * binary protocol format, starting at `ptr` and finishing at or before `end` + */ +int64_t watchman_load_array_header(char **ptr, char *end) { + if (*ptr >= end) { + rb_raise(rb_eArgError, "unexpected end of input"); + } + + // verify and consume marker + if (*ptr[0] != WATCHMAN_ARRAY_MARKER) { + rb_raise(rb_eArgError, "not an array"); + } + *ptr += sizeof(int8_t); + + // expect a count + if (*ptr + sizeof(int8_t) * 2 > end) { + rb_raise(rb_eArgError, "incomplete array header"); + } + return watchman_load_int(ptr, end); +} + +/** + * Reads and returns an array encoded in the Watchman binary protocol format, + * starting at `ptr` and finishing at or before `end` + */ +VALUE watchman_load_array(char **ptr, char *end) { + int64_t count, i; + VALUE array; + + count = watchman_load_array_header(ptr, end); + array = rb_ary_new2(count); + + for (i = 0; i < count; i++) { + rb_ary_push(array, watchman_load(ptr, end)); + } + + return array; +} + +/** + * Reads and returns a hash encoded in the Watchman binary protocol format, + * starting at `ptr` and finishing at or before `end` + */ +VALUE watchman_load_hash(char **ptr, char *end) { + int64_t count, i; + VALUE hash, key, value; + + *ptr += sizeof(int8_t); // caller has already verified the marker + + // expect a count + if (*ptr + sizeof(int8_t) * 2 > end) { + rb_raise(rb_eArgError, "incomplete hash header"); + } + count = watchman_load_int(ptr, end); + + hash = rb_hash_new(); + + for (i = 0; i < count; i++) { + key = watchman_load_string(ptr, end); + value = watchman_load(ptr, end); + rb_hash_aset(hash, key, value); + } + + return hash; +} + +/** + * Reads and returns a templated array encoded in the Watchman binary protocol + * format, starting at `ptr` and finishing at or before `end` + * + * Templated arrays are arrays of hashes which have repetitive key information + * pulled out into a separate "headers" prefix. + * + * @see https://github.com/facebook/watchman/blob/master/website/_docs/BSER.markdown + */ +VALUE watchman_load_template(char **ptr, char *end) { + int64_t header_items_count, i, row_count; + VALUE array, hash, header, key, value; + + *ptr += sizeof(int8_t); // caller has already verified the marker + + // process template header array + header_items_count = watchman_load_array_header(ptr, end); + header = rb_ary_new2(header_items_count); + for (i = 0; i < header_items_count; i++) { + rb_ary_push(header, watchman_load_string(ptr, end)); + } + + // process row items + row_count = watchman_load_int(ptr, end); + array = rb_ary_new2(header_items_count); + while (row_count--) { + hash = rb_hash_new(); + for (i = 0; i < header_items_count; i++) { + if (*ptr >= end) { + rb_raise(rb_eArgError, "unexpected end of input"); + } + + if (*ptr[0] == WATCHMAN_SKIP_MARKER) { + *ptr += sizeof(uint8_t); + } else { + value = watchman_load(ptr, end); + key = rb_ary_entry(header, i); + rb_hash_aset(hash, key, value); + } + } + rb_ary_push(array, hash); + } + return array; +} + +/** + * Reads and returns an object encoded in the Watchman binary protocol format, + * starting at `ptr` and finishing at or before `end` + */ +VALUE watchman_load(char **ptr, char *end) { + if (*ptr >= end) { + rb_raise(rb_eArgError, "unexpected end of input"); + } + + switch (*ptr[0]) { + case WATCHMAN_ARRAY_MARKER: + return watchman_load_array(ptr, end); + case WATCHMAN_HASH_MARKER: + return watchman_load_hash(ptr, end); + case WATCHMAN_STRING_MARKER: + return watchman_load_string(ptr, end); + case WATCHMAN_INT8_MARKER: + case WATCHMAN_INT16_MARKER: + case WATCHMAN_INT32_MARKER: + case WATCHMAN_INT64_MARKER: + return LL2NUM(watchman_load_int(ptr, end)); + case WATCHMAN_FLOAT_MARKER: + return rb_float_new(watchman_load_double(ptr, end)); + case WATCHMAN_TRUE: + *ptr += 1; + return Qtrue; + case WATCHMAN_FALSE: + *ptr += 1; + return Qfalse; + case WATCHMAN_NIL: + *ptr += 1; + return Qnil; + case WATCHMAN_TEMPLATE_MARKER: + return watchman_load_template(ptr, end); + default: + rb_raise(rb_eTypeError, "unsupported type"); + } + + return Qnil; // keep the compiler happy +} + +/** + * CommandT::Watchman::Utils.load(serialized) + * + * Converts the binary object, `serialized`, from the Watchman binary protocol + * format into a normal Ruby object. + */ +VALUE CommandTWatchmanUtils_load(VALUE self, VALUE serialized) { + char *ptr, *end; + long len; + uint64_t payload_size; + VALUE loaded; + serialized = StringValue(serialized); + len = RSTRING_LEN(serialized); + ptr = RSTRING_PTR(serialized); + end = ptr + len; + + // expect at least the binary marker and a int8_t length counter + if ((size_t)len < sizeof(WATCHMAN_BINARY_MARKER) - 1 + sizeof(int8_t) * 2) { + rb_raise(rb_eArgError, "undersized header"); + } + + if (memcmp(ptr, WATCHMAN_BINARY_MARKER, sizeof(WATCHMAN_BINARY_MARKER) - 1)) { + rb_raise(rb_eArgError, "missing binary marker"); + } + + // get size marker + ptr += sizeof(WATCHMAN_BINARY_MARKER) - 1; + payload_size = watchman_load_int(&ptr, end); + if (!payload_size) { + rb_raise(rb_eArgError, "empty payload"); + } + + // sanity check length + if (ptr + payload_size != end) { + rb_raise( + rb_eArgError, + "payload size mismatch (%lu)", + (unsigned long)(end - (ptr + payload_size)) + ); + } + + loaded = watchman_load(&ptr, end); + + // one more sanity check + if (ptr != end) { + rb_raise( + rb_eArgError, + "payload termination mismatch (%lu)", + (unsigned long)(end - ptr) + ); + } + + return loaded; +} + +/** + * CommandT::Watchman::Utils.dump(serializable) + * + * Converts the Ruby object, `serializable`, into a binary string in the + * Watchman binary protocol format. + * + * Examples of serializable objects include arrays, hashes, strings, numbers + * (integers, floats), booleans, and nil. + */ +VALUE CommandTWatchmanUtils_dump(VALUE self, VALUE serializable) { + uint64_t *len; + VALUE serialized; + watchman_t *w = watchman_init(); + watchman_dump(w, serializable); + + // update header with final length information + len = (uint64_t *)(w->data + sizeof(WATCHMAN_HEADER) - sizeof(uint64_t) - 1); + *len = w->len - sizeof(WATCHMAN_HEADER) + 1; + + // prepare final return value + serialized = rb_str_buf_new(w->len); + rb_str_buf_cat(serialized, (const char*)w->data, w->len); + watchman_free(w); + return serialized; +} + +/** + * Helper method for raising a SystemCallError wrapping a lower-level error code + * coming from the `errno` global variable. + */ +void watchman_raise_system_call_error(int number) { + VALUE error = INT2FIX(number); + rb_exc_raise(rb_class_new_instance(1, &error, rb_eSystemCallError)); +} + +// How far we have to look to figure out the size of the PDU header +#define WATCHMAN_SNIFF_BUFFER_SIZE sizeof(WATCHMAN_BINARY_MARKER) - 1 + sizeof(int8_t) + +// How far we have to peek, at most, to figure out the size of the PDU itself +#define WATCHMAN_PEEK_BUFFER_SIZE \ + sizeof(WATCHMAN_BINARY_MARKER) - 1 + \ + sizeof(WATCHMAN_INT64_MARKER) + \ + sizeof(int64_t) + +/** + * CommandT::Watchman::Utils.query(query, socket) + * + * Converts `query`, a Watchman query comprising Ruby objects, into the Watchman + * binary protocol format, transmits it over socket, and unserializes and + * returns the result. + */ +VALUE CommandTWatchmanUtils_query(VALUE self, VALUE query, VALUE socket) { + char *payload; + int fileno, flags; + int8_t peek[WATCHMAN_PEEK_BUFFER_SIZE]; + int8_t sizes[] = { 0, 0, 0, 1, 2, 4, 8 }; + int8_t sizes_idx; + int8_t *pdu_size_ptr; + int64_t payload_size; + long query_len; + ssize_t peek_size, sent, received; + void *buffer; + VALUE loaded, serialized; + fileno = NUM2INT(rb_funcall(socket, rb_intern("fileno"), 0)); + + // do blocking I/O to simplify the following logic + flags = fcntl(fileno, F_GETFL); + if (fcntl(fileno, F_SETFL, flags & ~O_NONBLOCK) == -1) { + rb_raise(rb_eRuntimeError, "unable to clear O_NONBLOCK flag"); + } + + // send the message + serialized = CommandTWatchmanUtils_dump(self, query); + query_len = RSTRING_LEN(serialized); + sent = send(fileno, RSTRING_PTR(serialized), query_len, 0); + if (sent == -1) { + watchman_raise_system_call_error(errno); + } else if (sent != query_len) { + rb_raise(rb_eRuntimeError, "expected to send %ld bytes but sent %zd", + query_len, sent); + } + + // sniff to see how large the header is + received = recv(fileno, peek, WATCHMAN_SNIFF_BUFFER_SIZE, MSG_PEEK | MSG_WAITALL); + if (received == -1) { + watchman_raise_system_call_error(errno); + } else if (received != WATCHMAN_SNIFF_BUFFER_SIZE) { + rb_raise(rb_eRuntimeError, "failed to sniff PDU header"); + } + + // peek at size of PDU + sizes_idx = peek[sizeof(WATCHMAN_BINARY_MARKER) - 1]; + if (sizes_idx < WATCHMAN_INT8_MARKER || sizes_idx > WATCHMAN_INT64_MARKER) { + rb_raise(rb_eRuntimeError, "bad PDU size marker"); + } + peek_size = sizeof(WATCHMAN_BINARY_MARKER) - 1 + sizeof(int8_t) + + sizes[sizes_idx]; + + received = recv(fileno, peek, peek_size, MSG_PEEK); + if (received == -1) { + watchman_raise_system_call_error(errno); + } else if (received != peek_size) { + rb_raise(rb_eRuntimeError, "failed to peek at PDU header"); + } + pdu_size_ptr = peek + sizeof(WATCHMAN_BINARY_MARKER) - sizeof(int8_t); + payload_size = + peek_size + + watchman_load_int((char **)&pdu_size_ptr, (char *)peek + peek_size); + + // actually read the PDU + buffer = xmalloc(payload_size); + if (!buffer) { + rb_raise( + rb_eNoMemError, + "failed to allocate %lld bytes", + (long long int)payload_size + ); + } + received = recv(fileno, buffer, payload_size, MSG_WAITALL); + if (received == -1) { + watchman_raise_system_call_error(errno); + } else if (received != payload_size) { + rb_raise(rb_eRuntimeError, "failed to load PDU"); + } + payload = (char *)buffer + peek_size; + loaded = watchman_load(&payload, payload + payload_size); + free(buffer); + return loaded; +} + +#else /* don't build Watchman utils; supply stubs only*/ + +VALUE CommandTWatchmanUtils_load(VALUE self, VALUE serialized) { + rb_raise(rb_eRuntimeError, "unsupported operation"); +} + +VALUE CommandTWatchmanUtils_dump(VALUE self, VALUE serializable) { + rb_raise(rb_eRuntimeError, "unsupported operation"); +} + +VALUE CommandTWatchmanUtils_query(VALUE self, VALUE query, VALUE socket) { + rb_raise(rb_eRuntimeError, "unsupported operation"); +} + +#endif diff -Nru vim-command-t-4.0/ruby/command-t/ext/command-t/watchman.h vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/ext/command-t/watchman.h --- vim-command-t-4.0/ruby/command-t/ext/command-t/watchman.h 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/ext/command-t/watchman.h 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,32 @@ +// Copyright 2014-present Greg Hurrell. All rights reserved. +// Licensed under the terms of the BSD 2-clause license. + +#include + +/** + * @module CommandT::Watchman::Utils + * + * Methods for working with the Watchman binary protocol + * + * @see https://github.com/facebook/watchman/blob/master/website/_docs/BSER.markdown + */ + +/** + * Convert an object serialized using the Watchman binary protocol[0] into an + * unpacked Ruby object + */ +extern VALUE CommandTWatchmanUtils_load(VALUE self, VALUE serialized); + +/** + * Serialize a Ruby object into the Watchman binary protocol format + */ +extern VALUE CommandTWatchmanUtils_dump(VALUE self, VALUE serializable); + +/** + * Issue `query` to the Watchman instance listening on `socket` (a `UNIXSocket` + * instance) and return the result + * + * The query is serialized following the Watchman binary protocol and the + * result is converted to native Ruby objects before returning to the caller. + */ +extern VALUE CommandTWatchmanUtils_query(VALUE self, VALUE query, VALUE socket); diff -Nru vim-command-t-4.0/ruby/command-t/ext.c vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/ext.c --- vim-command-t-4.0/ruby/command-t/ext.c 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/ext.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -// Copyright 2010-present Greg Hurrell. All rights reserved. -// Licensed under the terms of the BSD 2-clause license. - -#include "matcher.h" -#include "watchman.h" - -VALUE mCommandT = 0; // module CommandT -VALUE cCommandTMatcher = 0; // class CommandT::Matcher -VALUE mCommandTWatchman = 0; // module CommandT::Watchman -VALUE mCommandTWatchmanUtils = 0; // module CommandT::Watchman::Utils - -VALUE CommandT_option_from_hash(const char *option, VALUE hash) -{ - VALUE key; - if (NIL_P(hash)) - return Qnil; - key = ID2SYM(rb_intern(option)); - if (rb_funcall(hash, rb_intern("has_key?"), 1, key) == Qtrue) - return rb_hash_aref(hash, key); - else - return Qnil; -} - -void Init_ext() -{ - // module CommandT - mCommandT = rb_define_module("CommandT"); - - // class CommandT::Matcher - cCommandTMatcher = rb_define_class_under(mCommandT, "Matcher", rb_cObject); - rb_define_method(cCommandTMatcher, "initialize", CommandTMatcher_initialize, -1); - rb_define_method(cCommandTMatcher, "sorted_matches_for", CommandTMatcher_sorted_matches_for, -1); - - // module CommandT::Watchman::Utils - mCommandTWatchman = rb_define_module_under(mCommandT, "Watchman"); - mCommandTWatchmanUtils = rb_define_module_under(mCommandTWatchman, "Utils"); - rb_define_singleton_method(mCommandTWatchmanUtils, "load", CommandTWatchmanUtils_load, 1); - rb_define_singleton_method(mCommandTWatchmanUtils, "dump", CommandTWatchmanUtils_dump, 1); - rb_define_singleton_method(mCommandTWatchmanUtils, "query", CommandTWatchmanUtils_query, 2); -} diff -Nru vim-command-t-4.0/ruby/command-t/extconf.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/extconf.rb --- vim-command-t-4.0/ruby/command-t/extconf.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/extconf.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,66 +0,0 @@ -# Copyright 2010-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -require 'pathname' - -begin - require 'mkmf' -rescue LoadError - puts <<-DOC.gsub(/^\s+/, '') - Unable to require "mkmf"; you may need to install Ruby development tools - (depending on your system, a "ruby-dev"/"ruby-devel" package or similar). - [exiting] - DOC - exit 1 -end - -def header(item) - unless find_header(item) - puts "couldn't find #{item} (required)" - exit 1 - end -end - -# mandatory headers -header('float.h') -header('ruby.h') -header('stdlib.h') -header('string.h') - -# optional headers (for CommandT::Watchman::Utils) -if have_header('fcntl.h') && - have_header('stdint.h') && - have_header('sys/errno.h') && - have_header('sys/socket.h') - RbConfig::MAKEFILE_CONFIG['DEFS'] ||= '' - RbConfig::MAKEFILE_CONFIG['DEFS'] += ' -DWATCHMAN_BUILD' - - have_header('ruby/st.h') # >= 1.9; sets HAVE_RUBY_ST_H - have_header('st.h') # 1.8; sets HAVE_ST_H -end - -# optional -if RbConfig::CONFIG['THREAD_MODEL'] == 'pthread' - have_library('pthread', 'pthread_create') # sets HAVE_PTHREAD_H if found -end - -RbConfig::MAKEFILE_CONFIG['CC'] = ENV['CC'] if ENV['CC'] - -create_makefile('ext') - -# Create `metadata.rb`, which is used to diagnose installation problems. -basedir = Pathname.new(__FILE__).dirname -(basedir + 'metadata.rb').open('w') do |f| - f.puts <<-END.gsub(/^ /, '') - # This file was generated by #{(basedir + 'extconf.rb').to_s} - module CommandT - module Metadata - EXPECTED_RUBY_VERSION = #{RUBY_VERSION.inspect} - EXPECTED_RUBY_PATCHLEVEL = #{ - defined?(RUBY_PATCHLEVEL) ? RUBY_PATCHLEVEL.inspect : nil.inspect - } - UNKNOWN = false - end - end - END -end diff -Nru vim-command-t-4.0/ruby/command-t/ext.h vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/ext.h --- vim-command-t-4.0/ruby/command-t/ext.h 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/ext.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -// Copyright 2010-present Greg Hurrell. All rights reserved. -// Licensed under the terms of the BSD 2-clause license. - -#include - -extern VALUE mCommandT; // module CommandT -extern VALUE cCommandTMatcher; // class CommandT::Matcher -extern VALUE mCommandTWatchman; // module CommandT::Watchman -extern VALUE mCommandTWatchmanUtils; // module CommandT::Watchman::Utils - -// Encapsulates common pattern of checking for an option in an optional -// options hash. The hash itself may be nil, but an exception will be -// raised if it is not nil and not a hash. -VALUE CommandT_option_from_hash(const char *option, VALUE hash); - -// Debugging macros. -#define L(...) { \ - fprintf(stdout, __VA_ARGS__); \ - fflush(stdout); \ -} while (0) -#define RUBY_INSPECT(obj) do { \ - rb_funcall(rb_mKernel, rb_intern("p"), 1, obj); \ - fflush(stdout); \ -} while (0) diff -Nru vim-command-t-4.0/ruby/command-t/finder/buffer_finder.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/finder/buffer_finder.rb --- vim-command-t-4.0/ruby/command-t/finder/buffer_finder.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/finder/buffer_finder.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,17 +0,0 @@ -# Copyright 2010-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -module CommandT - class Finder - class BufferFinder < Finder - def initialize - @scanner = Scanner::BufferScanner.new - @matcher = Matcher.new @scanner, :always_show_dot_files => true - end - - def name - 'Buffers' - end - end - end -end diff -Nru vim-command-t-4.0/ruby/command-t/finder/command_finder.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/finder/command_finder.rb --- vim-command-t-4.0/ruby/command-t/finder/command_finder.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/finder/command_finder.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -# Copyright 2011-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -module CommandT - class Finder - class CommandFinder < Finder - def initialize(options = {}) - @scanner = Scanner::CommandScanner.new - @matcher = Matcher.new @scanner, :always_show_dot_files => true - end - - def open_selection(command, selection, options = {}) - ::VIM::command "call feedkeys(':#{selection} ', 'nt')" - end - - def flush; end - - def name - 'Commands' - end - end - end -end diff -Nru vim-command-t-4.0/ruby/command-t/finder/file_finder.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/finder/file_finder.rb --- vim-command-t-4.0/ruby/command-t/finder/file_finder.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/finder/file_finder.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -# Copyright 2010-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -module CommandT - class Finder - class FileFinder < Finder - def initialize(path = Dir.pwd, options = {}) - case options.delete(:scanner) - when 'ruby', nil # ruby is the default - @scanner = Scanner::FileScanner::RubyFileScanner.new(path, options) - when 'find' - @scanner = Scanner::FileScanner::FindFileScanner.new(path, options) - when 'watchman' - @scanner = Scanner::FileScanner::WatchmanFileScanner.new(path, options) - when 'git' - @scanner = Scanner::FileScanner::GitFileScanner.new(path, options) - else - raise ArgumentError, "unknown scanner type '#{options[:scanner]}'" - end - - @matcher = Matcher.new @scanner, options - end - - def flush - @scanner.flush - end - - def name - 'Files' - end - end - end -end diff -Nru vim-command-t-4.0/ruby/command-t/finder/help_finder.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/finder/help_finder.rb --- vim-command-t-4.0/ruby/command-t/finder/help_finder.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/finder/help_finder.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -# Copyright 2011-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -module CommandT - class Finder - class HelpFinder < Finder - def initialize(options = {}) - @scanner = Scanner::HelpScanner.new - @matcher = Matcher.new @scanner, :always_show_dot_files => true - end - - def open_selection(command, selection, options = {}) - ::VIM::command "help #{selection}" - end - - def flush - @scanner.flush - end - - def name - 'Help' - end - end - end -end diff -Nru vim-command-t-4.0/ruby/command-t/finder/history_finder.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/finder/history_finder.rb --- vim-command-t-4.0/ruby/command-t/finder/history_finder.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/finder/history_finder.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -# Copyright 2011-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -module CommandT - class Finder - class HistoryFinder < Finder - def initialize(options = {}) - @history_type = options[:history_type] # / or : - @scanner = Scanner::HistoryScanner.new("silent history #{@history_type}") - @matcher = Matcher.new @scanner, :always_show_dot_files => true - end - - def open_selection(command, selection, options = {}) - # Need to unescape to reverse the work done by `#sanitize_path_string`. - unescaped = selection.gsub(/\\(.)/, '\1') - escaped = VIM.escape_for_single_quotes unescaped - ::VIM::command "call feedkeys('#{@history_type}#{escaped} ', 'nt')" - end - - def flush; end - - def name - @history_type == ':' ? 'History' : 'Searches' - end - end - end -end diff -Nru vim-command-t-4.0/ruby/command-t/finder/jump_finder.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/finder/jump_finder.rb --- vim-command-t-4.0/ruby/command-t/finder/jump_finder.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/finder/jump_finder.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,17 +0,0 @@ -# Copyright 2011-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -module CommandT - class Finder - class JumpFinder < Finder - def initialize - @scanner = Scanner::JumpScanner.new - @matcher = Matcher.new @scanner, :always_show_dot_files => true - end - - def name - 'Jumps' - end - end - end -end diff -Nru vim-command-t-4.0/ruby/command-t/finder/line_finder.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/finder/line_finder.rb --- vim-command-t-4.0/ruby/command-t/finder/line_finder.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/finder/line_finder.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -# Copyright 2011-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -module CommandT - class Finder - class LineFinder < Finder - def initialize(options = {}) - @scanner = Scanner::LineScanner.new - @matcher = Matcher.new @scanner, :always_show_dot_files => true - end - - def open_selection(command, selection, options = {}) - ::VIM::command "#{selection.sub(/.+:(\d+)$/, '\1')}" - end - - def flush; end - - def name - 'Lines' - end - end - end -end diff -Nru vim-command-t-4.0/ruby/command-t/finder/mru_buffer_finder.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/finder/mru_buffer_finder.rb --- vim-command-t-4.0/ruby/command-t/finder/mru_buffer_finder.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/finder/mru_buffer_finder.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -# Copyright 2014-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -module CommandT - class Finder - class MRUBufferFinder < BufferFinder - def initialize - @scanner = Scanner::MRUBufferScanner.new - @matcher = Matcher.new @scanner, :always_show_dot_files => true - end - - # Override sorted_matches_for to prevent MRU ordered matches from being - # ordered alphabetically. - def sorted_matches_for(str, options = {}) - matches = super(str, options.merge(:sort => false)) - - # take current buffer (by definition, the most recently used) and move it - # to the end of the results - if MRU.last && - relative_path_under_working_directory(MRU.last.name) == matches.first - matches[1..-1] + [matches.first] - else - matches - end - end - - def name - 'Recent' - end - end - end -end diff -Nru vim-command-t-4.0/ruby/command-t/finder/tag_finder.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/finder/tag_finder.rb --- vim-command-t-4.0/ruby/command-t/finder/tag_finder.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/finder/tag_finder.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ -# Copyright 2011-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -module CommandT - class Finder - class TagFinder < Finder - def initialize(options = {}) - @scanner = Scanner::TagScanner.new options - @matcher = Matcher.new @scanner, :always_show_dot_files => true - end - - def open_selection(command, selection, options = {}) - if @scanner.include_filenames - selection = selection[0, selection.index(':')] - end - - # open the tag and center the screen on it - ::VIM::command "silent! tag #{selection} | :normal zz" - end - - def flush - @scanner.flush - end - - def name - 'Tags' - end - end - end -end diff -Nru vim-command-t-4.0/ruby/command-t/finder.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/finder.rb --- vim-command-t-4.0/ruby/command-t/finder.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/finder.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,50 +0,0 @@ -# Copyright 2010-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -require 'command-t/ext' # CommandT::Matcher, CommandT::Watchman::Utils - -module CommandT - # Encapsulates a Scanner instance (which builds up a list of available files - # in a directory) and a Matcher instance (which selects from that list based - # on a search string). - # - # Specialized subclasses use different kinds of scanners adapted for - # different kinds of search (files, buffers). - class Finder - autoload :BufferFinder, 'command-t/finder/buffer_finder' - autoload :CommandFinder, 'command-t/finder/command_finder' - autoload :FileFinder, 'command-t/finder/file_finder' - autoload :HelpFinder, 'command-t/finder/help_finder' - autoload :HistoryFinder, 'command-t/finder/history_finder' - autoload :JumpFinder, 'command-t/finder/jump_finder' - autoload :LineFinder, 'command-t/finder/line_finder' - autoload :MRUBufferFinder, 'command-t/finder/mru_buffer_finder' - autoload :TagFinder, 'command-t/finder/tag_finder' - - include PathUtilities - - def initialize(path = Dir.pwd, options = {}) - raise RuntimeError, 'Subclass responsibility' - end - - # Returns a human-readable name describing the finder, for display in the - # statusline attached to the MatchWindow buffer. - def name - raise RuntimeError, 'Subclass responsibility' - end - - # Options: - # :limit (integer): limit the number of returned matches - def sorted_matches_for(str, options = {}) - @matcher.sorted_matches_for str, options - end - - def open_selection(command, selection, options = {}) - ::VIM::command "silent #{command} #{selection}" - end - - def path=(path) - @scanner.path = path - end - end -end diff -Nru vim-command-t-4.0/ruby/command-t/.gitignore vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/.gitignore --- vim-command-t-4.0/ruby/command-t/.gitignore 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/.gitignore 1970-01-01 00:00:00.000000000 +0000 @@ -1,7 +0,0 @@ -/*.log -/*.o -/Makefile -/ext.* -/metadata.rb -!/ext.c -!/ext.h diff -Nru vim-command-t-4.0/ruby/command-t/heap.c vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/heap.c --- vim-command-t-4.0/ruby/command-t/heap.c 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/heap.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,146 +0,0 @@ -// Copyright 2016-present Greg Hurrell. All rights reserved. -// Licensed under the terms of the BSD 2-clause license. - -#include /* for free(), malloc(), NULL */ - -#include "heap.h" - -#define HEAP_PARENT(index) ((index - 1) / 2) -#define HEAP_LEFT(index) (2 * index + 1) -#define HEAP_RIGHT(index) (2 * index + 2) - -/** - * Returns a new heap, or NULL on failure. - */ -heap_t *heap_new(long capacity, heap_compare_entries comparator) { - heap_t *heap = malloc(sizeof(heap_t)); - if (!heap) { - return NULL; - } - heap->capacity = capacity; - heap->comparator = comparator; - heap->count = 0; - - heap->entries = malloc(capacity * sizeof(void *)); - if (!heap->entries) { - free(heap); - return NULL; - } - return heap; -} - -/** - * Frees a previously created heap. - */ -void heap_free(heap_t *heap) { - free(heap->entries); - free(heap); -} - -/** - * @internal - * - * Compare values at indices `a_idx` and `b_idx` using the heap's comparator - * function. - */ -int heap_compare(heap_t *heap, long a_idx, long b_idx) { - const void *a = heap->entries[a_idx]; - const void *b = heap->entries[b_idx]; - return heap->comparator(a, b); -} - -/** - * @internal - * - * Returns 1 if the heap property holds (ie. parent < child). - */ -int heap_property(heap_t *heap, long parent_idx, long child_idx) { - return heap_compare(heap, parent_idx, child_idx) > 0; -} - -/** - * @internal - * - * Swaps the values at indexes `a` and `b` within `heap`. - */ -void heap_swap(heap_t *heap, long a, long b) { - void *tmp = heap->entries[a]; - heap->entries[a] = heap->entries[b]; - heap->entries[b] = tmp; -} - -/** - * Inserts `value` into `heap`. - */ -void heap_insert(heap_t *heap, void *value) { - long idx, parent_idx; - - // If at capacity, ignore. - if (heap->count == heap->capacity) { - return; - } - - // Insert into first empty slot. - idx = heap->count; - heap->entries[idx] = value; - heap->count++; - - // Bubble upwards until heap property is restored. - parent_idx = HEAP_PARENT(idx); - while (idx && !heap_property(heap, parent_idx, idx)) { - heap_swap(heap, idx, parent_idx); - idx = parent_idx; - parent_idx = HEAP_PARENT(idx); - } -} - -/** - * @internal - * - * Restores the heap property starting at `idx`. - */ -void heap_heapify(heap_t *heap, long idx) { - long left_idx = HEAP_LEFT(idx); - long right_idx = HEAP_RIGHT(idx); - long smallest_idx = - right_idx < heap->count ? - - // Right (and therefore left) child exists. - (heap_compare(heap, left_idx, right_idx) > 0 ? left_idx : right_idx) : - - left_idx < heap->count ? - - // Only left child exists. - left_idx : - - // No children exist. - idx; - - if ( - smallest_idx != idx && - !heap_property(heap, idx, smallest_idx) - ) { - // Swap with smallest_idx child. - heap_swap(heap, idx, smallest_idx); - heap_heapify(heap, smallest_idx); - } -} - -/** - * Extracts the minimum value from `heap`. - */ -void *heap_extract(heap_t *heap) { - void *extracted = NULL; - if (heap->count) { - // Grab root value. - extracted = heap->entries[0]; - - // Move last item to root. - heap->entries[0] = heap->entries[heap->count - 1]; - heap->count--; - - // Restore heap property. - heap_heapify(heap, 0); - } - return extracted; -} diff -Nru vim-command-t-4.0/ruby/command-t/heap.h vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/heap.h --- vim-command-t-4.0/ruby/command-t/heap.h 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/heap.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -// Copyright 2016-present Greg Hurrell. All rights reserved. -// Licensed under the terms of the BSD 2-clause license. - -/** - * A fixed size min-heap implementation. - */ - -typedef int (*heap_compare_entries)(const void *a, const void *b); - -typedef struct { - long count; - long capacity; - void **entries; - heap_compare_entries comparator; -} heap_t; - -#define HEAP_PEEK(heap) (heap->entries[0]) - -heap_t *heap_new(long capacity, heap_compare_entries comparator); -void heap_free(heap_t *heap); -void heap_insert(heap_t *heap, void *value); -void *heap_extract(heap_t *heap); diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/controller.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/controller.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/controller.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/controller.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,612 @@ +# Copyright 2010-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +module CommandT + class Controller + include PathUtilities + include SCMUtilities + + # Wraps `method` in a `rescue` clause that attempts to print some useful + # information to the screen before re-raising any exception. Without this, + # most of the useful output is unhelpfully swallowed by Vim. + def self.guard(method) + class_eval <<-END + alias original_#{method} #{method} + def #{method}(*args, &block) + original_#{method}(*args, &block) + rescue Exception => e + backtrace = e.backtrace + trimmed = backtrace.take(backtrace.length - 2) + text = VIM::escape_for_single_quotes trimmed.join("\n") + ::VIM::command "echo '\#{text}'" + raise e + end + END + end + + def initialize + encoding = VIM::get_string('g:CommandTEncoding') + if encoding + begin + encoding = Encoding.find(encoding) + Encoding.default_external = encoding + Encoding.default_internal = encoding + rescue + end + end + @nowait = '' if ::VIM::evaluate('v:version') >= 704 + end + + # For possible use in status lines. + def active_finder + @active_finder && @active_finder.class.name + end + + # For possible use in status lines. + def path + @path + end + + # For possible use in status lines. + def is_own_buffer(buffer_number) + @match_window && buffer_number == @match_window.buffer_number + end + + # For possible use in status lines. + def return_is_own_buffer(buffer_number) + if is_own_buffer(buffer_number) + ::VIM::command 'return 1' + else + ::VIM::command 'return 0' + end + end + + def show_buffer_finder + @path = VIM::pwd + @active_finder = buffer_finder + show + end + guard :show_buffer_finder + + def show_command_finder + @path = VIM::pwd + @active_finder = command_finder + show + end + guard :show_command_finder + + def show_help_finder + @path = VIM::pwd + @active_finder = help_finder + show + end + guard :show_help_finder + + def show_history_finder + @path = VIM::pwd + @active_finder = history_finder + show + end + guard :show_history_finder + + def show_jump_finder + @path = VIM::pwd + @active_finder = jump_finder + show + end + guard :show_jump_finder + + def show_line_finder + @path = VIM::pwd + @active_finder = line_finder + show + end + guard :show_line_finder + + def show_mru_finder + @path = VIM::pwd + @active_finder = mru_finder + show + end + guard :show_mru_finder + + def show_search_finder + @path = VIM::pwd + @active_finder = search_finder + show + end + guard :show_search_finder + + def show_tag_finder + @path = VIM::pwd + @active_finder = tag_finder + show + end + guard :show_tag_finder + + def show_file_finder + # optional parameter will be desired starting directory, or "" + + arg = ::VIM::evaluate('a:arg') + if arg && arg.size > 0 + @path = File.expand_path(arg, VIM::pwd) + else + traverse = VIM::get_string('g:CommandTTraverseSCM') || 'file' + case traverse + when 'file' + @path = nearest_ancestor(VIM::current_file_dir, scm_markers) || VIM::pwd + when 'dir' + @path = nearest_ancestor(VIM::pwd, scm_markers) || VIM::pwd + else + @path = VIM::pwd + end + end + + @active_finder = file_finder + file_finder.path = @path + show + rescue Errno::ENOENT + # probably a problem with the optional parameter + @match_window.print_no_such_file_or_directory + end + guard :show_file_finder + + def hide + @match_window.leave + if VIM::Window.select @initial_window + if @initial_buffer.number == 0 + # upstream bug: buffer number misreported as 0 + # see: https://wincent.com/issues/1617 + ::VIM::command "silent b #{@initial_buffer.name}" + else + ::VIM::command "silent b #{@initial_buffer.number}" + end + end + end + + # Take current matches and stick them in the quickfix window. + def quickfix + hide + + matches = @matches.map do |match| + "{ 'filename': '#{VIM::escape_for_single_quotes match}' }" + end.join(', ') + + ::VIM::command 'call setqflist([' + matches + '])' + ::VIM::command 'cope' + end + guard :quickfix + + def refresh + return unless @active_finder && @active_finder.respond_to?(:flush) + @active_finder.flush + list_matches! + end + guard :refresh + + def flush + @file_finder = nil + @max_height = nil + @min_height = nil + @prompt = nil + @tag_finder = nil + end + guard :flush + + def handle_key + key = ::VIM::evaluate('a:arg').to_i.chr + if @focus == prompt + prompt.add! key + update + else + @match_window.find key + end + end + guard :handle_key + + def backspace + if @focus == prompt + prompt.backspace! + update + end + end + guard :backspace + + def delete + if @focus == prompt + prompt.delete! + update + end + end + guard :delete + + def remove_buffer + return unless @active_finder.class <= CommandT::Finder::BufferFinder + selection = @match_window.selection + + if @initial_buffer.name != selection + ::VIM::command "bd #{selection}" + end + list_matches! + end + guard :remove_buffer + + def accept_selection(options = {}) + selection = @match_window.selection + hide + open_selection(selection, options) unless selection.nil? + end + guard :accept_selection + + def toggle_focus + @focus.unfocus # old focus + @focus = @focus == prompt ? @match_window : prompt + @focus.focus # new focus + end + guard :toggle_focus + + def cancel + hide + end + guard :cancel + + def select_next + @match_window.select_next + end + guard :select_next + + def select_prev + @match_window.select_prev + end + guard :select_prev + + def clear + prompt.clear! + list_matches! + end + guard :clear + + def clear_prev_word + prompt.clear_prev_word! + list_matches! + end + guard :clear_prev_word + + def cursor_left + prompt.cursor_left if @focus == prompt + end + guard :cursor_left + + def cursor_right + prompt.cursor_right if @focus == prompt + end + guard :cursor_right + + def cursor_end + prompt.cursor_end if @focus == prompt + end + guard :cursor_end + + def cursor_start + prompt.cursor_start if @focus == prompt + end + guard :cursor_start + + def leave + @match_window.leave + end + + def unload + @match_window.unload + end + + def list_matches(options = {}) + return unless @needs_update || options[:force] + + @matches = @active_finder.sorted_matches_for( + prompt.abbrev, + :case_sensitive => case_sensitive?, + :limit => match_limit, + :threads => CommandT::Util.processor_count, + :ignore_spaces => VIM::get_bool('g:CommandTIgnoreSpaces', true), + :recurse => VIM::get_bool('g:CommandTRecursiveMatch', true) + ) + @match_window.matches = @matches + + # Scanner may have overwritten prompt to show progress. + prompt.redraw + + @needs_update = false + end + guard :list_matches + + def tab_command + VIM::get_string('g:CommandTAcceptSelectionTabCommand') || 'CommandTOpen tabedit' + end + + def split_command + VIM::get_string('g:CommandTAcceptSelectionSplitCommand') || 'CommandTOpen split' + end + + def vsplit_command + VIM::get_string('g:CommandTAcceptSelectionVSplitCommand') || 'CommandTOpen vsplit' + end + + private + + def update + if @debounce_interval > 0 + @needs_update = true + else + list_matches! + end + end + + def prompt + @prompt ||= Prompt.new( + :cursor_color => VIM::get_string('g:CommandTCursorColor') + ) + end + + def scm_markers + markers = VIM::get_string('g:CommandTSCMDirectories') + markers = markers && markers.split(/\s*,\s*/) + markers = %w[.git .hg .svn .bzr _darcs] unless markers && markers.any? + markers + end + + def list_matches! + list_matches(:force => true) + end + + def show + @initial_window = $curwin + @initial_buffer = $curbuf + @debounce_interval = VIM::get_number('g:CommandTInputDebounce') || 0 + @match_window = MatchWindow.new \ + :encoding => VIM::get_string('g:CommandTEncoding'), + :highlight_color => VIM::get_string('g:CommandTHighlightColor'), + :match_window_at_top => VIM::get_bool('g:CommandTMatchWindowAtTop'), + :match_window_reverse => VIM::get_bool('g:CommandTMatchWindowReverse', true), + :min_height => min_height, + :debounce_interval => @debounce_interval, + :prompt => prompt, + :name => "Command-T [#{@active_finder.name}]" + @focus = prompt + prompt.focus + register_for_key_presses + set_up_autocmds + clear # clears prompt and lists matches + end + + def max_height + @max_height ||= VIM::get_number('g:CommandTMaxHeight') || 15 + end + + def min_height + @min_height ||= begin + min_height = VIM::get_number('g:CommandTMinHeight') || 0 + min_height = max_height if max_height != 0 && min_height > max_height + min_height + end + end + + def case_sensitive? + if prompt.abbrev.match(/[A-Z]/) + if VIM::exists?('g:CommandTSmartCase') + smart_case = VIM::get_bool('g:CommandTSmartCase') + else + smart_case = VIM::get_bool('&smartcase') + end + + if smart_case + return true + end + end + + if VIM::exists?('g:CommandTIgnoreCase') + return !VIM::get_bool('g:CommandTIgnoreCase') + end + + false + end + + # Backslash-escape space, \, |, %, #, " + def sanitize_path_string(str) + # for details on escaping command-line mode arguments see: :h : + # (that is, help on ":") in the Vim documentation. + str.gsub(/[ \\|%#"]/, '\\\\\0') + end + + def current_buffer_visible_in_other_window + count = (0...::VIM::Window.count).to_a.inject(0) do |acc, i| + acc += 1 if ::VIM::Window[i].buffer.number == $curbuf.number + acc + end + count > 1 + end + + def default_open_command + if !VIM::get_bool('&modified') || + VIM::get_bool('&hidden') || + VIM::get_bool('&autowriteall') && !VIM::get_bool('&readonly') || + current_buffer_visible_in_other_window + VIM::get_string('g:CommandTAcceptSelectionCommand') || 'CommandTOpen edit' + else + 'split' + end + end + + def ensure_appropriate_window_selection + # Normally we try to open the selection in the current window, but there + # is one exception: + # + # - We don't touch any "unlisted" buffer with buftype "nofile" (such as + # NERDTree or MiniBufExplorer); this is to avoid things like the "Not + # enough room" error which occurs when trying to open in a split in a + # shallow (potentially 1-line) buffer like MiniBufExplorer is current + # + # Other "unlisted" buffers, such as those with buftype "help" are treated + # normally. + initial = $curwin + while true do + check_expression = VIM::get_string('g:CommandTWindowFilter') || + '!&buflisted && &buftype == "nofile"' + break unless ::VIM::evaluate(check_expression).to_i == 1 + ::VIM::command 'wincmd w' # try next window + break if $curwin == initial # have already tried all + end + end + + def open_selection(selection, options = {}) + command = options[:command] || default_open_command + if @active_finder.respond_to?(:prepare_selection) + selection = @active_finder.prepare_selection(selection) + else + selection = File.expand_path selection, @path + selection = relative_path_under_working_directory selection + selection = sanitize_path_string selection + selection = File.join('.', selection) if selection =~ /^\+/ + end + ensure_appropriate_window_selection + + @active_finder.open_selection command, selection, options + end + + def map(key, function, param = nil) + ::VIM::command "noremap #{@nowait} #{key} " \ + ":call commandt#private##{function}(#{param})" + end + + def term + @term ||= ::VIM::evaluate('&term') + end + + def register_for_key_presses + # "normal" keys (interpreted literally) + numbers = ('0'..'9').to_a.join + lowercase = ('a'..'z').to_a.join + uppercase = lowercase.upcase + punctuation = '<>`@#~!"$%^&/()=+*-_.,;:?\\|\'{}[]' + space = ' ' + (numbers + lowercase + uppercase + punctuation + space).each_byte do |b| + map "", 'HandleKey', b + end + + # "special" keys (overridable by settings) + { + 'AcceptSelection' => '', + 'AcceptSelectionSplit' => ['', ''], + 'AcceptSelectionTab' => '', + 'AcceptSelectionVSplit' => '', + 'Backspace' => '', + 'Cancel' => ['', ''], + 'Clear' => '', + 'ClearPrevWord' => '', + 'CursorEnd' => '', + 'CursorLeft' => ['', ''], + 'CursorRight' => ['', ''], + 'CursorStart' => '', + 'Delete' => '', + 'Quickfix' => '', + 'Refresh' => '', + 'RemoveBuffer' => '', + 'SelectNext' => ['', '', ''], + 'SelectPrev' => ['', '', ''], + 'ToggleFocus' => '', + }.each do |key, value| + if override = VIM::get_list_or_string("g:CommandT#{key}Map") + Array(override).each do |mapping| + map mapping, key + end + else + Array(value).each do |mapping| + unless mapping == '' && term =~ /\A(rxvt|screen|vt100|xterm)/ + map mapping, key + end + end + end + end + end + + def set_up_autocmds + if @debounce_interval > 0 + ::VIM::command 'augroup CommandTController' + ::VIM::command 'autocmd!' + ::VIM::command 'autocmd CursorHold :call commandt#private#ListMatches()' + ::VIM::command 'augroup END' + end + end + + # Returns the desired maximum number of matches, based on available vertical + # space and the g:CommandTMaxHeight option. + # + # Note the "available" space is actually a theoretical upper bound; it takes + # into account screen dimensions but not things like existing splits which + # may reduce the amount of space in practice. + def match_limit + limit = [1, VIM::Screen.lines - 5].max + limit = [limit, max_height].min if max_height > 0 + limit + end + + def buffer_finder + @buffer_finder ||= CommandT::Finder::BufferFinder.new + end + + def command_finder + @command_finder ||= CommandT::Finder::CommandFinder.new + end + + def mru_finder + @mru_finder ||= CommandT::Finder::MRUBufferFinder.new + end + + def wildignore + ignore = VIM::get_string('g:CommandTWildIgnore') + if ignore.nil? && VIM::exists?('&wildignore') + ignore = ::VIM::evaluate('&wildignore').to_s + end + VIM::wildignore_to_regexp(ignore) unless ignore.nil? + end + + def file_finder + @file_finder ||= CommandT::Finder::FileFinder.new nil, + :max_depth => VIM::get_number('g:CommandTMaxDepth'), + :max_files => VIM::get_number('g:CommandTMaxFiles'), + :max_caches => VIM::get_number('g:CommandTMaxCachedDirectories'), + :always_show_dot_files => VIM::get_bool('g:CommandTAlwaysShowDotFiles'), + :never_show_dot_files => VIM::get_bool('g:CommandTNeverShowDotFiles'), + :scan_dot_directories => VIM::get_bool('g:CommandTScanDotDirectories'), + :wildignore => wildignore, + :scanner => VIM::get_string('g:CommandTFileScanner'), + :git_scan_submodules => VIM::get_bool('g:CommandTGitScanSubmodules'), + :git_include_untracked => VIM::get_bool('g:CommandTGitIncludeUntracked') + end + + def help_finder + @help_finder ||= CommandT::Finder::HelpFinder.new + end + + def history_finder + CommandT::Finder::HistoryFinder.new(:history_type => ':') + end + + def jump_finder + @jump_finder ||= CommandT::Finder::JumpFinder.new + end + + def line_finder + CommandT::Finder::LineFinder.new + end + + def search_finder + CommandT::Finder::HistoryFinder.new(:history_type => '/') + end + + def tag_finder + @tag_finder ||= CommandT::Finder::TagFinder.new \ + :include_filenames => VIM::get_bool('g:CommandTTagIncludeFilenames') + end + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/finder/buffer_finder.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/finder/buffer_finder.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/finder/buffer_finder.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/finder/buffer_finder.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,17 @@ +# Copyright 2010-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +module CommandT + class Finder + class BufferFinder < Finder + def initialize + @scanner = Scanner::BufferScanner.new + @matcher = Matcher.new @scanner, :always_show_dot_files => true + end + + def name + 'Buffers' + end + end + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/finder/command_finder.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/finder/command_finder.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/finder/command_finder.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/finder/command_finder.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,31 @@ +# Copyright 2011-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +module CommandT + class Finder + class CommandFinder < Finder + def initialize(options = {}) + @scanner = Scanner::CommandScanner.new + @matcher = Matcher.new @scanner, :always_show_dot_files => true + end + + def open_selection(command, selection, options = {}) + escaped = VIM.escape_for_single_quotes selection + ::VIM::command "call feedkeys(':#{selection} ', 'nt')" + end + + def prepare_selection(selection) + # Pass selection through as-is, bypassing path-based stuff that the + # controller would otherwise do, like `expand_path`, + # `sanitize_path_string` and `relative_path_under_working_directory`. + selection + end + + def flush; end + + def name + 'Commands' + end + end + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/finder/file_finder.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/finder/file_finder.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/finder/file_finder.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/finder/file_finder.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,33 @@ +# Copyright 2010-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +module CommandT + class Finder + class FileFinder < Finder + def initialize(path = Dir.pwd, options = {}) + case options.delete(:scanner) + when 'ruby', nil # ruby is the default + @scanner = Scanner::FileScanner::RubyFileScanner.new(path, options) + when 'find' + @scanner = Scanner::FileScanner::FindFileScanner.new(path, options) + when 'watchman' + @scanner = Scanner::FileScanner::WatchmanFileScanner.new(path, options) + when 'git' + @scanner = Scanner::FileScanner::GitFileScanner.new(path, options) + else + raise ArgumentError, "unknown scanner type '#{options[:scanner]}'" + end + + @matcher = Matcher.new @scanner, options + end + + def flush + @scanner.flush + end + + def name + 'Files' + end + end + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/finder/help_finder.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/finder/help_finder.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/finder/help_finder.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/finder/help_finder.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,32 @@ +# Copyright 2011-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +module CommandT + class Finder + class HelpFinder < Finder + def initialize(options = {}) + @scanner = Scanner::HelpScanner.new + @matcher = Matcher.new @scanner, :always_show_dot_files => true + end + + def open_selection(command, selection, options = {}) + ::VIM::command "help #{selection}" + end + + def prepare_selection(selection) + # Pass selection through as-is, bypassing path-based stuff that the + # controller would otherwise do, like `expand_path`, + # `sanitize_path_string` and `relative_path_under_working_directory`. + selection + end + + def flush + @scanner.flush + end + + def name + 'Help' + end + end + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/finder/history_finder.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/finder/history_finder.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/finder/history_finder.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/finder/history_finder.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,32 @@ +# Copyright 2011-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +module CommandT + class Finder + class HistoryFinder < Finder + def initialize(options = {}) + @history_type = options[:history_type] # / or : + @scanner = Scanner::HistoryScanner.new("silent history #{@history_type}") + @matcher = Matcher.new @scanner, :always_show_dot_files => true + end + + def open_selection(command, selection, options = {}) + escaped = VIM.escape_for_single_quotes(selection) + ::VIM::command "call feedkeys('#{@history_type}#{escaped} ', 'nt')" + end + + def prepare_selection(selection) + # Pass selection through as-is, bypassing path-based stuff that the + # controller would otherwise do, like `expand_path`, + # `sanitize_path_string` and `relative_path_under_working_directory`. + selection + end + + def flush; end + + def name + @history_type == ':' ? 'History' : 'Searches' + end + end + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/finder/jump_finder.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/finder/jump_finder.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/finder/jump_finder.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/finder/jump_finder.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,17 @@ +# Copyright 2011-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +module CommandT + class Finder + class JumpFinder < Finder + def initialize + @scanner = Scanner::JumpScanner.new + @matcher = Matcher.new @scanner, :always_show_dot_files => true + end + + def name + 'Jumps' + end + end + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/finder/line_finder.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/finder/line_finder.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/finder/line_finder.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/finder/line_finder.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,23 @@ +# Copyright 2011-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +module CommandT + class Finder + class LineFinder < Finder + def initialize(options = {}) + @scanner = Scanner::LineScanner.new + @matcher = Matcher.new @scanner, :always_show_dot_files => true + end + + def open_selection(command, selection, options = {}) + ::VIM::command "#{selection.sub(/.+:(\d+)$/, '\1')}" + end + + def flush; end + + def name + 'Lines' + end + end + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/finder/mru_buffer_finder.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/finder/mru_buffer_finder.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/finder/mru_buffer_finder.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/finder/mru_buffer_finder.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,32 @@ +# Copyright 2014-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +module CommandT + class Finder + class MRUBufferFinder < BufferFinder + def initialize + @scanner = Scanner::MRUBufferScanner.new + @matcher = Matcher.new @scanner, :always_show_dot_files => true + end + + # Override sorted_matches_for to prevent MRU ordered matches from being + # ordered alphabetically. + def sorted_matches_for(str, options = {}) + matches = super(str, options.merge(:sort => false)) + + # take current buffer (by definition, the most recently used) and move it + # to the end of the results + if MRU.last && + relative_path_under_working_directory(MRU.last.name) == matches.first + matches[1..-1] + [matches.first] + else + matches + end + end + + def name + 'Recent' + end + end + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/finder/tag_finder.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/finder/tag_finder.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/finder/tag_finder.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/finder/tag_finder.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,37 @@ +# Copyright 2011-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +module CommandT + class Finder + class TagFinder < Finder + def initialize(options = {}) + @scanner = Scanner::TagScanner.new options + @matcher = Matcher.new @scanner, :always_show_dot_files => true + end + + def open_selection(command, selection, options = {}) + if @scanner.include_filenames + selection = selection[0, selection.index(':')] + end + + # open the tag and center the screen on it + ::VIM::command "silent! tag #{selection} | :normal zz" + end + + def prepare_selection(selection) + # Pass selection through as-is, bypassing path-based stuff that the + # controller would otherwise do, like `expand_path`, + # `sanitize_path_string` and `relative_path_under_working_directory`. + selection + end + + def flush + @scanner.flush + end + + def name + 'Tags' + end + end + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/finder.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/finder.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/finder.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/finder.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,50 @@ +# Copyright 2010-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +require 'command-t/ext' # CommandT::Matcher, CommandT::Watchman::Utils + +module CommandT + # Encapsulates a Scanner instance (which builds up a list of available files + # in a directory) and a Matcher instance (which selects from that list based + # on a search string). + # + # Specialized subclasses use different kinds of scanners adapted for + # different kinds of search (files, buffers). + class Finder + autoload :BufferFinder, 'command-t/finder/buffer_finder' + autoload :CommandFinder, 'command-t/finder/command_finder' + autoload :FileFinder, 'command-t/finder/file_finder' + autoload :HelpFinder, 'command-t/finder/help_finder' + autoload :HistoryFinder, 'command-t/finder/history_finder' + autoload :JumpFinder, 'command-t/finder/jump_finder' + autoload :LineFinder, 'command-t/finder/line_finder' + autoload :MRUBufferFinder, 'command-t/finder/mru_buffer_finder' + autoload :TagFinder, 'command-t/finder/tag_finder' + + include PathUtilities + + def initialize(path = Dir.pwd, options = {}) + raise RuntimeError, 'Subclass responsibility' + end + + # Returns a human-readable name describing the finder, for display in the + # statusline attached to the MatchWindow buffer. + def name + raise RuntimeError, 'Subclass responsibility' + end + + # Options: + # :limit (integer): limit the number of returned matches + def sorted_matches_for(str, options = {}) + @matcher.sorted_matches_for str, options + end + + def open_selection(command, selection, options = {}) + ::VIM::command "silent #{command} #{selection}" + end + + def path=(path) + @scanner.path = path + end + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/match_window.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/match_window.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/match_window.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/match_window.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,537 @@ +# Copyright 2010-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +require 'ostruct' + +module CommandT + class MatchWindow + SELECTION_MARKER = '> ' + MARKER_LENGTH = SELECTION_MARKER.length + UNSELECTED_MARKER = ' ' * MARKER_LENGTH + MH_START = '' + MH_END = '' + @@buffer = nil + + Highlight = Struct.new(:highlight, :bang) + + def initialize(options = {}) + @encoding = options[:encoding] + @highlight_color = options[:highlight_color] || 'PmenuSel' + @min_height = options[:min_height] + @prompt = options[:prompt] + @reverse_list = options[:match_window_reverse] + + quoted_name = VIM::escape_for_single_quotes(options[:name]) + escaped_name = ::VIM::evaluate("fnameescape('#{quoted_name}')") + + run_will_show_autocmd + + set 'timeout', true # ensure mappings timeout + set 'hlsearch', false # don't highlight search strings + set 'insertmode', false # don't make Insert mode the default + set 'showcmd', false # don't show command info on last line + set 'equalalways', false # don't auto-balance window sizes + set 'timeoutlen', 0 # respond immediately to mappings + set 'report', 9999 # don't show "X lines changed" reports + set 'scrolloff', 0 # don't scroll near buffer edges + set 'sidescroll', 0 # don't sidescroll in jumps + set 'sidescrolloff', 0 # don't sidescroll automatically + + if options[:debounce_interval] > 0 + set 'updatetime', options[:debounce_interval] + end + + # Save existing window views so we can restore them later. + current_window = ::VIM::evaluate('winnr()') + @windows = (0..(::VIM::Window.count - 1)).map do |i| + focus_window(i + 1) + view = ::VIM::evaluate('winsaveview()') + window = OpenStruct.new( + :index => i, + :height => ::VIM::Window[i].height, + :width => ::VIM::Window[i].width, + :lnum => view['lnum'], + :col => view['col'], + :coladd => view['coladd'], + :curswant => view['curswant'], + :topline => view['topline'], + :topfill => view['topfill'], + :leftcol => view['leftcol'], + :skipcol => view['skipcol'] + ) + + # When creating a split for the match window, move the cursor to the + # opposite side of the window's viewport to prevent unwanted scrolling. + boundary_line = options[:match_window_at_top] ? + ::VIM::evaluate("line('w$')") : + view['topline'] + ::VIM::evaluate("winrestview({'lnum': #{boundary_line}})") + + window + end + focus_window(current_window) + + # show match window + split_location = options[:match_window_at_top] ? 'topleft' : 'botright' + if ((number = buffer_number)) # still have buffer from last time + ::VIM::command "silent! #{split_location} #{number}sbuffer" + if $curbuf.number != number + raise "Can't re-open Command-T match listing buffer" + end + $curwin.height = 1 + ::VIM::command "0file" + ::VIM::command "keepalt file #{escaped_name}" + else # creating match window for first time and set it up + ::VIM::command "silent! keepalt #{split_location} 1split #{escaped_name}" + set 'bufhidden', 'unload' # unload buf when no longer displayed + set 'buftype', 'nofile' # buffer is not related to any file + set 'filetype', 'command-t' # provide for detectability/extensibility + set 'modifiable', false # prevent manual edits + set 'readonly', false # avoid W10 "Changing a readonly file" + set 'swapfile', false # don't create a swapfile + set 'wrap', false # don't soft-wrap + set 'number', false # don't show line numbers + set 'list', false # don't use List mode (visible tabs etc) + set 'foldcolumn', 0 # don't show a fold column at side + set 'foldlevel', 99 # don't fold anything + set 'cursorline', false # don't highlight line cursor is on + set 'spell', false # spell-checking off + set 'buflisted', false # don't show up in the buffer list + set 'textwidth', 0 # don't hard-wrap (break long lines) + + # don't show the color column + set 'colorcolumn', 0 if VIM::exists?('+colorcolumn') + + # don't show relative line numbers + set 'relativenumber', false if VIM::exists?('+relativenumber') + + # sanity check: make sure the buffer really was created + if File.basename($curbuf.name) != options[:name] + raise "Can't find Command-T match listing buffer" + end + @@buffer = $curbuf + end + + # syntax coloring + if VIM::has?('syntax') + ::VIM::command "syntax match CommandTSelection \"^#{SELECTION_MARKER}.\\+$\"" + ::VIM::command 'syntax match CommandTNoEntries "^-- NO MATCHES --$"' + ::VIM::command 'syntax match CommandTNoEntries "^-- NO SUCH FILE OR DIRECTORY --$"' + set 'synmaxcol', 9999 + + if VIM::has?('conceal') + set 'conceallevel', 2 + set 'concealcursor', 'nvic' + ::VIM::command 'syntax region CommandTCharMatched ' \ + "matchgroup=CommandTCharMatched start=+#{MH_START}+ " \ + "matchgroup=CommandTCharMatchedEnd end=+#{MH_END}+ concealends" + ::VIM::command 'highlight def CommandTCharMatched ' \ + 'term=bold,underline cterm=bold,underline ' \ + 'gui=bold,underline' + end + + ::VIM::command "highlight link CommandTSelection #{@highlight_color}" + ::VIM::command 'highlight link CommandTNoEntries Error' + + # hide cursor + @cursor_highlight = get_cursor_highlight + hide_cursor + end + + # perform cleanup using an autocmd to ensure we don't get caught out + # by some unexpected means of dismissing or leaving the Command-T window + # (eg. , etc) + ::VIM::command 'augroup CommandTMatchWindow' + ::VIM::command 'autocmd!' + ::VIM::command 'autocmd BufLeave silent! ruby $command_t.leave' + ::VIM::command 'autocmd BufUnload silent! ruby $command_t.unload' + ::VIM::command 'augroup END' + + @has_focus = false + @abbrev = '' + @window = $curwin + end + + def buffer_number + @@buffer && @@buffer.number + rescue Vim::DeletedBufferError + # Beware of people manually deleting Command-T's hidden, unlisted buffer. + @@buffer = nil + end + + def close + # Unlisted buffers like those provided by Netrw, NERDTree and Vim's help + # don't actually appear in the buffer list; if they are the only such + # buffers present when Command-T is invoked (for example, when invoked + # immediately after starting Vim with a directory argument, like `vim .`) + # then performing the normal clean-up will yield an "E90: Cannot unload + # last buffer" error. We can work around that by doing a :quit first. + if ::VIM::Buffer.count == 0 + ::VIM::command 'silent quit' + end + + # Workaround for upstream bug in Vim 7.3 on some platforms + # + # On some platforms, $curbuf.number always returns 0. One workaround is + # to build Vim with --disable-largefile, but as this is producing lots of + # support requests, implement the following fallback to the buffer name + # instead, at least until upstream gets fixed. + # + # For more details, see: https://wincent.com/issues/1617 + if $curbuf.number == 0 + # use bwipeout as bunload fails if passed the name of a hidden buffer + base = File.basename($curbuf.name) + escaped_name = ::VIM::evaluate("fnameescape('#{base}')") + ::VIM::command "silent! bwipeout! #{escaped_name}" + @@buffer = nil + else + ::VIM::command "silent! bunload! #{@@buffer.number}" + end + end + + def leave + close + unload + end + + def unload + restore_window_views + @prompt.dispose + @settings.restore + show_cursor + run_did_hide_autocmd + end + + def add!(char) + @abbrev += char + end + + def backspace! + @abbrev.chop! + end + + def select_next + @reverse_list ? _prev : _next + end + + def select_prev + @reverse_list ? _next : _prev + end + + def matches=(matches) + if matches != @matches + @matches = matches + @selection = 0 + print_matches + move_cursor_to_selected_line + end + end + + def focus + unless @has_focus + @has_focus = true + if VIM::has?('syntax') + ::VIM::command 'highlight link CommandTSelection Search' + end + end + end + + def unfocus + if @has_focus + @has_focus = false + if VIM::has?('syntax') + ::VIM::command "highlight link CommandTSelection #{@highlight_color}" + end + end + end + + def find(char) + # is this a new search or the continuation of a previous one? + now = Time.now + if @last_key_time.nil? || @last_key_time < (now - 0.5) + @find_string = char + else + @find_string += char + end + @last_key_time = now + + # see if there's anything up ahead that matches + matches = @reverse_list ? @matches.reverse : @matches + matches.each_with_index do |match, idx| + if match[0, @find_string.length].casecmp(@find_string) == 0 + old_selection = @selection + @selection = @reverse_list ? matches.length - idx - 1 : idx + print_match(old_selection) # redraw old selection (removes marker) + print_match(@selection) # redraw new selection (adds marker) + break + end + end + end + + # Returns the currently selected item as a String. + def selection + @matches[@selection] + end + + def print_no_such_file_or_directory + print_error 'NO SUCH FILE OR DIRECTORY' + end + + private + + def focus_window(number) + ::VIM::command("noautocmd #{number}wincmd w") + end + + def _next + if @selection < [@window.height, @matches.length].min - 1 + @selection += 1 + print_match(@selection - 1) # redraw old selection (removes marker) + print_match(@selection) # redraw new selection (adds marker) + move_cursor_to_selected_line + end + end + + def _prev + if @selection > 0 + @selection -= 1 + print_match(@selection + 1) # redraw old selection (removes marker) + print_match(@selection) # redraw new selection (adds marker) + move_cursor_to_selected_line + end + end + + # Translate from a 0-indexed match index to a 1-indexed Vim line number. + # Also takes into account reversed listings. + def line(match_index) + @reverse_list ? @window.height - match_index : match_index + 1 + end + + def set(setting, value) + @settings ||= Settings.new + @settings.set(setting, value) + end + + def move_cursor_to_selected_line + # on some non-GUI terminals, the cursor doesn't hide properly + # so we move the cursor to prevent it from blinking away in the + # upper-left corner in a distracting fashion + @window.cursor = [line(@selection), 0] + end + + def print_error(msg) + return unless VIM::Window.select(@window) + unlock + clear + @window.height = [1, @min_height].min + @@buffer[1] = "-- #{msg} --" + lock + end + + def restore_window_views + # sort from tallest to shortest, tie-breaking on window width + @windows.sort! do |a, b| + order = b.height <=> a.height + if order.zero? + b.width <=> a.width + else + order + end + end + + # starting with the tallest ensures that there are no constraints + # preventing windows on the side of vertical splits from regaining + # their original full size + current_window = ::VIM::evaluate('winnr()') + @windows.each do |w| + # beware: window may be nil + if window = ::VIM::Window[w.index] + window.height = w.height + window.width = w.width + focus_window(w.index + 1) + ::VIM::evaluate("winrestview({" + + "'lnum': #{w.lnum}," + + "'col': #{w.col}, " + + "'coladd': #{w.coladd}, " + + "'curswant': #{w.curswant}, " + + "'topline': #{w.topline}, " + + "'topfill': #{w.topfill}, " + + "'leftcol': #{w.leftcol}, " + + "'skipcol': #{w.skipcol}" + + "})") + end + end + focus_window(current_window) + end + + def run_will_show_autocmd + run_autocmd('CommandTWillShowMatchListing') + end + + def run_did_hide_autocmd + run_autocmd('CommandTDidHideMatchListing') + end + + def run_autocmd(cmd) + ::VIM::command("call commandt#private#RunAutocmd('#{cmd}')") + end + + def match_text_for_idx(idx) + match = truncated_match @matches[idx].to_s + if idx == @selection + prefix = SELECTION_MARKER + suffix = padding_for_selected_match match + else + if VIM::has?('syntax') && VIM::has?('conceal') + match = match_with_syntax_highlight match + end + prefix = UNSELECTED_MARKER + suffix = '' + end + prefix + match + suffix + end + + # Highlight matching characters within the matched string. + # + # Note that this is only approximate; it will highlight the first matching + # instances within the string, which may not actually be the instances that + # were used by the matching/scoring algorithm to determine the best score + # for the match. + # + def match_with_syntax_highlight(match) + highlight_chars = @prompt.abbrev.downcase.scan(/./mu) + if @encoding && + match.respond_to?(:force_encoding) && + match.encoding != @encoding + match = match.force_encoding(@encoding) + end + match.scan(/./mu).inject([]) do |output, char| + if char.downcase == highlight_chars.first + highlight_chars.shift + output.concat [MH_START, char, MH_END] + else + output << char + end + end.join + end + + # Print just the specified match. + def print_match(idx) + return unless VIM::Window.select(@window) + unlock + @@buffer[line(idx)] = match_text_for_idx idx + lock + end + + def max_lines + [1, VIM::Screen.lines - 5].max + end + + # Print all matches. + def print_matches + match_count = @matches.length + if match_count == 0 + print_error 'NO MATCHES' + else + return unless VIM::Window.select(@window) + unlock + clear + @window_width = @window.width # update cached value + desired_lines = [match_count, @min_height].max + desired_lines = [max_lines, desired_lines].min + @window.height = desired_lines + matches = [] + (0...@window.height).each do |idx| + text = match_text_for_idx(idx) + @reverse_list ? matches.unshift(text) : matches.push(text) + end + matches.each_with_index do |match, idx| + if @@buffer.count > idx + @@buffer[idx + 1] = match + else + @@buffer.append(idx, match) + end + end + lock + end + end + + # Prepare padding for match text (trailing spaces) so that selection + # highlighting extends all the way to the right edge of the window. + def padding_for_selected_match(str) + len = str.length + if len >= @window_width - MARKER_LENGTH + '' + else + ' ' * (@window_width - MARKER_LENGTH - len) + end + end + + # Convert "really/long/path" into "really...path" based on available + # window width. + def truncated_match(str) + len = str.length + available_width = @window_width - MARKER_LENGTH + return str if len <= available_width + left = (available_width / 2) - 1 + right = (available_width / 2) - 2 + (available_width % 2) + str[0, left] + '...' + str[-right, right] + end + + def clear + # range = % (whole buffer) + # action = d (delete) + # register = _ (black hole register, don't record deleted text) + ::VIM::command 'silent %d _' + end + + def get_cursor_highlight + # there are 4 possible formats to check for, each needing to be + # transformed in a certain way in order to reapply the highlight: + # Cursor xxx guifg=bg guibg=fg -> :hi! Cursor guifg=bg guibg=fg + # Cursor xxx links to SomethingElse -> :hi! link Cursor SomethingElse + # Cursor xxx [definition] + # links to VisualNOS -> both of the above + # Cursor xxx cleared -> :hi! clear Cursor + highlight = VIM::capture 'silent! 0verbose highlight Cursor' + + if highlight =~ /^Cursor\s+xxx\s+(.+)\blinks to (\w+)/m + [ + Highlight.new("Cursor #{$~[1]}"), + Highlight.new("link Cursor #{$~[2]}", '!') + ] + elsif highlight =~ /^Cursor\s+xxx\s+links to (\w+)/m + [Highlight.new("link Cursor #{$~[1]}")] + elsif highlight =~ /^Cursor\s+xxx\s+cleared/m + [Highlight.new('clear Cursor')] + elsif highlight =~ /Cursor\s+xxx\s+(.+)/m + [Highlight.new("Cursor #{$~[1]}")] + else # likely cause E411 Cursor highlight group not found + [] + end + end + + def hide_cursor + if @cursor_highlight + ::VIM::command 'highlight Cursor NONE' + end + end + + def show_cursor + if @cursor_highlight + @cursor_highlight.each do |highlight| + config = highlight.highlight.gsub(/\s+/, ' ') + ::VIM::command "highlight#{highlight.bang} #{config}" + end + end + end + + def lock + set 'modifiable', false + end + + def unlock + set 'modifiable', true + end + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/metadata/fallback.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/metadata/fallback.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/metadata/fallback.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/metadata/fallback.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,12 @@ +# Copyright 2015-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +module CommandT + module Metadata + # This file gets overwritten with actual data during the installation + # process (when `ruby extconf.rb` is run). + EXPECTED_RUBY_VERSION = '[unknown]' + EXPECTED_RUBY_PATCHLEVEL = '[unknown]' + UNKNOWN = true + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/mru.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/mru.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/mru.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/mru.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,43 @@ +# Copyright 2014-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +module CommandT + # Maintains a stack of seen buffers in MRU (most recently used) order. + module MRU + class << self + # The stack of used buffers in MRU order. + def stack + @stack ||= [] + end + + # The (last) most recent buffer in the stack, if any. + def last + stack.last + end + + # Mark the current buffer as having been used, effectively moving it to + # the top of the stack. + def touch + return unless ::VIM::evaluate('buflisted(%d)' % $curbuf.number) == 1 + return unless $curbuf.name + + stack.delete $curbuf + stack.push $curbuf + end + + # Mark a buffer as deleted, removing it from the stack. + def delete + # Note that $curbuf does not point to the buffer that is being deleted; + # we need to use Vim's for the correct buffer number. + stack.delete_if do |b| + b.number == ::VIM::evaluate('expand("")').to_i + end + end + + # Returns `true` if `buffer` has been used (ie. is present in the stack). + def used?(buffer) + stack.include?(buffer) + end + end + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/path_utilities.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/path_utilities.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/path_utilities.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/path_utilities.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,17 @@ +# Copyright 2010-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +module CommandT + module PathUtilities + + private + + def relative_path_under_working_directory(path) + # any path under the working directory will be specified as a relative + # path to improve the readability of the buffer list etc + pwd = File.expand_path(VIM::pwd) + '/' + path.index(pwd) == 0 ? path[pwd.length..-1] : path + end + + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/progress_reporter.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/progress_reporter.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/progress_reporter.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/progress_reporter.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,38 @@ +# Copyright 2010-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +module CommandT + # Simple class for displaying scan progress to the user. + # + # The active scanner calls the `#update` method with a `count` to inform it of + # progress, the reporter updates the UI and then returns a suggested count at + # which to invoke `#update` again in the future (the suggested count is based + # on a heuristic that seeks to update the UI about 5 times per second). + class ProgressReporter + SPINNER = %w[^ > v <] + + def initialize + @spinner ||= SPINNER.first + end + + def update(count) + @spinner = SPINNER[(SPINNER.index(@spinner) + 1) % SPINNER.length] + + ::VIM::command "echon '#{@spinner} #{count}'" + ::VIM::command 'redraw' + + # Aim for 5 updates per second. + now = Time.now.to_f + if @last_time + time_diff = now - @last_time + count_diff = count - @last_count + next_count = count + ((0.2 / time_diff) * count_diff).to_i + else + next_count = count + 100 + end + @last_time = now + @last_count = count + next_count + end + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/prompt.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/prompt.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/prompt.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/prompt.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,163 @@ +# Copyright 2010-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +module CommandT + # Abuse the status line as a prompt. + class Prompt + attr_accessor :abbrev + + def initialize(options = {}) + @abbrev = '' # abbreviation entered so far + @col = 0 # cursor position + @cursor_color = options[:cursor_color] || 'Underlined' + @has_focus = false + end + + # Erase whatever is displayed in the prompt line, + # effectively disposing of the prompt + def dispose + ::VIM::command 'echo' + ::VIM::command 'redraw' + end + + # Clear any entered text. + def clear! + @abbrev = '' + @col = 0 + redraw + end + + # Remove word before cursor + def clear_prev_word! + suffix_length = @abbrev.length - @col + if @abbrev.match( + %r{ + (.*) # prefix + \b\w.* # "word" to clear + (.{#{suffix_length}}) # suffix + \z + }x + ) + @abbrev = $~[1] + $~[2] + @col = @abbrev.length - suffix_length + redraw + end + end + + # Insert a character at (before) the current cursor position. + def add!(char) + left, cursor, right = abbrev_segments + @abbrev = left + char + cursor + right + @col += 1 + redraw + end + + # Delete a character to the left of the current cursor position. + def backspace! + if @col > 0 + left, cursor, right = abbrev_segments + @abbrev = left.chop! + cursor + right + @col -= 1 + redraw + end + end + + # Delete a character at the current cursor position. + def delete! + if @col < @abbrev.length + left, cursor, right = abbrev_segments + @abbrev = left + right + redraw + end + end + + def cursor_left + if @col > 0 + @col -= 1 + redraw + end + end + + def cursor_right + if @col < @abbrev.length + @col += 1 + redraw + end + end + + def cursor_end + if @col < @abbrev.length + @col = @abbrev.length + redraw + end + end + + def cursor_start + if @col != 0 + @col = 0 + redraw + end + end + + def focus + unless @has_focus + @has_focus = true + redraw + end + end + + def unfocus + if @has_focus + @has_focus = false + redraw + end + end + + def redraw + if @has_focus + prompt_highlight = 'Comment' + normal_highlight = 'None' + cursor_highlight = @cursor_color + else + prompt_highlight = 'NonText' + normal_highlight = 'NonText' + cursor_highlight = 'NonText' + end + left, cursor, right = abbrev_segments + components = [prompt_highlight, '>>', 'None', ' '] + components += [normal_highlight, left] unless left.empty? + components += [cursor_highlight, cursor] unless cursor.empty? + components += [normal_highlight, right] unless right.empty? + components += [cursor_highlight, ' '] if cursor.empty? + set_status *components + end + + private + + # Returns the @abbrev string divided up into three sections, any of + # which may actually be zero width, depending on the location of the + # cursor: + # - left segment (to left of cursor) + # - cursor segment (character at cursor) + # - right segment (to right of cursor) + def abbrev_segments + left = @abbrev[0, @col] + cursor = @abbrev[@col, 1] + right = @abbrev[(@col + 1)..-1] || '' + [left, cursor, right] + end + + def set_status(*args) + # see ':help :echo' for why forcing a redraw here helps + # prevent the status line from getting inadvertantly cleared + # after our echo commands + ::VIM::command 'redraw' + while (highlight = args.shift) && (text = args.shift) + text = VIM::escape_for_single_quotes text + ::VIM::command "echohl #{highlight}" + ::VIM::command "echon '#{text}'" + end + ::VIM::command 'echohl None' + end + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/scanner/buffer_scanner.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/scanner/buffer_scanner.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/scanner/buffer_scanner.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/scanner/buffer_scanner.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,23 @@ +# Copyright 2010-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +module CommandT + class Scanner + # Returns a list of all open buffers. + class BufferScanner < Scanner + include PathUtilities + + def paths + (0..(::VIM::Buffer.count - 1)).map do |n| + buffer = ::VIM::Buffer[n] + # Beware, name may be nil, and on Neovim unlisted buffers (like + # Command-T's match listing itself) will be returned and must be + # skipped. + if buffer.name && ::VIM::evaluate("buflisted(#{buffer.number})") != 0 + relative_path_under_working_directory buffer.name + end + end.compact + end + end + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/scanner/command_scanner.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/scanner/command_scanner.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/scanner/command_scanner.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/scanner/command_scanner.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,33 @@ +# Copyright 2011-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +module CommandT + class Scanner + class CommandScanner < Scanner + def paths + @paths ||= paths! + end + + private + + def paths! + # Get user commands. + commands = VIM.capture('silent command').split("\n")[2..-1].map do |line| + line.sub(/\A.{4}(\S+).+/, '\1') + end + + # Get built-in commands from `ex-cmd-index`. + ex_cmd_index = ::VIM.evaluate('expand(findfile("doc/index.txt", &runtimepath))') + if File.readable?(ex_cmd_index) + File.readlines(ex_cmd_index).each do |line| + if line =~ %r{\A\|:([^|]+)\|\s+} + commands << $~[1] + end + end + end + + commands.uniq + end + end + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/scanner/file_scanner/find_file_scanner.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/scanner/file_scanner/find_file_scanner.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/scanner/file_scanner/find_file_scanner.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/scanner/file_scanner/find_file_scanner.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,55 @@ +# Copyright 2014-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +require 'open3' + +module CommandT + class Scanner + class FileScanner + # A FileScanner which shells out to the `find` executable in order to scan. + class FindFileScanner < FileScanner + include PathUtilities + + def paths! + # temporarily set field separator to NUL byte; this setting is + # respected by both `each_line` and `chomp!` below, and makes it easier + # to parse the output of `find -print0` + separator = $/ + $/ = "\x00" + + unless @scan_dot_directories + dot_directory_filter = [ + '-not', '-path', "#{@path}/.*/*", # top-level dot dir + '-and', '-not', '-path', "#{@path}/*/.*/*" # lower-level dot dir + ] + end + + paths = [] + Open3.popen3(*([ + 'find', '-L', # follow symlinks + @path, # anchor search here + '-maxdepth', @max_depth.to_s, # limit depth of DFS + '-type', 'f', # only show regular files (not dirs etc) + dot_directory_filter, # possibly skip out dot directories + '-print0' # NUL-terminate results + ].flatten.compact)) do |stdin, stdout, stderr| + counter = 1 + next_progress = progress_reporter.update(counter) + stdout.each_line do |line| + next if path_excluded?(line.chomp!) + paths << line[@prefix_len..-1] + next_progress = progress_reporter.update(counter) if counter == next_progress + if (counter += 1) > @max_files + show_max_files_warning + break + end + end + end + paths + ensure + $/ = separator + end + end + end + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/scanner/file_scanner/git_file_scanner.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/scanner/file_scanner/git_file_scanner.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/scanner/file_scanner/git_file_scanner.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/scanner/file_scanner/git_file_scanner.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,61 @@ +# Copyright 2014-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +module CommandT + class Scanner + class FileScanner + # Uses git ls-files to scan for files + class GitFileScanner < FindFileScanner + LsFilesError = Class.new(::RuntimeError) + + def paths! + Dir.chdir(@path) do + command = %w[git ls-files --exclude-standard -cz] + if @include_untracked + command << %q(--others) + end + all_files = list_files(command) + + if @scan_submodules + base = nil + list_files(%w[ + git submodule foreach --recursive + git ls-files --exclude-standard -z + ]).each do |path| + if path =~ /\AEntering '(.*)'\n(.*)\z/ + base = $~[1] + path = $~[2] + end + all_files.push(base + File::SEPARATOR + path) + end + end + + filtered = all_files. + map { |path| path.chomp }. + reject { |path| path_excluded?(path, 0) } + truncated = filtered.take(@max_files) + if truncated.count < filtered.count + show_max_files_warning + end + truncated.to_a + end + rescue LsFilesError + super + rescue Errno::ENOENT + # git executable not present and executable + super + end + + private + + def list_files(command) + stdin, stdout, stderr = Open3.popen3(*command) + stdout.read.split("\0") + ensure + raise LsFilesError if stderr && stderr.gets + end + + end + end + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/scanner/file_scanner/ruby_file_scanner.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/scanner/file_scanner/ruby_file_scanner.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/scanner/file_scanner/ruby_file_scanner.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/scanner/file_scanner/ruby_file_scanner.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,60 @@ +# Copyright 2010-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +module CommandT + class Scanner + class FileScanner + FileLimitExceeded = Class.new(::RuntimeError) + + # Pure Ruby implementation of a file scanner. + class RubyFileScanner < FileScanner + def paths! + accumulator = [] + @depth = 0 + @files = 0 + @next_progress = progress_reporter.update(@files) + add_paths_for_directory(@path, accumulator) + accumulator + rescue FileLimitExceeded + show_max_files_warning + accumulator + end + + private + + def looped_symlink?(path) + if File.symlink?(path) + target = File.expand_path(File.readlink(path), File.dirname(path)) + target.include?(@path) || @path.include?(target) + end + end + + def add_paths_for_directory(dir, accumulator) + Dir.foreach(dir) do |entry| + next if ['.', '..'].include?(entry) + path = File.join(dir, entry) + unless path_excluded?(path) + if File.file?(path) + @files += 1 + @next_progress = progress_reporter.update(@files) if @files == @next_progress + raise FileLimitExceeded if @files > @max_files + accumulator << path[@prefix_len..-1] + elsif File.directory?(path) + next if @depth >= @max_depth + next if (entry.match(/\A\./) && !@scan_dot_directories) + next if looped_symlink?(path) + @depth += 1 + add_paths_for_directory(path, accumulator) + @depth -= 1 + end + end + end + rescue Errno::EACCES + # skip over directories for which we don't have access + rescue ArgumentError + # skip over bad file names + end + end + end + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/scanner/file_scanner/watchman_file_scanner.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/scanner/file_scanner/watchman_file_scanner.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/scanner/file_scanner/watchman_file_scanner.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/scanner/file_scanner/watchman_file_scanner.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,72 @@ +# Copyright 2014-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +require 'pathname' +require 'socket' + +module CommandT + class Scanner + class FileScanner + # A FileScanner which delegates the heavy lifting to Watchman + # (https://github.com/facebook/watchman); useful for very large hierarchies. + # + # Inherits from FindFileScanner so that it can fall back to it in the event + # that Watchman isn't available or able to fulfil the request. + class WatchmanFileScanner < FindFileScanner + # Exception raised when Watchman is unavailable or unable to process the + # requested path. + WatchmanError = Class.new(::RuntimeError) + + def paths! + sockname = extract_value( + Watchman::Utils.load(get_raw_sockname), + 'sockname' + ) + + UNIXSocket.open(sockname) do |socket| + root = Pathname.new(@path).realpath.to_s + roots = Watchman::Utils.query(['watch-list'], socket)['roots'] + if !roots.include?(root) + # this path isn't being watched yet; try to set up watch + result = Watchman::Utils.query(['watch', root], socket) + + # root_restrict_files setting may prevent Watchman from working + # or enforce_root_files/root_files (>= version 3.1) + extract_value(result) + end + + query = ['query', root, { + 'expression' => ['type', 'f'], + 'fields' => ['name'], + }] + paths = Watchman::Utils.query(query, socket) + + # could return error if watch is removed + extracted = extract_value(paths, 'files') + if @wildignore + extracted.select { |path| path !~ @wildignore } + else + extracted + end + end + rescue Errno::ENOENT, WatchmanError + # watchman executable not present, or unable to fulfil request + super + end + + private + + def extract_value(object, key = nil) + raise WatchmanError, object['error'] if object.has_key?('error') + object[key] + end + + def get_raw_sockname + raw_sockname = %x{watchman --output-encoding=bser get-sockname} + raise WatchmanError, 'get-sockname failed' if !$?.exitstatus.zero? + raw_sockname + end + end + end + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/scanner/file_scanner.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/scanner/file_scanner.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/scanner/file_scanner.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/scanner/file_scanner.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,89 @@ +# Copyright 2010-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +module CommandT + class Scanner + # Reads the current directory recursively for the paths to all regular files. + # + # This is an abstract superclass; the real work is done by subclasses which + # obtain file listings via different strategies (for examples, see the + # RubyFileScanner and FindFileScanner subclasses). + class FileScanner < Scanner + # Subclasses + autoload :FindFileScanner, 'command-t/scanner/file_scanner/find_file_scanner' + autoload :GitFileScanner, 'command-t/scanner/file_scanner/git_file_scanner' + autoload :RubyFileScanner, 'command-t/scanner/file_scanner/ruby_file_scanner' + autoload :WatchmanFileScanner, 'command-t/scanner/file_scanner/watchman_file_scanner' + + attr_accessor :path + + def initialize(path = Dir.pwd, options = {}) + @paths = {} + @paths_keys = [] + @path = path + @max_depth = options[:max_depth] || 15 + @max_files = options[:max_files] || 100_000 + @max_caches = options[:max_caches] || 1 + @scan_dot_directories = options[:scan_dot_directories] || false + @wildignore = options[:wildignore] + @scan_submodules = options[:git_scan_submodules] || false + @include_untracked = options[:git_include_untracked] || false + end + + def paths + @paths[@path] ||= begin + ensure_cache_under_limit + @prefix_len = @path.chomp('/').length + 1 + paths! + end + end + + def flush + @paths = {} + end + + private + + def show_max_files_warning + unless VIM::get_bool('g:CommandTSuppressMaxFilesWarning', false) + ::VIM::command('redraw!') + ::VIM::command('echohl ErrorMsg') + warning = + "Warning: maximum file limit reached\n" + + "\n" + + "Increase it by setting a higher value in $MYVIMRC; eg:\n" + + " let g:CommandTMaxFiles=#{@max_files * 2}\n" + + "Or suppress this warning by setting:\n" + + " let g:CommandTSuppressMaxFilesWarning=1\n" + + "For best performance, consider using a fast scanner; see:\n" + + " :help g:CommandTFileScanner\n" + + "\n" + + "Press ENTER to continue." + ::VIM::evaluate(%{input("#{warning}")}) + ::VIM::command('echohl None') + end + end + + def paths! + raise RuntimeError, 'Subclass responsibility' + end + + def ensure_cache_under_limit + # Ruby 1.8 doesn't have an ordered hash, so use a separate stack to + # track and expire the oldest entry in the cache + if @max_caches > 0 && @paths_keys.length >= @max_caches + @paths.delete @paths_keys.shift + end + @paths_keys << @path + end + + def path_excluded?(path, prefix_len = @prefix_len) + if @wildignore + # First strip common prefix (@path) from path to match Vim's behavior. + path = path[prefix_len..-1] + path =~ @wildignore + end + end + end + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/scanner/help_scanner.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/scanner/help_scanner.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/scanner/help_scanner.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/scanner/help_scanner.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,45 @@ +# Copyright 2011-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +module CommandT + class Scanner + class HelpScanner < Scanner + def paths + runtimepath = ::VIM::evaluate('&runtimepath') + if runtimepath != @runtimepath + @cached_tags = nil + @runtimepath = runtimepath + end + @cached_tags ||= paths! + end + + def flush + @cached_tags = nil + end + + private + + def paths! + # Vim doesn't provide an easy way to get a list of all help tags. + # `tagfiles()` only shows the tagfiles for the current buffer, so you + # need to already be in a buffer of `'buftype'` `help` for that to work. + # Likewise, `taglist()` only shows tags that apply to the current file + # type, and `:tag` has the same restriction. + # + # So, we look for a "doc/tags" file at every location in the + # `'runtimepath'` and try to manually parse it. + tags = [] + + ::VIM::evaluate('findfile("doc/tags", &runtimepath, -1)').each do |path| + if File.readable?(path) + File.readlines(path).each do |tag| + tags << tag.split.first if tag.split.first + end + end + end + + tags + end + end + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/scanner/history_scanner.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/scanner/history_scanner.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/scanner/history_scanner.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/scanner/history_scanner.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,24 @@ +# Copyright 2011-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +module CommandT + class Scanner + class HistoryScanner < Scanner + def initialize(history_command) + @history_command = history_command + end + + def paths + @paths ||= paths! + end + + private + + def paths! + VIM.capture(@history_command).split("\n")[2..-1].map do |line| + line.sub(/\A>?\s*\d+\s*(.+)/, '\1').strip + end.uniq + end + end + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/scanner/jump_scanner.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/scanner/jump_scanner.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/scanner/jump_scanner.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/scanner/jump_scanner.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,32 @@ +# Copyright 2011-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +module CommandT + class Scanner + # Returns a list of files in the jumplist. + class JumpScanner < Scanner + include PathUtilities + + def paths + jumps_with_filename = jumps.lines.select do |line| + line_contains_filename?(line) + end + filenames = jumps_with_filename[1..-2].map do |line| + relative_path_under_working_directory line.split[3] + end + + filenames.sort.uniq + end + + private + + def line_contains_filename?(line) + line.split.count > 3 + end + + def jumps + VIM::capture 'silent jumps' + end + end + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/scanner/line_scanner.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/scanner/line_scanner.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/scanner/line_scanner.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/scanner/line_scanner.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,45 @@ +# Copyright 2011-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +module CommandT + class Scanner + class LineScanner < Scanner + def paths + @lines ||= paths! + end + + private + + def paths! + # $curbuf is the Command-T match listing; we actually want the last + # buffer, but passing `$`, `#`, `%` etc to `bufnr()` returns the wrong + # value. + number = ::VIM.evaluate("g:CommandTCurrentBuffer").to_i + return [] unless number > 0 + buffer = nil + (0...(::VIM::Buffer.count)).each do |n| + buffer = ::VIM::Buffer[n] + if buffer_number(buffer) == number + break + else + buffer = nil + end + end + return [] unless buffer + + (1..(buffer.length)).map do |n| + line = buffer[n] + unless line.match(/\A\s*\z/) + line.sub(/\A\s*/, '') + ':' + n.to_s + end + end.compact + end + + def buffer_number(buffer) + buffer && buffer.number + rescue Vim::DeletedBufferError + # Beware of people manually deleting Command-T's hidden, unlisted buffer. + end + end + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/scanner/mru_buffer_scanner.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/scanner/mru_buffer_scanner.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/scanner/mru_buffer_scanner.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/scanner/mru_buffer_scanner.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,27 @@ +# Copyright 2014-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +module CommandT + class Scanner + # Returns a list of all open buffers, sorted in MRU order. + class MRUBufferScanner < BufferScanner + include PathUtilities + + def paths + # Collect all buffers that have not been used yet. + unused_buffers = (0..(::VIM::Buffer.count - 1)).map do |n| + buffer = ::VIM::Buffer[n] + buffer if buffer.name && !MRU.used?(buffer) + end + + # Combine all most recently used buffers and all unused buffers, and + # return all listed buffer paths. + (unused_buffers + MRU.stack).map do |buffer| + if buffer && buffer.name + relative_path_under_working_directory buffer.name + end + end.compact.reverse + end + end + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/scanner/tag_scanner.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/scanner/tag_scanner.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/scanner/tag_scanner.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/scanner/tag_scanner.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,33 @@ +# Copyright 2011-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +module CommandT + class Scanner + class TagScanner < Scanner + attr_reader :include_filenames + + def initialize(options = {}) + @include_filenames = options[:include_filenames] || false + @cached_tags = nil + end + + def paths + @cached_tags ||= taglist.map do |tag| + path = tag['name'] + path << ":#{tag['filename']}" if @include_filenames + path + end.uniq.sort + end + + def flush + @cached_tags = nil + end + + private + + def taglist + ::VIM::evaluate 'taglist(".")' + end + end + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/scanner.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/scanner.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/scanner.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/scanner.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,32 @@ +# Copyright 2010-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +module CommandT + class Scanner + autoload :BufferScanner, 'command-t/scanner/buffer_scanner' + autoload :CommandScanner, 'command-t/scanner/command_scanner' + autoload :FileScanner, 'command-t/scanner/file_scanner' + autoload :HelpScanner, 'command-t/scanner/help_scanner' + autoload :HistoryScanner, 'command-t/scanner/history_scanner' + autoload :JumpScanner, 'command-t/scanner/jump_scanner' + autoload :LineScanner, 'command-t/scanner/line_scanner' + autoload :MRUBufferScanner, 'command-t/scanner/mru_buffer_scanner' + autoload :TagScanner, 'command-t/scanner/tag_scanner' + + # Subclasses implement this method to return the list of paths that should + # be searched. + # + # Note that as an optimization, the C extension will record the + # `Object#object_id` of the returned array and assumes it will not be + # mutated. + def paths + raise RuntimeError, 'Subclass responsibility' + end + + private + + def progress_reporter + @progress_reporter ||= ProgressReporter.new + end + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/scm_utilities.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/scm_utilities.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/scm_utilities.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/scm_utilities.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,22 @@ +# Copyright 2014-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +module CommandT + module SCMUtilities + + private + + def nearest_ancestor(starting_directory, markers) + path = File.expand_path(starting_directory) + while !markers. + map { |dir| File.join(path, dir) }. + map { |dir| File.exist?(dir) }. + any? + next_path = File.expand_path(File.join(path, '..')) + return nil if next_path == path + path = next_path + end + path + end + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/settings.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/settings.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/settings.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/settings.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,99 @@ +# Copyright 2010-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +module CommandT + # Convenience class for saving and restoring global settings. + class Settings + # Settings which apply globally and so must be manually saved and restored + GLOBAL_SETTINGS = %w[ + equalalways + hlsearch + insertmode + report + showcmd + scrolloff + sidescroll + sidescrolloff + timeout + timeoutlen + updatetime + ] + + # Settings which can be made locally to the Command-T buffer or window + LOCAL_SETTINGS = %w[ + bufhidden + buflisted + buftype + colorcolumn + concealcursor + conceallevel + cursorline + filetype + foldcolumn + foldlevel + list + modifiable + number + readonly + relativenumber + spell + swapfile + synmaxcol + textwidth + wrap + ] + + KNOWN_SETTINGS = GLOBAL_SETTINGS + LOCAL_SETTINGS + + def initialize + @settings = [] + end + + def set(setting, value) + raise "Unknown setting #{setting}" unless KNOWN_SETTINGS.include?(setting) + + case value + when TrueClass, FalseClass + @settings.push([setting, VIM::get_bool("&#{setting}")]) if global?(setting) + set_bool setting, value + when Numeric + @settings.push([setting, VIM::get_number("&#{setting}")]) if global?(setting) + set_number setting, value + when String + @settings.push([setting, VIM::get_string("&#{setting}")]) if global?(setting) + set_string setting, value + end + end + + def restore + @settings.each do |setting, value| + case value + when TrueClass, FalseClass + set_bool setting, value + when Numeric + set_number setting, value + when String + set_string setting, value + end + end + end + + private + + def global?(setting) + GLOBAL_SETTINGS.include?(setting) + end + + def set_bool(setting, value) + command = global?(setting) ? 'set' : 'setlocal' + setting = value ? setting : "no#{setting}" + ::VIM::command "#{command} #{setting}" + end + + def set_number(setting, value) + command = global?(setting) ? 'set' : 'setlocal' + ::VIM::command "#{command} #{setting}=#{value}" + end + alias set_string set_number + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/stub.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/stub.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/stub.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/stub.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,40 @@ +# Copyright 2010-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +module CommandT + class Stub + expected = "#{Metadata::EXPECTED_RUBY_VERSION}-p#{Metadata::EXPECTED_RUBY_PATCHLEVEL}" + actual = "#{RUBY_VERSION}-p#{defined?(RUBY_PATCHLEVEL) ? RUBY_PATCHLEVEL : '[unknown]'}" + @@load_error = [ + 'command-t.vim could not load the C extension.', + 'Please see INSTALLATION and TROUBLE-SHOOTING in the help.', + "Vim Ruby version: #{actual}" + ] + @@load_error << "Expected version: #{expected}" if actual != expected + @@load_error << 'For more information type: :help command-t' + + [ + :flush, + :show_buffer_finder, + :show_command_finder, + :show_file_finder, + :show_history_finder, + :show_help_finder, + :show_jump_finder, + :show_line_finder, + :show_mru_finder, + :show_search_finder, + :show_tag_finder + ].each do |method| + define_method(method) { warn *@@load_error } + end + + private + + def warn(*msg) + ::VIM::command 'echohl WarningMsg' + msg.each { |m| ::VIM::command "echo '#{m}'" } + ::VIM::command 'echohl none' + end + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/util.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/util.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/util.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/util.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,94 @@ +# Copyright 2013-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +require 'rbconfig' + +module CommandT + module Util + class << self + def processor_count + @processor_count ||= begin + count = processor_count! + count = 1 if count < 1 # sanity check + count = 32 if count > 32 # sanity check + count + end + end + + private + + # This method derived from: + # + # https://github.com/grosser/parallel/blob/d11e4a3c8c1a/lib/parallel.rb + # + # Number of processors seen by the OS and used for process scheduling. + # + # * AIX: /usr/sbin/pmcycles (AIX 5+), /usr/sbin/lsdev + # * BSD: /sbin/sysctl + # * Cygwin: /proc/cpuinfo + # * Darwin: /usr/bin/hwprefs, /usr/sbin/sysctl + # * HP-UX: /usr/sbin/ioscan + # * IRIX: /usr/sbin/sysconf + # * Linux: /proc/cpuinfo + # * Minix 3+: /proc/cpuinfo + # * Solaris: /usr/sbin/psrinfo + # * Tru64 UNIX: /usr/sbin/psrinfo + # * UnixWare: /usr/sbin/psrinfo + # + # Copyright (C) 2013 Michael Grosser + # + # Permission is hereby granted, free of charge, to any person obtaining + # a copy of this software and associated documentation files (the + # "Software"), to deal in the Software without restriction, including + # without limitation the rights to use, copy, modify, merge, publish, + # distribute, sublicense, and/or sell copies of the Software, and to + # permit persons to whom the Software is furnished to do so, subject to + # the following conditions: + # + # The above copyright notice and this permission notice shall be + # included in all copies or substantial portions of the Software. + # + # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + # + def processor_count! + os_name = RbConfig::CONFIG['target_os'] + if os_name =~ /mingw|mswin/ + require 'win32ole' + result = WIN32OLE.connect('winmgmts://').ExecQuery( + 'select NumberOfLogicalProcessors from Win32_Processor') + result.to_enum.collect(&:NumberOfLogicalProcessors).reduce(:+) + elsif File.readable?('/proc/cpuinfo') + IO.read('/proc/cpuinfo').scan(/^processor/).size + elsif File.executable?('/usr/bin/hwprefs') + IO.popen(%w[/usr/bin/hwprefs thread_count]).read.to_i + elsif File.executable?('/usr/sbin/psrinfo') + IO.popen('/usr/sbin/psrinfo').read.scan(/^.*on-*line/).size + elsif File.executable?('/usr/sbin/ioscan') + IO.popen(%w[/usr/sbin/ioscan -kC processor]) do |out| + out.read.scan(/^.*processor/).size + end + elsif File.executable?('/usr/sbin/pmcycles') + IO.popen(%w[/usr/sbin/pmcycles -m]).read.count("\n") + elsif File.executable?('/usr/sbin/lsdev') + IO.popen(%w[/usr/sbin/lsdev -Cc processor -S 1]).read.count("\n") + elsif File.executable?('/usr/sbin/sysconf') && os_name =~ /irix/i + IO.popen(%w[/usr/sbin/sysconf NPROC_ONLN]).read.to_i + elsif File.executable?('/usr/sbin/sysctl') + IO.popen(%w[/usr/sbin/sysctl -n hw.ncpu]).read.to_i + elsif File.executable?('/sbin/sysctl') + IO.popen(%w[/sbin/sysctl -n hw.ncpu]).read.to_i + else # unknown platform + 1 + end + rescue + 1 + end + end + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/vim/screen.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/vim/screen.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/vim/screen.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/vim/screen.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,14 @@ +# Copyright 2010-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +module CommandT + module VIM + module Screen + class << self + def lines + ::VIM::evaluate('&lines').to_i + end + end + end + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/vim/window.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/vim/window.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/vim/window.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/vim/window.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,20 @@ +# Copyright 2010-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +module CommandT + module VIM + module Window + class << self + def select(window) + return true if $curwin == window + initial = $curwin + while true do + ::VIM::command 'wincmd w' # cycle through windows + return true if $curwin == window # have selected desired window + return false if $curwin == initial # have already looped through all + end + end + end + end + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t/vim.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/vim.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t/vim.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t/vim.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,96 @@ +# Copyright 2010-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +module CommandT + module VIM + autoload :Screen, 'command-t/vim/screen' + autoload :Window, 'command-t/vim/window' + + class << self + # Check for the existence of a feature such as "conceal" or "syntax". + def has?(feature) + ::VIM::evaluate(%{has("#{feature}")}).to_i != 0 + end + + # Check for the presence of a setting such as: + # + # - g:CommandTSmartCase (plug-in setting) + # - &wildignore (Vim setting) + # - +cursorcolumn (Vim setting, that works) + # + def exists?(str) + ::VIM::evaluate(%{exists("#{str}")}).to_i != 0 + end + + def get_number(name) + exists?(name) ? ::VIM::evaluate("#{name}").to_i : nil + end + + def get_bool(name, default = nil) + exists?(name) ? ::VIM::evaluate("#{name}").to_i != 0 : default + end + + def get_string(name) + exists?(name) ? ::VIM::evaluate("#{name}").to_s : nil + end + + # expect a string or a list of strings + def get_list_or_string(name) + return nil unless exists?(name) + list_or_string = ::VIM::evaluate("#{name}") + if list_or_string.kind_of?(Array) + list_or_string.map { |item| item.to_s } + else + list_or_string.to_s + end + end + + def pwd + ::VIM::evaluate 'getcwd()' + end + + def current_file_dir + ::VIM::evaluate 'expand("%:p:h")' + end + + # Execute cmd, capturing the output into a variable and returning it. + def capture(cmd) + ::VIM::command 'silent redir => g:command_t_captured_output' + ::VIM::command cmd + ::VIM::command 'silent redir END' + ::VIM::evaluate 'g:command_t_captured_output' + end + + # Escape a string for safe inclusion in a Vim single-quoted string + # (single quotes escaped by doubling, everything else is literal) + def escape_for_single_quotes(str) + str.gsub "'", "''" + end + + # Conservatively convert wildignore patterns that we understand to a + # regex. Supported patterns noted in the inline comments below. + # + # If this ends up doing something wrong, set `g:CommandTWildIgnore` to '' + # to opt out or otherwise override to produce a conforming pattern. + def wildignore_to_regexp(str) + patterns = str.split(',') + regex = patterns.map do |pattern| + if pattern.match(%r{\A([^*/]+)\z}) + # something (match file at any level) + '(\A|/)' + Regexp.escape($~[1]) + '\z' + elsif pattern.match(%r{\A\*\.([^*]+)\z}) + # *.something (match file with extension at any level) + '\.' + Regexp.escape($~[1]) + '\z' + elsif pattern.match(%r{\A\*/([^/]+)/\*\z}) + # */something/* (match directories at any level) + '(\A|/)' + Regexp.escape($~[1]) + '/.+' + elsif pattern.match(%r{\A\*/(.+)\z}) + # */something (match files or directories at any level) + '(\A|/)' + Regexp.escape($~[1]) + '(/|\z)' + end + end.compact.join('|') + Regexp.new(regex) unless regex.empty? + end + end + end +end diff -Nru vim-command-t-4.0/ruby/command-t/lib/command-t.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t.rb --- vim-command-t-4.0/ruby/command-t/lib/command-t.rb 1970-01-01 00:00:00.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/lib/command-t.rb 2017-11-17 03:46:11.000000000 +0000 @@ -0,0 +1,24 @@ +# Copyright 2014-present Greg Hurrell. All rights reserved. +# Licensed under the terms of the BSD 2-clause license. + +module CommandT + begin + require 'command-t/metadata' + rescue LoadError + require 'command-t/metadata/fallback' + end + + autoload :Controller, 'command-t/controller' + autoload :Finder, 'command-t/finder' + autoload :MRU, 'command-t/mru' + autoload :MatchWindow, 'command-t/match_window' + autoload :PathUtilities, 'command-t/path_utilities' + autoload :ProgressReporter, 'command-t/progress_reporter' + autoload :Prompt, 'command-t/prompt' + autoload :SCMUtilities, 'command-t/scm_utilities' + autoload :Scanner, 'command-t/scanner' + autoload :Settings, 'command-t/settings' + autoload :Stub, 'command-t/stub' + autoload :Util, 'command-t/util' + autoload :VIM, 'command-t/vim' +end diff -Nru vim-command-t-4.0/ruby/command-t/match.c vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/match.c --- vim-command-t-4.0/ruby/command-t/match.c 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/match.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,243 +0,0 @@ -// Copyright 2010-present Greg Hurrell. All rights reserved. -// Licensed under the terms of the BSD 2-clause license. - -#include /* for DBL_MAX */ -#include "match.h" -#include "ext.h" -#include "ruby_compat.h" - -#define UNSET_SCORE FLT_MAX - -// Use a struct to make passing params during recursion easier. -typedef struct { - char *haystack_p; // Pointer to the path string to be searched. - long haystack_len; // Length of same. - char *needle_p; // Pointer to search string (needle). - long needle_len; // Length of same. - long *rightmost_match_p; // Rightmost match for each char in needle. - float max_score_per_char; - int always_show_dot_files; // Boolean. - int never_show_dot_files; // Boolean. - int case_sensitive; // Boolean. - int recurse; // Boolean. - float *memo; // Memoization. -} matchinfo_t; - -float recursive_match( - matchinfo_t *m, // Sharable meta-data. - long haystack_idx, // Where in the path string to start. - long needle_idx, // Where in the needle string to start. - long last_idx, // Location of last matched character. - float score // Cumulative score so far. -) { - long distance, i, j; - float *memoized = NULL; - float score_for_char; - float seen_score = 0; - - // Iterate over needle. - for (i = needle_idx; i < m->needle_len; i++) { - // Iterate over (valid range of) haystack. - for (j = haystack_idx; j <= m->rightmost_match_p[i]; j++) { - char c, d; - - // Do we have a memoized result we can return? - memoized = &m->memo[j * m->needle_len + i]; - if (*memoized != UNSET_SCORE) { - return *memoized > seen_score ? *memoized : seen_score; - } - c = m->needle_p[i]; - d = m->haystack_p[j]; - if (d == '.') { - if (j == 0 || m->haystack_p[j - 1] == '/') { // This is a dot-file. - int dot_search = c == '.'; // Searching for a dot. - if ( - m->never_show_dot_files || - (!dot_search && !m->always_show_dot_files) - ) { - return *memoized = 0.0; - } - } - } else if (d >= 'A' && d <= 'Z' && !m->case_sensitive) { - d += 'a' - 'A'; // Add 32 to downcase. - } - - if (c == d) { - // Calculate score. - float sub_score = 0; - score_for_char = m->max_score_per_char; - distance = j - last_idx; - - if (distance > 1) { - float factor = 1.0; - char last = m->haystack_p[j - 1]; - char curr = m->haystack_p[j]; // Case matters, so get again. - if (last == '/') { - factor = 0.9; - } else if ( - last == '-' || - last == '_' || - last == ' ' || - (last >= '0' && last <= '9') - ) { - factor = 0.8; - } else if ( - last >= 'a' && last <= 'z' && - curr >= 'A' && curr <= 'Z' - ) { - factor = 0.8; - } else if (last == '.') { - factor = 0.7; - } else { - // If no "special" chars behind char, factor diminishes - // as distance from last matched char increases. - factor = (1.0 / distance) * 0.75; - } - score_for_char *= factor; - } - - if (j < m->rightmost_match_p[i] && m->recurse) { - sub_score = recursive_match(m, j + 1, i, last_idx, score); - if (sub_score > seen_score) { - seen_score = sub_score; - } - } - last_idx = j; - haystack_idx = last_idx + 1; - score += score_for_char; - *memoized = seen_score > score ? seen_score : score; - if (i == m->needle_len - 1) { - // Whole string matched. - return *memoized; - } - if (!m->recurse) { - break; - } - } - } - } - return *memoized = score; -} - -float calculate_match( - VALUE haystack, - VALUE needle, - VALUE case_sensitive, - VALUE always_show_dot_files, - VALUE never_show_dot_files, - VALUE recurse, - long needle_bitmask, - long *haystack_bitmask -) { - matchinfo_t m; - long i; - float score = 1.0; - int compute_bitmasks = *haystack_bitmask == UNSET_BITMASK; - m.haystack_p = RSTRING_PTR(haystack); - m.haystack_len = RSTRING_LEN(haystack); - m.needle_p = RSTRING_PTR(needle); - m.needle_len = RSTRING_LEN(needle); - m.rightmost_match_p = NULL; - m.max_score_per_char = (1.0 / m.haystack_len + 1.0 / m.needle_len) / 2; - m.always_show_dot_files = always_show_dot_files == Qtrue; - m.never_show_dot_files = never_show_dot_files == Qtrue; - m.case_sensitive = (int)case_sensitive; - m.recurse = recurse == Qtrue; - - // Special case for zero-length search string. - if (m.needle_len == 0) { - // Filter out dot files. - if (m.never_show_dot_files || !m.always_show_dot_files) { - for (i = 0; i < m.haystack_len; i++) { - char c = m.haystack_p[i]; - if (c == '.' && (i == 0 || m.haystack_p[i - 1] == '/')) { - return 0.0; - } - } - } - } else { - long haystack_limit; - long memo_size; - long needle_idx; - long mask; - long rightmost_match_p[m.needle_len]; - - if (*haystack_bitmask != UNSET_BITMASK) { - if ((needle_bitmask & *haystack_bitmask) != needle_bitmask) { - return 0.0; - } - } - - // Pre-scan string: - // - Bail if it can't match at all. - // - Record rightmost match for each character (prune search space). - // - Record bitmask for haystack to speed up future searches. - m.rightmost_match_p = rightmost_match_p; - needle_idx = m.needle_len - 1; - mask = 0; - for (i = m.haystack_len - 1; i >= 0; i--) { - char c = m.haystack_p[i]; - char lower = c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c; - if (!m.case_sensitive) { - c = lower; - } - if (compute_bitmasks) { - mask |= (1 << (lower - 'a')); - } - - if (needle_idx >= 0) { - char d = m.needle_p[needle_idx]; - if (c == d) { - rightmost_match_p[needle_idx] = i; - needle_idx--; - } - } - } - if (compute_bitmasks) { - *haystack_bitmask = mask; - } - if (needle_idx != -1) { - return 0.0; - } - - // Prepare for memoization. - haystack_limit = rightmost_match_p[m.needle_len - 1] + 1; - memo_size = m.needle_len * haystack_limit; - { - float memo[memo_size]; - for (i = 0; i < memo_size; i++) { - memo[i] = UNSET_SCORE; - } - m.memo = memo; - score = recursive_match(&m, 0, 0, 0, 0.0); - -#ifdef DEBUG - fprintf(stdout, " "); - for (i = 0; i < m.needle_len; i++) { - fprintf(stdout, " %c ", m.needle_p[i]); - } - fprintf(stdout, "\n"); - for (i = 0; i < memo_size; i++) { - char formatted[8]; - if (i % m.needle_len == 0) { - long haystack_idx = i / m.needle_len; - fprintf(stdout, "%c: ", m.haystack_p[haystack_idx]); - } - if (memo[i] == UNSET_SCORE) { - snprintf(formatted, sizeof(formatted), " - "); - } else { - snprintf(formatted, sizeof(formatted), " %-.4f", memo[i]); - } - fprintf(stdout, "%s", formatted); - if ((i + 1) % m.needle_len == 0) { - fprintf(stdout, "\n"); - } else { - fprintf(stdout, " "); - } - } - fprintf(stdout, "Final score: %f\n\n", score); -#endif - } - } - return score; -} diff -Nru vim-command-t-4.0/ruby/command-t/matcher.c vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/matcher.c --- vim-command-t-4.0/ruby/command-t/matcher.c 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/matcher.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,382 +0,0 @@ -// Copyright 2010-present Greg Hurrell. All rights reserved. -// Licensed under the terms of the BSD 2-clause license. - -#include /* for qsort() */ -#include /* for strncmp() */ -#include "match.h" -#include "matcher.h" -#include "heap.h" -#include "ext.h" -#include "ruby_compat.h" - -// order matters; we want this to be evaluated only after ruby.h -#ifdef HAVE_PTHREAD_H -#include /* for pthread_create, pthread_join etc */ -#endif - -// Comparison function for use with qsort. -int cmp_alpha(const void *a, const void *b) -{ - match_t a_match = *(match_t *)a; - match_t b_match = *(match_t *)b; - VALUE a_str = a_match.path; - VALUE b_str = b_match.path; - char *a_p = RSTRING_PTR(a_str); - long a_len = RSTRING_LEN(a_str); - char *b_p = RSTRING_PTR(b_str); - long b_len = RSTRING_LEN(b_str); - int order = 0; - - if (a_len > b_len) { - order = strncmp(a_p, b_p, b_len); - if (order == 0) - order = 1; // shorter string (b) wins. - } else if (a_len < b_len) { - order = strncmp(a_p, b_p, a_len); - if (order == 0) - order = -1; // shorter string (a) wins. - } else { - order = strncmp(a_p, b_p, a_len); - } - - return order; -} - -// Comparison function for use with qsort. -int cmp_score(const void *a, const void *b) -{ - match_t a_match = *(match_t *)a; - match_t b_match = *(match_t *)b; - - if (a_match.score > b_match.score) - return -1; // a scores higher, a should appear sooner. - else if (a_match.score < b_match.score) - return 1; // b scores higher, a should appear later. - else - return cmp_alpha(a, b); -} - -VALUE CommandTMatcher_initialize(int argc, VALUE *argv, VALUE self) -{ - VALUE always_show_dot_files; - VALUE never_show_dot_files; - VALUE options; - VALUE scanner; - - // Process arguments: 1 mandatory, 1 optional. - if (rb_scan_args(argc, argv, "11", &scanner, &options) == 1) - options = Qnil; - if (NIL_P(scanner)) - rb_raise(rb_eArgError, "nil scanner"); - - rb_iv_set(self, "@scanner", scanner); - - // Check optional options hash for overrides. - always_show_dot_files = CommandT_option_from_hash("always_show_dot_files", options); - never_show_dot_files = CommandT_option_from_hash("never_show_dot_files", options); - - rb_iv_set(self, "@always_show_dot_files", always_show_dot_files); - rb_iv_set(self, "@never_show_dot_files", never_show_dot_files); - - return Qnil; -} - -typedef struct { - long thread_count; - long thread_index; - long case_sensitive; - long limit; - match_t *matches; - long path_count; - VALUE haystacks; - VALUE needle; - VALUE always_show_dot_files; - VALUE never_show_dot_files; - VALUE recurse; - long needle_bitmask; -} thread_args_t; - -void *match_thread(void *thread_args) -{ - long i; - float score; - heap_t *heap = NULL; - thread_args_t *args = (thread_args_t *)thread_args; - - if (args->limit) { - // Reserve one extra slot so that we can do an insert-then-extract even - // when "full" (effectively allows use of min-heap to maintain a - // top-"limit" list of items). - heap = heap_new(args->limit + 1, cmp_score); - } - - for ( - i = args->thread_index; - i < args->path_count; - i += args->thread_count - ) { - args->matches[i].path = RARRAY_PTR(args->haystacks)[i]; - if (args->needle_bitmask == UNSET_BITMASK) { - args->matches[i].bitmask = UNSET_BITMASK; - } - args->matches[i].score = calculate_match( - args->matches[i].path, - args->needle, - args->case_sensitive, - args->always_show_dot_files, - args->never_show_dot_files, - args->recurse, - args->needle_bitmask, - &args->matches[i].bitmask - ); - if (heap) { - if (heap->count == args->limit) { - score = ((match_t *)HEAP_PEEK(heap))->score; - if (args->matches[i].score >= score) { - heap_insert(heap, &args->matches[i]); - (void)heap_extract(heap); - } - } else { - heap_insert(heap, &args->matches[i]); - } - } - } - - return heap; -} - -long calculate_bitmask(VALUE string) { - char *str = RSTRING_PTR(string); - long len = RSTRING_LEN(string); - long i; - long mask = 0; - for (i = 0; i < len; i++) { - if (str[i] >= 'a' && str[i] <= 'z') { - mask |= (1 << (str[i] - 'a')); - } else if (str[i] >= 'A' && str[i] <= 'Z') { - mask |= (1 << (str[i] - 'A')); - } - } - return mask; -} - -VALUE CommandTMatcher_sorted_matches_for(int argc, VALUE *argv, VALUE self) -{ - long i, j, limit, path_count, thread_count; -#ifdef HAVE_PTHREAD_H - long err; - pthread_t *threads; -#endif - long needle_bitmask = UNSET_BITMASK; - long heap_matches_count; - int use_heap; - int sort; - match_t *matches; - match_t *heap_matches = NULL; - heap_t *heap; - thread_args_t *thread_args; - VALUE always_show_dot_files; - VALUE case_sensitive; - VALUE recurse; - VALUE ignore_spaces; - VALUE limit_option; - VALUE needle; - VALUE never_show_dot_files; - VALUE new_paths_object_id; - VALUE options; - VALUE paths; - VALUE paths_object_id; - VALUE results; - VALUE scanner; - VALUE sort_option; - VALUE threads_option; - VALUE wrapped_matches; - - // Process arguments: 1 mandatory, 1 optional. - if (rb_scan_args(argc, argv, "11", &needle, &options) == 1) - options = Qnil; - if (NIL_P(needle)) - rb_raise(rb_eArgError, "nil needle"); - - // Check optional options hash for overrides. - case_sensitive = CommandT_option_from_hash("case_sensitive", options); - limit_option = CommandT_option_from_hash("limit", options); - threads_option = CommandT_option_from_hash("threads", options); - sort_option = CommandT_option_from_hash("sort", options); - ignore_spaces = CommandT_option_from_hash("ignore_spaces", options); - always_show_dot_files = rb_iv_get(self, "@always_show_dot_files"); - never_show_dot_files = rb_iv_get(self, "@never_show_dot_files"); - recurse = CommandT_option_from_hash("recurse", options); - - limit = NIL_P(limit_option) ? 15 : NUM2LONG(limit_option); - sort = NIL_P(sort_option) || sort_option == Qtrue; - use_heap = limit && sort; - heap_matches_count = 0; - - needle = StringValue(needle); - if (case_sensitive != Qtrue) - needle = rb_funcall(needle, rb_intern("downcase"), 0); - - if (ignore_spaces == Qtrue) - needle = rb_funcall(needle, rb_intern("delete"), 1, rb_str_new2(" ")); - - // Get unsorted matches. - scanner = rb_iv_get(self, "@scanner"); - paths = rb_funcall(scanner, rb_intern("paths"), 0); - path_count = RARRAY_LEN(paths); - - // Cached C data, not visible to Ruby layer. - paths_object_id = rb_ivar_get(self, rb_intern("paths_object_id")); - new_paths_object_id = rb_funcall(paths, rb_intern("object_id"), 0); - rb_ivar_set(self, rb_intern("paths_object_id"), new_paths_object_id); - if ( - NIL_P(paths_object_id) || - NUM2LONG(new_paths_object_id) != NUM2LONG(paths_object_id) - ) { - // `paths` changed, need to replace matches array. - paths_object_id = new_paths_object_id; - matches = malloc(path_count * sizeof(match_t)); - if (!matches) { - rb_raise(rb_eNoMemError, "memory allocation failed"); - } - wrapped_matches = Data_Wrap_Struct( - rb_cObject, - 0, - free, - matches - ); - rb_ivar_set(self, rb_intern("matches"), wrapped_matches); - } else { - // Get existing array. - Data_Get_Struct( - rb_ivar_get(self, rb_intern("matches")), - match_t, - matches - ); - - // Will compare against previously computed haystack bitmasks. - needle_bitmask = calculate_bitmask(needle); - } - - thread_count = NIL_P(threads_option) ? 1 : NUM2LONG(threads_option); - if (use_heap) { - heap_matches = malloc(thread_count * limit * sizeof(match_t)); - if (!heap_matches) { - rb_raise(rb_eNoMemError, "memory allocation failed"); - } - } - -#ifdef HAVE_PTHREAD_H -#define THREAD_THRESHOLD 1000 /* avoid the overhead of threading when search space is small */ - if (path_count < THREAD_THRESHOLD) { - thread_count = 1; - } - threads = malloc(sizeof(pthread_t) * thread_count); - if (!threads) - rb_raise(rb_eNoMemError, "memory allocation failed"); -#endif - - thread_args = malloc(sizeof(thread_args_t) * thread_count); - if (!thread_args) - rb_raise(rb_eNoMemError, "memory allocation failed"); - for (i = 0; i < thread_count; i++) { - thread_args[i].thread_count = thread_count; - thread_args[i].thread_index = i; - thread_args[i].case_sensitive = case_sensitive == Qtrue; - thread_args[i].matches = matches; - thread_args[i].limit = use_heap ? limit : 0; - thread_args[i].path_count = path_count; - thread_args[i].haystacks = paths; - thread_args[i].needle = needle; - thread_args[i].always_show_dot_files = always_show_dot_files; - thread_args[i].never_show_dot_files = never_show_dot_files; - thread_args[i].recurse = recurse; - thread_args[i].needle_bitmask = needle_bitmask; - -#ifdef HAVE_PTHREAD_H - if (i == thread_count - 1) { -#endif - // For the last "worker", we'll just use the main thread. - heap = match_thread(&thread_args[i]); - if (heap) { - for (j = 0; j < heap->count; j++) { - heap_matches[heap_matches_count++] = *(match_t *)heap->entries[j]; - } - heap_free(heap); - } -#ifdef HAVE_PTHREAD_H - } else { - err = pthread_create(&threads[i], NULL, match_thread, (void *)&thread_args[i]); - if (err != 0) { - rb_raise(rb_eSystemCallError, "pthread_create() failure (%d)", (int)err); - } - } -#endif - } - -#ifdef HAVE_PTHREAD_H - for (i = 0; i < thread_count - 1; i++) { - err = pthread_join(threads[i], (void **)&heap); - if (err != 0) { - rb_raise(rb_eSystemCallError, "pthread_join() failure (%d)", (int)err); - } - if (heap) { - for (j = 0; j < heap->count; j++) { - heap_matches[heap_matches_count++] = *(match_t *)heap->entries[j]; - } - heap_free(heap); - } - } - free(threads); -#endif - - if (sort) { - if ( - RSTRING_LEN(needle) == 0 || - (RSTRING_LEN(needle) == 1 && RSTRING_PTR(needle)[0] == '.') - ) { - // Alphabetic order if search string is only "" or "." - // TODO: make those semantics fully apply to heap case as well - // (they don't because the heap itself calls cmp_score, which means - // that the items which stay in the top [limit] may (will) be - // different). - qsort( - use_heap ? heap_matches : matches, - use_heap ? heap_matches_count : path_count, - sizeof(match_t), - cmp_alpha - ); - } else { - qsort( - use_heap ? heap_matches : matches, - use_heap ? heap_matches_count : path_count, - sizeof(match_t), - cmp_score - ); - } - } - - results = rb_ary_new(); - if (limit == 0) - limit = path_count; - for ( - i = 0; - i < (use_heap ? heap_matches_count : path_count) && limit > 0; - i++ - ) { - if ((use_heap ? heap_matches : matches)[i].score > 0.0) { - rb_funcall( - results, - rb_intern("push"), - 1, - (use_heap ? heap_matches : matches)[i].path - ); - limit--; - } - } - - if (use_heap) { - free(heap_matches); - } - return results; -} diff -Nru vim-command-t-4.0/ruby/command-t/matcher.h vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/matcher.h --- vim-command-t-4.0/ruby/command-t/matcher.h 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/matcher.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,7 +0,0 @@ -// Copyright 2010-present Greg Hurrell. All rights reserved. -// Licensed under the terms of the BSD 2-clause license. - -#include - -extern VALUE CommandTMatcher_initialize(int argc, VALUE *argv, VALUE self); -extern VALUE CommandTMatcher_sorted_matches_for(int argc, VALUE *argv, VALUE self); diff -Nru vim-command-t-4.0/ruby/command-t/match.h vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/match.h --- vim-command-t-4.0/ruby/command-t/match.h 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/match.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -// Copyright 2010-present Greg Hurrell. All rights reserved. -// Licensed under the terms of the BSD 2-clause license. - -#include - -#define UNSET_BITMASK (-1) - -// Struct for representing an individual match. -typedef struct { - VALUE path; - long bitmask; - float score; -} match_t; - -extern float calculate_match( - VALUE str, - VALUE needle, - VALUE case_sensitive, - VALUE always_show_dot_files, - VALUE never_show_dot_files, - VALUE recurse, - long needle_bitmask, - long *haystack_bitmask -); diff -Nru vim-command-t-4.0/ruby/command-t/match_window.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/match_window.rb --- vim-command-t-4.0/ruby/command-t/match_window.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/match_window.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,537 +0,0 @@ -# Copyright 2010-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -require 'ostruct' - -module CommandT - class MatchWindow - SELECTION_MARKER = '> ' - MARKER_LENGTH = SELECTION_MARKER.length - UNSELECTED_MARKER = ' ' * MARKER_LENGTH - MH_START = '' - MH_END = '' - @@buffer = nil - - Highlight = Struct.new(:highlight, :bang) - - def initialize(options = {}) - @encoding = options[:encoding] - @highlight_color = options[:highlight_color] || 'PmenuSel' - @min_height = options[:min_height] - @prompt = options[:prompt] - @reverse_list = options[:match_window_reverse] - - quoted_name = VIM::escape_for_single_quotes(options[:name]) - escaped_name = ::VIM::evaluate("fnameescape('#{quoted_name}')") - - run_will_show_autocmd - - set 'timeout', true # ensure mappings timeout - set 'hlsearch', false # don't highlight search strings - set 'insertmode', false # don't make Insert mode the default - set 'showcmd', false # don't show command info on last line - set 'equalalways', false # don't auto-balance window sizes - set 'timeoutlen', 0 # respond immediately to mappings - set 'report', 9999 # don't show "X lines changed" reports - set 'scrolloff', 0 # don't scroll near buffer edges - set 'sidescroll', 0 # don't sidescroll in jumps - set 'sidescrolloff', 0 # don't sidescroll automatically - - if options[:debounce_interval] > 0 - set 'updatetime', options[:debounce_interval] - end - - # Save existing window views so we can restore them later. - current_window = ::VIM::evaluate('winnr()') - @windows = (0..(::VIM::Window.count - 1)).map do |i| - focus_window(i + 1) - view = ::VIM::evaluate('winsaveview()') - window = OpenStruct.new( - :index => i, - :height => ::VIM::Window[i].height, - :width => ::VIM::Window[i].width, - :lnum => view['lnum'], - :col => view['col'], - :coladd => view['coladd'], - :curswant => view['curswant'], - :topline => view['topline'], - :topfill => view['topfill'], - :leftcol => view['leftcol'], - :skipcol => view['skipcol'] - ) - - # When creating a split for the match window, move the cursor to the - # opposite side of the window's viewport to prevent unwanted scrolling. - boundary_line = options[:match_window_at_top] ? - ::VIM::evaluate("line('w$')") : - view['topline'] - ::VIM::evaluate("winrestview({'lnum': #{boundary_line}})") - - window - end - focus_window(current_window) - - # show match window - split_location = options[:match_window_at_top] ? 'topleft' : 'botright' - if ((number = buffer_number)) # still have buffer from last time - ::VIM::command "silent! #{split_location} #{number}sbuffer" - if $curbuf.number != number - raise "Can't re-open Command-T match listing buffer" - end - $curwin.height = 1 - ::VIM::command "0file" - ::VIM::command "keepalt file #{escaped_name}" - else # creating match window for first time and set it up - ::VIM::command "silent! keepalt #{split_location} 1split #{escaped_name}" - set 'bufhidden', 'unload' # unload buf when no longer displayed - set 'buftype', 'nofile' # buffer is not related to any file - set 'filetype', 'command-t' # provide for detectability/extensibility - set 'modifiable', false # prevent manual edits - set 'readonly', false # avoid W10 "Changing a readonly file" - set 'swapfile', false # don't create a swapfile - set 'wrap', false # don't soft-wrap - set 'number', false # don't show line numbers - set 'list', false # don't use List mode (visible tabs etc) - set 'foldcolumn', 0 # don't show a fold column at side - set 'foldlevel', 99 # don't fold anything - set 'cursorline', false # don't highlight line cursor is on - set 'spell', false # spell-checking off - set 'buflisted', false # don't show up in the buffer list - set 'textwidth', 0 # don't hard-wrap (break long lines) - - # don't show the color column - set 'colorcolumn', 0 if VIM::exists?('+colorcolumn') - - # don't show relative line numbers - set 'relativenumber', false if VIM::exists?('+relativenumber') - - # sanity check: make sure the buffer really was created - if File.basename($curbuf.name) != options[:name] - raise "Can't find Command-T match listing buffer" - end - @@buffer = $curbuf - end - - # syntax coloring - if VIM::has?('syntax') - ::VIM::command "syntax match CommandTSelection \"^#{SELECTION_MARKER}.\\+$\"" - ::VIM::command 'syntax match CommandTNoEntries "^-- NO MATCHES --$"' - ::VIM::command 'syntax match CommandTNoEntries "^-- NO SUCH FILE OR DIRECTORY --$"' - set 'synmaxcol', 9999 - - if VIM::has?('conceal') - set 'conceallevel', 2 - set 'concealcursor', 'nvic' - ::VIM::command 'syntax region CommandTCharMatched ' \ - "matchgroup=CommandTCharMatched start=+#{MH_START}+ " \ - "matchgroup=CommandTCharMatchedEnd end=+#{MH_END}+ concealends" - ::VIM::command 'highlight def CommandTCharMatched ' \ - 'term=bold,underline cterm=bold,underline ' \ - 'gui=bold,underline' - end - - ::VIM::command "highlight link CommandTSelection #{@highlight_color}" - ::VIM::command 'highlight link CommandTNoEntries Error' - - # hide cursor - @cursor_highlight = get_cursor_highlight - hide_cursor - end - - # perform cleanup using an autocmd to ensure we don't get caught out - # by some unexpected means of dismissing or leaving the Command-T window - # (eg. , etc) - ::VIM::command 'augroup CommandTMatchWindow' - ::VIM::command 'autocmd!' - ::VIM::command 'autocmd BufLeave silent! ruby $command_t.leave' - ::VIM::command 'autocmd BufUnload silent! ruby $command_t.unload' - ::VIM::command 'augroup END' - - @has_focus = false - @abbrev = '' - @window = $curwin - end - - def buffer_number - @@buffer && @@buffer.number - rescue Vim::DeletedBufferError - # Beware of people manually deleting Command-T's hidden, unlisted buffer. - @@buffer = nil - end - - def close - # Unlisted buffers like those provided by Netrw, NERDTree and Vim's help - # don't actually appear in the buffer list; if they are the only such - # buffers present when Command-T is invoked (for example, when invoked - # immediately after starting Vim with a directory argument, like `vim .`) - # then performing the normal clean-up will yield an "E90: Cannot unload - # last buffer" error. We can work around that by doing a :quit first. - if ::VIM::Buffer.count == 0 - ::VIM::command 'silent quit' - end - - # Workaround for upstream bug in Vim 7.3 on some platforms - # - # On some platforms, $curbuf.number always returns 0. One workaround is - # to build Vim with --disable-largefile, but as this is producing lots of - # support requests, implement the following fallback to the buffer name - # instead, at least until upstream gets fixed. - # - # For more details, see: https://wincent.com/issues/1617 - if $curbuf.number == 0 - # use bwipeout as bunload fails if passed the name of a hidden buffer - base = File.basename($curbuf.name) - escaped_name = ::VIM::evaluate("fnameescape('#{base}')") - ::VIM::command "silent! bwipeout! #{escaped_name}" - @@buffer = nil - else - ::VIM::command "silent! bunload! #{@@buffer.number}" - end - end - - def leave - close - unload - end - - def unload - restore_window_views - @prompt.dispose - @settings.restore - show_cursor - run_did_hide_autocmd - end - - def add!(char) - @abbrev += char - end - - def backspace! - @abbrev.chop! - end - - def select_next - @reverse_list ? _prev : _next - end - - def select_prev - @reverse_list ? _next : _prev - end - - def matches=(matches) - if matches != @matches - @matches = matches - @selection = 0 - print_matches - move_cursor_to_selected_line - end - end - - def focus - unless @has_focus - @has_focus = true - if VIM::has?('syntax') - ::VIM::command 'highlight link CommandTSelection Search' - end - end - end - - def unfocus - if @has_focus - @has_focus = false - if VIM::has?('syntax') - ::VIM::command "highlight link CommandTSelection #{@highlight_color}" - end - end - end - - def find(char) - # is this a new search or the continuation of a previous one? - now = Time.now - if @last_key_time.nil? || @last_key_time < (now - 0.5) - @find_string = char - else - @find_string += char - end - @last_key_time = now - - # see if there's anything up ahead that matches - matches = @reverse_list ? @matches.reverse : @matches - matches.each_with_index do |match, idx| - if match[0, @find_string.length].casecmp(@find_string) == 0 - old_selection = @selection - @selection = @reverse_list ? matches.length - idx - 1 : idx - print_match(old_selection) # redraw old selection (removes marker) - print_match(@selection) # redraw new selection (adds marker) - break - end - end - end - - # Returns the currently selected item as a String. - def selection - @matches[@selection] - end - - def print_no_such_file_or_directory - print_error 'NO SUCH FILE OR DIRECTORY' - end - - private - - def focus_window(number) - ::VIM::command("noautocmd #{number}wincmd w") - end - - def _next - if @selection < [@window.height, @matches.length].min - 1 - @selection += 1 - print_match(@selection - 1) # redraw old selection (removes marker) - print_match(@selection) # redraw new selection (adds marker) - move_cursor_to_selected_line - end - end - - def _prev - if @selection > 0 - @selection -= 1 - print_match(@selection + 1) # redraw old selection (removes marker) - print_match(@selection) # redraw new selection (adds marker) - move_cursor_to_selected_line - end - end - - # Translate from a 0-indexed match index to a 1-indexed Vim line number. - # Also takes into account reversed listings. - def line(match_index) - @reverse_list ? @window.height - match_index : match_index + 1 - end - - def set(setting, value) - @settings ||= Settings.new - @settings.set(setting, value) - end - - def move_cursor_to_selected_line - # on some non-GUI terminals, the cursor doesn't hide properly - # so we move the cursor to prevent it from blinking away in the - # upper-left corner in a distracting fashion - @window.cursor = [line(@selection), 0] - end - - def print_error(msg) - return unless VIM::Window.select(@window) - unlock - clear - @window.height = [1, @min_height].min - @@buffer[1] = "-- #{msg} --" - lock - end - - def restore_window_views - # sort from tallest to shortest, tie-breaking on window width - @windows.sort! do |a, b| - order = b.height <=> a.height - if order.zero? - b.width <=> a.width - else - order - end - end - - # starting with the tallest ensures that there are no constraints - # preventing windows on the side of vertical splits from regaining - # their original full size - current_window = ::VIM::evaluate('winnr()') - @windows.each do |w| - # beware: window may be nil - if window = ::VIM::Window[w.index] - window.height = w.height - window.width = w.width - focus_window(w.index + 1) - ::VIM::evaluate("winrestview({" + - "'lnum': #{w.lnum}," + - "'col': #{w.col}, " + - "'coladd': #{w.coladd}, " + - "'curswant': #{w.curswant}, " + - "'topline': #{w.topline}, " + - "'topfill': #{w.topfill}, " + - "'leftcol': #{w.leftcol}, " + - "'skipcol': #{w.skipcol}" + - "})") - end - end - focus_window(current_window) - end - - def run_will_show_autocmd - run_autocmd('CommandTWillShowMatchListing') - end - - def run_did_hide_autocmd - run_autocmd('CommandTDidHideMatchListing') - end - - def run_autocmd(cmd) - ::VIM::command("call commandt#private#RunAutocmd('#{cmd}')") - end - - def match_text_for_idx(idx) - match = truncated_match @matches[idx].to_s - if idx == @selection - prefix = SELECTION_MARKER - suffix = padding_for_selected_match match - else - if VIM::has?('syntax') && VIM::has?('conceal') - match = match_with_syntax_highlight match - end - prefix = UNSELECTED_MARKER - suffix = '' - end - prefix + match + suffix - end - - # Highlight matching characters within the matched string. - # - # Note that this is only approximate; it will highlight the first matching - # instances within the string, which may not actually be the instances that - # were used by the matching/scoring algorithm to determine the best score - # for the match. - # - def match_with_syntax_highlight(match) - highlight_chars = @prompt.abbrev.downcase.scan(/./mu) - if @encoding && - match.respond_to?(:force_encoding) && - match.encoding != @encoding - match = match.force_encoding(@encoding) - end - match.scan(/./mu).inject([]) do |output, char| - if char.downcase == highlight_chars.first - highlight_chars.shift - output.concat [MH_START, char, MH_END] - else - output << char - end - end.join - end - - # Print just the specified match. - def print_match(idx) - return unless VIM::Window.select(@window) - unlock - @@buffer[line(idx)] = match_text_for_idx idx - lock - end - - def max_lines - [1, VIM::Screen.lines - 5].max - end - - # Print all matches. - def print_matches - match_count = @matches.length - if match_count == 0 - print_error 'NO MATCHES' - else - return unless VIM::Window.select(@window) - unlock - clear - @window_width = @window.width # update cached value - desired_lines = [match_count, @min_height].max - desired_lines = [max_lines, desired_lines].min - @window.height = desired_lines - matches = [] - (0...@window.height).each do |idx| - text = match_text_for_idx(idx) - @reverse_list ? matches.unshift(text) : matches.push(text) - end - matches.each_with_index do |match, idx| - if @@buffer.count > idx - @@buffer[idx + 1] = match - else - @@buffer.append(idx, match) - end - end - lock - end - end - - # Prepare padding for match text (trailing spaces) so that selection - # highlighting extends all the way to the right edge of the window. - def padding_for_selected_match(str) - len = str.length - if len >= @window_width - MARKER_LENGTH - '' - else - ' ' * (@window_width - MARKER_LENGTH - len) - end - end - - # Convert "really/long/path" into "really...path" based on available - # window width. - def truncated_match(str) - len = str.length - available_width = @window_width - MARKER_LENGTH - return str if len <= available_width - left = (available_width / 2) - 1 - right = (available_width / 2) - 2 + (available_width % 2) - str[0, left] + '...' + str[-right, right] - end - - def clear - # range = % (whole buffer) - # action = d (delete) - # register = _ (black hole register, don't record deleted text) - ::VIM::command 'silent %d _' - end - - def get_cursor_highlight - # there are 4 possible formats to check for, each needing to be - # transformed in a certain way in order to reapply the highlight: - # Cursor xxx guifg=bg guibg=fg -> :hi! Cursor guifg=bg guibg=fg - # Cursor xxx links to SomethingElse -> :hi! link Cursor SomethingElse - # Cursor xxx [definition] - # links to VisualNOS -> both of the above - # Cursor xxx cleared -> :hi! clear Cursor - highlight = VIM::capture 'silent! 0verbose highlight Cursor' - - if highlight =~ /^Cursor\s+xxx\s+(.+)\blinks to (\w+)/m - [ - Highlight.new("Cursor #{$~[1]}"), - Highlight.new("link Cursor #{$~[2]}", '!') - ] - elsif highlight =~ /^Cursor\s+xxx\s+links to (\w+)/m - [Highlight.new("link Cursor #{$~[1]}")] - elsif highlight =~ /^Cursor\s+xxx\s+cleared/m - [Highlight.new('clear Cursor')] - elsif highlight =~ /Cursor\s+xxx\s+(.+)/m - [Highlight.new("Cursor #{$~[1]}")] - else # likely cause E411 Cursor highlight group not found - [] - end - end - - def hide_cursor - if @cursor_highlight - ::VIM::command 'highlight Cursor NONE' - end - end - - def show_cursor - if @cursor_highlight - @cursor_highlight.each do |highlight| - config = highlight.highlight.gsub(/\s+/, ' ') - ::VIM::command "highlight#{highlight.bang} #{config}" - end - end - end - - def lock - set 'modifiable', false - end - - def unlock - set 'modifiable', true - end - end -end diff -Nru vim-command-t-4.0/ruby/command-t/metadata/fallback.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/metadata/fallback.rb --- vim-command-t-4.0/ruby/command-t/metadata/fallback.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/metadata/fallback.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -# Copyright 2015-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -module CommandT - module Metadata - # This file gets overwritten with actual data during the installation - # process (when `ruby extconf.rb` is run). - EXPECTED_RUBY_VERSION = '[unknown]' - EXPECTED_RUBY_PATCHLEVEL = '[unknown]' - UNKNOWN = true - end -end diff -Nru vim-command-t-4.0/ruby/command-t/mru.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/mru.rb --- vim-command-t-4.0/ruby/command-t/mru.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/mru.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ -# Copyright 2014-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -module CommandT - # Maintains a stack of seen buffers in MRU (most recently used) order. - module MRU - class << self - # The stack of used buffers in MRU order. - def stack - @stack ||= [] - end - - # The (last) most recent buffer in the stack, if any. - def last - stack.last - end - - # Mark the current buffer as having been used, effectively moving it to - # the top of the stack. - def touch - return unless ::VIM::evaluate('buflisted(%d)' % $curbuf.number) == 1 - return unless $curbuf.name - - stack.delete $curbuf - stack.push $curbuf - end - - # Mark a buffer as deleted, removing it from the stack. - def delete - # Note that $curbuf does not point to the buffer that is being deleted; - # we need to use Vim's for the correct buffer number. - stack.delete_if do |b| - b.number == ::VIM::evaluate('expand("")').to_i - end - end - - # Returns `true` if `buffer` has been used (ie. is present in the stack). - def used?(buffer) - stack.include?(buffer) - end - end - end -end diff -Nru vim-command-t-4.0/ruby/command-t/path_utilities.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/path_utilities.rb --- vim-command-t-4.0/ruby/command-t/path_utilities.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/path_utilities.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,17 +0,0 @@ -# Copyright 2010-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -module CommandT - module PathUtilities - - private - - def relative_path_under_working_directory(path) - # any path under the working directory will be specified as a relative - # path to improve the readability of the buffer list etc - pwd = File.expand_path(VIM::pwd) + '/' - path.index(pwd) == 0 ? path[pwd.length..-1] : path - end - - end -end diff -Nru vim-command-t-4.0/ruby/command-t/progress_reporter.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/progress_reporter.rb --- vim-command-t-4.0/ruby/command-t/progress_reporter.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/progress_reporter.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -# Copyright 2010-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -module CommandT - # Simple class for displaying scan progress to the user. - # - # The active scanner calls the `#update` method with a `count` to inform it of - # progress, the reporter updates the UI and then returns a suggested count at - # which to invoke `#update` again in the future (the suggested count is based - # on a heuristic that seeks to update the UI about 5 times per second). - class ProgressReporter - SPINNER = %w[^ > v <] - - def initialize - @spinner ||= SPINNER.first - end - - def update(count) - @spinner = SPINNER[(SPINNER.index(@spinner) + 1) % SPINNER.length] - - ::VIM::command "echon '#{@spinner} #{count}'" - ::VIM::command 'redraw' - - # Aim for 5 updates per second. - now = Time.now.to_f - if @last_time - time_diff = now - @last_time - count_diff = count - @last_count - next_count = count + ((0.2 / time_diff) * count_diff).to_i - else - next_count = count + 100 - end - @last_time = now - @last_count = count - next_count - end - end -end diff -Nru vim-command-t-4.0/ruby/command-t/prompt.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/prompt.rb --- vim-command-t-4.0/ruby/command-t/prompt.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/prompt.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,162 +0,0 @@ -# Copyright 2010-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -module CommandT - # Abuse the status line as a prompt. - class Prompt - attr_accessor :abbrev - - def initialize(options = {}) - @abbrev = '' # abbreviation entered so far - @col = 0 # cursor position - @cursor_color = options[:cursor_color] || 'Underlined' - @has_focus = false - end - - # Erase whatever is displayed in the prompt line, - # effectively disposing of the prompt - def dispose - ::VIM::command 'echo' - ::VIM::command 'redraw' - end - - # Clear any entered text. - def clear! - @abbrev = '' - @col = 0 - redraw - end - - # Remove word before cursor - def clear_prev_word! - suffix_length = @abbrev.length - @col - @abbrev.match( - %r{ - (.*?) # prefix - \w*\s* # word to clear - (.{#{suffix_length}}) # suffix - \z - }x - ) - @abbrev = $~[1] + $~[2] - @col = @abbrev.length - suffix_length - redraw - end - - # Insert a character at (before) the current cursor position. - def add!(char) - left, cursor, right = abbrev_segments - @abbrev = left + char + cursor + right - @col += 1 - redraw - end - - # Delete a character to the left of the current cursor position. - def backspace! - if @col > 0 - left, cursor, right = abbrev_segments - @abbrev = left.chop! + cursor + right - @col -= 1 - redraw - end - end - - # Delete a character at the current cursor position. - def delete! - if @col < @abbrev.length - left, cursor, right = abbrev_segments - @abbrev = left + right - redraw - end - end - - def cursor_left - if @col > 0 - @col -= 1 - redraw - end - end - - def cursor_right - if @col < @abbrev.length - @col += 1 - redraw - end - end - - def cursor_end - if @col < @abbrev.length - @col = @abbrev.length - redraw - end - end - - def cursor_start - if @col != 0 - @col = 0 - redraw - end - end - - def focus - unless @has_focus - @has_focus = true - redraw - end - end - - def unfocus - if @has_focus - @has_focus = false - redraw - end - end - - def redraw - if @has_focus - prompt_highlight = 'Comment' - normal_highlight = 'None' - cursor_highlight = @cursor_color - else - prompt_highlight = 'NonText' - normal_highlight = 'NonText' - cursor_highlight = 'NonText' - end - left, cursor, right = abbrev_segments - components = [prompt_highlight, '>>', 'None', ' '] - components += [normal_highlight, left] unless left.empty? - components += [cursor_highlight, cursor] unless cursor.empty? - components += [normal_highlight, right] unless right.empty? - components += [cursor_highlight, ' '] if cursor.empty? - set_status *components - end - - private - - # Returns the @abbrev string divided up into three sections, any of - # which may actually be zero width, depending on the location of the - # cursor: - # - left segment (to left of cursor) - # - cursor segment (character at cursor) - # - right segment (to right of cursor) - def abbrev_segments - left = @abbrev[0, @col] - cursor = @abbrev[@col, 1] - right = @abbrev[(@col + 1)..-1] || '' - [left, cursor, right] - end - - def set_status(*args) - # see ':help :echo' for why forcing a redraw here helps - # prevent the status line from getting inadvertantly cleared - # after our echo commands - ::VIM::command 'redraw' - while (highlight = args.shift) && (text = args.shift) - text = VIM::escape_for_single_quotes text - ::VIM::command "echohl #{highlight}" - ::VIM::command "echon '#{text}'" - end - ::VIM::command 'echohl None' - end - end -end diff -Nru vim-command-t-4.0/ruby/command-t/ruby_compat.h vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/ruby_compat.h --- vim-command-t-4.0/ruby/command-t/ruby_compat.h 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/ruby_compat.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -// Copyright 2010-present Greg Hurrell. All rights reserved. -// Licensed under the terms of the BSD 2-clause license. - -#include - -// for compatibility with older versions of Ruby which don't declare RSTRING_PTR -#ifndef RSTRING_PTR -#define RSTRING_PTR(s) (RSTRING(s)->ptr) -#endif - -// for compatibility with older versions of Ruby which don't declare RSTRING_LEN -#ifndef RSTRING_LEN -#define RSTRING_LEN(s) (RSTRING(s)->len) -#endif - -// for compatibility with older versions of Ruby which don't declare RARRAY_PTR -#ifndef RARRAY_PTR -#define RARRAY_PTR(a) (RARRAY(a)->ptr) -#endif - -// for compatibility with older versions of Ruby which don't declare RARRAY_LEN -#ifndef RARRAY_LEN -#define RARRAY_LEN(a) (RARRAY(a)->len) -#endif - -// for compatibility with older versions of Ruby which don't declare RFLOAT_VALUE -#ifndef RFLOAT_VALUE -#define RFLOAT_VALUE(f) (RFLOAT(f)->value) -#endif diff -Nru vim-command-t-4.0/ruby/command-t/scanner/buffer_scanner.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/scanner/buffer_scanner.rb --- vim-command-t-4.0/ruby/command-t/scanner/buffer_scanner.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/scanner/buffer_scanner.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ -# Copyright 2010-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -module CommandT - class Scanner - # Returns a list of all open buffers. - class BufferScanner < Scanner - include PathUtilities - - def paths - (0..(::VIM::Buffer.count - 1)).map do |n| - buffer = ::VIM::Buffer[n] - if buffer.name # beware, may be nil - relative_path_under_working_directory buffer.name - end - end.compact - end - end - end -end diff -Nru vim-command-t-4.0/ruby/command-t/scanner/command_scanner.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/scanner/command_scanner.rb --- vim-command-t-4.0/ruby/command-t/scanner/command_scanner.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/scanner/command_scanner.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -# Copyright 2011-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -module CommandT - class Scanner - class CommandScanner < Scanner - def paths - @paths ||= paths! - end - - private - - def paths! - # Get user commands. - commands = VIM.capture('silent command').split("\n")[2..-1].map do |line| - line.sub(/\A.{4}(\S+).+/, '\1') - end - - # Get built-in commands from `ex-cmd-index`. - ex_cmd_index = ::VIM.evaluate('expand(findfile("doc/index.txt", &runtimepath))') - if File.readable?(ex_cmd_index) - File.readlines(ex_cmd_index).each do |line| - if line =~ %r{\A\|:([^|]+)\|\s+} - commands << $~[1] - end - end - end - - commands.uniq - end - end - end -end diff -Nru vim-command-t-4.0/ruby/command-t/scanner/file_scanner/find_file_scanner.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/scanner/file_scanner/find_file_scanner.rb --- vim-command-t-4.0/ruby/command-t/scanner/file_scanner/find_file_scanner.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/scanner/file_scanner/find_file_scanner.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,55 +0,0 @@ -# Copyright 2014-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -require 'open3' - -module CommandT - class Scanner - class FileScanner - # A FileScanner which shells out to the `find` executable in order to scan. - class FindFileScanner < FileScanner - include PathUtilities - - def paths! - # temporarily set field separator to NUL byte; this setting is - # respected by both `each_line` and `chomp!` below, and makes it easier - # to parse the output of `find -print0` - separator = $/ - $/ = "\x00" - - unless @scan_dot_directories - dot_directory_filter = [ - '-not', '-path', "#{@path}/.*/*", # top-level dot dir - '-and', '-not', '-path', "#{@path}/*/.*/*" # lower-level dot dir - ] - end - - paths = [] - Open3.popen3(*([ - 'find', '-L', # follow symlinks - @path, # anchor search here - '-maxdepth', @max_depth.to_s, # limit depth of DFS - '-type', 'f', # only show regular files (not dirs etc) - dot_directory_filter, # possibly skip out dot directories - '-print0' # NUL-terminate results - ].flatten.compact)) do |stdin, stdout, stderr| - counter = 1 - next_progress = progress_reporter.update(counter) - stdout.each_line do |line| - next if path_excluded?(line.chomp!) - paths << line[@prefix_len..-1] - next_progress = progress_reporter.update(counter) if counter == next_progress - if (counter += 1) > @max_files - show_max_files_warning - break - end - end - end - paths - ensure - $/ = separator - end - end - end - end -end diff -Nru vim-command-t-4.0/ruby/command-t/scanner/file_scanner/git_file_scanner.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/scanner/file_scanner/git_file_scanner.rb --- vim-command-t-4.0/ruby/command-t/scanner/file_scanner/git_file_scanner.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/scanner/file_scanner/git_file_scanner.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -# Copyright 2014-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -module CommandT - class Scanner - class FileScanner - # Uses git ls-files to scan for files - class GitFileScanner < FindFileScanner - LsFilesError = Class.new(::RuntimeError) - - def paths! - Dir.chdir(@path) do - all_files = list_files(%w[git ls-files --exclude-standard -z]) - - if @scan_submodules - base = nil - list_files(%w[ - git submodule foreach --recursive - git ls-files --exclude-standard -z - ]).each do |path| - if path =~ /\AEntering '(.*)'\n(.*)\z/ - base = $~[1] - path = $~[2] - end - all_files.push(base + File::SEPARATOR + path) - end - end - - filtered = all_files. - map { |path| path.chomp }. - reject { |path| path_excluded?(path, 0) } - truncated = filtered.take(@max_files) - if truncated.count < filtered.count - show_max_files_warning - end - truncated.to_a - end - rescue LsFilesError - super - rescue Errno::ENOENT - # git executable not present and executable - super - end - - private - - def list_files(command) - stdin, stdout, stderr = Open3.popen3(*command) - stdout.read.split("\0") - ensure - raise LsFilesError if stderr && stderr.gets - end - - end - end - end -end diff -Nru vim-command-t-4.0/ruby/command-t/scanner/file_scanner/ruby_file_scanner.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/scanner/file_scanner/ruby_file_scanner.rb --- vim-command-t-4.0/ruby/command-t/scanner/file_scanner/ruby_file_scanner.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/scanner/file_scanner/ruby_file_scanner.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,60 +0,0 @@ -# Copyright 2010-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -module CommandT - class Scanner - class FileScanner - FileLimitExceeded = Class.new(::RuntimeError) - - # Pure Ruby implementation of a file scanner. - class RubyFileScanner < FileScanner - def paths! - accumulator = [] - @depth = 0 - @files = 0 - @next_progress = progress_reporter.update(@files) - add_paths_for_directory(@path, accumulator) - accumulator - rescue FileLimitExceeded - show_max_files_warning - accumulator - end - - private - - def looped_symlink?(path) - if File.symlink?(path) - target = File.expand_path(File.readlink(path), File.dirname(path)) - target.include?(@path) || @path.include?(target) - end - end - - def add_paths_for_directory(dir, accumulator) - Dir.foreach(dir) do |entry| - next if ['.', '..'].include?(entry) - path = File.join(dir, entry) - unless path_excluded?(path) - if File.file?(path) - @files += 1 - @next_progress = progress_reporter.update(@files) if @files == @next_progress - raise FileLimitExceeded if @files > @max_files - accumulator << path[@prefix_len..-1] - elsif File.directory?(path) - next if @depth >= @max_depth - next if (entry.match(/\A\./) && !@scan_dot_directories) - next if looped_symlink?(path) - @depth += 1 - add_paths_for_directory(path, accumulator) - @depth -= 1 - end - end - end - rescue Errno::EACCES - # skip over directories for which we don't have access - rescue ArgumentError - # skip over bad file names - end - end - end - end -end diff -Nru vim-command-t-4.0/ruby/command-t/scanner/file_scanner/watchman_file_scanner.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/scanner/file_scanner/watchman_file_scanner.rb --- vim-command-t-4.0/ruby/command-t/scanner/file_scanner/watchman_file_scanner.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/scanner/file_scanner/watchman_file_scanner.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,75 +0,0 @@ -# Copyright 2014-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -require 'pathname' -require 'socket' - -module CommandT - class Scanner - class FileScanner - # A FileScanner which delegates the heavy lifting to Watchman - # (https://github.com/facebook/watchman); useful for very large hierarchies. - # - # Inherits from FindFileScanner so that it can fall back to it in the event - # that Watchman isn't available or able to fulfil the request. - class WatchmanFileScanner < FindFileScanner - # Exception raised when Watchman is unavailable or unable to process the - # requested path. - WatchmanError = Class.new(::RuntimeError) - - def paths! - sockname = extract_value( - Watchman::Utils.load(get_raw_sockname), - 'sockname' - ) - - UNIXSocket.open(sockname) do |socket| - root = Pathname.new(@path).realpath.to_s - roots = Watchman::Utils.query(['watch-list'], socket)['roots'] - if !roots.include?(root) - # this path isn't being watched yet; try to set up watch - result = Watchman::Utils.query(['watch', root], socket) - - # root_restrict_files setting may prevent Watchman from working - # or enforce_root_files/root_files (>= version 3.1) - extract_value(result) - end - - query = ['query', root, { - 'expression' => ['type', 'f'], - 'fields' => ['name'], - }] - paths = Watchman::Utils.query(query, socket) - - # could return error if watch is removed - extracted = extract_value(paths, 'files') - if ( - apply_wild_ignore? && - (regex = VIM::wildignore_to_regexp(@wild_ignore || @base_wild_ignore)) - ) - extracted.select { |path| path !~ regex } - else - extracted - end - end - rescue Errno::ENOENT, WatchmanError - # watchman executable not present, or unable to fulfil request - super - end - - private - - def extract_value(object, key = nil) - raise WatchmanError, object['error'] if object.has_key?('error') - object[key] - end - - def get_raw_sockname - raw_sockname = %x{watchman --output-encoding=bser get-sockname} - raise WatchmanError, 'get-sockname failed' if !$?.exitstatus.zero? - raw_sockname - end - end - end - end -end diff -Nru vim-command-t-4.0/ruby/command-t/scanner/file_scanner.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/scanner/file_scanner.rb --- vim-command-t-4.0/ruby/command-t/scanner/file_scanner.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/scanner/file_scanner.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,115 +0,0 @@ -# Copyright 2010-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -module CommandT - class Scanner - # Reads the current directory recursively for the paths to all regular files. - # - # This is an abstract superclass; the real work is done by subclasses which - # obtain file listings via different strategies (for examples, see the - # RubyFileScanner and FindFileScanner subclasses). - class FileScanner < Scanner - # Subclasses - autoload :FindFileScanner, 'command-t/scanner/file_scanner/find_file_scanner' - autoload :GitFileScanner, 'command-t/scanner/file_scanner/git_file_scanner' - autoload :RubyFileScanner, 'command-t/scanner/file_scanner/ruby_file_scanner' - autoload :WatchmanFileScanner, 'command-t/scanner/file_scanner/watchman_file_scanner' - - attr_accessor :path - - def initialize(path = Dir.pwd, options = {}) - @paths = {} - @paths_keys = [] - @path = path - @max_depth = options[:max_depth] || 15 - @max_files = options[:max_files] || 100_000 - @max_caches = options[:max_caches] || 1 - @scan_dot_directories = options[:scan_dot_directories] || false - @wild_ignore = options[:wild_ignore] - @scan_submodules = options[:git_scan_submodules] || false - @base_wild_ignore = wild_ignore - end - - def paths - @paths[@path] ||= begin - ensure_cache_under_limit - @prefix_len = @path.chomp('/').length + 1 - set_wild_ignore { paths! } - end - end - - def flush - @paths = {} - end - - private - - def show_max_files_warning - unless VIM::get_bool('g:CommandTSuppressMaxFilesWarning', false) - ::VIM::command('redraw!') - ::VIM::command('echohl ErrorMsg') - warning = - "Warning: maximum file limit reached\n" + - "\n" + - "Increase it by setting a higher value in $MYVIMRC; eg:\n" + - " let g:CommandTMaxFiles=#{@max_files * 2}\n" + - "Or suppress this warning by setting:\n" + - " let g:CommandTSuppressMaxFilesWarning=1\n" + - "For best performance, consider using a fast scanner; see:\n" + - " :help g:CommandTFileScanner\n" + - "\n" + - "Press ENTER to continue." - ::VIM::evaluate(%{input("#{warning}")}) - ::VIM::command('echohl None') - end - end - - def wild_ignore - VIM::exists?('&wildignore') && ::VIM::evaluate('&wildignore').to_s - end - - def paths! - raise RuntimeError, 'Subclass responsibility' - end - - def ensure_cache_under_limit - # Ruby 1.8 doesn't have an ordered hash, so use a separate stack to - # track and expire the oldest entry in the cache - if @max_caches > 0 && @paths_keys.length >= @max_caches - @paths.delete @paths_keys.shift - end - @paths_keys << @path - end - - def path_excluded?(path, prefix_len = @prefix_len) - if apply_wild_ignore? - # first strip common prefix (@path) from path to match VIM's behavior - path = path[prefix_len..-1] - path = VIM::escape_for_single_quotes path - ::VIM::evaluate("empty(expand(fnameescape('#{path}')))").to_i == 1 - end - end - - def has_custom_wild_ignore? - !!@wild_ignore - end - - # Used to skip expensive calls to `expand()` when there is no applicable - # wildignore. - def apply_wild_ignore? - if has_custom_wild_ignore? - !@wild_ignore.empty? - else - !!@base_wild_ignore - end - end - - def set_wild_ignore(&block) - ::VIM::command("set wildignore=#{@wild_ignore}") if has_custom_wild_ignore? - yield - ensure - ::VIM::command("set wildignore=#{@base_wild_ignore}") if has_custom_wild_ignore? - end - end - end -end diff -Nru vim-command-t-4.0/ruby/command-t/scanner/help_scanner.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/scanner/help_scanner.rb --- vim-command-t-4.0/ruby/command-t/scanner/help_scanner.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/scanner/help_scanner.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -# Copyright 2011-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -module CommandT - class Scanner - class HelpScanner < Scanner - def paths - @cached_tags ||= paths! - end - - def flush - @cached_tags = nil - end - - private - - def paths! - # Vim doesn't provide an easy way to get a list of all help tags. - # `tagfiles()` only shows the tagfiles for the current buffer, so you - # need to already be in a buffer of `'buftype'` `help` for that to work. - # Likewise, `taglist()` only shows tags that apply to the current file - # type, and `:tag` has the same restriction. - # - # So, we look for a "doc/tags" file at every location in the - # `'runtimepath'` and try to manually parse it. - tags = [] - - ::VIM::evaluate('findfile("doc/tags", &runtimepath, -1)').each do |path| - if File.readable?(path) - File.readlines(path).each do |tag| - tags << tag.split.first if tag.split.first - end - end - end - - tags - end - end - end -end diff -Nru vim-command-t-4.0/ruby/command-t/scanner/history_scanner.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/scanner/history_scanner.rb --- vim-command-t-4.0/ruby/command-t/scanner/history_scanner.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/scanner/history_scanner.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -# Copyright 2011-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -module CommandT - class Scanner - class HistoryScanner < Scanner - def initialize(history_command) - @history_command = history_command - end - - def paths - @paths ||= paths! - end - - private - - def paths! - VIM.capture(@history_command).split("\n")[2..-1].map do |line| - line.sub(/\A>?\s*\d+\s*(.+)/, '\1').strip - end.uniq - end - end - end -end diff -Nru vim-command-t-4.0/ruby/command-t/scanner/jump_scanner.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/scanner/jump_scanner.rb --- vim-command-t-4.0/ruby/command-t/scanner/jump_scanner.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/scanner/jump_scanner.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -# Copyright 2011-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -module CommandT - class Scanner - # Returns a list of files in the jumplist. - class JumpScanner < Scanner - include PathUtilities - - def paths - jumps_with_filename = jumps.lines.select do |line| - line_contains_filename?(line) - end - filenames = jumps_with_filename[1..-2].map do |line| - relative_path_under_working_directory line.split[3] - end - - filenames.sort.uniq - end - - private - - def line_contains_filename?(line) - line.split.count > 3 - end - - def jumps - VIM::capture 'silent jumps' - end - end - end -end diff -Nru vim-command-t-4.0/ruby/command-t/scanner/line_scanner.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/scanner/line_scanner.rb --- vim-command-t-4.0/ruby/command-t/scanner/line_scanner.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/scanner/line_scanner.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -# Copyright 2011-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -module CommandT - class Scanner - class LineScanner < Scanner - def paths - @lines ||= paths! - end - - private - - def paths! - # $curbuf is the Command-T match listing; we actually want the last - # buffer, but passing `$`, `#`, `%` etc to `bufnr()` returns the wrong - # value. - number = ::VIM.evaluate("g:CommandTCurrentBuffer").to_i - return [] unless number > 0 - buffer = nil - (0...(::VIM::Buffer.count)).each do |n| - buffer = ::VIM::Buffer[n] - if buffer_number(buffer) == number - break - else - buffer = nil - end - end - return [] unless buffer - - (1..(buffer.length)).map do |n| - line = buffer[n] - unless line.match(/\A\s*\z/) - line.sub(/\A\s*/, '') + ':' + n.to_s - end - end.compact - end - - def buffer_number(buffer) - buffer && buffer.number - rescue Vim::DeletedBufferError - # Beware of people manually deleting Command-T's hidden, unlisted buffer. - end - end - end -end diff -Nru vim-command-t-4.0/ruby/command-t/scanner/mru_buffer_scanner.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/scanner/mru_buffer_scanner.rb --- vim-command-t-4.0/ruby/command-t/scanner/mru_buffer_scanner.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/scanner/mru_buffer_scanner.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -# Copyright 2014-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -module CommandT - class Scanner - # Returns a list of all open buffers, sorted in MRU order. - class MRUBufferScanner < BufferScanner - include PathUtilities - - def paths - # Collect all buffers that have not been used yet. - unused_buffers = (0..(::VIM::Buffer.count - 1)).map do |n| - buffer = ::VIM::Buffer[n] - buffer if buffer.name && !MRU.used?(buffer) - end - - # Combine all most recently used buffers and all unused buffers, and - # return all listed buffer paths. - (unused_buffers + MRU.stack).map do |buffer| - if buffer && buffer.name - relative_path_under_working_directory buffer.name - end - end.compact.reverse - end - end - end -end diff -Nru vim-command-t-4.0/ruby/command-t/scanner/tag_scanner.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/scanner/tag_scanner.rb --- vim-command-t-4.0/ruby/command-t/scanner/tag_scanner.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/scanner/tag_scanner.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -# Copyright 2011-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -module CommandT - class Scanner - class TagScanner < Scanner - attr_reader :include_filenames - - def initialize(options = {}) - @include_filenames = options[:include_filenames] || false - @cached_tags = nil - end - - def paths - @cached_tags ||= taglist.map do |tag| - path = tag['name'] - path << ":#{tag['filename']}" if @include_filenames - path - end.uniq.sort - end - - def flush - @cached_tags = nil - end - - private - - def taglist - ::VIM::evaluate 'taglist(".")' - end - end - end -end diff -Nru vim-command-t-4.0/ruby/command-t/scanner.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/scanner.rb --- vim-command-t-4.0/ruby/command-t/scanner.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/scanner.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -# Copyright 2010-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -module CommandT - class Scanner - autoload :BufferScanner, 'command-t/scanner/buffer_scanner' - autoload :CommandScanner, 'command-t/scanner/command_scanner' - autoload :FileScanner, 'command-t/scanner/file_scanner' - autoload :HelpScanner, 'command-t/scanner/help_scanner' - autoload :HistoryScanner, 'command-t/scanner/history_scanner' - autoload :JumpScanner, 'command-t/scanner/jump_scanner' - autoload :LineScanner, 'command-t/scanner/line_scanner' - autoload :MRUBufferScanner, 'command-t/scanner/mru_buffer_scanner' - autoload :TagScanner, 'command-t/scanner/tag_scanner' - - # Subclasses implement this method to return the list of paths that should - # be searched. - # - # Note that as an optimization, the C extension will record the - # `Object#object_id` of the returned array and assumes it will not be - # mutated. - def paths - raise RuntimeError, 'Subclass responsibility' - end - - private - - def progress_reporter - @progress_reporter ||= ProgressReporter.new - end - end -end diff -Nru vim-command-t-4.0/ruby/command-t/scm_utilities.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/scm_utilities.rb --- vim-command-t-4.0/ruby/command-t/scm_utilities.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/scm_utilities.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -# Copyright 2014-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -module CommandT - module SCMUtilities - - private - - def nearest_ancestor(starting_directory, markers) - path = File.expand_path(starting_directory) - while !markers. - map { |dir| File.join(path, dir) }. - map { |dir| File.exist?(dir) }. - any? - next_path = File.expand_path(File.join(path, '..')) - return nil if next_path == path - path = next_path - end - path - end - end -end diff -Nru vim-command-t-4.0/ruby/command-t/settings.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/settings.rb --- vim-command-t-4.0/ruby/command-t/settings.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/settings.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,99 +0,0 @@ -# Copyright 2010-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -module CommandT - # Convenience class for saving and restoring global settings. - class Settings - # Settings which apply globally and so must be manually saved and restored - GLOBAL_SETTINGS = %w[ - equalalways - hlsearch - insertmode - report - showcmd - scrolloff - sidescroll - sidescrolloff - timeout - timeoutlen - updatetime - ] - - # Settings which can be made locally to the Command-T buffer or window - LOCAL_SETTINGS = %w[ - bufhidden - buflisted - buftype - colorcolumn - concealcursor - conceallevel - cursorline - filetype - foldcolumn - foldlevel - list - modifiable - number - readonly - relativenumber - spell - swapfile - synmaxcol - textwidth - wrap - ] - - KNOWN_SETTINGS = GLOBAL_SETTINGS + LOCAL_SETTINGS - - def initialize - @settings = [] - end - - def set(setting, value) - raise "Unknown setting #{setting}" unless KNOWN_SETTINGS.include?(setting) - - case value - when TrueClass, FalseClass - @settings.push([setting, VIM::get_bool("&#{setting}")]) if global?(setting) - set_bool setting, value - when Numeric - @settings.push([setting, VIM::get_number("&#{setting}")]) if global?(setting) - set_number setting, value - when String - @settings.push([setting, VIM::get_string("&#{setting}")]) if global?(setting) - set_string setting, value - end - end - - def restore - @settings.each do |setting, value| - case value - when TrueClass, FalseClass - set_bool setting, value - when Numeric - set_number setting, value - when String - set_string setting, value - end - end - end - - private - - def global?(setting) - GLOBAL_SETTINGS.include?(setting) - end - - def set_bool(setting, value) - command = global?(setting) ? 'set' : 'setlocal' - setting = value ? setting : "no#{setting}" - ::VIM::command "#{command} #{setting}" - end - - def set_number(setting, value) - command = global?(setting) ? 'set' : 'setlocal' - ::VIM::command "#{command} #{setting}=#{value}" - end - alias set_string set_number - end -end diff -Nru vim-command-t-4.0/ruby/command-t/stub.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/stub.rb --- vim-command-t-4.0/ruby/command-t/stub.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/stub.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,39 +0,0 @@ -# Copyright 2010-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -module CommandT - class Stub - @@expected_version = Metadata::EXPECTED_RUBY_VERSION - @@expected_patchlevel = Metadata::EXPECTED_RUBY_PATCHLEVEL - @@patch_level = defined?(RUBY_PATCHLEVEL) ? RUBY_PATCHLEVEL : '[unknown]' - @@load_error = ['command-t.vim could not load the C extension', - 'Please see INSTALLATION and TROUBLE-SHOOTING in the help', - "Vim Ruby version: #{RUBY_VERSION}-p#{@@patch_level}", - "Expected version: #{@@expected_version}-p#{@@expected_patchlevel}", - 'For more information type: :help command-t'] - - [ - :flush, - :show_buffer_finder, - :show_command_finder, - :show_file_finder, - :show_history_finder, - :show_help_finder, - :show_jump_finder, - :show_line_finder, - :show_mru_finder, - :show_search_finder, - :show_tag_finder - ].each do |method| - define_method(method) { warn *@@load_error } - end - - private - - def warn(*msg) - ::VIM::command 'echohl WarningMsg' - msg.each { |m| ::VIM::command "echo '#{m}'" } - ::VIM::command 'echohl none' - end - end -end diff -Nru vim-command-t-4.0/ruby/command-t/util.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/util.rb --- vim-command-t-4.0/ruby/command-t/util.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/util.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,94 +0,0 @@ -# Copyright 2013-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -require 'rbconfig' - -module CommandT - module Util - class << self - def processor_count - @processor_count ||= begin - count = processor_count! - count = 1 if count < 1 # sanity check - count = 32 if count > 32 # sanity check - count - end - end - - private - - # This method derived from: - # - # https://github.com/grosser/parallel/blob/d11e4a3c8c1a/lib/parallel.rb - # - # Number of processors seen by the OS and used for process scheduling. - # - # * AIX: /usr/sbin/pmcycles (AIX 5+), /usr/sbin/lsdev - # * BSD: /sbin/sysctl - # * Cygwin: /proc/cpuinfo - # * Darwin: /usr/bin/hwprefs, /usr/sbin/sysctl - # * HP-UX: /usr/sbin/ioscan - # * IRIX: /usr/sbin/sysconf - # * Linux: /proc/cpuinfo - # * Minix 3+: /proc/cpuinfo - # * Solaris: /usr/sbin/psrinfo - # * Tru64 UNIX: /usr/sbin/psrinfo - # * UnixWare: /usr/sbin/psrinfo - # - # Copyright (C) 2013 Michael Grosser - # - # Permission is hereby granted, free of charge, to any person obtaining - # a copy of this software and associated documentation files (the - # "Software"), to deal in the Software without restriction, including - # without limitation the rights to use, copy, modify, merge, publish, - # distribute, sublicense, and/or sell copies of the Software, and to - # permit persons to whom the Software is furnished to do so, subject to - # the following conditions: - # - # The above copyright notice and this permission notice shall be - # included in all copies or substantial portions of the Software. - # - # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - # - def processor_count! - os_name = RbConfig::CONFIG['target_os'] - if os_name =~ /mingw|mswin/ - require 'win32ole' - result = WIN32OLE.connect('winmgmts://').ExecQuery( - 'select NumberOfLogicalProcessors from Win32_Processor') - result.to_enum.collect(&:NumberOfLogicalProcessors).reduce(:+) - elsif File.readable?('/proc/cpuinfo') - IO.read('/proc/cpuinfo').scan(/^processor/).size - elsif File.executable?('/usr/bin/hwprefs') - IO.popen(%w[/usr/bin/hwprefs thread_count]).read.to_i - elsif File.executable?('/usr/sbin/psrinfo') - IO.popen('/usr/sbin/psrinfo').read.scan(/^.*on-*line/).size - elsif File.executable?('/usr/sbin/ioscan') - IO.popen(%w[/usr/sbin/ioscan -kC processor]) do |out| - out.read.scan(/^.*processor/).size - end - elsif File.executable?('/usr/sbin/pmcycles') - IO.popen(%w[/usr/sbin/pmcycles -m]).read.count("\n") - elsif File.executable?('/usr/sbin/lsdev') - IO.popen(%w[/usr/sbin/lsdev -Cc processor -S 1]).read.count("\n") - elsif File.executable?('/usr/sbin/sysconf') && os_name =~ /irix/i - IO.popen(%w[/usr/sbin/sysconf NPROC_ONLN]).read.to_i - elsif File.executable?('/usr/sbin/sysctl') - IO.popen(%w[/usr/sbin/sysctl -n hw.ncpu]).read.to_i - elsif File.executable?('/sbin/sysctl') - IO.popen(%w[/sbin/sysctl -n hw.ncpu]).read.to_i - else # unknown platform - 1 - end - rescue - 1 - end - end - end -end diff -Nru vim-command-t-4.0/ruby/command-t/vim/screen.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/vim/screen.rb --- vim-command-t-4.0/ruby/command-t/vim/screen.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/vim/screen.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,14 +0,0 @@ -# Copyright 2010-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -module CommandT - module VIM - module Screen - class << self - def lines - ::VIM::evaluate('&lines').to_i - end - end - end - end -end diff -Nru vim-command-t-4.0/ruby/command-t/vim/window.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/vim/window.rb --- vim-command-t-4.0/ruby/command-t/vim/window.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/vim/window.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ -# Copyright 2010-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -module CommandT - module VIM - module Window - class << self - def select(window) - return true if $curwin == window - initial = $curwin - while true do - ::VIM::command 'wincmd w' # cycle through windows - return true if $curwin == window # have selected desired window - return false if $curwin == initial # have already looped through all - end - end - end - end - end -end diff -Nru vim-command-t-4.0/ruby/command-t/vim.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/vim.rb --- vim-command-t-4.0/ruby/command-t/vim.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/vim.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,96 +0,0 @@ -# Copyright 2010-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -module CommandT - module VIM - autoload :Screen, 'command-t/vim/screen' - autoload :Window, 'command-t/vim/window' - - class << self - # Check for the existence of a feature such as "conceal" or "syntax". - def has?(feature) - ::VIM::evaluate(%{has("#{feature}")}).to_i != 0 - end - - # Check for the presence of a setting such as: - # - # - g:CommandTSmartCase (plug-in setting) - # - &wildignore (Vim setting) - # - +cursorcolumn (Vim setting, that works) - # - def exists?(str) - ::VIM::evaluate(%{exists("#{str}")}).to_i != 0 - end - - def get_number(name) - exists?(name) ? ::VIM::evaluate("#{name}").to_i : nil - end - - def get_bool(name, default = nil) - exists?(name) ? ::VIM::evaluate("#{name}").to_i != 0 : default - end - - def get_string(name) - exists?(name) ? ::VIM::evaluate("#{name}").to_s : nil - end - - # expect a string or a list of strings - def get_list_or_string(name) - return nil unless exists?(name) - list_or_string = ::VIM::evaluate("#{name}") - if list_or_string.kind_of?(Array) - list_or_string.map { |item| item.to_s } - else - list_or_string.to_s - end - end - - def pwd - ::VIM::evaluate 'getcwd()' - end - - def current_file_dir - ::VIM::evaluate 'expand("%:p:h")' - end - - # Execute cmd, capturing the output into a variable and returning it. - def capture(cmd) - ::VIM::command 'silent redir => g:command_t_captured_output' - ::VIM::command cmd - ::VIM::command 'silent redir END' - ::VIM::evaluate 'g:command_t_captured_output' - end - - # Escape a string for safe inclusion in a Vim single-quoted string - # (single quotes escaped by doubling, everything else is literal) - def escape_for_single_quotes(str) - str.gsub "'", "''" - end - - # Conservatively convert wildignore patterns that we understand to a - # regex. Supported patterns noted in the inline comments below. - # - # If this ends up doing something wrong, set `g:CommandTWildIgnore` to '' - # to opt out or otherwise override to produce a conforming pattern. - def wildignore_to_regexp(str) - patterns = str.split(',') - regex = patterns.map do |pattern| - if pattern.match(%r{\A([^*/]+)\z}) - # something (match file at any level) - '(\A|/)' + Regexp.escape($~[1]) + '\z' - elsif pattern.match(%r{\A\*\.([^*]+)\z}) - # *.something (match file with extension at any level) - '\.' + Regexp.escape($~[1]) + '\z' - elsif pattern.match(%r{\A\*/(.+)\z}) - # */something (match files or directories at any level) - '(\A|/)' + Regexp.escape($~[1]) + '(/|\z)' - elsif pattern.match(%r{\A\*/([^*]+)/*\z}) - # */something/* (match directories at any level) - '(\A|/)' + Regexp.escape($~[1]) + '(/|\z)' - end - end.compact.join('|') - Regexp.new(regex) unless regex.empty? - end - end - end -end diff -Nru vim-command-t-4.0/ruby/command-t/watchman.c vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/watchman.c --- vim-command-t-4.0/ruby/command-t/watchman.c 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/watchman.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,660 +0,0 @@ -// Copyright 2014-present Greg Hurrell. All rights reserved. -// Licensed under the terms of the BSD 2-clause license. - -#include "watchman.h" - -#ifdef WATCHMAN_BUILD - -#if defined(HAVE_RUBY_ST_H) -#include -#elif defined(HAVE_ST_H) -#include -#else -#error no st.h header found -#endif - -#include /* for uint8_t */ -#include /* for fcntl() */ -#include /* for errno */ -#include /* for recv(), MSG_PEEK */ - -typedef struct { - uint8_t *data; // payload - size_t cap; // total capacity - size_t len; // current length -} watchman_t; - -// Forward declarations: -VALUE watchman_load(char **ptr, char *end); -void watchman_dump(watchman_t *w, VALUE serializable); - -#define WATCHMAN_DEFAULT_STORAGE 4096 - -#define WATCHMAN_BINARY_MARKER "\x00\x01" -#define WATCHMAN_ARRAY_MARKER 0x00 -#define WATCHMAN_HASH_MARKER 0x01 -#define WATCHMAN_STRING_MARKER 0x02 -#define WATCHMAN_INT8_MARKER 0x03 -#define WATCHMAN_INT16_MARKER 0x04 -#define WATCHMAN_INT32_MARKER 0x05 -#define WATCHMAN_INT64_MARKER 0x06 -#define WATCHMAN_FLOAT_MARKER 0x07 -#define WATCHMAN_TRUE 0x08 -#define WATCHMAN_FALSE 0x09 -#define WATCHMAN_NIL 0x0a -#define WATCHMAN_TEMPLATE_MARKER 0x0b -#define WATCHMAN_SKIP_MARKER 0x0c - -#define WATCHMAN_HEADER \ - WATCHMAN_BINARY_MARKER \ - "\x06" \ - "\x00\x00\x00\x00\x00\x00\x00\x00" - -static const char watchman_array_marker = WATCHMAN_ARRAY_MARKER; -static const char watchman_hash_marker = WATCHMAN_HASH_MARKER; -static const char watchman_string_marker = WATCHMAN_STRING_MARKER; -static const char watchman_true = WATCHMAN_TRUE; -static const char watchman_false = WATCHMAN_FALSE; -static const char watchman_nil = WATCHMAN_NIL; - -/** - * Appends `len` bytes, starting at `data`, to the watchman_t struct `w` - * - * Will attempt to reallocate the underlying storage if it is not sufficient. - */ -void watchman_append(watchman_t *w, const char *data, size_t len) { - if (w->len + len > w->cap) { - w->cap += w->len + WATCHMAN_DEFAULT_STORAGE; - REALLOC_N(w->data, uint8_t, w->cap); - } - memcpy(w->data + w->len, data, len); - w->len += len; -} - -/** - * Allocate a new watchman_t struct - * - * The struct has a small amount of extra capacity preallocated, and a blank - * header that can be filled in later to describe the PDU. - */ -watchman_t *watchman_init() { - watchman_t *w = ALLOC(watchman_t); - w->cap = WATCHMAN_DEFAULT_STORAGE; - w->len = 0; - w->data = ALLOC_N(uint8_t, WATCHMAN_DEFAULT_STORAGE); - - watchman_append(w, WATCHMAN_HEADER, sizeof(WATCHMAN_HEADER) - 1); - return w; -} - -/** - * Free a watchman_t struct `w` that was previously allocated with - * `watchman_init` - */ -void watchman_free(watchman_t *w) { - xfree(w->data); - xfree(w); -} - -/** - * Encodes and appends the integer `num` to `w` - */ -void watchman_dump_int(watchman_t *w, int64_t num) { - char encoded[1 + sizeof(int64_t)]; - - if (num == (int8_t)num) { - encoded[0] = WATCHMAN_INT8_MARKER; - encoded[1] = (int8_t)num; - watchman_append(w, encoded, 1 + sizeof(int8_t)); - } else if (num == (int16_t)num) { - encoded[0] = WATCHMAN_INT16_MARKER; - *(int16_t *)(encoded + 1) = (int16_t)num; - watchman_append(w, encoded, 1 + sizeof(int16_t)); - } else if (num == (int32_t)num) { - encoded[0] = WATCHMAN_INT32_MARKER; - *(int32_t *)(encoded + 1) = (int32_t)num; - watchman_append(w, encoded, 1 + sizeof(int32_t)); - } else { - encoded[0] = WATCHMAN_INT64_MARKER; - *(int64_t *)(encoded + 1) = (int64_t)num; - watchman_append(w, encoded, 1 + sizeof(int64_t)); - } -} - -/** - * Encodes and appends the string `string` to `w` - */ -void watchman_dump_string(watchman_t *w, VALUE string) { - watchman_append(w, &watchman_string_marker, sizeof(watchman_string_marker)); - watchman_dump_int(w, RSTRING_LEN(string)); - watchman_append(w, RSTRING_PTR(string), RSTRING_LEN(string)); -} - -/** - * Encodes and appends the double `num` to `w` - */ -void watchman_dump_double(watchman_t *w, double num) { - char encoded[1 + sizeof(double)]; - encoded[0] = WATCHMAN_FLOAT_MARKER; - *(double *)(encoded + 1) = num; - watchman_append(w, encoded, sizeof(encoded)); -} - -/** - * Encodes and appends the array `array` to `w` - */ -void watchman_dump_array(watchman_t *w, VALUE array) { - long i; - watchman_append(w, &watchman_array_marker, sizeof(watchman_array_marker)); - watchman_dump_int(w, RARRAY_LEN(array)); - for (i = 0; i < RARRAY_LEN(array); i++) { - watchman_dump(w, rb_ary_entry(array, i)); - } -} - -/** - * Helper method that encodes and appends a key/value pair (`key`, `value`) from - * a hash to the watchman_t struct passed in via `data` - */ -int watchman_dump_hash_iterator(VALUE key, VALUE value, VALUE data) { - watchman_t *w = (watchman_t *)data; - watchman_dump_string(w, StringValue(key)); - watchman_dump(w, value); - return ST_CONTINUE; -} - -/** - * Encodes and appends the hash `hash` to `w` - */ -void watchman_dump_hash(watchman_t *w, VALUE hash) { - watchman_append(w, &watchman_hash_marker, sizeof(watchman_hash_marker)); - watchman_dump_int(w, RHASH_SIZE(hash)); - rb_hash_foreach(hash, watchman_dump_hash_iterator, (VALUE)w); -} - -/** - * Encodes and appends the serialized Ruby object `serializable` to `w` - * - * Examples of serializable objects include arrays, hashes, strings, numbers - * (integers, floats), booleans, and nil. - */ -void watchman_dump(watchman_t *w, VALUE serializable) { - switch (TYPE(serializable)) { - case T_ARRAY: - return watchman_dump_array(w, serializable); - case T_HASH: - return watchman_dump_hash(w, serializable); - case T_STRING: - return watchman_dump_string(w, serializable); - case T_FIXNUM: // up to 63 bits - return watchman_dump_int(w, FIX2LONG(serializable)); - case T_BIGNUM: - return watchman_dump_int(w, NUM2LL(serializable)); - case T_FLOAT: - return watchman_dump_double(w, NUM2DBL(serializable)); - case T_TRUE: - return watchman_append(w, &watchman_true, sizeof(watchman_true)); - case T_FALSE: - return watchman_append(w, &watchman_false, sizeof(watchman_false)); - case T_NIL: - return watchman_append(w, &watchman_nil, sizeof(watchman_nil)); - default: - rb_raise(rb_eTypeError, "unsupported type"); - } -} - -/** - * Extract and return the int encoded at `ptr` - * - * Moves `ptr` past the extracted int. - * - * Will raise an ArgumentError if extracting the int would take us beyond the - * end of the buffer indicated by `end`, or if there is no int encoded at `ptr`. - * - * @returns The extracted int - */ -int64_t watchman_load_int(char **ptr, char *end) { - char *val_ptr = *ptr + sizeof(int8_t); - int64_t val = 0; - - if (val_ptr >= end) { - rb_raise(rb_eArgError, "insufficient int storage"); - } - - switch (*ptr[0]) { - case WATCHMAN_INT8_MARKER: - if (val_ptr + sizeof(int8_t) > end) { - rb_raise(rb_eArgError, "overrun extracting int8_t"); - } - val = *(int8_t *)val_ptr; - *ptr = val_ptr + sizeof(int8_t); - break; - case WATCHMAN_INT16_MARKER: - if (val_ptr + sizeof(int16_t) > end) { - rb_raise(rb_eArgError, "overrun extracting int16_t"); - } - val = *(int16_t *)val_ptr; - *ptr = val_ptr + sizeof(int16_t); - break; - case WATCHMAN_INT32_MARKER: - if (val_ptr + sizeof(int32_t) > end) { - rb_raise(rb_eArgError, "overrun extracting int32_t"); - } - val = *(int32_t *)val_ptr; - *ptr = val_ptr + sizeof(int32_t); - break; - case WATCHMAN_INT64_MARKER: - if (val_ptr + sizeof(int64_t) > end) { - rb_raise(rb_eArgError, "overrun extracting int64_t"); - } - val = *(int64_t *)val_ptr; - *ptr = val_ptr + sizeof(int64_t); - break; - default: - rb_raise(rb_eArgError, "bad integer marker 0x%02x", (unsigned int)*ptr[0]); - break; - } - - return val; -} - -/** - * Reads and returns a string encoded in the Watchman binary protocol format, - * starting at `ptr` and finishing at or before `end` - */ -VALUE watchman_load_string(char **ptr, char *end) { - int64_t len; - VALUE string; - if (*ptr >= end) { - rb_raise(rb_eArgError, "unexpected end of input"); - } - - if (*ptr[0] != WATCHMAN_STRING_MARKER) { - rb_raise(rb_eArgError, "not a number"); - } - - *ptr += sizeof(int8_t); - if (*ptr >= end) { - rb_raise(rb_eArgError, "invalid string header"); - } - - len = watchman_load_int(ptr, end); - if (len == 0) { // special case for zero-length strings - return rb_str_new2(""); - } else if (*ptr + len > end) { - rb_raise(rb_eArgError, "insufficient string storage"); - } - - string = rb_str_new(*ptr, len); - *ptr += len; - return string; -} - -/** - * Reads and returns a double encoded in the Watchman binary protocol format, - * starting at `ptr` and finishing at or before `end` - */ -double watchman_load_double(char **ptr, char *end) { - double val; - *ptr += sizeof(int8_t); // caller has already verified the marker - if (*ptr + sizeof(double) > end) { - rb_raise(rb_eArgError, "insufficient double storage"); - } - val = *(double *)*ptr; - *ptr += sizeof(double); - return val; -} - -/** - * Helper method which returns length of the array encoded in the Watchman - * binary protocol format, starting at `ptr` and finishing at or before `end` - */ -int64_t watchman_load_array_header(char **ptr, char *end) { - if (*ptr >= end) { - rb_raise(rb_eArgError, "unexpected end of input"); - } - - // verify and consume marker - if (*ptr[0] != WATCHMAN_ARRAY_MARKER) { - rb_raise(rb_eArgError, "not an array"); - } - *ptr += sizeof(int8_t); - - // expect a count - if (*ptr + sizeof(int8_t) * 2 > end) { - rb_raise(rb_eArgError, "incomplete array header"); - } - return watchman_load_int(ptr, end); -} - -/** - * Reads and returns an array encoded in the Watchman binary protocol format, - * starting at `ptr` and finishing at or before `end` - */ -VALUE watchman_load_array(char **ptr, char *end) { - int64_t count, i; - VALUE array; - - count = watchman_load_array_header(ptr, end); - array = rb_ary_new2(count); - - for (i = 0; i < count; i++) { - rb_ary_push(array, watchman_load(ptr, end)); - } - - return array; -} - -/** - * Reads and returns a hash encoded in the Watchman binary protocol format, - * starting at `ptr` and finishing at or before `end` - */ -VALUE watchman_load_hash(char **ptr, char *end) { - int64_t count, i; - VALUE hash, key, value; - - *ptr += sizeof(int8_t); // caller has already verified the marker - - // expect a count - if (*ptr + sizeof(int8_t) * 2 > end) { - rb_raise(rb_eArgError, "incomplete hash header"); - } - count = watchman_load_int(ptr, end); - - hash = rb_hash_new(); - - for (i = 0; i < count; i++) { - key = watchman_load_string(ptr, end); - value = watchman_load(ptr, end); - rb_hash_aset(hash, key, value); - } - - return hash; -} - -/** - * Reads and returns a templated array encoded in the Watchman binary protocol - * format, starting at `ptr` and finishing at or before `end` - * - * Templated arrays are arrays of hashes which have repetitive key information - * pulled out into a separate "headers" prefix. - * - * @see https://github.com/facebook/watchman/blob/master/website/_docs/BSER.markdown - */ -VALUE watchman_load_template(char **ptr, char *end) { - int64_t header_items_count, i, row_count; - VALUE array, hash, header, key, value; - - *ptr += sizeof(int8_t); // caller has already verified the marker - - // process template header array - header_items_count = watchman_load_array_header(ptr, end); - header = rb_ary_new2(header_items_count); - for (i = 0; i < header_items_count; i++) { - rb_ary_push(header, watchman_load_string(ptr, end)); - } - - // process row items - row_count = watchman_load_int(ptr, end); - array = rb_ary_new2(header_items_count); - while (row_count--) { - hash = rb_hash_new(); - for (i = 0; i < header_items_count; i++) { - if (*ptr >= end) { - rb_raise(rb_eArgError, "unexpected end of input"); - } - - if (*ptr[0] == WATCHMAN_SKIP_MARKER) { - *ptr += sizeof(uint8_t); - } else { - value = watchman_load(ptr, end); - key = rb_ary_entry(header, i); - rb_hash_aset(hash, key, value); - } - } - rb_ary_push(array, hash); - } - return array; -} - -/** - * Reads and returns an object encoded in the Watchman binary protocol format, - * starting at `ptr` and finishing at or before `end` - */ -VALUE watchman_load(char **ptr, char *end) { - if (*ptr >= end) { - rb_raise(rb_eArgError, "unexpected end of input"); - } - - switch (*ptr[0]) { - case WATCHMAN_ARRAY_MARKER: - return watchman_load_array(ptr, end); - case WATCHMAN_HASH_MARKER: - return watchman_load_hash(ptr, end); - case WATCHMAN_STRING_MARKER: - return watchman_load_string(ptr, end); - case WATCHMAN_INT8_MARKER: - case WATCHMAN_INT16_MARKER: - case WATCHMAN_INT32_MARKER: - case WATCHMAN_INT64_MARKER: - return LL2NUM(watchman_load_int(ptr, end)); - case WATCHMAN_FLOAT_MARKER: - return rb_float_new(watchman_load_double(ptr, end)); - case WATCHMAN_TRUE: - *ptr += 1; - return Qtrue; - case WATCHMAN_FALSE: - *ptr += 1; - return Qfalse; - case WATCHMAN_NIL: - *ptr += 1; - return Qnil; - case WATCHMAN_TEMPLATE_MARKER: - return watchman_load_template(ptr, end); - default: - rb_raise(rb_eTypeError, "unsupported type"); - } - - return Qnil; // keep the compiler happy -} - -/** - * CommandT::Watchman::Utils.load(serialized) - * - * Converts the binary object, `serialized`, from the Watchman binary protocol - * format into a normal Ruby object. - */ -VALUE CommandTWatchmanUtils_load(VALUE self, VALUE serialized) { - char *ptr, *end; - long len; - uint64_t payload_size; - VALUE loaded; - serialized = StringValue(serialized); - len = RSTRING_LEN(serialized); - ptr = RSTRING_PTR(serialized); - end = ptr + len; - - // expect at least the binary marker and a int8_t length counter - if ((size_t)len < sizeof(WATCHMAN_BINARY_MARKER) - 1 + sizeof(int8_t) * 2) { - rb_raise(rb_eArgError, "undersized header"); - } - - if (memcmp(ptr, WATCHMAN_BINARY_MARKER, sizeof(WATCHMAN_BINARY_MARKER) - 1)) { - rb_raise(rb_eArgError, "missing binary marker"); - } - - // get size marker - ptr += sizeof(WATCHMAN_BINARY_MARKER) - 1; - payload_size = watchman_load_int(&ptr, end); - if (!payload_size) { - rb_raise(rb_eArgError, "empty payload"); - } - - // sanity check length - if (ptr + payload_size != end) { - rb_raise( - rb_eArgError, - "payload size mismatch (%lu)", - (unsigned long)(end - (ptr + payload_size)) - ); - } - - loaded = watchman_load(&ptr, end); - - // one more sanity check - if (ptr != end) { - rb_raise( - rb_eArgError, - "payload termination mismatch (%lu)", - (unsigned long)(end - ptr) - ); - } - - return loaded; -} - -/** - * CommandT::Watchman::Utils.dump(serializable) - * - * Converts the Ruby object, `serializable`, into a binary string in the - * Watchman binary protocol format. - * - * Examples of serializable objects include arrays, hashes, strings, numbers - * (integers, floats), booleans, and nil. - */ -VALUE CommandTWatchmanUtils_dump(VALUE self, VALUE serializable) { - uint64_t *len; - VALUE serialized; - watchman_t *w = watchman_init(); - watchman_dump(w, serializable); - - // update header with final length information - len = (uint64_t *)(w->data + sizeof(WATCHMAN_HEADER) - sizeof(uint64_t) - 1); - *len = w->len - sizeof(WATCHMAN_HEADER) + 1; - - // prepare final return value - serialized = rb_str_buf_new(w->len); - rb_str_buf_cat(serialized, (const char*)w->data, w->len); - watchman_free(w); - return serialized; -} - -/** - * Helper method for raising a SystemCallError wrapping a lower-level error code - * coming from the `errno` global variable. - */ -void watchman_raise_system_call_error(int number) { - VALUE error = INT2FIX(number); - rb_exc_raise(rb_class_new_instance(1, &error, rb_eSystemCallError)); -} - -// How far we have to look to figure out the size of the PDU header -#define WATCHMAN_SNIFF_BUFFER_SIZE sizeof(WATCHMAN_BINARY_MARKER) - 1 + sizeof(int8_t) - -// How far we have to peek, at most, to figure out the size of the PDU itself -#define WATCHMAN_PEEK_BUFFER_SIZE \ - sizeof(WATCHMAN_BINARY_MARKER) - 1 + \ - sizeof(WATCHMAN_INT64_MARKER) + \ - sizeof(int64_t) - -/** - * CommandT::Watchman::Utils.query(query, socket) - * - * Converts `query`, a Watchman query comprising Ruby objects, into the Watchman - * binary protocol format, transmits it over socket, and unserializes and - * returns the result. - */ -VALUE CommandTWatchmanUtils_query(VALUE self, VALUE query, VALUE socket) { - char *payload; - int fileno, flags; - int8_t peek[WATCHMAN_PEEK_BUFFER_SIZE]; - int8_t sizes[] = { 0, 0, 0, 1, 2, 4, 8 }; - int8_t sizes_idx; - int8_t *pdu_size_ptr; - int64_t payload_size; - long query_len; - ssize_t peek_size, sent, received; - void *buffer; - VALUE loaded, serialized; - fileno = NUM2INT(rb_funcall(socket, rb_intern("fileno"), 0)); - - // do blocking I/O to simplify the following logic - flags = fcntl(fileno, F_GETFL); - if (fcntl(fileno, F_SETFL, flags & ~O_NONBLOCK) == -1) { - rb_raise(rb_eRuntimeError, "unable to clear O_NONBLOCK flag"); - } - - // send the message - serialized = CommandTWatchmanUtils_dump(self, query); - query_len = RSTRING_LEN(serialized); - sent = send(fileno, RSTRING_PTR(serialized), query_len, 0); - if (sent == -1) { - watchman_raise_system_call_error(errno); - } else if (sent != query_len) { - rb_raise(rb_eRuntimeError, "expected to send %ld bytes but sent %zd", - query_len, sent); - } - - // sniff to see how large the header is - received = recv(fileno, peek, WATCHMAN_SNIFF_BUFFER_SIZE, MSG_PEEK | MSG_WAITALL); - if (received == -1) { - watchman_raise_system_call_error(errno); - } else if (received != WATCHMAN_SNIFF_BUFFER_SIZE) { - rb_raise(rb_eRuntimeError, "failed to sniff PDU header"); - } - - // peek at size of PDU - sizes_idx = peek[sizeof(WATCHMAN_BINARY_MARKER) - 1]; - if (sizes_idx < WATCHMAN_INT8_MARKER || sizes_idx > WATCHMAN_INT64_MARKER) { - rb_raise(rb_eRuntimeError, "bad PDU size marker"); - } - peek_size = sizeof(WATCHMAN_BINARY_MARKER) - 1 + sizeof(int8_t) + - sizes[sizes_idx]; - - received = recv(fileno, peek, peek_size, MSG_PEEK); - if (received == -1) { - watchman_raise_system_call_error(errno); - } else if (received != peek_size) { - rb_raise(rb_eRuntimeError, "failed to peek at PDU header"); - } - pdu_size_ptr = peek + sizeof(WATCHMAN_BINARY_MARKER) - sizeof(int8_t); - payload_size = - peek_size + - watchman_load_int((char **)&pdu_size_ptr, (char *)peek + peek_size); - - // actually read the PDU - buffer = xmalloc(payload_size); - if (!buffer) { - rb_raise( - rb_eNoMemError, - "failed to allocate %lld bytes", - (long long int)payload_size - ); - } - received = recv(fileno, buffer, payload_size, MSG_WAITALL); - if (received == -1) { - watchman_raise_system_call_error(errno); - } else if (received != payload_size) { - rb_raise(rb_eRuntimeError, "failed to load PDU"); - } - payload = (char *)buffer + peek_size; - loaded = watchman_load(&payload, payload + payload_size); - free(buffer); - return loaded; -} - -#else /* don't build Watchman utils; supply stubs only*/ - -VALUE CommandTWatchmanUtils_load(VALUE self, VALUE serialized) { - rb_raise(rb_eRuntimeError, "unsupported operation"); -} - -VALUE CommandTWatchmanUtils_dump(VALUE self, VALUE serializable) { - rb_raise(rb_eRuntimeError, "unsupported operation"); -} - -VALUE CommandTWatchmanUtils_query(VALUE self, VALUE query, VALUE socket) { - rb_raise(rb_eRuntimeError, "unsupported operation"); -} - -#endif diff -Nru vim-command-t-4.0/ruby/command-t/watchman.h vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/watchman.h --- vim-command-t-4.0/ruby/command-t/watchman.h 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t/watchman.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -// Copyright 2014-present Greg Hurrell. All rights reserved. -// Licensed under the terms of the BSD 2-clause license. - -#include - -/** - * @module CommandT::Watchman::Utils - * - * Methods for working with the Watchman binary protocol - * - * @see https://github.com/facebook/watchman/blob/master/website/_docs/BSER.markdown - */ - -/** - * Convert an object serialized using the Watchman binary protocol[0] into an - * unpacked Ruby object - */ -extern VALUE CommandTWatchmanUtils_load(VALUE self, VALUE serialized); - -/** - * Serialize a Ruby object into the Watchman binary protocol format - */ -extern VALUE CommandTWatchmanUtils_dump(VALUE self, VALUE serializable); - -/** - * Issue `query` to the Watchman instance listening on `socket` (a `UNIXSocket` - * instance) and return the result - * - * The query is serialized following the Watchman binary protocol and the - * result is converted to native Ruby objects before returning to the caller. - */ -extern VALUE CommandTWatchmanUtils_query(VALUE self, VALUE query, VALUE socket); diff -Nru vim-command-t-4.0/ruby/command-t.rb vim-command-t-5.0.2-5-g7147ba9/ruby/command-t.rb --- vim-command-t-4.0/ruby/command-t.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/ruby/command-t.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -# Copyright 2014-present Greg Hurrell. All rights reserved. -# Licensed under the terms of the BSD 2-clause license. - -module CommandT - begin - require 'command-t/metadata' - rescue LoadError - require 'command-t/metadata/fallback' - end - - autoload :Controller, 'command-t/controller' - autoload :Finder, 'command-t/finder' - autoload :MRU, 'command-t/mru' - autoload :MatchWindow, 'command-t/match_window' - autoload :PathUtilities, 'command-t/path_utilities' - autoload :ProgressReporter, 'command-t/progress_reporter' - autoload :Prompt, 'command-t/prompt' - autoload :SCMUtilities, 'command-t/scm_utilities' - autoload :Scanner, 'command-t/scanner' - autoload :Settings, 'command-t/settings' - autoload :Stub, 'command-t/stub' - autoload :Util, 'command-t/util' - autoload :VIM, 'command-t/vim' -end diff -Nru vim-command-t-4.0/spec/command-t/controller_spec.rb vim-command-t-5.0.2-5-g7147ba9/spec/command-t/controller_spec.rb --- vim-command-t-4.0/spec/command-t/controller_spec.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/spec/command-t/controller_spec.rb 2017-11-17 03:46:11.000000000 +0000 @@ -24,21 +24,21 @@ stub(::VIM).evaluate('a:arg').returns('') set_string('g:CommandTTraverseSCM', 'pwd') controller.show_file_finder - mock(::VIM).command('silent e path/to/selection') + mock(::VIM).command('silent CommandTOpen edit path/to/selection') controller.accept_selection end it 'opens absolute paths outside the working directory' do stub(::VIM).evaluate('a:arg').returns('../outside') controller.show_file_finder - mock(::VIM).command('silent e /working/outside/path/to/selection') + mock(::VIM).command('silent CommandTOpen edit /working/outside/path/to/selection') controller.accept_selection end it 'does not get confused by common directory prefixes' do stub(::VIM).evaluate('a:arg').returns('../directory-oops') controller.show_file_finder - mock(::VIM).command('silent e /working/directory-oops/path/to/selection') + mock(::VIM).command('silent CommandTOpen edit /working/directory-oops/path/to/selection') controller.accept_selection end @@ -95,5 +95,7 @@ stub(::VIM).evaluate('&buflisted').returns('1') stub(::VIM).evaluate('&lines').returns('80') stub(::VIM).evaluate('&term').returns('vt100') + stub(::VIM).evaluate('v:version').returns(704) + stub(::VIM).evaluate('!&buflisted && &buftype == "nofile"') end end diff -Nru vim-command-t-4.0/spec/command-t/finder/buffer_finder_spec.rb vim-command-t-5.0.2-5-g7147ba9/spec/command-t/finder/buffer_finder_spec.rb --- vim-command-t-4.0/spec/command-t/finder/buffer_finder_spec.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/spec/command-t/finder/buffer_finder_spec.rb 2017-11-17 03:46:11.000000000 +0000 @@ -37,9 +37,8 @@ expect(@finder.sorted_matches_for('i')).to include('.vim/notes') end - it "does not use the Vim expand() function to consult the 'wildignore' setting" do - do_not_allow(::VIM).evaluate - @finder.sorted_matches_for('i') + it "does not consult the 'wildignore' setting" do + expect(@finder.sorted_matches_for('').count).to eq(5) end it 'obeys the :limit option for empty search strings' do diff -Nru vim-command-t-4.0/spec/command-t/scanner/file_scanner/ruby_file_scanner_spec.rb vim-command-t-5.0.2-5-g7147ba9/spec/command-t/scanner/file_scanner/ruby_file_scanner_spec.rb --- vim-command-t-4.0/spec/command-t/scanner/file_scanner/ruby_file_scanner_spec.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/spec/command-t/scanner/file_scanner/ruby_file_scanner_spec.rb 2017-11-17 03:46:11.000000000 +0000 @@ -13,7 +13,6 @@ stub(::VIM).evaluate(/exists/) { 1 } stub(::VIM).evaluate(/expand\(.+\)/) { '0' } - stub(::VIM).evaluate(/wildignore/) { '' } stub(::VIM).command(/echon/) stub(::VIM).command('redraw') end @@ -40,20 +39,18 @@ describe "'wildignore' exclusion" do context "when there is a 'wildignore' setting in effect" do - it "calls on VIM's expand() function for pattern filtering" do - stub(::VIM).command(/set wildignore/) + it "filters out matching files" do scanner = - CommandT::Scanner::FileScanner::RubyFileScanner.new @dir, :wild_ignore => '*.o' - mock(::VIM).evaluate(/expand\(.+\)/).times(10) - scanner.paths + CommandT::Scanner::FileScanner::RubyFileScanner.new @dir, + :wildignore => CommandT::VIM::wildignore_to_regexp('xyz') + expect(scanner.paths.count).to eq(@all_fixtures.count - 1) end end context "when there is no 'wildignore' setting in effect" do - it "does not call VIM's expand() function" do + it "does nothing" do scanner = CommandT::Scanner::FileScanner::RubyFileScanner.new @dir - mock(::VIM).evaluate(/expand\(.+\)/).never - scanner.paths + expect(scanner.paths.count).to eq(@all_fixtures.count) end end end diff -Nru vim-command-t-4.0/spec/command-t/vim_spec.rb vim-command-t-5.0.2-5-g7147ba9/spec/command-t/vim_spec.rb --- vim-command-t-4.0/spec/command-t/vim_spec.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/spec/command-t/vim_spec.rb 2017-11-17 03:46:11.000000000 +0000 @@ -11,4 +11,70 @@ expect(CommandT::VIM.escape_for_single_quotes(input)).to eq(expected) end end + + describe '.wildignore_to_regexp' do + subject do + Regexp.new(CommandT::VIM.wildignore_to_regexp(wildignore)) + end + + describe '"foo"' do + let(:wildignore) { 'foo' } + + it 'matches the right strings' do + expect(subject).to_not match('a.foo') + expect(subject).to_not match('a/b.foo') + expect(subject).to match('foo') + expect(subject).to match('a/foo') + expect(subject).to_not match('a/foo/b') + end + end + + describe '".foo"' do + let(:wildignore) { '*.foo' } + + it 'matches the right strings' do + expect(subject).to match('a.foo') + expect(subject).to match('a/b.foo') + expect(subject).to_not match('foo') + expect(subject).to_not match('a/foo') + expect(subject).to_not match('a/foo/b') + end + end + + describe '"*/foo/*"' do + let(:wildignore) { '*/foo' } + + it 'matches the right strings' do + expect(subject).to_not match('a.foo') + expect(subject).to_not match('a/b.foo') + expect(subject).to match('foo') + expect(subject).to match('a/foo') + expect(subject).to match('a/foo/b') + end + end + + describe '"*/foo/*"' do + let(:wildignore) { '*/foo/*' } + + it 'matches the right strings' do + expect(subject).to_not match('a.foo') + expect(subject).to_not match('a/b.foo') + expect(subject).to_not match('foo') + expect(subject).to_not match('a/foo') + expect(subject).to match('a/foo/b') + end + end + + describe 'multiple patterns' do + let(:wildignore) { '*.foo,*/foo/*' } + + it 'matches the right strings' do + expect(subject).to match('a.foo') + expect(subject).to match('a/b.foo') + expect(subject).to_not match('foo') + expect(subject).to_not match('a/foo') + expect(subject).to match('a/foo/b') + end + end + end end diff -Nru vim-command-t-4.0/spec/spec_helper.rb vim-command-t-5.0.2-5-g7147ba9/spec/spec_helper.rb --- vim-command-t-4.0/spec/spec_helper.rb 2016-05-17 05:31:31.000000000 +0000 +++ vim-command-t-5.0.2-5-g7147ba9/spec/spec_helper.rb 2017-11-17 03:46:11.000000000 +0000 @@ -8,10 +8,10 @@ end require 'rspec' -lib = File.expand_path('../ruby', File.dirname(__FILE__)) -unless $LOAD_PATH.include? lib - $LOAD_PATH.unshift lib -end +ext = File.expand_path('../ruby/command-t/lib', File.dirname(__FILE__)) +lib = File.expand_path('../ruby/command-t/ext', File.dirname(__FILE__)) +$LOAD_PATH.unshift(ext) unless $LOAD_PATH.include?(ext) +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'command-t' require 'command-t/ext'