mirror of https://github.com/captn3m0/dotfiles.git
Updates directory structure to use stow
This commit is contained in:
parent
ed44835252
commit
16374bc2ea
|
@ -1 +0,0 @@
|
|||
Subproject commit e9267044261481fbb6717b482c2f3811eb61b409
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 98cec44ef6e8c93f89fb7911a03d7eaa75fe1249
|
|
@ -1 +0,0 @@
|
|||
Subproject commit ac395b57fec47f034cba151d01669d134ac7041b
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 64716b9622e5c3fae0caec7e9589988a9da146cb
|
|
@ -1 +0,0 @@
|
|||
Subproject commit ca8b897f67e8e15cf39a308ca012c5a53929d10d
|
|
@ -0,0 +1,3 @@
|
|||
.release-notes.txt
|
||||
command-t.recipe
|
||||
/.bundle
|
|
@ -0,0 +1,6 @@
|
|||
[submodule "vendor/vimball"]
|
||||
path = vendor/vimball
|
||||
url = git://github.com/tomtom/vimball.rb.git
|
||||
[submodule "vendor/vimscriptuploader"]
|
||||
path = vendor/vimscriptuploader
|
||||
url = git://github.com/tomtom/vimscriptuploader.rb.git
|
|
@ -0,0 +1,5 @@
|
|||
Nicolas Alpi <nicolas.alpi@gmail.com> Spyou <nicolas.alpi@gmail.com>
|
||||
Noon Silk <noonsilk@gmail.com> Noon Silk <noonsilk@gmail.com>
|
||||
Noon Silk <noonsilk@gmail.com> Noon Silk <superhappyfun@gmail.com>
|
||||
Sung Pae <sung@metablu.com> guns <sung@metablu.com>
|
||||
Sung Pae <sung@metablu.com> guns <self@sungpae.com>
|
|
@ -0,0 +1 @@
|
|||
--colour
|
|
@ -0,0 +1,2 @@
|
|||
--- {}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
source :rubygems
|
||||
gem 'mechanize'
|
||||
gem 'rake'
|
||||
gem 'rr'
|
||||
gem 'rspec', '>= 2.0.0.rc'
|
|
@ -0,0 +1,26 @@
|
|||
GEM
|
||||
remote: http://rubygems.org/
|
||||
specs:
|
||||
diff-lcs (1.1.2)
|
||||
mechanize (1.0.0)
|
||||
nokogiri (>= 1.2.1)
|
||||
nokogiri (1.4.4)
|
||||
rake (0.8.7)
|
||||
rr (1.0.2)
|
||||
rspec (2.5.0)
|
||||
rspec-core (~> 2.5.0)
|
||||
rspec-expectations (~> 2.5.0)
|
||||
rspec-mocks (~> 2.5.0)
|
||||
rspec-core (2.5.1)
|
||||
rspec-expectations (2.5.0)
|
||||
diff-lcs (~> 1.1.2)
|
||||
rspec-mocks (2.5.0)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
mechanize
|
||||
rake
|
||||
rr
|
||||
rspec (>= 2.0.0.rc)
|
|
@ -0,0 +1,22 @@
|
|||
Copyright 2010-2012 Wincent Colaiuta. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,21 @@
|
|||
rubyfiles := $(shell find ruby -name '*.rb')
|
||||
cfiles := $(shell find ruby -name '*.c')
|
||||
cheaders := $(shell find ruby -name '*.h')
|
||||
depends := $(shell find ruby -name depend)
|
||||
txtfiles := $(shell find doc -name '*.txt')
|
||||
vimfiles := $(shell find plugin -name '*.vim')
|
||||
|
||||
vimball: command-t.vba
|
||||
|
||||
command-t.recipe: $(rubyfiles) $(cfiles) $(cheaders) $(depends) $(txtfiles) $(vimfiles)
|
||||
echo "$^" | perl -pe 's/ /\n/g' > $@
|
||||
command-t.vba: command-t.recipe
|
||||
vendor/vimball/vimball.rb -d . -b . vba $^
|
||||
|
||||
.PHONY: spec
|
||||
spec:
|
||||
rspec spec
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f command-t.vba
|
|
@ -0,0 +1 @@
|
|||
doc/command-t.txt
|
|
@ -0,0 +1,217 @@
|
|||
require 'yaml'
|
||||
|
||||
def bail_on_failure
|
||||
exitstatus = $?.exitstatus
|
||||
if exitstatus != 0
|
||||
err "last command failed with exit status #{exitstatus}"
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
|
||||
def version
|
||||
`git describe`.chomp
|
||||
end
|
||||
|
||||
def rubygems_version
|
||||
# RubyGems will barf if we try to pass an intermediate version number
|
||||
# like "1.1b2-10-g61a374a", so no choice but to abbreviate it
|
||||
`git describe --abbrev=0`.chomp
|
||||
end
|
||||
|
||||
def yellow
|
||||
"\033[33m"
|
||||
end
|
||||
|
||||
def red
|
||||
"\033[31m"
|
||||
end
|
||||
|
||||
def clear
|
||||
"\033[0m"
|
||||
end
|
||||
|
||||
def warn str
|
||||
puts "#{yellow}warning: #{str}#{clear}"
|
||||
end
|
||||
|
||||
def err str
|
||||
puts "#{red}error: #{str}#{clear}"
|
||||
end
|
||||
|
||||
def prepare_release_notes
|
||||
# extract base release notes from README.txt HISTORY section
|
||||
File.open('.release-notes.txt', 'w') do |out|
|
||||
lines = File.readlines('README.txt').each { |line| line.chomp! }
|
||||
while line = lines.shift do
|
||||
next unless line =~ /^HISTORY +\*command-t-history\*$/
|
||||
break unless lines.shift == '' &&
|
||||
(line = lines.shift) && line =~ /^\d\.\d/ &&
|
||||
lines.shift == ''
|
||||
while line = lines.shift and line != ''
|
||||
out.puts line
|
||||
end
|
||||
break
|
||||
end
|
||||
out.puts ''
|
||||
out.puts '# Please edit the release notes to taste.'
|
||||
out.puts '# Blank lines and lines beginning with a hash will be removed.'
|
||||
out.puts '# To abort, exit your editor with a non-zero exit status (:cquit in Vim).'
|
||||
end
|
||||
|
||||
unless system "$EDITOR .release-notes.txt"
|
||||
err "editor exited with non-zero exit status; aborting"
|
||||
exit 1
|
||||
end
|
||||
|
||||
filtered = read_release_notes
|
||||
File.open('.release-notes.txt', 'w') do |out|
|
||||
out.print filtered
|
||||
end
|
||||
end
|
||||
|
||||
def read_release_notes
|
||||
File.readlines('.release-notes.txt').reject do |line|
|
||||
line =~ /^(#.*|\s*)$/ # filter comment lines and blank lines
|
||||
end.join
|
||||
end
|
||||
|
||||
task :default => :spec
|
||||
|
||||
desc 'Print help on preparing a release'
|
||||
task :help do
|
||||
puts <<-END
|
||||
|
||||
The general release sequence is:
|
||||
|
||||
rake prerelease
|
||||
rake gem
|
||||
rake push
|
||||
bundle exec rake upload:all
|
||||
rake archive
|
||||
|
||||
Most of the Rake tasks run fine without Bundler, and in fact, we
|
||||
don't want Bundler in the prerelease task because it will tamper
|
||||
with the environment in a way that breaks multiruby.
|
||||
|
||||
We use Bundler for the upload task because the www.vim.org
|
||||
uploader uses Bundler to ensure that the Mechanize gem is available.
|
||||
|
||||
END
|
||||
end
|
||||
|
||||
task :check_bundler do
|
||||
unless ENV.has_key? 'BUNDLE_GEMFILE'
|
||||
warn 'warning: Bundler is not loaded; try running with `bundle exec rake`'
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Run specs'
|
||||
task :spec do
|
||||
system 'bundle exec rspec spec'
|
||||
bail_on_failure
|
||||
end
|
||||
|
||||
desc 'Create vimball archive'
|
||||
task :vimball => :check_tag do
|
||||
system 'make'
|
||||
bail_on_failure
|
||||
FileUtils.cp 'command-t.vba', "command-t-#{version}.vba"
|
||||
end
|
||||
|
||||
desc 'Clean compiled products'
|
||||
task :clean do
|
||||
Dir.chdir 'ruby/command-t' do
|
||||
system 'make clean' if File.exists?('Makefile')
|
||||
system 'rm -f Makefile'
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Clobber all generated files'
|
||||
task :clobber => :clean do
|
||||
system 'make clean'
|
||||
end
|
||||
|
||||
desc 'Compile extension'
|
||||
task :make do
|
||||
Dir.chdir 'ruby/command-t' do
|
||||
ruby 'extconf.rb'
|
||||
system 'make clean'
|
||||
bail_on_failure
|
||||
system 'make'
|
||||
bail_on_failure
|
||||
end
|
||||
end
|
||||
|
||||
namespace :make do
|
||||
desc 'Compile under all multiruby versions'
|
||||
task :all do
|
||||
system './compile-test.sh'
|
||||
bail_on_failure
|
||||
end
|
||||
end
|
||||
|
||||
namespace :spec do
|
||||
desc 'Run specs under all multiruby versions'
|
||||
task :all do
|
||||
system './multi-spec.sh'
|
||||
bail_on_failure
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Check that the current HEAD is tagged'
|
||||
task :check_tag do
|
||||
unless system 'git describe --exact-match HEAD 2> /dev/null'
|
||||
warn 'current HEAD is not tagged'
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Run checks prior to release'
|
||||
task :prerelease => ['make:all', 'spec:all', :vimball, :check_tag]
|
||||
|
||||
namespace :upload do
|
||||
desc 'Upload current vimball to Amazon S3'
|
||||
task :s3 => :vimball do
|
||||
sh 'aws put ' +
|
||||
"s3.wincent.com/command-t/releases/command-t-#{version}.vba " +
|
||||
"command-t-#{version}.vba"
|
||||
sh 'aws put ' +
|
||||
"s3.wincent.com/command-t/releases/command-t-#{version}.vba?acl " +
|
||||
'--public'
|
||||
end
|
||||
|
||||
desc 'Upload current vimball to www.vim.org'
|
||||
task :vim => [:check_bundler, :vimball] do
|
||||
prepare_release_notes
|
||||
sh "vendor/vimscriptuploader/vimscriptuploader.rb \
|
||||
--id 3025 \
|
||||
--file command-t-#{version}.vba \
|
||||
--message-file .release-notes.txt \
|
||||
--version #{version} \
|
||||
--config ~/.vim_org.yml \
|
||||
.vim_org.yml"
|
||||
end
|
||||
|
||||
desc 'Upload current vimball everywhere'
|
||||
task :all => [ :s3, :vim ]
|
||||
end
|
||||
|
||||
desc 'Add current vimball to releases branch'
|
||||
task :archive => :vimball do
|
||||
v = version # store version before switching branches
|
||||
sh 'git stash && ' +
|
||||
'git checkout releases && ' +
|
||||
"git add command-t-#{v}.vba && " +
|
||||
"git commit -s -m 'Add #{v} release vimball' && " +
|
||||
'git checkout @{-1} && ' +
|
||||
'git stash pop || true'
|
||||
end
|
||||
|
||||
desc 'Create the ruby gem package'
|
||||
task :gem => :check_tag do
|
||||
sh "gem build command-t.gemspec"
|
||||
end
|
||||
|
||||
desc 'Push gem to Gemcutter ("gem push")'
|
||||
task :push => :gem do
|
||||
sh "gem push command-t-#{rubygems_version}.gem"
|
||||
end
|
|
@ -0,0 +1,2 @@
|
|||
*
|
||||
!.gitignore
|
|
@ -0,0 +1,37 @@
|
|||
Gem::Specification.new do |s|
|
||||
s.name = "command-t"
|
||||
|
||||
# see note in the Rakefile about how intermediate version numbers
|
||||
# can break RubyGems
|
||||
v = `git describe --abbrev=0`.chomp
|
||||
s.version = v
|
||||
|
||||
s.authors = ["Wincent Colaiuta"]
|
||||
s.date = "2011-01-05"
|
||||
s.email = "win@wincent.com"
|
||||
|
||||
files =
|
||||
["README.txt", "LICENSE", "Gemfile", "Rakefile"] +
|
||||
Dir.glob("{ruby,doc,plugin}/**/*")
|
||||
|
||||
files = files.reject { |f| f =~ /\.(rbc|o|log|plist|dSYM)/ }
|
||||
|
||||
s.files = files
|
||||
s.require_path = "ruby"
|
||||
s.extensions = "ruby/command-t/extconf.rb"
|
||||
|
||||
s.executables = []
|
||||
|
||||
s.has_rdoc = false
|
||||
s.homepage = "https://wincent.com/products/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
|
|
@ -0,0 +1,10 @@
|
|||
#!/bin/sh -e
|
||||
cd ruby/command-t
|
||||
for RUBY_VERSION in $(ls ~/.multiruby/install); do
|
||||
echo "$RUBY_VERSION: building"
|
||||
export PATH=~/.multiruby/install/$RUBY_VERSION/bin:$PATH
|
||||
ruby extconf.rb
|
||||
make clean
|
||||
make
|
||||
echo "$RUBY_VERSION: finished"
|
||||
done
|
|
@ -0,0 +1 @@
|
|||
tags
|
|
@ -0,0 +1,896 @@
|
|||
*command-t.txt* Command-T plug-in for Vim *command-t*
|
||||
|
||||
CONTENTS *command-t-contents*
|
||||
|
||||
1. Introduction |command-t-intro|
|
||||
2. Requirements |command-t-requirements|
|
||||
3. Installation |command-t-installation|
|
||||
3. Managing using Pathogen |command-t-pathogen|
|
||||
4. Trouble-shooting |command-t-trouble-shooting|
|
||||
5. Usage |command-t-usage|
|
||||
6. Commands |command-t-commands|
|
||||
7. Mappings |command-t-mappings|
|
||||
8. Options |command-t-options|
|
||||
9. Authors |command-t-authors|
|
||||
10. Development |command-t-development|
|
||||
11. Website |command-t-website|
|
||||
12. Donations |command-t-donations|
|
||||
13. License |command-t-license|
|
||||
14. History |command-t-history|
|
||||
|
||||
|
||||
INTRODUCTION *command-t-intro*
|
||||
|
||||
The Command-T plug-in provides an extremely fast, intuitive mechanism for
|
||||
opening files and buffers with a minimal number of keystrokes. It's named
|
||||
"Command-T" because it is inspired by the "Go to File" window bound to
|
||||
Command-T in TextMate.
|
||||
|
||||
Files are selected by typing characters that appear in their paths, and are
|
||||
ordered by an algorithm which knows that characters that appear in certain
|
||||
locations (for example, immediately after a path separator) should be given
|
||||
more weight.
|
||||
|
||||
To search efficiently, especially in large projects, you should adopt a
|
||||
"path-centric" rather than a "filename-centric" mentality. That is you should
|
||||
think more about where the desired file is found rather than what it is
|
||||
called. This means narrowing your search down by including some characters
|
||||
from the upper path components rather than just entering characters from the
|
||||
filename itself.
|
||||
|
||||
Screencasts demonstrating the plug-in can be viewed at:
|
||||
|
||||
https://wincent.com/products/command-t
|
||||
|
||||
|
||||
REQUIREMENTS *command-t-requirements*
|
||||
|
||||
The plug-in requires Vim compiled with Ruby support, a compatible Ruby
|
||||
installation at the operating system level, and a C compiler to build
|
||||
the Ruby extension.
|
||||
|
||||
|
||||
1. Vim compiled with Ruby support
|
||||
|
||||
You can check for Ruby support by launching Vim with the --version switch:
|
||||
|
||||
vim --version
|
||||
|
||||
If "+ruby" appears in the version information then your version of Vim has
|
||||
Ruby support.
|
||||
|
||||
Another way to check is to simply try using the :ruby command from within Vim
|
||||
itself:
|
||||
|
||||
:ruby 1
|
||||
|
||||
If your Vim lacks support you'll see an error message like this:
|
||||
|
||||
E319: Sorry, the command is not available in this version
|
||||
|
||||
The version of Vim distributed with Mac OS X does not include Ruby support,
|
||||
while MacVim does; it is available from:
|
||||
|
||||
http://github.com/b4winckler/macvim/downloads
|
||||
|
||||
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
|
||||
Ruby 1.9, but apparently has some bugs that need to be resolved).
|
||||
|
||||
|
||||
2. Ruby
|
||||
|
||||
In addition to having Ruby support in Vim, your system itself must have a
|
||||
compatible Ruby install. "Compatible" means the same version as Vim itself
|
||||
links against. If you use a different version then Command-T is unlikely
|
||||
to work (see TROUBLE-SHOOTING below).
|
||||
|
||||
On Mac OS X Snow Leopard, the system comes with Ruby 1.8.7 and all recent
|
||||
versions of MacVim (the 7.2 snapshots and 7.3) are linked against it.
|
||||
|
||||
On Linux and similar platforms, the linked version of Ruby will depend on
|
||||
your distribution. You can usually find this out by examining the
|
||||
compilation and linking flags displayed by the |:version| command in Vim, and
|
||||
by looking at the output of:
|
||||
|
||||
:ruby puts RUBY_VERSION
|
||||
|
||||
A suitable Ruby environment for Windows can be installed using the Ruby
|
||||
1.8.7-p299 RubyInstaller available at:
|
||||
|
||||
http://rubyinstaller.org/downloads/archives
|
||||
|
||||
If using RubyInstaller be sure to download the installer executable, not the
|
||||
7-zip archive. When installing mark the checkbox "Add Ruby executables to your
|
||||
PATH" so that Vim can find them.
|
||||
|
||||
|
||||
3. C compiler
|
||||
|
||||
Part of Command-T is implemented in C as a Ruby extension for speed, allowing
|
||||
it to work responsively even on directory hierarchies containing enormous
|
||||
numbers of files. As such, a C compiler is required in order to build the
|
||||
extension and complete the installation.
|
||||
|
||||
On Mac OS X, this can be obtained by installing the Xcode Tools that come on
|
||||
the Mac OS X install disc.
|
||||
|
||||
On Windows, the RubyInstaller Development Kit can be used to conveniently
|
||||
install the necessary tool chain:
|
||||
|
||||
http://rubyinstaller.org/downloads/archives
|
||||
|
||||
At the time of writing, the appropriate development kit for use with Ruby
|
||||
1.8.7 is DevKit-3.4.5r3-20091110.
|
||||
|
||||
To use the Development Kit extract the archive contents to your C:\Ruby
|
||||
folder.
|
||||
|
||||
|
||||
INSTALLATION *command-t-installation*
|
||||
|
||||
Command-T is distributed as a "vimball" which means that it can be installed
|
||||
by opening it in Vim and then sourcing it:
|
||||
|
||||
:e command-t.vba
|
||||
:so %
|
||||
|
||||
The files will be installed in your |'runtimepath'|. To check where this is
|
||||
you can issue:
|
||||
|
||||
:echo &rtp
|
||||
|
||||
The C extension must then be built, which can be done from the shell. If you
|
||||
use a typical |'runtimepath'| then the files were installed inside ~/.vim and
|
||||
you can build the extension with:
|
||||
|
||||
cd ~/.vim/ruby/command-t
|
||||
ruby extconf.rb
|
||||
make
|
||||
|
||||
Note: If you are an RVM or rbenv user, you must perform the build using the
|
||||
same version of Ruby that Vim itself is linked against. This will often be the
|
||||
system Ruby, which can be selected before issuing the "make" command with one
|
||||
of the following commands:
|
||||
|
||||
rvm use system
|
||||
rbenv local system
|
||||
|
||||
Note: Make sure you compile targeting the same architecture Vim was built for.
|
||||
For instance, MacVim binaries are built for i386, but sometimes GCC compiles
|
||||
for x86_64. First you have to check the platfom Vim was built for:
|
||||
|
||||
vim --version
|
||||
...
|
||||
Compilation: gcc ... -arch i386 ...
|
||||
...
|
||||
|
||||
and make sure you use the correct ARCHFLAGS during compilation:
|
||||
|
||||
export ARCHFLAGS="-arch i386"
|
||||
make
|
||||
|
||||
|
||||
MANAGING USING PATHOGEN *command-t-pathogen*
|
||||
|
||||
Pathogen is a plugin that allows you to maintain plugin installations in
|
||||
separate, isolated subdirectories under the "bundle" directory in your
|
||||
|'runtimepath'|. The following examples assume that you already have
|
||||
Pathogen installed and configured, and that you are installing into
|
||||
~/.vim/bundle. For more information about Pathogen, see:
|
||||
|
||||
http://www.vim.org/scripts/script.php?script_id=2332
|
||||
|
||||
If you manage your entire ~/.vim folder using Git then you can add the
|
||||
Command-T repository as a submodule:
|
||||
|
||||
cd ~/.vim
|
||||
git submodule add git://git.wincent.com/command-t.git bundle/command-t
|
||||
git submodule init
|
||||
|
||||
Or if you just wish to do a simple clone instead of using submodules:
|
||||
|
||||
cd ~/.vim
|
||||
git clone git://git.wincent.com/command-t.git bundle/command-t
|
||||
|
||||
Once you have a local copy of the repository you can update it at any time
|
||||
with:
|
||||
|
||||
cd ~/.vim/bundle/command-t
|
||||
git pull
|
||||
|
||||
Or you can switch to a specific release with:
|
||||
|
||||
cd ~/.vim/bundle/command-t
|
||||
git checkout 0.8b
|
||||
|
||||
After installing or updating you must build the extension:
|
||||
|
||||
cd ~/.vim/bundle/command-t/ruby/command-t
|
||||
ruby extconf.rb
|
||||
make
|
||||
|
||||
While the Vimball installation automatically generates the help tags, under
|
||||
Pathogen it is necessary to do so explicitly from inside Vim:
|
||||
|
||||
:call pathogen#helptags()
|
||||
|
||||
|
||||
TROUBLE-SHOOTING *command-t-trouble-shooting*
|
||||
|
||||
Most installation problems are caused by a mismatch between the version of
|
||||
Ruby on the host operating system, and the version of Ruby that Vim itself
|
||||
linked against at compile time. For example, if one is 32-bit and the other is
|
||||
64-bit, or one is from the Ruby 1.9 series and the other is from the 1.8
|
||||
series, then the plug-in is not likely to work.
|
||||
|
||||
As such, on Mac OS X, I recommend using the standard Ruby that comes with the
|
||||
system (currently 1.8.7) along with the latest version of MacVim (currently
|
||||
version 7.3). If you wish to use custom builds of Ruby or of MacVim (not
|
||||
recommmended) then you will have to take extra care to ensure that the exact
|
||||
same Ruby environment is in effect when building Ruby, Vim and the Command-T
|
||||
extension.
|
||||
|
||||
For Windows, the following combination is known to work:
|
||||
|
||||
- Vim 7.2 from http://www.vim.org/download.php:
|
||||
ftp://ftp.vim.org/pub/vim/pc/gvim72.exe
|
||||
- Ruby 1.8.7-p299 from http://rubyinstaller.org/downloads/archives:
|
||||
http://rubyforge.org/frs/download.php/71492/rubyinstaller-1.8.7-p299.exe
|
||||
- DevKit 3.4.5r3-20091110 from http://rubyinstaller.org/downloads/archives:
|
||||
http://rubyforge.org/frs/download.php/66888/devkit-3.4.5r3-20091110.7z
|
||||
|
||||
If a problem occurs the first thing you should do is inspect the output of:
|
||||
|
||||
ruby extconf.rb
|
||||
make
|
||||
|
||||
During the installation, and:
|
||||
|
||||
vim --version
|
||||
|
||||
And compare the compilation and linker flags that were passed to the
|
||||
extension and to Vim itself when they were built. If the Ruby-related
|
||||
flags or architecture flags are different then it is likely that something
|
||||
has changed in your Ruby environment and the extension may not work until
|
||||
you eliminate the discrepancy.
|
||||
|
||||
|
||||
USAGE *command-t-usage*
|
||||
|
||||
Bring up the Command-T file window by typing:
|
||||
|
||||
<Leader>t
|
||||
|
||||
This mapping is set up automatically for you, provided you do not already have
|
||||
a mapping for <Leader>t or |:CommandT|. You can also bring up the file window
|
||||
by issuing the command:
|
||||
|
||||
:CommandT
|
||||
|
||||
A prompt will appear at the bottom of the screen along with a file window
|
||||
showing all of the files in the current directory (as returned by the
|
||||
|:pwd| command).
|
||||
|
||||
For the most efficient file navigation within a project it's recommended that
|
||||
you |:cd| into the root directory of your project when starting to work on it.
|
||||
If you wish to open a file from outside of the project folder you can pass in
|
||||
an optional path argument (relative or absolute) to |:CommandT|:
|
||||
|
||||
:CommandT ../path/to/other/files
|
||||
|
||||
Type letters in the prompt to narrow down the selection, showing only the
|
||||
files whose paths contain those letters in the specified order. Letters do not
|
||||
need to appear consecutively in a path in order for it to be classified as a
|
||||
match.
|
||||
|
||||
Once the desired file has been selected it can be opened by pressing <CR>.
|
||||
(By default files are opened in the current window, but there are other
|
||||
mappings that you can use to open in a vertical or horizontal split, or in
|
||||
a new tab.) Note that if you have |'nohidden'| set and there are unsaved
|
||||
changes in the current window when you press <CR> then opening in the current
|
||||
window would fail; in this case Command-T will open the file in a new split.
|
||||
|
||||
The following mappings are active when the prompt has focus:
|
||||
|
||||
<BS> delete the character to the left of the cursor
|
||||
<Del> delete the character at the cursor
|
||||
<Left> move the cursor one character to the left
|
||||
<C-h> move the cursor one character to the left
|
||||
<Right> move the cursor one character to the right
|
||||
<C-l> move the cursor one character to the right
|
||||
<C-a> move the cursor to the start (left)
|
||||
<C-e> move the cursor to the end (right)
|
||||
<C-u> clear the contents of the prompt
|
||||
<Tab> change focus to the file listing
|
||||
|
||||
The following mappings are active when the file listing has focus:
|
||||
|
||||
<Tab> change focus to the prompt
|
||||
|
||||
The following mappings are active when either the prompt or the file listing
|
||||
has focus:
|
||||
|
||||
<CR> open the selected file
|
||||
<C-CR> open the selected file in a new split window
|
||||
<C-s> open the selected file in a new split window
|
||||
<C-v> open the selected file in a new vertical split window
|
||||
<C-t> open the selected file in a new tab
|
||||
<C-j> select next file in the file listing
|
||||
<C-n> select next file in the file listing
|
||||
<Down> select next file in the file listing
|
||||
<C-k> select previous file in the file listing
|
||||
<C-p> select previous file in the file listing
|
||||
<Up> select previous file in the file listing
|
||||
<C-f> flush the cache (see |:CommandTFlush| for details)
|
||||
<C-c> cancel (dismisses file listing)
|
||||
|
||||
The following is also available on terminals which support it:
|
||||
|
||||
<Esc> cancel (dismisses file listing)
|
||||
|
||||
Note that the default mappings can be overriden by setting options in your
|
||||
~/.vimrc file (see the OPTIONS section for a full list of available options).
|
||||
|
||||
In addition, when the file listing has focus, typing a character will cause
|
||||
the selection to jump to the first path which begins with that character.
|
||||
Typing multiple characters consecutively can be used to distinguish between
|
||||
paths which begin with the same prefix.
|
||||
|
||||
|
||||
COMMANDS *command-t-commands*
|
||||
|
||||
*:CommandT*
|
||||
|:CommandT| Brings up the Command-T file window, starting in the
|
||||
current working directory as returned by the|:pwd|
|
||||
command.
|
||||
|
||||
*:CommandTBuffer*
|
||||
|:CommandTBuffer|Brings up the Command-T buffer window.
|
||||
This works exactly like the standard file window,
|
||||
except that the selection is limited to files that
|
||||
you already have open in buffers.
|
||||
|
||||
*:CommandTJumps*
|
||||
|:CommandTJump| Brings up the Command-T jumplist window.
|
||||
This works exactly like the standard file window,
|
||||
except that the selection is limited to files that
|
||||
you already have in the jumplist. Note that jumps
|
||||
can persist across Vim sessions (see Vim's |jumplist|
|
||||
documentation for more info).
|
||||
|
||||
*:CommandTTag*
|
||||
|:CommandTTag| Brings up the Command-T window tags window, which can
|
||||
be used to select from the tags, if any, returned by
|
||||
Vim's |taglist()| function. See Vim's |tag| documentation
|
||||
for general info on tags.
|
||||
|
||||
*:CommandTFlush*
|
||||
|:CommandTFlush|Instructs the plug-in to flush its path cache, causing
|
||||
the directory to be rescanned for new or deleted paths
|
||||
the next time the file window is shown (pressing <C-f> when
|
||||
a match listing is visible flushes the cache immediately; this
|
||||
mapping is configurable via the |g:CommandTRefreshMap|
|
||||
setting). In addition, all configuration settings are
|
||||
re-evaluated, causing any changes made to settings via the
|
||||
|:let| command to be picked up.
|
||||
|
||||
|
||||
MAPPINGS *command-t-mappings*
|
||||
|
||||
By default Command-T comes with only two mappings:
|
||||
|
||||
<Leader>t bring up the Command-T file window
|
||||
<Leader>b bring up the Command-T buffer window
|
||||
|
||||
However, 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 <silent> <Leader>t :CommandT<CR>
|
||||
nnoremap <silent> <Leader>b :CommandTBuffer<CR>
|
||||
|
||||
Replacing "<Leader>t" or "<Leader>b" with your mapping of choice.
|
||||
|
||||
Note that in the case of MacVim you actually can map to Command-T (written
|
||||
as <D-t> in Vim) in your ~/.gvimrc file if you first unmap the existing menu
|
||||
binding of Command-T to "New Tab":
|
||||
|
||||
if has("gui_macvim")
|
||||
macmenu &File.New\ Tab key=<nop>
|
||||
map <D-t> :CommandT<CR>
|
||||
endif
|
||||
|
||||
When the Command-T window is active a number of other additional mappings
|
||||
become available for doing things like moving between and selecting matches.
|
||||
These are fully described above in the USAGE section, and settings for
|
||||
overriding the mappings are listed below under OPTIONS.
|
||||
|
||||
|
||||
OPTIONS *command-t-options*
|
||||
|
||||
A number of options may be set in your ~/.vimrc to influence the behaviour of
|
||||
the plug-in. To set an option, you include a line like this in your ~/.vimrc:
|
||||
|
||||
let g:CommandTMaxFiles=20000
|
||||
|
||||
To have Command-T pick up new settings immediately (that is, without having
|
||||
to restart Vim) you can issue the |:CommandTFlush| command after making
|
||||
changes via |:let|.
|
||||
|
||||
Following is a list of all available options:
|
||||
|
||||
*g:CommandTMaxFiles*
|
||||
|g:CommandTMaxFiles| number (default 10000)
|
||||
|
||||
The maximum number of files that will be considered when scanning the
|
||||
current directory. Upon reaching this number scanning stops. This
|
||||
limit applies only to file listings and is ignored for buffer
|
||||
listings.
|
||||
|
||||
*g:CommandTMaxDepth*
|
||||
|g:CommandTMaxDepth| number (default 15)
|
||||
|
||||
The maximum depth (levels of recursion) to be explored when scanning the
|
||||
current directory. Any directories at levels beyond this depth will be
|
||||
skipped.
|
||||
|
||||
*g:CommandTMaxCachedDirectories*
|
||||
|g:CommandTMaxCachedDirectories| number (default 1)
|
||||
|
||||
The maximum number of directories whose contents should be cached when
|
||||
recursively scanning. With the default value of 1, each time you change
|
||||
directories the cache will be emptied and Command-T will have to
|
||||
rescan. Higher values will make Command-T hold more directories in the
|
||||
cache, bringing performance at the cost of memory usage. If set to 0,
|
||||
there is no limit on the number of cached directories.
|
||||
|
||||
*g:CommandTMaxHeight*
|
||||
|g:CommandTMaxHeight| number (default: 0)
|
||||
|
||||
The maximum height in lines the match window is allowed to expand to.
|
||||
If set to 0, the window will occupy as much of the available space as
|
||||
needed to show matching entries.
|
||||
|
||||
*g:CommandTMinHeight*
|
||||
|g:CommandTMinHeight| number (default: 0)
|
||||
|
||||
The minimum height in lines the match window is allowed to shrink to.
|
||||
If set to 0, will default to a single line. If set above the max height,
|
||||
will default to |g:CommandTMaxHeight|.
|
||||
|
||||
*g:CommandTAlwaysShowDotFiles*
|
||||
|g:CommandTAlwaysShowDotFiles| boolean (default: 0)
|
||||
|
||||
When showing the file listing Command-T will by default show dot-files
|
||||
only if the entered search string contains a dot that could cause a
|
||||
dot-file to match. When set to a non-zero value, this setting instructs
|
||||
Command-T to always include matching dot-files in the match list
|
||||
regardless of whether the search string contains a dot. See also
|
||||
|g:CommandTNeverShowDotFiles|. Note that this setting only influences
|
||||
the file listing; the buffer listing treats dot-files like any other
|
||||
file.
|
||||
|
||||
*g:CommandTNeverShowDotFiles*
|
||||
|g:CommandTNeverShowDotFiles| boolean (default: 0)
|
||||
|
||||
In the file listing, Command-T will by default show dot-files if the
|
||||
entered search string contains a dot that could cause a dot-file to
|
||||
match. When set to a non-zero value, this setting instructs Command-T to
|
||||
never show dot-files under any circumstances. Note that it is
|
||||
contradictory to set both this setting and
|
||||
|g:CommandTAlwaysShowDotFiles| to true, and if you do so Vim will suffer
|
||||
from headaches, nervous twitches, and sudden mood swings. This setting
|
||||
has no effect in buffer listings, where dot files are treated like any
|
||||
other file.
|
||||
|
||||
*g:CommandTScanDotDirectories*
|
||||
|g:CommandTScanDotDirectories| boolean (default: 0)
|
||||
|
||||
Normally Command-T will not recurse into "dot-directories" (directories
|
||||
whose names begin with a dot) while performing its initial scan. Set
|
||||
this setting to a non-zero value to override this behavior and recurse.
|
||||
Note that this setting is completely independent of the
|
||||
|g:CommandTAlwaysShowDotFiles| and |g:CommandTNeverShowDotFiles|
|
||||
settings; those apply only to the selection and display of matches
|
||||
(after scanning has been performed), whereas
|
||||
|g:CommandTScanDotDirectories| affects the behaviour at scan-time.
|
||||
|
||||
Note also that even with this setting off you can still use Command-T to
|
||||
open files inside a "dot-directory" such as ~/.vim, but you have to use
|
||||
the |:cd| command to change into that directory first. For example:
|
||||
|
||||
:cd ~/.vim
|
||||
:CommandT
|
||||
|
||||
*g:CommandTMatchWindowAtTop*
|
||||
|g:CommandTMatchWindowAtTop| boolean (default: 0)
|
||||
|
||||
When this setting is off (the default) the match window will appear at
|
||||
the bottom so as to keep it near to the prompt. Turning it on causes the
|
||||
match window to appear at the top instead. This may be preferable if you
|
||||
want the best match (usually the first one) to appear in a fixed location
|
||||
on the screen rather than moving as the number of matches changes during
|
||||
typing.
|
||||
|
||||
*g:CommandTMatchWindowReverse*
|
||||
|g:CommandTMatchWindowReverse| boolean (default: 0)
|
||||
|
||||
When this setting is off (the default) the matches will appear from
|
||||
top to bottom with the topmost being selected. Turning it on causes the
|
||||
matches to be reversed so the best match is at the bottom and the
|
||||
initially selected match is the bottom most. This may be preferable if
|
||||
you want the best match to appear in a fixed location on the screen
|
||||
but still be near the prompt at the bottom.
|
||||
|
||||
*g:CommandTTagIncludeFilenames*
|
||||
|g:CommandTTagIncludeFilenames| boolean (default: 0)
|
||||
|
||||
When this setting is off (the default) the matches in the |:CommandTTag|
|
||||
listing do not include filenames.
|
||||
|
||||
As well as the basic options listed above, there are a number of settings that
|
||||
can be used to override the default key mappings used by Command-T. For
|
||||
example, to set <C-x> as the mapping for cancelling (dismissing) the Command-T
|
||||
window, you would add the following to your ~/.vimrc:
|
||||
|
||||
let g:CommandTCancelMap='<C-x>'
|
||||
|
||||
Multiple, alternative mappings may be specified using list syntax:
|
||||
|
||||
let g:CommandTCancelMap=['<C-x>', '<C-c>']
|
||||
|
||||
Following is a list of all map settings and their defaults:
|
||||
|
||||
Setting Default mapping(s)
|
||||
|
||||
*g:CommandTBackspaceMap*
|
||||
|g:CommandTBackspaceMap| <BS>
|
||||
|
||||
*g:CommandTDeleteMap*
|
||||
|g:CommandTDeleteMap| <Del>
|
||||
|
||||
*g:CommandTAcceptSelectionMap*
|
||||
|g:CommandTAcceptSelectionMap| <CR>
|
||||
|
||||
*g:CommandTAcceptSelectionSplitMap*
|
||||
|g:CommandTAcceptSelectionSplitMap| <C-CR>
|
||||
<C-s>
|
||||
|
||||
*g:CommandTAcceptSelectionTabMap*
|
||||
|g:CommandTAcceptSelectionTabMap| <C-t>
|
||||
|
||||
*g:CommandTAcceptSelectionVSplitMap*
|
||||
|g:CommandTAcceptSelectionVSplitMap| <C-v>
|
||||
|
||||
*g:CommandTToggleFocusMap*
|
||||
|g:CommandTToggleFocusMap| <Tab>
|
||||
|
||||
*g:CommandTCancelMap*
|
||||
|g:CommandTCancelMap| <C-c>
|
||||
<Esc> (not on all terminals)
|
||||
|
||||
*g:CommandTSelectNextMap*
|
||||
|g:CommandTSelectNextMap| <C-n>
|
||||
<C-j>
|
||||
<Down>
|
||||
|
||||
*g:CommandTSelectPrevMap*
|
||||
|g:CommandTSelectPrevMap| <C-p>
|
||||
<C-k>
|
||||
<Up>
|
||||
|
||||
*g:CommandTClearMap*
|
||||
|g:CommandTClearMap| <C-u>
|
||||
|
||||
*g:CommandTRefreshMap*
|
||||
|g:CommandTRefreshMap| <C-f>
|
||||
|
||||
*g:CommandTCursorLeftMap*
|
||||
|g:CommandTCursorLeftMap| <Left>
|
||||
<C-h>
|
||||
|
||||
*g:CommandTCursorRightMap*
|
||||
|g:CommandTCursorRightMap| <Right>
|
||||
<C-l>
|
||||
|
||||
*g:CommandTCursorEndMap*
|
||||
|g:CommandTCursorEndMap| <C-e>
|
||||
|
||||
*g:CommandTCursorStartMap*
|
||||
|g:CommandTCursorStartMap| <C-a>
|
||||
|
||||
In addition to the options provided by Command-T itself, some of Vim's own
|
||||
settings can be used to control behavior:
|
||||
|
||||
*command-t-wildignore*
|
||||
|'wildignore'| string (default: '')
|
||||
|
||||
Vim's |'wildignore'| setting is used to determine which files should be
|
||||
excluded from listings. This is a comma-separated list of glob patterns.
|
||||
It defaults to the empty string, but common settings include "*.o,*.obj"
|
||||
(to exclude object files) or ".git,.svn" (to exclude SCM metadata
|
||||
directories). For example:
|
||||
|
||||
:set wildignore+=*.o,*.obj,.git
|
||||
|
||||
A pattern such as "vendor/rails/**" would exclude all files and
|
||||
subdirectories inside the "vendor/rails" directory (relative to
|
||||
directory Command-T starts in).
|
||||
|
||||
See the |'wildignore'| documentation for more information.
|
||||
|
||||
|
||||
AUTHORS *command-t-authors*
|
||||
|
||||
Command-T is written and maintained by Wincent Colaiuta <win@wincent.com>.
|
||||
Other contributors that have submitted patches include (in alphabetical
|
||||
order):
|
||||
|
||||
Anthony Panozzo Mike Lundy Steven Moazami
|
||||
Daniel Hahler Nate Kane Sung Pae
|
||||
Felix Tjandrawibawa Nicholas Alpi Thomas Pelletier
|
||||
Gary Bernhardt Nadav Samet Victor Hugo Borja
|
||||
Jeff Kreeftmeijer Noon Silk Woody Peterson
|
||||
Lucas de Vries Rainux Luo Yan Pritzker
|
||||
Marian Schubert Scott Bronson Zak Johnson
|
||||
Matthew Todd Seth Fowler
|
||||
|
||||
As this was the first Vim plug-in I had ever written I was heavily influenced
|
||||
by the design of the LustyExplorer plug-in by Stephen Bach, which I understand
|
||||
is one of the largest Ruby-based Vim plug-ins to date.
|
||||
|
||||
While the Command-T codebase doesn't contain any code directly copied from
|
||||
LustyExplorer, I did use it as a reference for answers to basic questions (like
|
||||
"How do you do 'X' in a Ruby-based Vim plug-in?"), and also copied some basic
|
||||
architectural decisions (like the division of the code into Prompt, Settings
|
||||
and MatchWindow classes).
|
||||
|
||||
LustyExplorer is available from:
|
||||
|
||||
http://www.vim.org/scripts/script.php?script_id=1890
|
||||
|
||||
|
||||
DEVELOPMENT *command-t-development*
|
||||
|
||||
Development in progress can be inspected via the project's Git web-based
|
||||
repository browser at:
|
||||
|
||||
https://wincent.com/repos/command-t
|
||||
|
||||
the clone URL for which is:
|
||||
|
||||
git://git.wincent.com/command-t.git
|
||||
|
||||
Mirrors exist on GitHub and Gitorious; these are automatically updated once
|
||||
per hour from the authoritative repository:
|
||||
|
||||
https://github.com/wincent/command-t
|
||||
https://gitorious.org/command-t/command-t
|
||||
|
||||
Patches are welcome via the usual mechanisms (pull requests, email, posting to
|
||||
the project issue tracker etc).
|
||||
|
||||
As many users choose to track Command-T using Pathogen, which often means
|
||||
running a version later than the last official release, the intention is that
|
||||
the "master" branch should be kept in a stable and reliable state as much as
|
||||
possible.
|
||||
|
||||
Riskier changes are first cooked on the "next" branch for a period before
|
||||
being merged into master. You can track this branch if you're feeling wild and
|
||||
experimental, but note that the "next" branch may periodically be rewound
|
||||
(force-updated) to keep it in sync with the "master" branch after each
|
||||
official release.
|
||||
|
||||
|
||||
WEBSITE *command-t-website*
|
||||
|
||||
The official website for Command-T is:
|
||||
|
||||
https://wincent.com/products/command-t
|
||||
|
||||
The latest release will always be available from there.
|
||||
|
||||
A copy of each release is also available from the official Vim scripts site
|
||||
at:
|
||||
|
||||
http://www.vim.org/scripts/script.php?script_id=3025
|
||||
|
||||
Bug reports should be submitted to the issue tracker at:
|
||||
|
||||
https://wincent.com/issues
|
||||
|
||||
|
||||
DONATIONS *command-t-donations*
|
||||
|
||||
Command-T itself is free software released under the terms of the BSD license.
|
||||
If you would like to support further development you can make a donation via
|
||||
PayPal to win@wincent.com:
|
||||
|
||||
https://wincent.com/products/command-t/donations
|
||||
|
||||
|
||||
LICENSE *command-t-license*
|
||||
|
||||
Copyright 2010-2012 Wincent Colaiuta. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
HISTORY *command-t-history*
|
||||
|
||||
1.4 (20 June 2012)
|
||||
|
||||
- added |:CommandTTag| command (patches from Noon Silk)
|
||||
- turn off |'colorcolumn'| and |'relativenumber'| in the match window (patch
|
||||
from Jeff Kreeftmeijer)
|
||||
- documentation update (patch from Nicholas Alpi)
|
||||
- added |:CommandTMinHeight| option (patch from Nate Kane)
|
||||
- highlight (by underlining) matched characters in the match listing (requires
|
||||
Vim to have been compiled with the +conceal feature, which is available in
|
||||
Vim 7.3 or later; patch from Steven Moazami)
|
||||
- added the ability to flush the cache while the match window is open using
|
||||
<C-f>
|
||||
|
||||
1.3.1 (18 December 2011)
|
||||
|
||||
- fix jumplist navigation under Ruby 1.9.x (patch from Woody Peterson)
|
||||
|
||||
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)
|
||||
|
||||
- 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)
|
||||
|
||||
- added |g:CommandTMatchWindowReverse| option, to reverse the order of items
|
||||
in the match listing (patch from Steven Moazami)
|
||||
|
||||
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)
|
||||
|
||||
- add |:CommandTBuffer| command for quickly selecting among open buffers
|
||||
|
||||
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 <C-W k> or similar)
|
||||
|
||||
1.0 (26 November 2010)
|
||||
|
||||
- make relative path simplification work on Windows
|
||||
|
||||
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)
|
||||
- re-use the buffer that is used to show the match listing, rather than
|
||||
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)
|
||||
|
||||
- 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)
|
||||
|
||||
- fix mapping issues for users who have set |'notimeout'| (patch from Sung
|
||||
Pae)
|
||||
|
||||
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
|
||||
- <Leader>t mapping only set up if no other map for |:CommandT| exists
|
||||
(patch from Scott Bronson)
|
||||
- prevent folds from appearing in the match listing
|
||||
- tweaks to avoid the likelihood of "Not enough room" errors when trying to
|
||||
open files
|
||||
- watch out for "nil" windows when restoring window dimensions
|
||||
- optimizations (avoid some repeated downcasing)
|
||||
- move all Ruby files under the "command-t" subdirectory and avoid polluting
|
||||
the "Vim" module namespace
|
||||
|
||||
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)
|
||||
|
||||
- handle more |'wildignore'| patterns by delegating to Vim's own |expand()|
|
||||
function; with this change it is now viable to exclude patterns such as
|
||||
'vendor/rails/**' in addition to filename-only patterns like '*.o' and
|
||||
'.git' (patch from Mike Lundy)
|
||||
- always sort results alphabetically for empty search strings; this eliminates
|
||||
filesystem-specific variations (patch from Mike Lundy)
|
||||
|
||||
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)
|
||||
|
||||
- fix for Ruby 1.9 compatibility regression introduced in 0.5
|
||||
- documentation enhancements, specifically targetted at Windows users
|
||||
|
||||
0.5 (3 April 2010)
|
||||
|
||||
- |:CommandTFlush| now re-evaluates settings, allowing changes made via |let|
|
||||
to be picked up without having to restart Vim
|
||||
- fix premature abort when scanning very deep directory hierarchies
|
||||
- remove broken |<Esc>| key mapping on vt100 and xterm terminals
|
||||
- provide settings for overriding default mappings
|
||||
- minor performance optimization
|
||||
|
||||
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)
|
||||
|
||||
- add |g:CommandTMaxHeight| setting for controlling the maximum height of the
|
||||
match window (patch from Lucas de Vries)
|
||||
- fix bug where |'list'| setting might be inappropriately set after dismissing
|
||||
Command-T
|
||||
- compatibility fix for different behaviour of "autoload" under Ruby 1.9.1
|
||||
- avoid "highlight group not found" warning when run under a version of Vim
|
||||
that does not have syntax highlighting support
|
||||
- open in split when opening normally would fail due to |'hidden'| and
|
||||
|'modified'| values
|
||||
|
||||
0.2 (23 March 2010)
|
||||
|
||||
- compatibility fixes for compilation under Ruby 1.9 series
|
||||
- compatibility fixes for compilation under Ruby 1.8.5
|
||||
- compatibility fixes for Windows and other non-UNIX platforms
|
||||
- suppress "mapping already exists" message if <Leader>t mapping is already
|
||||
defined when plug-in is loaded
|
||||
- exclude paths based on |'wildignore'| setting rather than a hardcoded
|
||||
regular expression
|
||||
|
||||
0.1 (22 March 2010)
|
||||
|
||||
- initial public release
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
vim:tw=78:ft=help:
|
|
@ -0,0 +1 @@
|
|||
.
|
|
@ -0,0 +1 @@
|
|||
.
|
|
@ -0,0 +1 @@
|
|||
.
|
|
@ -0,0 +1 @@
|
|||
.
|
|
@ -0,0 +1 @@
|
|||
.
|
|
@ -0,0 +1 @@
|
|||
.
|
|
@ -0,0 +1 @@
|
|||
.
|
|
@ -0,0 +1,25 @@
|
|||
#!/bin/sh -e
|
||||
|
||||
function build_quietly()
|
||||
{
|
||||
(bundle install > /dev/null &&
|
||||
cd ruby/command-t &&
|
||||
ruby extconf.rb > /dev/null &&
|
||||
make clean > /dev/null &&
|
||||
make > /dev/null)
|
||||
}
|
||||
|
||||
OLD_PATH=$PATH
|
||||
for RUBY_VERSION in $(ls ~/.multiruby/install); do
|
||||
echo "$RUBY_VERSION: building"
|
||||
export PATH=~/.multiruby/install/$RUBY_VERSION/bin:$OLD_PATH
|
||||
build_quietly
|
||||
echo "$RUBY_VERSION: running spec suite"
|
||||
bundle exec rspec spec
|
||||
echo "$RUBY_VERSION: finished"
|
||||
done
|
||||
|
||||
# put things back the way we found them
|
||||
export PATH=$OLD_PATH
|
||||
echo "Restoring: $(ruby -v)"
|
||||
build_quietly
|
|
@ -0,0 +1,186 @@
|
|||
" command-t.vim
|
||||
" Copyright 2010-2012 Wincent Colaiuta. All rights reserved.
|
||||
"
|
||||
" Redistribution and use in source and binary forms, with or without
|
||||
" modification, are permitted provided that the following conditions are met:
|
||||
"
|
||||
" 1. Redistributions of source code must retain the above copyright notice,
|
||||
" this list of conditions and the following disclaimer.
|
||||
" 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
" this list of conditions and the following disclaimer in the documentation
|
||||
" and/or other materials provided with the distribution.
|
||||
"
|
||||
" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
" POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
if exists("g:command_t_loaded") || &cp
|
||||
finish
|
||||
endif
|
||||
let g:command_t_loaded = 1
|
||||
|
||||
command CommandTBuffer call <SID>CommandTShowBufferFinder()
|
||||
command CommandTJump call <SID>CommandTShowJumpFinder()
|
||||
command CommandTTag call <SID>CommandTShowTagFinder()
|
||||
command -nargs=? -complete=dir CommandT call <SID>CommandTShowFileFinder(<q-args>)
|
||||
command CommandTFlush call <SID>CommandTFlush()
|
||||
|
||||
if !hasmapto(':CommandT<CR>')
|
||||
silent! nnoremap <unique> <silent> <Leader>t :CommandT<CR>
|
||||
endif
|
||||
|
||||
if !hasmapto(':CommandTBuffer<CR>')
|
||||
silent! nnoremap <unique> <silent> <Leader>b :CommandTBuffer<CR>
|
||||
endif
|
||||
|
||||
function s:CommandTRubyWarning()
|
||||
echohl WarningMsg
|
||||
echo "command-t.vim requires Vim to be compiled with Ruby support"
|
||||
echo "For more information type: :help command-t"
|
||||
echohl none
|
||||
endfunction
|
||||
|
||||
function s:CommandTShowBufferFinder()
|
||||
if has('ruby')
|
||||
ruby $command_t.show_buffer_finder
|
||||
else
|
||||
call s:CommandTRubyWarning()
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function s:CommandTShowFileFinder(arg)
|
||||
if has('ruby')
|
||||
ruby $command_t.show_file_finder
|
||||
else
|
||||
call s:CommandTRubyWarning()
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function s:CommandTShowJumpFinder()
|
||||
if has('ruby')
|
||||
ruby $command_t.show_jump_finder
|
||||
else
|
||||
call s:CommandTRubyWarning()
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function s:CommandTShowTagFinder()
|
||||
if has('ruby')
|
||||
ruby $command_t.show_tag_finder
|
||||
else
|
||||
call s:CommandTRubyWarning()
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function s:CommandTFlush()
|
||||
if has('ruby')
|
||||
ruby $command_t.flush
|
||||
else
|
||||
call s:CommandTRubyWarning()
|
||||
endif
|
||||
endfunction
|
||||
|
||||
if !has('ruby')
|
||||
finish
|
||||
endif
|
||||
|
||||
function CommandTHandleKey(arg)
|
||||
ruby $command_t.handle_key
|
||||
endfunction
|
||||
|
||||
function CommandTBackspace()
|
||||
ruby $command_t.backspace
|
||||
endfunction
|
||||
|
||||
function CommandTDelete()
|
||||
ruby $command_t.delete
|
||||
endfunction
|
||||
|
||||
function CommandTAcceptSelection()
|
||||
ruby $command_t.accept_selection
|
||||
endfunction
|
||||
|
||||
function CommandTAcceptSelectionTab()
|
||||
ruby $command_t.accept_selection :command => 'tabe'
|
||||
endfunction
|
||||
|
||||
function CommandTAcceptSelectionSplit()
|
||||
ruby $command_t.accept_selection :command => 'sp'
|
||||
endfunction
|
||||
|
||||
function CommandTAcceptSelectionVSplit()
|
||||
ruby $command_t.accept_selection :command => 'vs'
|
||||
endfunction
|
||||
|
||||
function CommandTRefresh()
|
||||
ruby $command_t.refresh
|
||||
endfunction
|
||||
|
||||
function CommandTToggleFocus()
|
||||
ruby $command_t.toggle_focus
|
||||
endfunction
|
||||
|
||||
function CommandTCancel()
|
||||
ruby $command_t.cancel
|
||||
endfunction
|
||||
|
||||
function CommandTSelectNext()
|
||||
ruby $command_t.select_next
|
||||
endfunction
|
||||
|
||||
function CommandTSelectPrev()
|
||||
ruby $command_t.select_prev
|
||||
endfunction
|
||||
|
||||
function CommandTClear()
|
||||
ruby $command_t.clear
|
||||
endfunction
|
||||
|
||||
function CommandTCursorLeft()
|
||||
ruby $command_t.cursor_left
|
||||
endfunction
|
||||
|
||||
function CommandTCursorRight()
|
||||
ruby $command_t.cursor_right
|
||||
endfunction
|
||||
|
||||
function CommandTCursorEnd()
|
||||
ruby $command_t.cursor_end
|
||||
endfunction
|
||||
|
||||
function CommandTCursorStart()
|
||||
ruby $command_t.cursor_start
|
||||
endfunction
|
||||
|
||||
ruby << EOF
|
||||
# require Ruby files
|
||||
begin
|
||||
# prepare controller
|
||||
require 'command-t/vim'
|
||||
require 'command-t/controller'
|
||||
$command_t = CommandT::Controller.new
|
||||
rescue LoadError
|
||||
load_path_modified = false
|
||||
::VIM::evaluate('&runtimepath').to_s.split(',').each do |path|
|
||||
lib = "#{path}/ruby"
|
||||
if !$LOAD_PATH.include?(lib) and File.exist?(lib)
|
||||
$LOAD_PATH << lib
|
||||
load_path_modified = true
|
||||
end
|
||||
end
|
||||
retry if load_path_modified
|
||||
|
||||
# could get here if C extension was not compiled, or was compiled
|
||||
# for the wrong architecture or Ruby version
|
||||
require 'command-t/stub'
|
||||
$command_t = CommandT::Stub.new
|
||||
end
|
||||
EOF
|
|
@ -0,0 +1,6 @@
|
|||
Makefile
|
||||
*.o
|
||||
*.log
|
||||
ext.*
|
||||
!ext.c
|
||||
!ext.h
|
|
@ -0,0 +1,357 @@
|
|||
# Copyright 2010-2012 Wincent Colaiuta. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
require 'command-t/finder/buffer_finder'
|
||||
require 'command-t/finder/jump_finder'
|
||||
require 'command-t/finder/file_finder'
|
||||
require 'command-t/finder/tag_finder'
|
||||
require 'command-t/match_window'
|
||||
require 'command-t/prompt'
|
||||
require 'command-t/vim/path_utilities'
|
||||
|
||||
module CommandT
|
||||
class Controller
|
||||
include VIM::PathUtilities
|
||||
|
||||
def initialize
|
||||
@prompt = Prompt.new
|
||||
end
|
||||
|
||||
def show_buffer_finder
|
||||
@path = VIM::pwd
|
||||
@active_finder = buffer_finder
|
||||
show
|
||||
end
|
||||
|
||||
def show_jump_finder
|
||||
@path = VIM::pwd
|
||||
@active_finder = jump_finder
|
||||
show
|
||||
end
|
||||
|
||||
def show_tag_finder
|
||||
@path = VIM::pwd
|
||||
@active_finder = tag_finder
|
||||
show
|
||||
end
|
||||
|
||||
def show_file_finder
|
||||
# optional parameter will be desired starting directory, or ""
|
||||
@path = File.expand_path(::VIM::evaluate('a:arg'), VIM::pwd)
|
||||
@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
|
||||
|
||||
def hide
|
||||
@match_window.close
|
||||
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
|
||||
|
||||
def refresh
|
||||
return unless @active_finder && @active_finder.respond_to?(:flush)
|
||||
@active_finder.flush
|
||||
list_matches
|
||||
end
|
||||
|
||||
def flush
|
||||
@max_height = nil
|
||||
@min_height = nil
|
||||
@file_finder = nil
|
||||
@tag_finder = nil
|
||||
end
|
||||
|
||||
def handle_key
|
||||
key = ::VIM::evaluate('a:arg').to_i.chr
|
||||
if @focus == @prompt
|
||||
@prompt.add! key
|
||||
list_matches
|
||||
else
|
||||
@match_window.find key
|
||||
end
|
||||
end
|
||||
|
||||
def backspace
|
||||
if @focus == @prompt
|
||||
@prompt.backspace!
|
||||
list_matches
|
||||
end
|
||||
end
|
||||
|
||||
def delete
|
||||
if @focus == @prompt
|
||||
@prompt.delete!
|
||||
list_matches
|
||||
end
|
||||
end
|
||||
|
||||
def accept_selection options = {}
|
||||
selection = @match_window.selection
|
||||
hide
|
||||
open_selection(selection, options) unless selection.nil?
|
||||
end
|
||||
|
||||
def toggle_focus
|
||||
@focus.unfocus # old focus
|
||||
@focus = @focus == @prompt ? @match_window : @prompt
|
||||
@focus.focus # new focus
|
||||
end
|
||||
|
||||
def cancel
|
||||
hide
|
||||
end
|
||||
|
||||
def select_next
|
||||
@match_window.select_next
|
||||
end
|
||||
|
||||
def select_prev
|
||||
@match_window.select_prev
|
||||
end
|
||||
|
||||
def clear
|
||||
@prompt.clear!
|
||||
list_matches
|
||||
end
|
||||
|
||||
def cursor_left
|
||||
@prompt.cursor_left if @focus == @prompt
|
||||
end
|
||||
|
||||
def cursor_right
|
||||
@prompt.cursor_right if @focus == @prompt
|
||||
end
|
||||
|
||||
def cursor_end
|
||||
@prompt.cursor_end if @focus == @prompt
|
||||
end
|
||||
|
||||
def cursor_start
|
||||
@prompt.cursor_start if @focus == @prompt
|
||||
end
|
||||
|
||||
def leave
|
||||
@match_window.leave
|
||||
end
|
||||
|
||||
def unload
|
||||
@match_window.unload
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def show
|
||||
@initial_window = $curwin
|
||||
@initial_buffer = $curbuf
|
||||
@match_window = MatchWindow.new \
|
||||
:prompt => @prompt,
|
||||
:match_window_at_top => get_bool('g:CommandTMatchWindowAtTop'),
|
||||
:match_window_reverse => get_bool('g:CommandTMatchWindowReverse'),
|
||||
:min_height => min_height
|
||||
@focus = @prompt
|
||||
@prompt.focus
|
||||
register_for_key_presses
|
||||
clear # clears prompt and lists matches
|
||||
end
|
||||
|
||||
def max_height
|
||||
@max_height ||= get_number('g:CommandTMaxHeight') || 0
|
||||
end
|
||||
|
||||
def min_height
|
||||
@min_height ||= begin
|
||||
min_height = get_number('g:CommandTMinHeight') || 0
|
||||
min_height = max_height if max_height != 0 && min_height > max_height
|
||||
min_height
|
||||
end
|
||||
end
|
||||
|
||||
def get_number name
|
||||
VIM::exists?(name) ? ::VIM::evaluate("#{name}").to_i : nil
|
||||
end
|
||||
|
||||
def get_bool name
|
||||
VIM::exists?(name) ? ::VIM::evaluate("#{name}").to_i != 0 : nil
|
||||
end
|
||||
|
||||
def get_string name
|
||||
VIM::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 VIM::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
|
||||
|
||||
# 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 default_open_command
|
||||
if !get_bool('&hidden') && get_bool('&modified')
|
||||
'sp'
|
||||
else
|
||||
'e'
|
||||
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
|
||||
ensure_appropriate_window_selection
|
||||
|
||||
@active_finder.open_selection command, selection, options
|
||||
end
|
||||
|
||||
def map key, function, param = nil
|
||||
::VIM::command "noremap <silent> <buffer> #{key} " \
|
||||
":call CommandT#{function}(#{param})<CR>"
|
||||
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 = '<>`@#~!"$%&/()=+*-_.,;:?\\\'{}[] ' # and space
|
||||
(numbers + lowercase + uppercase + punctuation).each_byte do |b|
|
||||
map "<Char-#{b}>", 'HandleKey', b
|
||||
end
|
||||
|
||||
# "special" keys (overridable by settings)
|
||||
{
|
||||
'AcceptSelection' => '<CR>',
|
||||
'AcceptSelectionSplit' => ['<C-CR>', '<C-s>'],
|
||||
'AcceptSelectionTab' => '<C-t>',
|
||||
'AcceptSelectionVSplit' => '<C-v>',
|
||||
'Backspace' => '<BS>',
|
||||
'Cancel' => ['<C-c>', '<Esc>'],
|
||||
'Clear' => '<C-u>',
|
||||
'CursorEnd' => '<C-e>',
|
||||
'CursorLeft' => ['<Left>', '<C-h>'],
|
||||
'CursorRight' => ['<Right>', '<C-l>'],
|
||||
'CursorStart' => '<C-a>',
|
||||
'Delete' => '<Del>',
|
||||
'Refresh' => '<C-f>',
|
||||
'SelectNext' => ['<C-n>', '<C-j>', '<Down>'],
|
||||
'SelectPrev' => ['<C-p>', '<C-k>', '<Up>'],
|
||||
'ToggleFocus' => '<Tab>',
|
||||
}.each do |key, value|
|
||||
if override = 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 == '<Esc>' && term =~ /\A(screen|xterm|vt100)/
|
||||
map mapping, key
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the desired maximum number of matches, based on available
|
||||
# vertical space and the g:CommandTMaxHeight option.
|
||||
def match_limit
|
||||
limit = VIM::Screen.lines - 5
|
||||
limit = 1 if limit < 0
|
||||
limit = [limit, max_height].min if max_height > 0
|
||||
limit
|
||||
end
|
||||
|
||||
def list_matches
|
||||
matches = @active_finder.sorted_matches_for @prompt.abbrev, :limit => match_limit
|
||||
@match_window.matches = matches
|
||||
end
|
||||
|
||||
def buffer_finder
|
||||
@buffer_finder ||= CommandT::BufferFinder.new
|
||||
end
|
||||
|
||||
def file_finder
|
||||
@file_finder ||= CommandT::FileFinder.new nil,
|
||||
:max_depth => get_number('g:CommandTMaxDepth'),
|
||||
:max_files => get_number('g:CommandTMaxFiles'),
|
||||
:max_caches => get_number('g:CommandTMaxCachedDirectories'),
|
||||
:always_show_dot_files => get_bool('g:CommandTAlwaysShowDotFiles'),
|
||||
:never_show_dot_files => get_bool('g:CommandTNeverShowDotFiles'),
|
||||
:scan_dot_directories => get_bool('g:CommandTScanDotDirectories')
|
||||
end
|
||||
|
||||
def jump_finder
|
||||
@jump_finder ||= CommandT::JumpFinder.new
|
||||
end
|
||||
|
||||
def tag_finder
|
||||
@tag_finder ||= CommandT::TagFinder.new \
|
||||
:include_filenames => get_bool('g:CommandTTagIncludeFilenames')
|
||||
end
|
||||
end # class Controller
|
||||
end # module commandT
|
|
@ -0,0 +1,24 @@
|
|||
# Copyright 2010 Wincent Colaiuta. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
CFLAGS += -std=c99 -Wall -Wextra -Wno-unused-parameter
|
|
@ -0,0 +1,65 @@
|
|||
// Copyright 2010 Wincent Colaiuta. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "match.h"
|
||||
#include "matcher.h"
|
||||
|
||||
VALUE mCommandT = 0; // module CommandT
|
||||
VALUE cCommandTMatch = 0; // class CommandT::Match
|
||||
VALUE cCommandTMatcher = 0; // class CommandT::Matcher
|
||||
|
||||
VALUE CommandT_option_from_hash(const char *option, VALUE hash)
|
||||
{
|
||||
if (NIL_P(hash))
|
||||
return Qnil;
|
||||
VALUE 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::Match
|
||||
cCommandTMatch = rb_define_class_under(mCommandT, "Match", rb_cObject);
|
||||
|
||||
// methods
|
||||
rb_define_method(cCommandTMatch, "initialize", CommandTMatch_initialize, -1);
|
||||
rb_define_method(cCommandTMatch, "matches?", CommandTMatch_matches, 0);
|
||||
rb_define_method(cCommandTMatch, "to_s", CommandTMatch_to_s, 0);
|
||||
|
||||
// attributes
|
||||
rb_define_attr(cCommandTMatch, "score", Qtrue, Qfalse); // reader: true, writer: false
|
||||
|
||||
// class CommandT::Matcher
|
||||
cCommandTMatcher = rb_define_class_under(mCommandT, "Matcher", rb_cObject);
|
||||
|
||||
// methods
|
||||
rb_define_method(cCommandTMatcher, "initialize", CommandTMatcher_initialize, -1);
|
||||
rb_define_method(cCommandTMatcher, "sorted_matches_for", CommandTMatcher_sorted_matches_for, 2);
|
||||
rb_define_method(cCommandTMatcher, "matches_for", CommandTMatcher_matches_for, 1);
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright 2010 Wincent Colaiuta. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <ruby.h>
|
||||
|
||||
extern VALUE mCommandT; // module CommandT
|
||||
extern VALUE cCommandTMatch; // class CommandT::Match
|
||||
extern VALUE cCommandTMatcher; // class CommandT::Matcher
|
||||
|
||||
// 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 macro.
|
||||
#define ruby_inspect(obj) rb_funcall(rb_mKernel, rb_intern("p"), 1, obj)
|
|
@ -0,0 +1,34 @@
|
|||
# Copyright 2010 Wincent Colaiuta. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
require 'mkmf'
|
||||
|
||||
def missing item
|
||||
puts "couldn't find #{item} (required)"
|
||||
exit 1
|
||||
end
|
||||
|
||||
RbConfig::MAKEFILE_CONFIG['CC'] = ENV['CC'] if ENV['CC']
|
||||
|
||||
have_header('ruby.h') or missing('ruby.h')
|
||||
create_makefile('ext')
|
|
@ -0,0 +1,54 @@
|
|||
# Copyright 2010-2012 Wincent Colaiuta. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
require 'command-t/ext' # CommandT::Matcher
|
||||
|
||||
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
|
||||
include VIM::PathUtilities
|
||||
|
||||
def initialize path = Dir.pwd, options = {}
|
||||
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 # class Finder
|
||||
end # CommandT
|
|
@ -0,0 +1,35 @@
|
|||
# Copyright 2010-2011 Wincent Colaiuta. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
require 'command-t/ext' # CommandT::Matcher
|
||||
require 'command-t/scanner/buffer_scanner'
|
||||
require 'command-t/finder'
|
||||
|
||||
module CommandT
|
||||
class BufferFinder < Finder
|
||||
def initialize
|
||||
@scanner = BufferScanner.new
|
||||
@matcher = Matcher.new @scanner, :always_show_dot_files => true
|
||||
end
|
||||
end # class BufferFinder
|
||||
end # CommandT
|
|
@ -0,0 +1,39 @@
|
|||
# Copyright 2010-2012 Wincent Colaiuta. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
require 'command-t/ext' # CommandT::Matcher
|
||||
require 'command-t/finder'
|
||||
require 'command-t/scanner/file_scanner'
|
||||
|
||||
module CommandT
|
||||
class FileFinder < Finder
|
||||
def initialize path = Dir.pwd, options = {}
|
||||
@scanner = FileScanner.new path, options
|
||||
@matcher = Matcher.new @scanner, options
|
||||
end
|
||||
|
||||
def flush
|
||||
@scanner.flush
|
||||
end
|
||||
end # class FileFinder
|
||||
end # CommandT
|
|
@ -0,0 +1,35 @@
|
|||
# Copyright 2011 Wincent Colaiuta. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
require 'command-t/ext' # CommandT::Matcher
|
||||
require 'command-t/scanner/jump_scanner'
|
||||
require 'command-t/finder'
|
||||
|
||||
module CommandT
|
||||
class JumpFinder < Finder
|
||||
def initialize
|
||||
@scanner = JumpScanner.new
|
||||
@matcher = Matcher.new @scanner, :always_show_dot_files => true
|
||||
end
|
||||
end # class JumpFinder
|
||||
end # module CommandT
|
|
@ -0,0 +1,44 @@
|
|||
# Copyright 2011-2012 Wincent Colaiuta. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
require 'command-t/ext' # CommandT::Matcher
|
||||
require 'command-t/scanner/tag_scanner'
|
||||
require 'command-t/finder'
|
||||
|
||||
module CommandT
|
||||
class TagFinder < Finder
|
||||
def initialize options = {}
|
||||
@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
|
||||
end # class TagFinder
|
||||
end # module CommandT
|
|
@ -0,0 +1,189 @@
|
|||
// Copyright 2010 Wincent Colaiuta. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "match.h"
|
||||
#include "ext.h"
|
||||
#include "ruby_compat.h"
|
||||
|
||||
// use a struct to make passing params during recursion easier
|
||||
typedef struct
|
||||
{
|
||||
char *str_p; // pointer to string to be searched
|
||||
long str_len; // length of same
|
||||
char *abbrev_p; // pointer to search string (abbreviation)
|
||||
long abbrev_len; // length of same
|
||||
double max_score_per_char;
|
||||
int dot_file; // boolean: true if str is a dot-file
|
||||
int always_show_dot_files; // boolean
|
||||
int never_show_dot_files; // boolean
|
||||
} matchinfo_t;
|
||||
|
||||
double recursive_match(matchinfo_t *m, // sharable meta-data
|
||||
long str_idx, // where in the path string to start
|
||||
long abbrev_idx, // where in the search string to start
|
||||
long last_idx, // location of last matched character
|
||||
double score) // cumulative score so far
|
||||
{
|
||||
double seen_score = 0; // remember best score seen via recursion
|
||||
int dot_file_match = 0; // true if abbrev matches a dot-file
|
||||
int dot_search = 0; // true if searching for a dot
|
||||
|
||||
for (long i = abbrev_idx; i < m->abbrev_len; i++)
|
||||
{
|
||||
char c = m->abbrev_p[i];
|
||||
if (c == '.')
|
||||
dot_search = 1;
|
||||
int found = 0;
|
||||
for (long j = str_idx; j < m->str_len; j++, str_idx++)
|
||||
{
|
||||
char d = m->str_p[j];
|
||||
if (d == '.')
|
||||
{
|
||||
if (j == 0 || m->str_p[j - 1] == '/')
|
||||
{
|
||||
m->dot_file = 1; // this is a dot-file
|
||||
if (dot_search) // and we are searching for a dot
|
||||
dot_file_match = 1; // so this must be a match
|
||||
}
|
||||
}
|
||||
else if (d >= 'A' && d <= 'Z')
|
||||
d += 'a' - 'A'; // add 32 to downcase
|
||||
if (c == d)
|
||||
{
|
||||
found = 1;
|
||||
dot_search = 0;
|
||||
|
||||
// calculate score
|
||||
double score_for_char = m->max_score_per_char;
|
||||
long distance = j - last_idx;
|
||||
if (distance > 1)
|
||||
{
|
||||
double factor = 1.0;
|
||||
char last = m->str_p[j - 1];
|
||||
char curr = m->str_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->str_len)
|
||||
{
|
||||
// bump cursor one char to the right and
|
||||
// use recursion to try and find a better match
|
||||
double sub_score = recursive_match(m, j, i, last_idx, score);
|
||||
if (sub_score > seen_score)
|
||||
seen_score = sub_score;
|
||||
}
|
||||
|
||||
score += score_for_char;
|
||||
last_idx = str_idx++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
return 0.0;
|
||||
}
|
||||
if (m->dot_file)
|
||||
{
|
||||
if (m->never_show_dot_files ||
|
||||
(!dot_file_match && !m->always_show_dot_files))
|
||||
return 0.0;
|
||||
}
|
||||
return (score > seen_score) ? score : seen_score;
|
||||
}
|
||||
|
||||
// Match.new abbrev, string, options = {}
|
||||
VALUE CommandTMatch_initialize(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
// process arguments: 2 mandatory, 1 optional
|
||||
VALUE str, abbrev, options;
|
||||
if (rb_scan_args(argc, argv, "21", &str, &abbrev, &options) == 2)
|
||||
options = Qnil;
|
||||
str = StringValue(str);
|
||||
abbrev = StringValue(abbrev); // already downcased by caller
|
||||
|
||||
// check optional options hash for overrides
|
||||
VALUE always_show_dot_files = CommandT_option_from_hash("always_show_dot_files", options);
|
||||
VALUE never_show_dot_files = CommandT_option_from_hash("never_show_dot_files", options);
|
||||
|
||||
matchinfo_t m;
|
||||
m.str_p = RSTRING_PTR(str);
|
||||
m.str_len = RSTRING_LEN(str);
|
||||
m.abbrev_p = RSTRING_PTR(abbrev);
|
||||
m.abbrev_len = RSTRING_LEN(abbrev);
|
||||
m.max_score_per_char = (1.0 / m.str_len + 1.0 / m.abbrev_len) / 2;
|
||||
m.dot_file = 0;
|
||||
m.always_show_dot_files = always_show_dot_files == Qtrue;
|
||||
m.never_show_dot_files = never_show_dot_files == Qtrue;
|
||||
|
||||
// calculate score
|
||||
double score = 1.0;
|
||||
if (m.abbrev_len == 0) // special case for zero-length search string
|
||||
{
|
||||
// filter out dot files
|
||||
if (!m.always_show_dot_files)
|
||||
{
|
||||
for (long i = 0; i < m.str_len; i++)
|
||||
{
|
||||
char c = m.str_p[i];
|
||||
if (c == '.' && (i == 0 || m.str_p[i - 1] == '/'))
|
||||
{
|
||||
score = 0.0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else // normal case
|
||||
score = recursive_match(&m, 0, 0, 0, 0.0);
|
||||
|
||||
// clean-up and final book-keeping
|
||||
rb_iv_set(self, "@score", rb_float_new(score));
|
||||
rb_iv_set(self, "@str", str);
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE CommandTMatch_matches(VALUE self)
|
||||
{
|
||||
double score = NUM2DBL(rb_iv_get(self, "@score"));
|
||||
return score > 0 ? Qtrue : Qfalse;
|
||||
}
|
||||
|
||||
VALUE CommandTMatch_to_s(VALUE self)
|
||||
{
|
||||
return rb_iv_get(self, "@str");
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright 2010 Wincent Colaiuta. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <ruby.h>
|
||||
|
||||
extern VALUE CommandTMatch_initialize(int argc, VALUE *argv, VALUE self);
|
||||
extern VALUE CommandTMatch_matches(VALUE self);
|
||||
extern VALUE CommandTMatch_score(VALUE self);
|
||||
extern VALUE CommandTMatch_to_s(VALUE self);
|
|
@ -0,0 +1,445 @@
|
|||
# Copyright 2010-2012 Wincent Colaiuta. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
require 'ostruct'
|
||||
require 'command-t/settings'
|
||||
|
||||
module CommandT
|
||||
class MatchWindow
|
||||
SELECTION_MARKER = '> '
|
||||
MARKER_LENGTH = SELECTION_MARKER.length
|
||||
UNSELECTED_MARKER = ' ' * MARKER_LENGTH
|
||||
MH_START = '<commandt>'
|
||||
MH_END = '</commandt>'
|
||||
@@buffer = nil
|
||||
|
||||
def initialize options = {}
|
||||
@prompt = options[:prompt]
|
||||
@reverse_list = options[:match_window_reverse]
|
||||
@min_height = options[:min_height]
|
||||
|
||||
# save existing window dimensions so we can restore them later
|
||||
@windows = []
|
||||
(0..(::VIM::Window.count - 1)).each do |i|
|
||||
@windows << OpenStruct.new(:index => i,
|
||||
:height => ::VIM::Window[i].height,
|
||||
:width => ::VIM::Window[i].width)
|
||||
end
|
||||
|
||||
# global settings (must manually save and restore)
|
||||
@settings = Settings.new
|
||||
::VIM::set_option 'timeout' # ensure mappings timeout
|
||||
::VIM::set_option 'timeoutlen=0' # respond immediately to mappings
|
||||
::VIM::set_option 'nohlsearch' # don't highlight search strings
|
||||
::VIM::set_option 'noinsertmode' # don't make Insert mode the default
|
||||
::VIM::set_option 'noshowcmd' # don't show command info on last line
|
||||
::VIM::set_option 'report=9999' # don't show "X lines changed" reports
|
||||
::VIM::set_option 'sidescroll=0' # don't sidescroll in jumps
|
||||
::VIM::set_option 'sidescrolloff=0' # don't sidescroll automatically
|
||||
::VIM::set_option 'noequalalways' # don't auto-balance window sizes
|
||||
|
||||
# show match window
|
||||
split_location = options[:match_window_at_top] ? 'topleft' : 'botright'
|
||||
if @@buffer # still have buffer from last time
|
||||
::VIM::command "silent! #{split_location} #{@@buffer.number}sbuffer"
|
||||
raise "Can't re-open GoToFile buffer" unless $curbuf.number == @@buffer.number
|
||||
$curwin.height = 1
|
||||
else # creating match window for first time and set it up
|
||||
split_command = "silent! #{split_location} 1split GoToFile"
|
||||
[
|
||||
split_command,
|
||||
'setlocal bufhidden=unload', # unload buf when no longer displayed
|
||||
'setlocal buftype=nofile', # buffer is not related to any file
|
||||
'setlocal nomodifiable', # prevent manual edits
|
||||
'setlocal noswapfile', # don't create a swapfile
|
||||
'setlocal nowrap', # don't soft-wrap
|
||||
'setlocal nonumber', # don't show line numbers
|
||||
'setlocal nolist', # don't use List mode (visible tabs etc)
|
||||
'setlocal foldcolumn=0', # don't show a fold column at side
|
||||
'setlocal foldlevel=99', # don't fold anything
|
||||
'setlocal nocursorline', # don't highlight line cursor is on
|
||||
'setlocal nospell', # spell-checking off
|
||||
'setlocal nobuflisted', # don't show up in the buffer list
|
||||
'setlocal textwidth=0' # don't hard-wrap (break long lines)
|
||||
].each { |command| ::VIM::command command }
|
||||
|
||||
# don't show the color column
|
||||
::VIM::command 'setlocal colorcolumn=0' if VIM::exists?('+colorcolumn')
|
||||
|
||||
# don't show relative line numbers
|
||||
::VIM::command 'setlocal norelativenumber' if VIM::exists?('+relativenumber')
|
||||
|
||||
# sanity check: make sure the buffer really was created
|
||||
raise "Can't find GoToFile buffer" unless $curbuf.name.match /GoToFile\z/
|
||||
@@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 --$"'
|
||||
::VIM::command 'setlocal synmaxcol=9999'
|
||||
|
||||
if VIM::has_conceal?
|
||||
::VIM::command 'setlocal conceallevel=2'
|
||||
::VIM::command 'setlocal 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 Visual'
|
||||
::VIM::command 'highlight link CommandTNoEntries Error'
|
||||
::VIM::evaluate 'clearmatches()'
|
||||
|
||||
# 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. <C-W q>, <C-W k> etc)
|
||||
::VIM::command 'autocmd! * <buffer>'
|
||||
::VIM::command 'autocmd BufLeave <buffer> silent! ruby $command_t.leave'
|
||||
::VIM::command 'autocmd BufUnload <buffer> silent! ruby $command_t.unload'
|
||||
|
||||
@has_focus = false
|
||||
@selection = nil
|
||||
@abbrev = ''
|
||||
@window = $curwin
|
||||
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
|
||||
::VIM::command 'silent! bwipeout! GoToFile'
|
||||
@@buffer = nil
|
||||
else
|
||||
::VIM::command "silent! bunload! #{@@buffer.number}"
|
||||
end
|
||||
end
|
||||
|
||||
def leave
|
||||
close
|
||||
unload
|
||||
end
|
||||
|
||||
def unload
|
||||
restore_window_dimensions
|
||||
@settings.restore
|
||||
@prompt.dispose
|
||||
show_cursor
|
||||
end
|
||||
|
||||
def add! char
|
||||
@abbrev += char
|
||||
end
|
||||
|
||||
def backspace!
|
||||
@abbrev.chop!
|
||||
end
|
||||
|
||||
def select_next
|
||||
if @selection < @matches.length - 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
|
||||
else
|
||||
# (possibly) loop or scroll
|
||||
end
|
||||
end
|
||||
|
||||
def select_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
|
||||
else
|
||||
# (possibly) loop or scroll
|
||||
end
|
||||
end
|
||||
|
||||
def matches= matches
|
||||
matches = matches.reverse if @reverse_list
|
||||
if matches != @matches
|
||||
@matches = matches
|
||||
@selection = @reverse_list ? @matches.length - 1 : 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 Visual'
|
||||
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? or @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.each_with_index do |match, idx|
|
||||
if match[0, @find_string.length].casecmp(@find_string) == 0
|
||||
old_selection = @selection
|
||||
@selection = 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 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 = [@selection + 1, 0]
|
||||
end
|
||||
|
||||
def print_error msg
|
||||
return unless VIM::Window.select(@window)
|
||||
unlock
|
||||
clear
|
||||
@window.height = @min_height > 0 ? @min_height : 1
|
||||
@@buffer[1] = "-- #{msg} --"
|
||||
lock
|
||||
end
|
||||
|
||||
def restore_window_dimensions
|
||||
# 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
|
||||
@windows.each do |w|
|
||||
# beware: window may be nil
|
||||
if window = ::VIM::Window[w.index]
|
||||
window.height = w.height
|
||||
window.width = w.width
|
||||
end
|
||||
end
|
||||
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.chars.to_a
|
||||
match.chars.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[idx + 1] = match_text_for_idx idx
|
||||
lock
|
||||
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
|
||||
actual_lines = 1
|
||||
@window_width = @window.width # update cached value
|
||||
max_lines = VIM::Screen.lines - 5
|
||||
max_lines = 1 if max_lines < 0
|
||||
actual_lines = match_count < @min_height ? @min_height : match_count
|
||||
actual_lines = max_lines if actual_lines > max_lines
|
||||
@window.height = actual_lines
|
||||
(1..actual_lines).each do |line|
|
||||
idx = line - 1
|
||||
if @@buffer.count >= line
|
||||
@@buffer[line] = match_text_for_idx idx
|
||||
else
|
||||
@@buffer.append line - 1, match_text_for_idx(idx)
|
||||
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 3 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 cleared -> :hi! clear Cursor
|
||||
highlight = VIM::capture 'silent! 0verbose highlight Cursor'
|
||||
|
||||
if highlight =~ /^Cursor\s+xxx\s+links to (\w+)/
|
||||
"link Cursor #{$~[1]}"
|
||||
elsif highlight =~ /^Cursor\s+xxx\s+cleared/
|
||||
'clear Cursor'
|
||||
elsif highlight =~ /Cursor\s+xxx\s+(.+)/
|
||||
"Cursor #{$~[1]}"
|
||||
else # likely cause E411 Cursor highlight group not found
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def hide_cursor
|
||||
if @cursor_highlight
|
||||
::VIM::command 'highlight Cursor NONE'
|
||||
end
|
||||
end
|
||||
|
||||
def show_cursor
|
||||
if @cursor_highlight
|
||||
::VIM::command "highlight #{@cursor_highlight}"
|
||||
end
|
||||
end
|
||||
|
||||
def lock
|
||||
::VIM::command 'setlocal nomodifiable'
|
||||
end
|
||||
|
||||
def unlock
|
||||
::VIM::command 'setlocal modifiable'
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,164 @@
|
|||
// Copyright 2010 Wincent Colaiuta. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <stdlib.h> /* for qsort() */
|
||||
#include <string.h> /* for strcmp() */
|
||||
#include "matcher.h"
|
||||
#include "ext.h"
|
||||
#include "ruby_compat.h"
|
||||
|
||||
// comparison function for use with qsort
|
||||
int comp_alpha(const void *a, const void *b)
|
||||
{
|
||||
VALUE a_val = *(VALUE *)a;
|
||||
VALUE b_val = *(VALUE *)b;
|
||||
ID to_s = rb_intern("to_s");
|
||||
|
||||
VALUE a_str = rb_funcall(a_val, to_s, 0);
|
||||
VALUE b_str = rb_funcall(b_val, to_s, 0);
|
||||
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 comp_score(const void *a, const void *b)
|
||||
{
|
||||
VALUE a_val = *(VALUE *)a;
|
||||
VALUE b_val = *(VALUE *)b;
|
||||
ID score = rb_intern("score");
|
||||
double a_score = RFLOAT_VALUE(rb_funcall(a_val, score, 0));
|
||||
double b_score = RFLOAT_VALUE(rb_funcall(b_val, score, 0));
|
||||
if (a_score > b_score)
|
||||
return -1; // a scores higher, a should appear sooner
|
||||
else if (a_score < b_score)
|
||||
return 1; // b scores higher, a should appear later
|
||||
else
|
||||
return comp_alpha(a, b);
|
||||
}
|
||||
|
||||
VALUE CommandTMatcher_initialize(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
// process arguments: 1 mandatory, 1 optional
|
||||
VALUE scanner, options;
|
||||
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
|
||||
VALUE always_show_dot_files = CommandT_option_from_hash("always_show_dot_files", options);
|
||||
if (always_show_dot_files != Qtrue)
|
||||
always_show_dot_files = Qfalse;
|
||||
VALUE never_show_dot_files = CommandT_option_from_hash("never_show_dot_files", options);
|
||||
if (never_show_dot_files != Qtrue)
|
||||
never_show_dot_files = Qfalse;
|
||||
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;
|
||||
}
|
||||
|
||||
VALUE CommandTMatcher_sorted_matches_for(VALUE self, VALUE abbrev, VALUE options)
|
||||
{
|
||||
// process optional options hash
|
||||
VALUE limit_option = CommandT_option_from_hash("limit", options);
|
||||
|
||||
// get unsorted matches
|
||||
VALUE matches = CommandTMatcher_matches_for(self, abbrev);
|
||||
|
||||
abbrev = StringValue(abbrev);
|
||||
if (RSTRING_LEN(abbrev) == 0 ||
|
||||
(RSTRING_LEN(abbrev) == 1 && RSTRING_PTR(abbrev)[0] == '.'))
|
||||
// alphabetic order if search string is only "" or "."
|
||||
qsort(RARRAY_PTR(matches), RARRAY_LEN(matches), sizeof(VALUE), comp_alpha);
|
||||
else
|
||||
// for all other non-empty search strings, sort by score
|
||||
qsort(RARRAY_PTR(matches), RARRAY_LEN(matches), sizeof(VALUE), comp_score);
|
||||
|
||||
// apply optional limit option
|
||||
long limit = NIL_P(limit_option) ? 0 : NUM2LONG(limit_option);
|
||||
if (limit == 0 || RARRAY_LEN(matches) < limit)
|
||||
limit = RARRAY_LEN(matches);
|
||||
|
||||
// will return an array of strings, not an array of Match objects
|
||||
for (long i = 0; i < limit; i++)
|
||||
{
|
||||
VALUE str = rb_funcall(RARRAY_PTR(matches)[i], rb_intern("to_s"), 0);
|
||||
RARRAY_PTR(matches)[i] = str;
|
||||
}
|
||||
|
||||
// trim off any items beyond the limit
|
||||
if (limit < RARRAY_LEN(matches))
|
||||
(void)rb_funcall(matches, rb_intern("slice!"), 2, LONG2NUM(limit),
|
||||
LONG2NUM(RARRAY_LEN(matches) - limit));
|
||||
return matches;
|
||||
}
|
||||
|
||||
VALUE CommandTMatcher_matches_for(VALUE self, VALUE abbrev)
|
||||
{
|
||||
if (NIL_P(abbrev))
|
||||
rb_raise(rb_eArgError, "nil abbrev");
|
||||
VALUE matches = rb_ary_new();
|
||||
VALUE scanner = rb_iv_get(self, "@scanner");
|
||||
VALUE always_show_dot_files = rb_iv_get(self, "@always_show_dot_files");
|
||||
VALUE never_show_dot_files = rb_iv_get(self, "@never_show_dot_files");
|
||||
VALUE options = Qnil;
|
||||
if (always_show_dot_files == Qtrue)
|
||||
{
|
||||
options = rb_hash_new();
|
||||
rb_hash_aset(options, ID2SYM(rb_intern("always_show_dot_files")), always_show_dot_files);
|
||||
}
|
||||
else if (never_show_dot_files == Qtrue)
|
||||
{
|
||||
options = rb_hash_new();
|
||||
rb_hash_aset(options, ID2SYM(rb_intern("never_show_dot_files")), never_show_dot_files);
|
||||
}
|
||||
abbrev = rb_funcall(abbrev, rb_intern("downcase"), 0);
|
||||
VALUE paths = rb_funcall(scanner, rb_intern("paths"), 0);
|
||||
for (long i = 0, max = RARRAY_LEN(paths); i < max; i++)
|
||||
{
|
||||
VALUE path = RARRAY_PTR(paths)[i];
|
||||
VALUE match = rb_funcall(cCommandTMatch, rb_intern("new"), 3, path, abbrev, options);
|
||||
if (rb_funcall(match, rb_intern("matches?"), 0) == Qtrue)
|
||||
rb_funcall(matches, rb_intern("push"), 1, match);
|
||||
}
|
||||
return matches;
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
// Copyright 2010 Wincent Colaiuta. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <ruby.h>
|
||||
|
||||
extern VALUE CommandTMatcher_initialize(int argc, VALUE *argv, VALUE self);
|
||||
extern VALUE CommandTMatcher_sorted_matches_for(VALUE self, VALUE abbrev, VALUE options);
|
||||
|
||||
// most likely the function will be subsumed by the sorted_matcher_for function
|
||||
extern VALUE CommandTMatcher_matches_for(VALUE self, VALUE abbrev);
|
|
@ -0,0 +1,165 @@
|
|||
# Copyright 2010 Wincent Colaiuta. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
module CommandT
|
||||
# Abuse the status line as a prompt.
|
||||
class Prompt
|
||||
attr_accessor :abbrev
|
||||
|
||||
def initialize
|
||||
@abbrev = '' # abbreviation entered so far
|
||||
@col = 0 # cursor position
|
||||
@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
|
||||
|
||||
# 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 redraw
|
||||
if @has_focus
|
||||
prompt_highlight = 'Comment'
|
||||
normal_highlight = 'None'
|
||||
cursor_highlight = 'Underlined'
|
||||
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
|
||||
|
||||
def focus
|
||||
unless @has_focus
|
||||
@has_focus = true
|
||||
redraw
|
||||
end
|
||||
end
|
||||
|
||||
def unfocus
|
||||
if @has_focus
|
||||
@has_focus = false
|
||||
redraw
|
||||
end
|
||||
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) and (text = args.shift) do
|
||||
text = VIM::escape_for_single_quotes text
|
||||
::VIM::command "echohl #{highlight}"
|
||||
::VIM::command "echon '#{text}'"
|
||||
end
|
||||
::VIM::command 'echohl None'
|
||||
end
|
||||
end # class Prompt
|
||||
end # module CommandT
|
|
@ -0,0 +1,49 @@
|
|||
// Copyright 2010 Wincent Colaiuta. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <ruby.h>
|
||||
|
||||
// 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
|
|
@ -0,0 +1,28 @@
|
|||
# Copyright 2010-2011 Wincent Colaiuta. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
require 'command-t/vim'
|
||||
|
||||
module CommandT
|
||||
class Scanner; end
|
||||
end # module CommandT
|
|
@ -0,0 +1,42 @@
|
|||
# Copyright 2010-2011 Wincent Colaiuta. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
require 'command-t/vim'
|
||||
require 'command-t/vim/path_utilities'
|
||||
require 'command-t/scanner'
|
||||
|
||||
module CommandT
|
||||
# Returns a list of all open buffers.
|
||||
class BufferScanner < Scanner
|
||||
include VIM::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 # class BufferScanner
|
||||
end # module CommandT
|
|
@ -0,0 +1,101 @@
|
|||
# Copyright 2010-2011 Wincent Colaiuta. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
require 'command-t/vim'
|
||||
require 'command-t/scanner'
|
||||
|
||||
module CommandT
|
||||
# Reads the current directory recursively for the paths to all regular files.
|
||||
class FileScanner < Scanner
|
||||
class FileLimitExceeded < ::RuntimeError; end
|
||||
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] || 10_000
|
||||
@max_caches = options[:max_caches] || 1
|
||||
@scan_dot_directories = options[:scan_dot_directories] || false
|
||||
end
|
||||
|
||||
def paths
|
||||
return @paths[@path] if @paths.has_key?(@path)
|
||||
begin
|
||||
ensure_cache_under_limit
|
||||
@paths[@path] = []
|
||||
@depth = 0
|
||||
@files = 0
|
||||
@prefix_len = @path.chomp('/').length
|
||||
add_paths_for_directory @path, @paths[@path]
|
||||
rescue FileLimitExceeded
|
||||
end
|
||||
@paths[@path]
|
||||
end
|
||||
|
||||
def flush
|
||||
@paths = {}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
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
|
||||
# first strip common prefix (@path) from path to match VIM's behavior
|
||||
path = path[(@prefix_len + 1)..-1]
|
||||
path = VIM::escape_for_single_quotes path
|
||||
::VIM::evaluate("empty(expand(fnameescape('#{path}')))").to_i == 1
|
||||
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
|
||||
raise FileLimitExceeded if @files > @max_files
|
||||
accumulator << path[@prefix_len + 1..-1]
|
||||
elsif File.directory?(path)
|
||||
next if @depth >= @max_depth
|
||||
next if (entry.match(/\A\./) && !@scan_dot_directories)
|
||||
@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
|
||||
end
|
||||
end # class FileScanner
|
||||
end # module CommandT
|
|
@ -0,0 +1,54 @@
|
|||
# Copyright 2011 Wincent Colaiuta. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
require 'command-t/vim'
|
||||
require 'command-t/vim/path_utilities'
|
||||
require 'command-t/scanner'
|
||||
|
||||
module CommandT
|
||||
# Returns a list of files in the jumplist.
|
||||
class JumpScanner < Scanner
|
||||
include VIM::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 # class JumpScanner
|
||||
end # module CommandT
|
|
@ -0,0 +1,49 @@
|
|||
# Copyright 2011-2012 Wincent Colaiuta. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
require 'command-t/vim'
|
||||
require 'command-t/scanner'
|
||||
|
||||
module CommandT
|
||||
class TagScanner < Scanner
|
||||
attr_reader :include_filenames
|
||||
|
||||
def initialize options = {}
|
||||
@include_filenames = options[:include_filenames] || false
|
||||
end
|
||||
|
||||
def paths
|
||||
taglist.map do |tag|
|
||||
path = tag['name']
|
||||
path << ":#{tag['filename']}" if @include_filenames
|
||||
path
|
||||
end.uniq.sort
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def taglist
|
||||
::VIM::evaluate 'taglist(".")'
|
||||
end
|
||||
end # class TagScanner
|
||||
end # module CommandT
|
|
@ -0,0 +1,77 @@
|
|||
# Copyright 2010 Wincent Colaiuta. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
module CommandT
|
||||
# Convenience class for saving and restoring global settings.
|
||||
class Settings
|
||||
def initialize
|
||||
save
|
||||
end
|
||||
|
||||
def save
|
||||
@timeoutlen = get_number 'timeoutlen'
|
||||
@report = get_number 'report'
|
||||
@sidescroll = get_number 'sidescroll'
|
||||
@sidescrolloff = get_number 'sidescrolloff'
|
||||
@timeout = get_bool 'timeout'
|
||||
@equalalways = get_bool 'equalalways'
|
||||
@hlsearch = get_bool 'hlsearch'
|
||||
@insertmode = get_bool 'insertmode'
|
||||
@showcmd = get_bool 'showcmd'
|
||||
end
|
||||
|
||||
def restore
|
||||
set_number 'timeoutlen', @timeoutlen
|
||||
set_number 'report', @report
|
||||
set_number 'sidescroll', @sidescroll
|
||||
set_number 'sidescrolloff', @sidescrolloff
|
||||
set_bool 'timeout', @timeout
|
||||
set_bool 'equalalways', @equalalways
|
||||
set_bool 'hlsearch', @hlsearch
|
||||
set_bool 'insertmode', @insertmode
|
||||
set_bool 'showcmd', @showcmd
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def get_number setting
|
||||
::VIM::evaluate("&#{setting}").to_i
|
||||
end
|
||||
|
||||
def get_bool setting
|
||||
::VIM::evaluate("&#{setting}").to_i == 1
|
||||
end
|
||||
|
||||
def set_number setting, value
|
||||
::VIM::set_option "#{setting}=#{value}"
|
||||
end
|
||||
|
||||
def set_bool setting, value
|
||||
if value
|
||||
::VIM::set_option setting
|
||||
else
|
||||
::VIM::set_option "no#{setting}"
|
||||
end
|
||||
end
|
||||
end # class Settings
|
||||
end # module CommandT
|
|
@ -0,0 +1,42 @@
|
|||
# Copyright 2010-2011 Wincent Colaiuta. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
module CommandT
|
||||
class Stub
|
||||
@@load_error = ['command-t.vim could not load the C extension',
|
||||
'Please see INSTALLATION and TROUBLE-SHOOTING in the help',
|
||||
'For more information type: :help command-t']
|
||||
|
||||
[:flush, :show_buffer_finder, :show_file_finder, :show_tag_finder].each do |method|
|
||||
define_method(method.to_sym) { 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 # class Stub
|
||||
end # module CommandT
|
|
@ -0,0 +1,59 @@
|
|||
# Copyright 2010-2012 Wincent Colaiuta. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
require 'command-t/vim/screen'
|
||||
require 'command-t/vim/window'
|
||||
|
||||
module CommandT
|
||||
module VIM
|
||||
def self.has_syntax?
|
||||
::VIM::evaluate('has("syntax")').to_i != 0
|
||||
end
|
||||
|
||||
def self.exists? str
|
||||
::VIM::evaluate(%{exists("#{str}")}).to_i != 0
|
||||
end
|
||||
|
||||
def self.has_conceal?
|
||||
::VIM::evaluate('has("conceal")').to_i != 0
|
||||
end
|
||||
|
||||
def self.pwd
|
||||
::VIM::evaluate 'getcwd()'
|
||||
end
|
||||
|
||||
# Execute cmd, capturing the output into a variable and returning it.
|
||||
def self.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 self.escape_for_single_quotes str
|
||||
str.gsub "'", "''"
|
||||
end
|
||||
end # module VIM
|
||||
end # module CommandT
|
|
@ -0,0 +1,40 @@
|
|||
# Copyright 2010-2011 Wincent Colaiuta. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
require 'command-t/vim'
|
||||
|
||||
module CommandT
|
||||
module VIM
|
||||
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 # module PathUtilities
|
||||
end # module VIM
|
||||
end # module CommandT
|
|
@ -0,0 +1,32 @@
|
|||
# Copyright 2010 Wincent Colaiuta. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
module CommandT
|
||||
module VIM
|
||||
module Screen
|
||||
def self.lines
|
||||
::VIM::evaluate('&lines').to_i
|
||||
end
|
||||
end # module Screen
|
||||
end # module VIM
|
||||
end # module CommandT
|
|
@ -0,0 +1,38 @@
|
|||
# Copyright 2010 Wincent Colaiuta. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
module CommandT
|
||||
module VIM
|
||||
class Window
|
||||
def self.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 # class Window
|
||||
end # module VIM
|
||||
end # module CommandT
|
|
@ -0,0 +1,102 @@
|
|||
# Copyright 2010-2011 Wincent Colaiuta. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
require 'spec_helper'
|
||||
require 'command-t/controller'
|
||||
|
||||
module VIM; end
|
||||
|
||||
describe CommandT::Controller do
|
||||
describe 'accept selection' do
|
||||
let(:controller) { CommandT::Controller.new }
|
||||
|
||||
before do
|
||||
check_ruby_1_9_2
|
||||
stub_finder
|
||||
stub_match_window 'path/to/selection'
|
||||
stub_prompt
|
||||
stub_vim '/working/directory'
|
||||
end
|
||||
|
||||
it 'opens relative paths inside the working directory' do
|
||||
stub(::VIM).evaluate('a:arg').returns('')
|
||||
controller.show_file_finder
|
||||
mock(::VIM).command('silent e 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')
|
||||
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')
|
||||
controller.accept_selection
|
||||
end
|
||||
end
|
||||
|
||||
def check_ruby_1_9_2
|
||||
if RUBY_VERSION =~ /\A1\.9\.2/
|
||||
pending 'broken in Ruby 1.9.2 (see https://gist.github.com/455547)'
|
||||
end
|
||||
end
|
||||
|
||||
def stub_finder(sorted_matches=[])
|
||||
finder = CommandT::FileFinder.new
|
||||
stub(finder).path = anything
|
||||
stub(finder).sorted_matches_for(anything, anything).returns(sorted_matches)
|
||||
stub(CommandT::FileFinder).new.returns(finder)
|
||||
end
|
||||
|
||||
def stub_match_window(selection)
|
||||
match_window = Object.new
|
||||
stub(match_window).matches = anything
|
||||
stub(match_window).close
|
||||
stub(match_window).selection.returns(selection)
|
||||
stub(CommandT::MatchWindow).new.returns(match_window)
|
||||
end
|
||||
|
||||
def stub_prompt(abbrev='')
|
||||
prompt = Object.new
|
||||
stub(prompt).focus
|
||||
stub(prompt).clear!
|
||||
stub(prompt).abbrev.returns(abbrev)
|
||||
stub(CommandT::Prompt).new.returns(prompt)
|
||||
end
|
||||
|
||||
def stub_vim(working_directory)
|
||||
stub($curbuf).number.returns('0')
|
||||
stub(::VIM).command(/noremap/)
|
||||
stub(::VIM).command('silent b 0')
|
||||
stub(::VIM).evaluate(/exists\(.+\)/).returns('0')
|
||||
stub(::VIM).evaluate('getcwd()').returns(working_directory)
|
||||
stub(::VIM).evaluate('&buflisted').returns('1')
|
||||
stub(::VIM).evaluate('&lines').returns('80')
|
||||
stub(::VIM).evaluate('&term').returns('vt100')
|
||||
end
|
||||
end
|
|
@ -0,0 +1,78 @@
|
|||
# Copyright 2010-2011 Wincent Colaiuta. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
require 'spec_helper'
|
||||
require 'command-t/finder/buffer_finder'
|
||||
|
||||
module VIM; end
|
||||
|
||||
describe CommandT::BufferFinder do
|
||||
before do
|
||||
@paths = %w(.git/config .vim/notes .vimrc baz foo/beta)
|
||||
any_instance_of(CommandT::BufferScanner, :paths => @paths)
|
||||
@finder = CommandT::BufferFinder.new
|
||||
end
|
||||
|
||||
describe 'sorted_matches_for method' do
|
||||
it 'returns an empty array when no matches' do
|
||||
@finder.sorted_matches_for('kung foo fighting').should == []
|
||||
end
|
||||
|
||||
it 'returns all files when query string is empty' do
|
||||
@finder.sorted_matches_for('').should == @paths
|
||||
end
|
||||
|
||||
it 'returns files in alphabetical order when query string is empty' do
|
||||
results = @finder.sorted_matches_for('')
|
||||
results.should == results.sort
|
||||
end
|
||||
|
||||
it 'returns matching files in score order' do
|
||||
@finder.sorted_matches_for('ba').should == %w(baz foo/beta)
|
||||
@finder.sorted_matches_for('a').should == %w(baz foo/beta)
|
||||
end
|
||||
|
||||
it 'returns matching dot files even when search term does not include a dot' do
|
||||
@finder.sorted_matches_for('i').should include('.vimrc')
|
||||
end
|
||||
|
||||
it 'returns matching files inside dot directories even when search term does not include a dot' do
|
||||
@finder.sorted_matches_for('i').should 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')
|
||||
end
|
||||
|
||||
it 'obeys the :limit option for empty search strings' do
|
||||
@finder.sorted_matches_for('', :limit => 1).
|
||||
should == %w(.git/config)
|
||||
end
|
||||
|
||||
it 'obeys the :limit option for non-empty search strings' do
|
||||
@finder.sorted_matches_for('i', :limit => 2).
|
||||
should == %w(.vimrc .vim/notes)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,80 @@
|
|||
# Copyright 2010-2011 Wincent Colaiuta. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
require 'spec_helper'
|
||||
require 'command-t/finder/file_finder'
|
||||
|
||||
module VIM; end
|
||||
|
||||
describe CommandT::FileFinder do
|
||||
before :all do
|
||||
@finder = CommandT::FileFinder.new File.join(File.dirname(__FILE__), '..',
|
||||
'..', '..', 'fixtures')
|
||||
@all_fixtures = %w(
|
||||
bar/abc
|
||||
bar/xyz
|
||||
baz
|
||||
bing
|
||||
foo/alpha/t1
|
||||
foo/alpha/t2
|
||||
foo/beta
|
||||
)
|
||||
end
|
||||
|
||||
before do
|
||||
# scanner will call VIM's expand() function for exclusion filtering
|
||||
stub(::VIM).evaluate(/expand\(.+\)/) { '0' }
|
||||
end
|
||||
|
||||
describe 'sorted_matches_for method' do
|
||||
it 'returns an empty array when no matches' do
|
||||
@finder.sorted_matches_for('kung foo fighting').should == []
|
||||
end
|
||||
|
||||
it 'returns all files when query string is empty' do
|
||||
@finder.sorted_matches_for('').should == @all_fixtures
|
||||
end
|
||||
|
||||
it 'returns files in alphabetical order when query string is empty' do
|
||||
results = @finder.sorted_matches_for('')
|
||||
results.should == results.sort
|
||||
end
|
||||
|
||||
it 'returns matching files in score order' do
|
||||
@finder.sorted_matches_for('ba').
|
||||
should == %w(baz bar/abc bar/xyz foo/beta)
|
||||
@finder.sorted_matches_for('a').
|
||||
should == %w(baz bar/abc bar/xyz foo/alpha/t1 foo/alpha/t2 foo/beta)
|
||||
end
|
||||
|
||||
it 'obeys the :limit option for empty search strings' do
|
||||
@finder.sorted_matches_for('', :limit => 2).
|
||||
should == %w(bar/abc bar/xyz)
|
||||
end
|
||||
|
||||
it 'obeys the :limit option for non-empty search strings' do
|
||||
@finder.sorted_matches_for('a', :limit => 3).
|
||||
should == %w(baz bar/abc bar/xyz)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,236 @@
|
|||
# Copyright 2010 Wincent Colaiuta. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
require 'spec_helper'
|
||||
require 'command-t/ext'
|
||||
|
||||
describe CommandT::Match do
|
||||
def match_for path, pattern
|
||||
CommandT::Match.new path, pattern
|
||||
end
|
||||
|
||||
it 'requires pattern to be lowercase' do
|
||||
# this is an optimization: we ask our caller (the Matcher class) to
|
||||
# downcase once before calling us, rather than downcase repeatedly
|
||||
# during looping, recursion, and initialization of thousands of Match
|
||||
# instances
|
||||
match_for('foo', 'Foo').matches?.should == false
|
||||
end
|
||||
|
||||
describe '#matches?' do
|
||||
it 'returns false for non-matches' do
|
||||
match_for('foo', 'bar').matches?.should == false
|
||||
end
|
||||
|
||||
it 'returns true for matches' do
|
||||
match_for('foo', 'foo').matches?.should == true
|
||||
end
|
||||
|
||||
it 'returns true for empty search strings' do
|
||||
match_for('foo', '').matches?.should == true
|
||||
end
|
||||
|
||||
it 'returns false for overlength matches' do
|
||||
match_for('foo', 'foo...').matches?.should == false
|
||||
end
|
||||
end
|
||||
|
||||
describe 'score method' do
|
||||
it 'assigns a score of 1.0 for empty search string' do
|
||||
match_for('foo', '').score.should == 1.0
|
||||
end
|
||||
|
||||
it 'assigns a score of zero for a non-match' do
|
||||
match_for('foo', 'bar').score.should == 0.0
|
||||
end
|
||||
|
||||
it 'assigns a score of zero for an overlength match' do
|
||||
match_for('foo', 'foo...').score.should == 0.0
|
||||
end
|
||||
|
||||
it 'assigns perfect matches a score of one' do
|
||||
match_for('foo', 'foo').score.should == 1.0
|
||||
end
|
||||
|
||||
it 'assigns perfect but incomplete matches a score of less than one' do
|
||||
match_for('foo', 'f').score.should < 1.0
|
||||
end
|
||||
|
||||
it 'prioritizes matches with more matching characters' do
|
||||
few_matches = match_for('foobar', 'fb')
|
||||
many_matches = match_for('foobar', 'fbar')
|
||||
many_matches.score.should > few_matches.score
|
||||
end
|
||||
|
||||
it 'prioritizes shorter paths over longer ones' do
|
||||
short_path = match_for('article.rb', 'art')
|
||||
long_path = match_for('articles_controller_spec.rb', 'art')
|
||||
short_path.score.should > long_path.score
|
||||
end
|
||||
|
||||
it 'prioritizes matches after "/"' do
|
||||
normal_match = match_for('fooobar', 'b')
|
||||
special_match = match_for('foo/bar', 'b')
|
||||
special_match.score.should > normal_match.score
|
||||
|
||||
# note that / beats _
|
||||
normal_match = match_for('foo_bar', 'b')
|
||||
special_match = match_for('foo/bar', 'b')
|
||||
special_match.score.should > normal_match.score
|
||||
|
||||
# / also beats -
|
||||
normal_match = match_for('foo-bar', 'b')
|
||||
special_match = match_for('foo/bar', 'b')
|
||||
special_match.score.should > normal_match.score
|
||||
|
||||
# and numbers
|
||||
normal_match = match_for('foo9bar', 'b')
|
||||
special_match = match_for('foo/bar', 'b')
|
||||
special_match.score.should > normal_match.score
|
||||
|
||||
# and periods
|
||||
normal_match = match_for('foo.bar', 'b')
|
||||
special_match = match_for('foo/bar', 'b')
|
||||
special_match.score.should > normal_match.score
|
||||
|
||||
# and spaces
|
||||
normal_match = match_for('foo bar', 'b')
|
||||
special_match = match_for('foo/bar', 'b')
|
||||
special_match.score.should > normal_match.score
|
||||
end
|
||||
|
||||
it 'prioritizes matches after "-"' do
|
||||
normal_match = match_for('fooobar', 'b')
|
||||
special_match = match_for('foo-bar', 'b')
|
||||
special_match.score.should > normal_match.score
|
||||
|
||||
# - also beats .
|
||||
normal_match = match_for('foo.bar', 'b')
|
||||
special_match = match_for('foo-bar', 'b')
|
||||
special_match.score.should > normal_match.score
|
||||
end
|
||||
|
||||
it 'prioritizes matches after "_"' do
|
||||
normal_match = match_for('fooobar', 'b')
|
||||
special_match = match_for('foo_bar', 'b')
|
||||
special_match.score.should > normal_match.score
|
||||
|
||||
# _ also beats .
|
||||
normal_match = match_for('foo.bar', 'b')
|
||||
special_match = match_for('foo_bar', 'b')
|
||||
special_match.score.should > normal_match.score
|
||||
end
|
||||
|
||||
it 'prioritizes matches after " "' do
|
||||
normal_match = match_for('fooobar', 'b')
|
||||
special_match = match_for('foo bar', 'b')
|
||||
special_match.score.should > normal_match.score
|
||||
|
||||
# " " also beats .
|
||||
normal_match = match_for('foo.bar', 'b')
|
||||
special_match = match_for('foo bar', 'b')
|
||||
special_match.score.should > normal_match.score
|
||||
end
|
||||
|
||||
it 'prioritizes matches after numbers' do
|
||||
normal_match = match_for('fooobar', 'b')
|
||||
special_match = match_for('foo9bar', 'b')
|
||||
special_match.score.should > normal_match.score
|
||||
|
||||
# numbers also beat .
|
||||
normal_match = match_for('foo.bar', 'b')
|
||||
special_match = match_for('foo9bar', 'b')
|
||||
special_match.score.should > normal_match.score
|
||||
end
|
||||
|
||||
it 'prioritizes matches after periods' do
|
||||
normal_match = match_for('fooobar', 'b')
|
||||
special_match = match_for('foo.bar', 'b')
|
||||
special_match.score.should > normal_match.score
|
||||
end
|
||||
|
||||
it 'prioritizes matching capitals following lowercase' do
|
||||
normal_match = match_for('foobar', 'b')
|
||||
special_match = match_for('fooBar', 'b')
|
||||
special_match.score.should > normal_match.score
|
||||
end
|
||||
|
||||
it 'prioritizes matches earlier in the string' do
|
||||
early_match = match_for('**b*****', 'b')
|
||||
late_match = match_for('******b*', 'b')
|
||||
early_match.score.should > late_match.score
|
||||
end
|
||||
|
||||
it 'prioritizes matches closer to previous matches' do
|
||||
early_match = match_for('**bc****', 'bc')
|
||||
late_match = match_for('**b***c*', 'bc')
|
||||
early_match.score.should > late_match.score
|
||||
end
|
||||
|
||||
it 'scores alternative matches of same path differently' do
|
||||
# given path: app/controllers/articles_controller.rb
|
||||
left_to_right_match = match_for('a**/****r******/**t*c***_*on*******.**', 'artcon')
|
||||
best_match = match_for('***/***********/art*****_con*******.**', 'artcon')
|
||||
best_match.score.should > left_to_right_match.score
|
||||
end
|
||||
|
||||
it 'returns the best possible score among alternatives' do
|
||||
# given path: app/controllers/articles_controller.rb
|
||||
best_match = match_for('***/***********/art*****_con*******.**', 'artcon')
|
||||
chosen_match = match_for('app/controllers/articles_controller.rb', 'artcon')
|
||||
chosen_match.score.should == best_match.score
|
||||
end
|
||||
|
||||
it 'provides intuitive results for "artcon" and "articles_controller"' do
|
||||
low = match_for('app/controllers/heartbeat_controller.rb', 'artcon')
|
||||
high = match_for('app/controllers/articles_controller.rb', 'artcon')
|
||||
high.score.should > low.score
|
||||
end
|
||||
|
||||
it 'provides intuitive results for "aca" and "a/c/articles_controller"' do
|
||||
low = match_for 'app/controllers/heartbeat_controller.rb', 'aca'
|
||||
high = match_for 'app/controllers/articles_controller.rb', 'aca'
|
||||
best_match = match_for 'a**/c**********/a******************.**', 'aca'
|
||||
high.score.should > low.score
|
||||
high.score.should == best_match.score
|
||||
end
|
||||
|
||||
it 'provides intuitive results for "d" and "doc/command-t.txt"' do
|
||||
low = match_for 'TODO', 'd'
|
||||
high = match_for 'doc/command-t.txt', 'd'
|
||||
high.score.should > low.score
|
||||
end
|
||||
|
||||
it 'provides intuitive results for "do" and "doc/command-t.txt"' do
|
||||
low = match_for 'TODO', 'do'
|
||||
high = match_for 'doc/command-t.txt', 'do'
|
||||
high.score.should > low.score
|
||||
end
|
||||
end
|
||||
|
||||
describe 'to_s method' do
|
||||
it 'returns the entire matched string' do
|
||||
match_for('abc', 'abc').to_s.should == 'abc'
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,78 @@
|
|||
# Copyright 2010 Wincent Colaiuta. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
require 'spec_helper'
|
||||
require 'command-t/scanner'
|
||||
require 'command-t/ext'
|
||||
|
||||
describe CommandT::Matcher do
|
||||
describe 'initialization' do
|
||||
it 'raises an ArgumentError if passed nil' do
|
||||
expect do
|
||||
CommandT::Matcher.new nil
|
||||
end.to raise_error(ArgumentError)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#matches_for' do
|
||||
before do
|
||||
@scanner = Object.new
|
||||
end
|
||||
|
||||
it 'raises an ArgumentError if passed nil' do
|
||||
@matcher = CommandT::Matcher.new @scanner
|
||||
expect do
|
||||
@matcher.matches_for(nil)
|
||||
end.to raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it 'returns empty array when source array empty' do
|
||||
stub(@scanner).paths { [] }
|
||||
@no_paths = CommandT::Matcher.new @scanner
|
||||
@no_paths.matches_for('foo').should == []
|
||||
@no_paths.matches_for('').should == []
|
||||
end
|
||||
|
||||
it 'returns empty array when no matches' do
|
||||
stub(@scanner).paths { ['foo/bar', 'foo/baz', 'bing'] }
|
||||
@no_matches = CommandT::Matcher.new @scanner
|
||||
@no_matches.matches_for('xyz').should == []
|
||||
end
|
||||
|
||||
it 'returns matching paths' do
|
||||
stub(@scanner).paths { ['foo/bar', 'foo/baz', 'bing'] }
|
||||
@foo_paths = CommandT::Matcher.new @scanner
|
||||
matches = @foo_paths.matches_for('z')
|
||||
matches.map { |m| m.to_s }.should == ['foo/baz']
|
||||
matches = @foo_paths.matches_for('bg')
|
||||
matches.map { |m| m.to_s }.should == ['bing']
|
||||
end
|
||||
|
||||
it 'performs case-insensitive matching' do
|
||||
stub(@scanner).paths { ['Foo'] }
|
||||
@path = CommandT::Matcher.new @scanner
|
||||
matches = @path.matches_for('f')
|
||||
matches.map { |m| m.to_s }.should == ['Foo']
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,54 @@
|
|||
# Copyright 2010-2011 Wincent Colaiuta. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
require 'spec_helper'
|
||||
require 'ostruct'
|
||||
require 'command-t/scanner/buffer_scanner'
|
||||
|
||||
module VIM
|
||||
class Buffer; end
|
||||
end
|
||||
|
||||
describe CommandT::BufferScanner do
|
||||
def buffer name
|
||||
b = OpenStruct.new
|
||||
b.name = name
|
||||
b
|
||||
end
|
||||
|
||||
before do
|
||||
@paths = %w(bar/abc bar/xyz baz bing foo/alpha/t1 foo/alpha/t2 foo/beta)
|
||||
@scanner = CommandT::BufferScanner.new
|
||||
stub(@scanner).relative_path_under_working_directory(is_a(String)) { |arg| arg }
|
||||
stub(::VIM::Buffer).count { 7 }
|
||||
(0..6).each do |n|
|
||||
stub(::VIM::Buffer)[n].returns(buffer @paths[n])
|
||||
end
|
||||
end
|
||||
|
||||
describe 'paths method' do
|
||||
it 'returns a list of regular files' do
|
||||
@scanner.paths.should =~ @paths
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,83 @@
|
|||
# Copyright 2010-2011 Wincent Colaiuta. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
require 'spec_helper'
|
||||
require 'command-t/scanner/file_scanner'
|
||||
|
||||
module VIM; end
|
||||
|
||||
describe CommandT::FileScanner do
|
||||
before do
|
||||
@dir = File.join(File.dirname(__FILE__), '..', '..', '..', 'fixtures')
|
||||
@all_fixtures = %w(
|
||||
bar/abc bar/xyz baz bing foo/alpha/t1 foo/alpha/t2 foo/beta
|
||||
)
|
||||
@scanner = CommandT::FileScanner.new @dir
|
||||
|
||||
# scanner will call VIM's expand() function for exclusion filtering
|
||||
stub(::VIM).evaluate(/expand\(.+\)/) { '0' }
|
||||
end
|
||||
|
||||
describe 'paths method' do
|
||||
it 'returns a list of regular files' do
|
||||
@scanner.paths.should =~ @all_fixtures
|
||||
end
|
||||
end
|
||||
|
||||
describe 'flush method' do
|
||||
it 'forces a rescan on next call to paths method' do
|
||||
first = @scanner.paths
|
||||
@scanner.flush
|
||||
@scanner.paths.object_id.should_not == first.object_id
|
||||
end
|
||||
end
|
||||
|
||||
describe 'path= method' do
|
||||
it 'allows repeated applications of scanner at different paths' do
|
||||
@scanner.paths.should =~ @all_fixtures
|
||||
|
||||
# drill down 1 level
|
||||
@scanner.path = File.join(@dir, 'foo')
|
||||
@scanner.paths.should =~ %w(alpha/t1 alpha/t2 beta)
|
||||
|
||||
# and another
|
||||
@scanner.path = File.join(@dir, 'foo', 'alpha')
|
||||
@scanner.paths.should =~ %w(t1 t2)
|
||||
end
|
||||
end
|
||||
|
||||
describe "'wildignore' exclusion" do
|
||||
it "calls on VIM's expand() function for pattern filtering" do
|
||||
@scanner = CommandT::FileScanner.new @dir
|
||||
mock(::VIM).evaluate(/expand\(.+\)/).times(10)
|
||||
@scanner.paths
|
||||
end
|
||||
end
|
||||
|
||||
describe ':max_depth option' do
|
||||
it 'does not descend below "max_depth" levels' do
|
||||
@scanner = CommandT::FileScanner.new @dir, :max_depth => 1
|
||||
@scanner.paths.should =~ %w(bar/abc bar/xyz baz bing foo/beta)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,38 @@
|
|||
# Copyright 2010 Wincent Colaiuta. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
if !Object.const_defined?('Bundler')
|
||||
require 'rubygems'
|
||||
require 'bundler'
|
||||
Bundler.setup
|
||||
end
|
||||
require 'rspec'
|
||||
|
||||
lib = File.expand_path('../ruby', File.dirname(__FILE__))
|
||||
unless $LOAD_PATH.include? lib
|
||||
$LOAD_PATH.unshift lib
|
||||
end
|
||||
|
||||
RSpec.configure do |config|
|
||||
config.mock_framework = :rr
|
||||
end
|
|
@ -0,0 +1,41 @@
|
|||
require 'spec/runner/formatter/base_text_formatter'
|
||||
require 'pathname'
|
||||
|
||||
# Format spec results for display in the Vim quickfix window
|
||||
# Use this custom formatter like this:
|
||||
# spec -r spec/vim_formatter.rb -f Spec::Runner::Formatter::VimFormatter spec
|
||||
module Spec
|
||||
module Runner
|
||||
module Formatter
|
||||
class VimFormatter < BaseTextFormatter
|
||||
|
||||
# TODO: handle pending issues
|
||||
# TODO: vim-side function for printing progress
|
||||
def dump_failure counter, failure
|
||||
path = failure.exception.backtrace.find do |frame|
|
||||
frame =~ %r{\bspec/.*_spec\.rb:\d+\z}
|
||||
end
|
||||
message = failure.exception.message.gsub("\n", ' ')
|
||||
@output.puts "#{relativize_path(path)}: #{message}" if path
|
||||
end
|
||||
|
||||
def dump_pending; end
|
||||
|
||||
def dump_summary duration, example_count, failure_count, pending_count
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def relativize_path path
|
||||
@wd ||= Pathname.new Dir.getwd
|
||||
begin
|
||||
return Pathname.new(path).relative_path_from(@wd)
|
||||
rescue ArgumentError
|
||||
# raised unless both paths relative, or both absolute
|
||||
return path
|
||||
end
|
||||
end
|
||||
end # class VimFormatter
|
||||
end # module Formatter
|
||||
end # module Runner
|
||||
end # module Spec
|
|
@ -0,0 +1,3 @@
|
|||
*~
|
||||
*.swp
|
||||
tags
|
|
@ -0,0 +1,76 @@
|
|||
# written by travis jeffery <travisjeffery@gmail.com>
|
||||
# contributions by scrooloose <github:scrooloose>
|
||||
|
||||
require 'rake'
|
||||
require 'find'
|
||||
require 'pathname'
|
||||
|
||||
IGNORE = [/\.gitignore$/, /Rakefile$/]
|
||||
|
||||
files = `git ls-files`.split("\n")
|
||||
files.reject! { |f| IGNORE.any? { |re| f.match(re) } }
|
||||
|
||||
desc 'Zip up the project files'
|
||||
task :zip do
|
||||
zip_name = File.basename(File.dirname(__FILE__))
|
||||
zip_name.gsub!(/ /, '_')
|
||||
zip_name = "#{zip_name}.zip"
|
||||
|
||||
if File.exist?(zip_name)
|
||||
abort("Zip file #{zip_name} already exists. Remove it first.")
|
||||
end
|
||||
|
||||
puts "Creating zip file: #{zip_name}"
|
||||
system("zip #{zip_name} #{files.join(" ")}")
|
||||
end
|
||||
|
||||
desc 'Install plugin and documentation'
|
||||
task :install do
|
||||
vimfiles = if ENV['VIMFILES']
|
||||
ENV['VIMFILES']
|
||||
elsif RUBY_PLATFORM =~ /(win|w)32$/
|
||||
File.expand_path("~/vimfiles")
|
||||
else
|
||||
File.expand_path("~/.vim")
|
||||
end
|
||||
files.each do |file|
|
||||
target_file = File.join(vimfiles, file)
|
||||
FileUtils.mkdir_p File.dirname(target_file)
|
||||
FileUtils.cp file, target_file
|
||||
|
||||
puts "Installed #{file} to #{target_file}"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
desc 'Pulls from origin'
|
||||
task :pull do
|
||||
puts "Updating local repo..."
|
||||
system("cd " << Dir.new(File.dirname(__FILE__)).path << " && git pull")
|
||||
end
|
||||
|
||||
desc 'Calls pull task and then install task'
|
||||
task :update => ['pull', 'install'] do
|
||||
puts "Update of vim script complete."
|
||||
end
|
||||
|
||||
desc 'Uninstall plugin and documentation'
|
||||
task :uninstall do
|
||||
vimfiles = if ENV['VIMFILES']
|
||||
ENV['VIMFILES']
|
||||
elsif RUBY_PLATFORM =~ /(win|w)32$/
|
||||
File.expand_path("~/vimfiles")
|
||||
else
|
||||
File.expand_path("~/.vim")
|
||||
end
|
||||
files.each do |file|
|
||||
target_file = File.join(vimfiles, file)
|
||||
FileUtils.rm target_file
|
||||
|
||||
puts "Uninstalled #{target_file}"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
task :default => ['update']
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,3 @@
|
|||
*.swp
|
||||
*.vba
|
||||
doc/tags
|
|
@ -0,0 +1,11 @@
|
|||
SHELL=/bin/bash
|
||||
|
||||
all: dist
|
||||
|
||||
dist:
|
||||
@rm supertab.vba 2> /dev/null || true
|
||||
@vim -c 'r! git ls-files doc plugin' \
|
||||
-c '$$,$$d _' -c '%MkVimball supertab.vba .' -c 'q!'
|
||||
|
||||
clean:
|
||||
@rm -R build 2> /dev/null || true
|
|
@ -0,0 +1,316 @@
|
|||
*supertab.txt*
|
||||
|
||||
Authors:
|
||||
Original: Gergely Kontra <kgergely@mcl.hu>
|
||||
Current: Eric Van Dewoestine <ervandew@gmail.com> (as of version 0.4)
|
||||
|
||||
Contributors:
|
||||
Christophe-Marie Duquesne <chm.duquesne@gmail.com> (documentation)
|
||||
|
||||
Please direct all correspondence to Eric.
|
||||
|
||||
This plugin is licensed under the terms of the BSD License. Please see
|
||||
supertab.vim for the license in its entirety.
|
||||
|
||||
==============================================================================
|
||||
Supertab *supertab*
|
||||
|
||||
1. Introduction |supertab-intro|
|
||||
2. Supertab Usage |supertab-usage|
|
||||
3. Supertab Options |supertab-options|
|
||||
Default completion type |supertab-defaultcompletion|
|
||||
Secondary default completion type |supertab-contextdefault|
|
||||
Completion contexts |supertab-completioncontexts|
|
||||
Context text |supertab-contexttext|
|
||||
Context Discover |supertab-contextdiscover|
|
||||
Example |supertab-contextexample|
|
||||
Completion Duration |supertab-duration|
|
||||
Preventing Completion After/Before... |supertab-preventcomplete|
|
||||
Changing default mapping |supertab-forwardbackward|
|
||||
Inserting true tabs |supertab-mappingtabliteral|
|
||||
Enhanced longest match support |supertab-longestenhanced|
|
||||
Preselecting the first entry |supertab-longesthighlight|
|
||||
|
||||
==============================================================================
|
||||
1. Introduction *supertab-intro*
|
||||
|
||||
Supertab is a plugin which allows you to perform all your insert completion
|
||||
(|ins-completion|) using the tab key.
|
||||
|
||||
Supertab requires Vim version 7.0 or above.
|
||||
|
||||
==============================================================================
|
||||
2. Supertab usage *supertab-usage*
|
||||
|
||||
Using Supertab is as easy as hitting <Tab> or <S-Tab> (shift+tab) while in
|
||||
insert mode, with at least one non whitespace character before the cursor, to
|
||||
start the completion and then <Tab> or <S-Tab> again to cycle forwards or
|
||||
backwards through the available completions.
|
||||
|
||||
Example ('|' denotes the cursor location):
|
||||
|
||||
bar
|
||||
baz
|
||||
b|<Tab> Hitting <Tab> here will start the completion, allowing you to
|
||||
then cycle through the suggested words ('bar' and 'baz').
|
||||
|
||||
==============================================================================
|
||||
3. Supertab Options *supertab-options*
|
||||
|
||||
Supertab is configured via several global variables that you can set in your
|
||||
|vimrc| file according to your needs. Below is a comprehensive list of
|
||||
the variables available.
|
||||
|
||||
|
||||
Default Completion Type *supertab-defaultcompletion*
|
||||
*g:SuperTabDefaultCompletionType*
|
||||
|
||||
g:SuperTabDefaultCompletionType (default value: "<c-p>")
|
||||
|
||||
Used to set the default completion type. There is no need to escape this
|
||||
value as that will be done for you when the type is set.
|
||||
|
||||
Example: setting the default completion to 'user' completion:
|
||||
|
||||
let g:SuperTabDefaultCompletionType = "<c-x><c-u>"
|
||||
|
||||
Note: a special value of 'context' is supported which will result in
|
||||
super tab attempting to use the text preceding the cursor to decide which
|
||||
type of completion to attempt. Currently super tab can recognize method
|
||||
calls or attribute references via '.', '::' or '->', and file path
|
||||
references containing '/'.
|
||||
|
||||
let g:SuperTabDefaultCompletionType = "context"
|
||||
|
||||
/usr/l<tab> # will use filename completion
|
||||
myvar.t<tab> # will use user completion if completefunc set,
|
||||
# or omni completion if omnifunc set.
|
||||
myvar-><tab> # same as above
|
||||
|
||||
When using context completion, super tab will fall back to a secondary default
|
||||
completion type set by |g:SuperTabContextDefaultCompletionType|.
|
||||
|
||||
Note: once the buffer has been initialized, changing the value of this setting
|
||||
will not change the default complete type used. If you want to change the
|
||||
default completion type for the current buffer after it has been set, perhaps
|
||||
in an ftplugin, you'll need to call SuperTabSetDefaultCompletionType like so,
|
||||
supplying the completion type you wish to switch to:
|
||||
|
||||
call SuperTabSetDefaultCompletionType("<c-x><c-u>")
|
||||
|
||||
|
||||
Secondary default completion type *supertab-contextdefault*
|
||||
*g:SuperTabContextDefaultCompletionType*
|
||||
|
||||
g:SuperTabContextDefaultCompletionType (default value: "<c-p>")
|
||||
|
||||
Sets the default completion type used when g:SuperTabDefaultCompletionType is
|
||||
set to 'context' and no completion type is returned by any of the configured
|
||||
contexts.
|
||||
|
||||
|
||||
Completion contexts *supertab-completioncontexts*
|
||||
*g:SuperTabCompletionContexts*
|
||||
|
||||
g:SuperTabCompletionContexts (default value: ['s:ContextText'])
|
||||
|
||||
Sets the list of contexts used for context completion. This value should
|
||||
be a list of function names which provide the context implementation.
|
||||
|
||||
When supertab starts the default completion, each of these contexts will be
|
||||
consulted, in the order they were supplied, to determine the completion type
|
||||
to use. If a context returns a completion type, that type will be used,
|
||||
otherwise the next context in the list will be consulted. If after executing
|
||||
all the context functions, no completion type has been determined, then the
|
||||
value of g:SuperTabContextDefaultCompletionType will be used.
|
||||
|
||||
Built in completion contexts:
|
||||
|
||||
s:ContextText *supertab-contexttext*
|
||||
|
||||
The text context will examine the text near the cursor to decide which type
|
||||
of completion to attempt. Currently the text context can recognize method
|
||||
calls or attribute references via '.', '::' or '->', and file path
|
||||
references containing '/'.
|
||||
|
||||
/usr/l<tab> # will use filename completion
|
||||
myvar.t<tab> # will use user completion if completefunc set, or
|
||||
# omni completion if omnifunc set.
|
||||
myvar-><tab> # same as above
|
||||
|
||||
Supported configuration attributes:
|
||||
|
||||
g:SuperTabContextTextFileTypeExclusions
|
||||
List of file types for which the text context will be skipped.
|
||||
|
||||
g:SuperTabContextTextOmniPrecedence
|
||||
List of omni completion option names in the order of precedence that they
|
||||
should be used if available. By default, user completion will be given
|
||||
precedence over omni completion, but you can use this variable to give
|
||||
omni completion higher precedence by placing it first in the list.
|
||||
|
||||
s:ContextDiscover *supertab-contextdiscover*
|
||||
|
||||
This context will use the 'g:SuperTabContextDiscoverDiscovery' variable to
|
||||
determine the completion type to use. It will evaluate each value, in the
|
||||
order they were defined, until a variable evaluates to a non-zero or
|
||||
non-empty value, then the associated completion type is used.
|
||||
|
||||
Supported configuration properties:
|
||||
|
||||
g:SuperTabContextDiscoverDiscovery
|
||||
List of variable:completionType mappings.
|
||||
|
||||
Example context configuration: *supertab-contextexample*
|
||||
|
||||
let g:SuperTabCompletionContexts = ['s:ContextText', 's:ContextDiscover']
|
||||
let g:SuperTabContextTextOmniPrecedence = ['&omnifunc', '&completefunc']
|
||||
let g:SuperTabContextDiscoverDiscovery =
|
||||
\ ["&completefunc:<c-x><c-u>", "&omnifunc:<c-x><c-o>"]
|
||||
|
||||
In addition to the default completion contexts, you can plug in your own
|
||||
implementation by creating a globally accessible function that returns
|
||||
the completion type to use (eg. "\<c-x>\<c-u>").
|
||||
|
||||
function MyTagContext()
|
||||
if filereadable(expand('%:p:h') . '/tags')
|
||||
return "\<c-x>\<c-]>"
|
||||
endif
|
||||
" no return will result in the evaluation of the next
|
||||
" configured context
|
||||
endfunction
|
||||
let g:SuperTabCompletionContexts =
|
||||
\ ['MyTagContext', 's:ContextText', 's:ContextDiscover']
|
||||
|
||||
Note: supertab also supports the b:SuperTabCompletionContexts variable
|
||||
allowing you to set the list of contexts separately for the current buffer,
|
||||
like from an ftplugin for example.
|
||||
|
||||
|
||||
Completion Duration *supertab-duration*
|
||||
*g:SuperTabRetainCompletionDuration*
|
||||
|
||||
g:SuperTabRetainCompletionDuration (default value: 'insert')
|
||||
|
||||
Determines if, and for how long, the current completion type is retained.
|
||||
The possible values include:
|
||||
'completion' - The current completion type is only retained for the
|
||||
current completion. Once you have chosen a completion
|
||||
result or exited the completion mode, the default
|
||||
completion type is restored.
|
||||
'insert' - The current completion type is saved until you exit insert
|
||||
mode (via ESC). Once you exit insert mode the default
|
||||
completion type is restored. (supertab default)
|
||||
'session' - The current completion type is saved for the duration of
|
||||
your vim session or until you enter a different completion
|
||||
mode.
|
||||
|
||||
|
||||
Preventing completion after... *supertab-preventcomplete*
|
||||
*g:SuperTabNoCompleteBefore*
|
||||
*g:SuperTabNoCompleteAfter*
|
||||
|
||||
g:SuperTabNoCompleteBefore (default value: [])
|
||||
g:SuperTabNoCompleteAfter (default value: ['\s'])
|
||||
|
||||
These two variables are used to control when supertab will attempt completion
|
||||
or instead fall back to inserting a literal <tab>, by specifying a list of
|
||||
patterns which are tested against the text before and after the current cursor
|
||||
position that when matched, prevent completion. So if you don't want supertab
|
||||
to start completion after a comma or space, you can set
|
||||
g:SuperTabNoCompleteAfter to [',', '\s'].
|
||||
|
||||
Note: That a buffer local version of these variables
|
||||
(b:SuperTabNoCompleteBefore, b:SuperTabNoCompleteAfter) is also supported
|
||||
should you wish to have different values depending on the file type for
|
||||
instance.
|
||||
|
||||
Changing the default mapping *supertab-forwardbackward*
|
||||
*g:SuperTabMappingForward*
|
||||
*g:SuperTabMappingBackward*
|
||||
|
||||
g:SuperTabMappingForward (default value: '<tab>')
|
||||
g:SuperTabMappingBackward (default value: '<s-tab>')
|
||||
|
||||
These two variables allow you to set the keys used to kick off the current
|
||||
completion. By default this is <tab> and <s-tab>. To change to something
|
||||
like <c-space> and <s-c-space>, you can add the following to your |vimrc|.
|
||||
|
||||
let g:SuperTabMappingForward = '<c-space>'
|
||||
let g:SuperTabMappingBackward = '<s-c-space>'
|
||||
|
||||
Note: if the above does not have the desired effect (which may happen in
|
||||
console version of vim), you can try the following mappings. Although the
|
||||
backwards mapping still doesn't seem to work in the console for me, your
|
||||
milage may vary.
|
||||
|
||||
let g:SuperTabMappingForward = '<nul>'
|
||||
let g:SuperTabMappingBackward = '<s-nul>'
|
||||
|
||||
|
||||
Inserting true tabs *supertab-mappingtabliteral*
|
||||
*g:SuperTabMappingTabLiteral*
|
||||
|
||||
g:SuperTabMappingTabLiteral (default value: '<c-tab>')
|
||||
|
||||
Sets the key mapping used to insert a literal tab where supertab would
|
||||
otherwise attempt to kick off insert completion. The default is '<c-tab>'
|
||||
(ctrl-tab) which unfortunately might not work at the console. So if you are
|
||||
using a console vim and want this functionality, you may have to change it to
|
||||
something that is supported. Alternatively, you can escape the <tab> with
|
||||
<c-v> (see |i_CTRL-V| for more infos).
|
||||
|
||||
|
||||
Enhanced longest match support *supertab-longestenhanced*
|
||||
*g:SuperTabLongestEnhanced*
|
||||
|
||||
g:SuperTabLongestEnhanced (default value: 0)
|
||||
|
||||
When enabled and 'longest' is in your |completeopt| setting, supertab will
|
||||
provide an enhanced longest match support where typing one or more letters and
|
||||
hitting tab again while in a completion mode will complete the longest common
|
||||
match using the new text in the buffer.
|
||||
|
||||
For example, say you have a buffer with the following contents:
|
||||
FooBarFoo
|
||||
FooBar
|
||||
Foo
|
||||
FooBarBaz
|
||||
And you then type F<tab>. Vim's builtin longest support will complete the
|
||||
longest common text 'Foo' and offer 'FooBarFoo', 'FooBar', 'Foo', and
|
||||
'FooBarBaz' as possible completions. With supertab's longest match
|
||||
enhancement disabled, typing B<tab> while still in the completion mode will
|
||||
end up completing 'FooBarBaz' or 'FooBarFoo' depending your settings, instead
|
||||
of the next longest common match of 'FooBar'. With supertab's enhanced
|
||||
longest match feature enabled, the typing of B<tab> will result in the next
|
||||
longest text being completed.
|
||||
|
||||
|
||||
Preselecting the first entry *supertab-longesthighlight*
|
||||
*g:SuperTabLongestHighlight*
|
||||
|
||||
g:SuperTabLongestHighlight (default value: 0)
|
||||
|
||||
Sets whether or not to pre-highlight the first match when completeopt has the
|
||||
popup menu enabled and the 'longest' option as well. When enabled, <tab> will
|
||||
kick off completion and pre-select the first entry in the popup menu, allowing
|
||||
you to simply hit <enter> to use it.
|
||||
|
||||
|
||||
Mapping <cr> to end completion *supertab-crmapping*
|
||||
*g:SuperTabCrMapping*
|
||||
|
||||
g:SuperTabCrMapping (default value: 1)
|
||||
|
||||
When enabled, <cr> will cancel completion mode preserving the current text.
|
||||
|
||||
|
||||
Close the preview window on <cr> *supertab-crclosepreview*
|
||||
*g:SuperTabCrClosePreview*
|
||||
|
||||
g:SuperTabCrClosePreview (default value: 0)
|
||||
|
||||
When enabled, <cr> will close the completion preview window if open. Note,
|
||||
|g:SuperTabCrMapping| must also be enabled.
|
||||
|
||||
vim:tw=78:ts=8:ft=help:norl:
|
|
@ -0,0 +1,768 @@
|
|||
" Author:
|
||||
" Original: Gergely Kontra <kgergely@mcl.hu>
|
||||
" Current: Eric Van Dewoestine <ervandew@gmail.com> (as of version 0.4)
|
||||
" Please direct all correspondence to Eric.
|
||||
" Version: 1.6
|
||||
" GetLatestVimScripts: 1643 1 :AutoInstall: supertab.vim
|
||||
"
|
||||
" Description: {{{
|
||||
" Use your tab key to do all your completion in insert mode!
|
||||
" You can cycle forward and backward with the <Tab> and <S-Tab> keys
|
||||
" Note: you must press <Tab> once to be able to cycle back
|
||||
"
|
||||
" http://www.vim.org/scripts/script.php?script_id=1643
|
||||
" }}}
|
||||
"
|
||||
" License: {{{
|
||||
" Copyright (c) 2002 - 2011
|
||||
" All rights reserved.
|
||||
"
|
||||
" Redistribution and use of this software in source and binary forms, with
|
||||
" or without modification, are permitted provided that the following
|
||||
" conditions are met:
|
||||
"
|
||||
" * Redistributions of source code must retain the above
|
||||
" copyright notice, this list of conditions and the
|
||||
" following disclaimer.
|
||||
"
|
||||
" * Redistributions in binary form must reproduce the above
|
||||
" copyright notice, this list of conditions and the
|
||||
" following disclaimer in the documentation and/or other
|
||||
" materials provided with the distribution.
|
||||
"
|
||||
" * Neither the name of Gergely Kontra or Eric Van Dewoestine nor the names
|
||||
" of its contributors may be used to endorse or promote products derived
|
||||
" from this software without specific prior written permission of Gergely
|
||||
" Kontra or Eric Van Dewoestine.
|
||||
"
|
||||
" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
" IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
" THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
" CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
" EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
" PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
" PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
" NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
" SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
" }}}
|
||||
"
|
||||
" Testing Info: {{{
|
||||
" Running vim + supertab with the absolute bar minimum settings:
|
||||
" $ vim -u NONE -U NONE -c "set nocp | runtime plugin/supertab.vim"
|
||||
" }}}
|
||||
|
||||
if v:version < 700
|
||||
finish
|
||||
endif
|
||||
|
||||
if exists('complType') " Integration with other completion functions.
|
||||
finish
|
||||
endif
|
||||
|
||||
let s:save_cpo=&cpo
|
||||
set cpo&vim
|
||||
|
||||
" Global Variables {{{
|
||||
|
||||
if !exists("g:SuperTabDefaultCompletionType")
|
||||
let g:SuperTabDefaultCompletionType = "<c-p>"
|
||||
endif
|
||||
|
||||
if !exists("g:SuperTabContextDefaultCompletionType")
|
||||
let g:SuperTabContextDefaultCompletionType = "<c-p>"
|
||||
endif
|
||||
|
||||
if !exists("g:SuperTabCompletionContexts")
|
||||
let g:SuperTabCompletionContexts = ['s:ContextText']
|
||||
endif
|
||||
|
||||
if !exists("g:SuperTabRetainCompletionDuration")
|
||||
let g:SuperTabRetainCompletionDuration = 'insert'
|
||||
endif
|
||||
|
||||
if !exists("g:SuperTabNoCompleteBefore")
|
||||
" retain backwards compatability
|
||||
if exists("g:SuperTabMidWordCompletion") && !g:SuperTabMidWordCompletion
|
||||
let g:SuperTabNoCompleteBefore = ['\k']
|
||||
else
|
||||
let g:SuperTabNoCompleteBefore = []
|
||||
endif
|
||||
endif
|
||||
|
||||
if !exists("g:SuperTabNoCompleteAfter")
|
||||
" retain backwards compatability
|
||||
if exists("g:SuperTabLeadingSpaceCompletion") && g:SuperTabLeadingSpaceCompletion
|
||||
let g:SuperTabNoCompleteAfter = []
|
||||
else
|
||||
let g:SuperTabNoCompleteAfter = ['\s']
|
||||
endif
|
||||
endif
|
||||
|
||||
if !exists("g:SuperTabMappingForward")
|
||||
let g:SuperTabMappingForward = '<tab>'
|
||||
endif
|
||||
if !exists("g:SuperTabMappingBackward")
|
||||
let g:SuperTabMappingBackward = '<s-tab>'
|
||||
endif
|
||||
|
||||
if !exists("g:SuperTabMappingTabLiteral")
|
||||
let g:SuperTabMappingTabLiteral = '<c-tab>'
|
||||
endif
|
||||
|
||||
if !exists("g:SuperTabLongestEnhanced")
|
||||
let g:SuperTabLongestEnhanced = 0
|
||||
endif
|
||||
|
||||
if !exists("g:SuperTabLongestHighlight")
|
||||
let g:SuperTabLongestHighlight = 0
|
||||
endif
|
||||
|
||||
if !exists("g:SuperTabCrMapping")
|
||||
let g:SuperTabCrMapping = 1
|
||||
endif
|
||||
|
||||
if !exists("g:SuperTabCrClosePreview")
|
||||
let g:SuperTabCrClosePreview = 0
|
||||
endif
|
||||
|
||||
" }}}
|
||||
|
||||
" Script Variables {{{
|
||||
|
||||
" construct the help text.
|
||||
let s:tabHelp =
|
||||
\ "Hit <CR> or CTRL-] on the completion type you wish to switch to.\n" .
|
||||
\ "Use :help ins-completion for more information.\n" .
|
||||
\ "\n" .
|
||||
\ "|<c-n>| - Keywords in 'complete' searching down.\n" .
|
||||
\ "|<c-p>| - Keywords in 'complete' searching up (SuperTab default).\n" .
|
||||
\ "|<c-x><c-l>| - Whole lines.\n" .
|
||||
\ "|<c-x><c-n>| - Keywords in current file.\n" .
|
||||
\ "|<c-x><c-k>| - Keywords in 'dictionary'.\n" .
|
||||
\ "|<c-x><c-t>| - Keywords in 'thesaurus', thesaurus-style.\n" .
|
||||
\ "|<c-x><c-i>| - Keywords in the current and included files.\n" .
|
||||
\ "|<c-x><c-]>| - Tags.\n" .
|
||||
\ "|<c-x><c-f>| - File names.\n" .
|
||||
\ "|<c-x><c-d>| - Definitions or macros.\n" .
|
||||
\ "|<c-x><c-v>| - Vim command-line.\n" .
|
||||
\ "|<c-x><c-u>| - User defined completion.\n" .
|
||||
\ "|<c-x><c-o>| - Omni completion.\n" .
|
||||
\ "|<c-x>s| - Spelling suggestions."
|
||||
|
||||
" set the available completion types and modes.
|
||||
let s:types =
|
||||
\ "\<c-e>\<c-y>\<c-l>\<c-n>\<c-k>\<c-t>\<c-i>\<c-]>" .
|
||||
\ "\<c-f>\<c-d>\<c-v>\<c-n>\<c-p>\<c-u>\<c-o>\<c-n>\<c-p>s"
|
||||
let s:modes = '/^E/^Y/^L/^N/^K/^T/^I/^]/^F/^D/^V/^P/^U/^O/s'
|
||||
let s:types = s:types . "np"
|
||||
let s:modes = s:modes . '/n/p'
|
||||
|
||||
" }}}
|
||||
|
||||
" SuperTabSetDefaultCompletionType(type) {{{
|
||||
" Globally available function that users can use to set the default
|
||||
" completion type for the current buffer, like in an ftplugin.
|
||||
function! SuperTabSetDefaultCompletionType(type)
|
||||
" init hack for <c-x><c-v> workaround.
|
||||
let b:complCommandLine = 0
|
||||
|
||||
let b:SuperTabDefaultCompletionType = a:type
|
||||
|
||||
" set the current completion type to the default
|
||||
call SuperTabSetCompletionType(b:SuperTabDefaultCompletionType)
|
||||
endfunction " }}}
|
||||
|
||||
" SuperTabSetCompletionType(type) {{{
|
||||
" Globally available function that users can use to create mappings to quickly
|
||||
" switch completion modes. Useful when a user wants to restore the default or
|
||||
" switch to another mode without having to kick off a completion of that type
|
||||
" or use SuperTabHelp. Note, this function only changes the current
|
||||
" completion type, not the default, meaning that the default will still be
|
||||
" restored once the configured retension duration has been met (see
|
||||
" g:SuperTabRetainCompletionDuration). To change the default for the current
|
||||
" buffer, use SuperTabDefaultCompletionType(type) instead. Example mapping to
|
||||
" restore SuperTab default:
|
||||
" nmap <F6> :call SetSuperTabCompletionType("<c-p>")<cr>
|
||||
function! SuperTabSetCompletionType(type)
|
||||
call s:InitBuffer()
|
||||
exec "let b:complType = \"" . escape(a:type, '<') . "\""
|
||||
endfunction " }}}
|
||||
|
||||
" SuperTabAlternateCompletion(type) {{{
|
||||
" Function which can be mapped to a key to kick off an alternate completion
|
||||
" other than the default. For instance, if you have 'context' as the default
|
||||
" and want to map ctrl+space to issue keyword completion.
|
||||
" Note: due to the way vim expands ctrl characters in mappings, you cannot
|
||||
" create the alternate mapping like so:
|
||||
" imap <c-space> <c-r>=SuperTabAlternateCompletion("<c-p>")<cr>
|
||||
" instead, you have to use \<lt> to prevent vim from expanding the key
|
||||
" when creating the mapping.
|
||||
" gvim:
|
||||
" imap <c-space> <c-r>=SuperTabAlternateCompletion("\<lt>c-p>")<cr>
|
||||
" console:
|
||||
" imap <nul> <c-r>=SuperTabAlternateCompletion("\<lt>c-p>")<cr>
|
||||
function! SuperTabAlternateCompletion(type)
|
||||
call SuperTabSetCompletionType(a:type)
|
||||
" end any current completion before attempting to start the new one.
|
||||
" use feedkeys to prevent possible remapping of <c-e> from causing issues.
|
||||
"call feedkeys("\<c-e>", 'n')
|
||||
" ^ since we can't detect completion mode vs regular insert mode, we force
|
||||
" vim into keyword completion mode and end that mode to prevent the regular
|
||||
" insert behavior of <c-e> from occurring.
|
||||
call feedkeys("\<c-x>\<c-p>\<c-e>", 'n')
|
||||
call feedkeys(b:complType, 'n')
|
||||
return ''
|
||||
endfunction " }}}
|
||||
|
||||
" SuperTabLongestHighlight(dir) {{{
|
||||
" When longest highlight is enabled, this function is used to do the actual
|
||||
" selection of the completion popup entry.
|
||||
function! SuperTabLongestHighlight(dir)
|
||||
if !pumvisible()
|
||||
return ''
|
||||
endif
|
||||
return a:dir == -1 ? "\<up>" : "\<down>"
|
||||
endfunction " }}}
|
||||
|
||||
" s:Init {{{
|
||||
" Global initilization when supertab is loaded.
|
||||
function! s:Init()
|
||||
" Setup mechanism to restore original completion type upon leaving insert
|
||||
" mode if configured to do so
|
||||
if g:SuperTabRetainCompletionDuration == 'insert'
|
||||
augroup supertab_retain
|
||||
autocmd!
|
||||
autocmd InsertLeave * call s:SetDefaultCompletionType()
|
||||
augroup END
|
||||
endif
|
||||
endfunction " }}}
|
||||
|
||||
" s:InitBuffer {{{
|
||||
" Per buffer initilization.
|
||||
function! s:InitBuffer()
|
||||
if exists('b:SuperTabNoCompleteBefore')
|
||||
return
|
||||
endif
|
||||
|
||||
let b:complReset = 0
|
||||
let b:complTypeManual = !exists('b:complTypeManual') ? '' : b:complTypeManual
|
||||
let b:complTypeContext = ''
|
||||
|
||||
" init hack for <c-x><c-v> workaround.
|
||||
let b:complCommandLine = 0
|
||||
|
||||
if !exists('b:SuperTabNoCompleteBefore')
|
||||
let b:SuperTabNoCompleteBefore = g:SuperTabNoCompleteBefore
|
||||
endif
|
||||
if !exists('b:SuperTabNoCompleteAfter')
|
||||
let b:SuperTabNoCompleteAfter = g:SuperTabNoCompleteAfter
|
||||
endif
|
||||
|
||||
if !exists('b:SuperTabDefaultCompletionType')
|
||||
let b:SuperTabDefaultCompletionType = g:SuperTabDefaultCompletionType
|
||||
endif
|
||||
|
||||
" set the current completion type to the default
|
||||
call SuperTabSetCompletionType(b:SuperTabDefaultCompletionType)
|
||||
|
||||
" hack to programatically revert a change to snipmate that breaks supertab
|
||||
" but which the new maintainers don't care about:
|
||||
" http://github.com/garbas/vim-snipmate/issues/37
|
||||
let snipmate = maparg('<tab>', 'i')
|
||||
if snipmate =~ '<C-G>u' && g:SuperTabMappingForward =~? '<tab>'
|
||||
let snipmate = substitute(snipmate, '<C-G>u', '', '')
|
||||
iunmap <tab>
|
||||
exec "inoremap <silent> <tab> " . snipmate
|
||||
endif
|
||||
endfunction " }}}
|
||||
|
||||
" s:ManualCompletionEnter() {{{
|
||||
" Handles manual entrance into completion mode.
|
||||
function! s:ManualCompletionEnter()
|
||||
if &smd
|
||||
echo '' | echohl ModeMsg | echo '-- ^X++ mode (' . s:modes . ')' | echohl None
|
||||
endif
|
||||
let complType = nr2char(getchar())
|
||||
if stridx(s:types, complType) != -1
|
||||
if stridx("\<c-e>\<c-y>", complType) != -1 " no memory, just scroll...
|
||||
return "\<c-x>" . complType
|
||||
elseif stridx('np', complType) != -1
|
||||
let complType = nr2char(char2nr(complType) - 96)
|
||||
else
|
||||
let complType = "\<c-x>" . complType
|
||||
endif
|
||||
|
||||
let b:complTypeManual = complType
|
||||
|
||||
if index(['insert', 'session'], g:SuperTabRetainCompletionDuration) != -1
|
||||
let b:complType = complType
|
||||
endif
|
||||
|
||||
" Hack to workaround bug when invoking command line completion via <c-r>=
|
||||
if complType == "\<c-x>\<c-v>"
|
||||
return s:CommandLineCompletion()
|
||||
endif
|
||||
|
||||
" optionally enable enhanced longest completion
|
||||
if g:SuperTabLongestEnhanced && &completeopt =~ 'longest'
|
||||
call s:EnableLongestEnhancement()
|
||||
endif
|
||||
|
||||
if g:SuperTabLongestHighlight &&
|
||||
\ &completeopt =~ 'longest' &&
|
||||
\ &completeopt =~ 'menu' &&
|
||||
\ !pumvisible()
|
||||
let dir = (complType == "\<c-x>\<c-p>") ? -1 : 1
|
||||
call feedkeys("\<c-r>=SuperTabLongestHighlight(" . dir . ")\<cr>", 'n')
|
||||
endif
|
||||
|
||||
return complType
|
||||
endif
|
||||
|
||||
echohl "Unknown mode"
|
||||
return complType
|
||||
endfunction " }}}
|
||||
|
||||
" s:SetCompletionType() {{{
|
||||
" Sets the completion type based on what the user has chosen from the help
|
||||
" buffer.
|
||||
function! s:SetCompletionType()
|
||||
let chosen = substitute(getline('.'), '.*|\(.*\)|.*', '\1', '')
|
||||
if chosen != getline('.')
|
||||
let winnr = b:winnr
|
||||
close
|
||||
exec winnr . 'winc w'
|
||||
call SuperTabSetCompletionType(chosen)
|
||||
endif
|
||||
endfunction " }}}
|
||||
|
||||
" s:SetDefaultCompletionType() {{{
|
||||
function! s:SetDefaultCompletionType()
|
||||
if exists('b:SuperTabDefaultCompletionType') &&
|
||||
\ (!exists('b:complCommandLine') || !b:complCommandLine)
|
||||
call SuperTabSetCompletionType(b:SuperTabDefaultCompletionType)
|
||||
endif
|
||||
endfunction " }}}
|
||||
|
||||
" s:SuperTab(command) {{{
|
||||
" Used to perform proper cycle navigation as the user requests the next or
|
||||
" previous entry in a completion list, and determines whether or not to simply
|
||||
" retain the normal usage of <tab> based on the cursor position.
|
||||
function! s:SuperTab(command)
|
||||
if exists('b:SuperTabDisabled') && b:SuperTabDisabled
|
||||
return "\<tab>"
|
||||
endif
|
||||
|
||||
call s:InitBuffer()
|
||||
|
||||
if s:WillComplete()
|
||||
" optionally enable enhanced longest completion
|
||||
if g:SuperTabLongestEnhanced && &completeopt =~ 'longest'
|
||||
call s:EnableLongestEnhancement()
|
||||
endif
|
||||
|
||||
if !pumvisible()
|
||||
let b:complTypeManual = ''
|
||||
endif
|
||||
|
||||
" exception: if in <c-p> mode, then <c-n> should move up the list, and
|
||||
" <c-p> down the list.
|
||||
if a:command == 'p' && !b:complReset &&
|
||||
\ (b:complType == "\<c-p>" ||
|
||||
\ (b:complType == 'context' &&
|
||||
\ b:complTypeManual == '' &&
|
||||
\ b:complTypeContext == "\<c-p>"))
|
||||
return "\<c-n>"
|
||||
|
||||
elseif a:command == 'p' && !b:complReset &&
|
||||
\ (b:complType == "\<c-n>" ||
|
||||
\ (b:complType == 'context' &&
|
||||
\ b:complTypeManual == '' &&
|
||||
\ b:complTypeContext == "\<c-n>"))
|
||||
return "\<c-p>"
|
||||
|
||||
" already in completion mode and not resetting for longest enhancement, so
|
||||
" just scroll to next/previous
|
||||
elseif pumvisible() && !b:complReset
|
||||
let type = b:complType == 'context' ? b:complTypeContext : b:complType
|
||||
if a:command == 'n'
|
||||
return type == "\<c-p>" ? "\<c-p>" : "\<c-n>"
|
||||
endif
|
||||
return type == "\<c-p>" ? "\<c-n>" : "\<c-p>"
|
||||
endif
|
||||
|
||||
" handle 'context' completion.
|
||||
if b:complType == 'context'
|
||||
let complType = s:ContextCompletion()
|
||||
if complType == ''
|
||||
exec "let complType = \"" .
|
||||
\ escape(g:SuperTabContextDefaultCompletionType, '<') . "\""
|
||||
endif
|
||||
let b:complTypeContext = complType
|
||||
|
||||
" Hack to workaround bug when invoking command line completion via <c-r>=
|
||||
elseif b:complType == "\<c-x>\<c-v>"
|
||||
let complType = s:CommandLineCompletion()
|
||||
else
|
||||
let complType = b:complType
|
||||
endif
|
||||
|
||||
" highlight first result if longest enabled
|
||||
if g:SuperTabLongestHighlight &&
|
||||
\ &completeopt =~ 'longest' &&
|
||||
\ &completeopt =~ 'menu' &&
|
||||
\ (!pumvisible() || b:complReset)
|
||||
let dir = (complType == "\<c-p>") ? -1 : 1
|
||||
call feedkeys("\<c-r>=SuperTabLongestHighlight(" . dir . ")\<cr>", 'n')
|
||||
endif
|
||||
|
||||
if b:complReset
|
||||
let b:complReset = 0
|
||||
" not an accurate condition for everyone, but better than sending <c-e>
|
||||
" at the wrong time.
|
||||
if pumvisible()
|
||||
return "\<c-e>" . complType
|
||||
endif
|
||||
endif
|
||||
|
||||
return complType
|
||||
endif
|
||||
|
||||
return "\<tab>"
|
||||
endfunction " }}}
|
||||
|
||||
" s:SuperTabHelp() {{{
|
||||
" Opens a help window where the user can choose a completion type to enter.
|
||||
function! s:SuperTabHelp()
|
||||
let winnr = winnr()
|
||||
if bufwinnr("SuperTabHelp") == -1
|
||||
botright split SuperTabHelp
|
||||
|
||||
setlocal noswapfile
|
||||
setlocal buftype=nowrite
|
||||
setlocal bufhidden=delete
|
||||
|
||||
let saved = @"
|
||||
let @" = s:tabHelp
|
||||
silent put
|
||||
call cursor(1, 1)
|
||||
silent 1,delete
|
||||
call cursor(4, 1)
|
||||
let @" = saved
|
||||
exec "resize " . line('$')
|
||||
|
||||
syntax match Special "|.\{-}|"
|
||||
|
||||
setlocal readonly
|
||||
setlocal nomodifiable
|
||||
|
||||
nmap <silent> <buffer> <cr> :call <SID>SetCompletionType()<cr>
|
||||
nmap <silent> <buffer> <c-]> :call <SID>SetCompletionType()<cr>
|
||||
else
|
||||
exec bufwinnr("SuperTabHelp") . "winc w"
|
||||
endif
|
||||
let b:winnr = winnr
|
||||
endfunction " }}}
|
||||
|
||||
" s:WillComplete() {{{
|
||||
" Determines if completion should be kicked off at the current location.
|
||||
function! s:WillComplete()
|
||||
if pumvisible()
|
||||
return 1
|
||||
endif
|
||||
|
||||
let line = getline('.')
|
||||
let cnum = col('.')
|
||||
|
||||
" Start of line.
|
||||
if line =~ '^\s*\%' . cnum . 'c'
|
||||
return 0
|
||||
endif
|
||||
|
||||
" honor SuperTabNoCompleteAfter
|
||||
let pre = line[:cnum - 2]
|
||||
for pattern in b:SuperTabNoCompleteAfter
|
||||
if pre =~ pattern . '$'
|
||||
return 0
|
||||
endif
|
||||
endfor
|
||||
|
||||
" honor SuperTabNoCompleteBefore
|
||||
" Within a word, but user does not have mid word completion enabled.
|
||||
let post = line[cnum - 1:]
|
||||
for pattern in b:SuperTabNoCompleteBefore
|
||||
if post =~ '^' . pattern
|
||||
return 0
|
||||
endif
|
||||
endfor
|
||||
|
||||
return 1
|
||||
endfunction " }}}
|
||||
|
||||
" s:EnableLongestEnhancement() {{{
|
||||
function! s:EnableLongestEnhancement()
|
||||
augroup supertab_reset
|
||||
autocmd!
|
||||
autocmd InsertLeave,CursorMovedI <buffer>
|
||||
\ call s:ReleaseKeyPresses() | autocmd! supertab_reset
|
||||
augroup END
|
||||
call s:CaptureKeyPresses()
|
||||
endfunction " }}}
|
||||
|
||||
" s:CompletionReset(char) {{{
|
||||
function! s:CompletionReset(char)
|
||||
let b:complReset = 1
|
||||
return a:char
|
||||
endfunction " }}}
|
||||
|
||||
" s:CaptureKeyPresses() {{{
|
||||
function! s:CaptureKeyPresses()
|
||||
if !exists('b:capturing') || !b:capturing
|
||||
let b:capturing = 1
|
||||
" save any previous mappings
|
||||
" TODO: capture additional info provided by vim 7.3.032 and up.
|
||||
let b:captured = {
|
||||
\ '<bs>': maparg('<bs>', 'i'),
|
||||
\ '<c-h>': maparg('<c-h>', 'i'),
|
||||
\ }
|
||||
" TODO: use &keyword to get an accurate list of chars to map
|
||||
for c in split('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_', '.\zs')
|
||||
exec 'imap <buffer> ' . c . ' <c-r>=<SID>CompletionReset("' . c . '")<cr>'
|
||||
endfor
|
||||
imap <buffer> <bs> <c-r>=<SID>CompletionReset("\<lt>bs>")<cr>
|
||||
imap <buffer> <c-h> <c-r>=<SID>CompletionReset("\<lt>c-h>")<cr>
|
||||
endif
|
||||
endfunction " }}}
|
||||
|
||||
" s:ReleaseKeyPresses() {{{
|
||||
function! s:ReleaseKeyPresses()
|
||||
if exists('b:capturing') && b:capturing
|
||||
let b:capturing = 0
|
||||
for c in split('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_', '.\zs')
|
||||
exec 'iunmap <buffer> ' . c
|
||||
endfor
|
||||
|
||||
iunmap <buffer> <bs>
|
||||
iunmap <buffer> <c-h>
|
||||
|
||||
" restore any previous mappings
|
||||
for [key, rhs] in items(b:captured)
|
||||
if rhs != ''
|
||||
let args = substitute(rhs, '.*\(".\{-}"\).*', '\1', '')
|
||||
if args != rhs
|
||||
let args = substitute(args, '<', '<lt>', 'g')
|
||||
let expr = substitute(rhs, '\(.*\)".\{-}"\(.*\)', '\1%s\2', '')
|
||||
let rhs = printf(expr, args)
|
||||
endif
|
||||
exec printf("imap <silent> %s %s", key, rhs)
|
||||
endif
|
||||
endfor
|
||||
unlet b:captured
|
||||
|
||||
if mode() == 'i' && &completeopt =~ 'menu'
|
||||
" force full exit from completion mode (don't exit insert mode since
|
||||
" that will break repeating with '.')
|
||||
call feedkeys("\<space>\<bs>", 'n')
|
||||
endif
|
||||
endif
|
||||
endfunction " }}}
|
||||
|
||||
" s:CommandLineCompletion() {{{
|
||||
" Hack needed to account for apparent bug in vim command line mode completion
|
||||
" when invoked via <c-r>=
|
||||
function! s:CommandLineCompletion()
|
||||
" This hack will trigger InsertLeave which will then invoke
|
||||
" s:SetDefaultCompletionType. To prevent default completion from being
|
||||
" restored prematurely, set an internal flag for s:SetDefaultCompletionType
|
||||
" to check for.
|
||||
let b:complCommandLine = 1
|
||||
return "\<c-\>\<c-o>:call feedkeys('\<c-x>\<c-v>\<c-v>', 'n') | " .
|
||||
\ "let b:complCommandLine = 0\<cr>"
|
||||
endfunction " }}}
|
||||
|
||||
" s:ContextCompletion() {{{
|
||||
function! s:ContextCompletion()
|
||||
let contexts = exists('b:SuperTabCompletionContexts') ?
|
||||
\ b:SuperTabCompletionContexts : g:SuperTabCompletionContexts
|
||||
|
||||
for context in contexts
|
||||
try
|
||||
let Context = function(context)
|
||||
let complType = Context()
|
||||
unlet Context
|
||||
if type(complType) == 1 && complType != ''
|
||||
return complType
|
||||
endif
|
||||
catch /E700/
|
||||
echohl Error
|
||||
echom 'supertab: no context function "' . context . '" found.'
|
||||
echohl None
|
||||
endtry
|
||||
endfor
|
||||
return ''
|
||||
endfunction " }}}
|
||||
|
||||
" s:ContextDiscover() {{{
|
||||
function! s:ContextDiscover()
|
||||
let discovery = exists('g:SuperTabContextDiscoverDiscovery') ?
|
||||
\ g:SuperTabContextDiscoverDiscovery : []
|
||||
|
||||
" loop through discovery list to find the default
|
||||
if !empty(discovery)
|
||||
for pair in discovery
|
||||
let var = substitute(pair, '\(.*\):.*', '\1', '')
|
||||
let type = substitute(pair, '.*:\(.*\)', '\1', '')
|
||||
exec 'let value = ' . var
|
||||
if value !~ '^\s*$' && value != '0'
|
||||
exec "let complType = \"" . escape(type, '<') . "\""
|
||||
return complType
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
endfunction " }}}
|
||||
|
||||
" s:ContextText() {{{
|
||||
function! s:ContextText()
|
||||
let exclusions = exists('g:SuperTabContextTextFileTypeExclusions') ?
|
||||
\ g:SuperTabContextTextFileTypeExclusions : []
|
||||
|
||||
if index(exclusions, &ft) == -1
|
||||
let curline = getline('.')
|
||||
let cnum = col('.')
|
||||
let synname = synIDattr(synID(line('.'), cnum - 1, 1), 'name')
|
||||
if curline =~ '.*/\w*\%' . cnum . 'c' ||
|
||||
\ ((has('win32') || has('win64')) && curline =~ '.*\\\w*\%' . cnum . 'c')
|
||||
return "\<c-x>\<c-f>"
|
||||
|
||||
elseif curline =~ '.*\(\w\|[\])]\)\(\.\|::\|->\)\w*\%' . cnum . 'c' &&
|
||||
\ synname !~ '\(String\|Comment\)'
|
||||
let omniPrecedence = exists('g:SuperTabContextTextOmniPrecedence') ?
|
||||
\ g:SuperTabContextTextOmniPrecedence : ['&completefunc', '&omnifunc']
|
||||
|
||||
for omniFunc in omniPrecedence
|
||||
if omniFunc !~ '^&'
|
||||
let omniFunc = '&' . omniFunc
|
||||
endif
|
||||
if getbufvar(bufnr('%'), omniFunc) != ''
|
||||
return omniFunc == '&omnifunc' ? "\<c-x>\<c-o>" : "\<c-x>\<c-u>"
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
endif
|
||||
endfunction " }}}
|
||||
|
||||
" s:ExpandMap(map) {{{
|
||||
function! s:ExpandMap(map)
|
||||
let map = a:map
|
||||
if map =~ '<Plug>'
|
||||
let plug = substitute(map, '.\{-}\(<Plug>\w\+\).*', '\1', '')
|
||||
let plug_map = maparg(plug, 'i')
|
||||
let map = substitute(map, '.\{-}\(<Plug>\w\+\).*', plug_map, '')
|
||||
endif
|
||||
return map
|
||||
endfunction " }}}
|
||||
|
||||
" Key Mappings {{{
|
||||
" map a regular tab to ctrl-tab (note: doesn't work in console vim)
|
||||
exec 'inoremap ' . g:SuperTabMappingTabLiteral . ' <tab>'
|
||||
|
||||
imap <c-x> <c-r>=<SID>ManualCompletionEnter()<cr>
|
||||
|
||||
imap <script> <Plug>SuperTabForward <c-r>=<SID>SuperTab('n')<cr>
|
||||
imap <script> <Plug>SuperTabBackward <c-r>=<SID>SuperTab('p')<cr>
|
||||
|
||||
exec 'imap ' . g:SuperTabMappingForward . ' <Plug>SuperTabForward'
|
||||
exec 'imap ' . g:SuperTabMappingBackward . ' <Plug>SuperTabBackward'
|
||||
|
||||
" After hitting <Tab>, hitting it once more will go to next match
|
||||
" (because in XIM mode <c-n> and <c-p> mappings are ignored)
|
||||
" and wont start a brand new completion
|
||||
" The side effect, that in the beginning of line <c-n> and <c-p> inserts a
|
||||
" <Tab>, but I hope it may not be a problem...
|
||||
let ctrl_n = maparg('<c-n>', 'i')
|
||||
if ctrl_n != ''
|
||||
let ctrl_n = substitute(ctrl_n, '<', '<lt>', 'g')
|
||||
exec 'imap <c-n> <c-r>=<SID>ForwardBack("n", "' . ctrl_n . '")<cr>'
|
||||
else
|
||||
imap <c-n> <Plug>SuperTabForward
|
||||
endif
|
||||
let ctrl_p = maparg('<c-p>', 'i')
|
||||
if ctrl_p != ''
|
||||
let ctrl_p = substitute(ctrl_p, '<', '<lt>', 'g')
|
||||
exec 'imap <c-p> <c-r>=<SID>ForwardBack("p", "' . ctrl_p . '")<cr>'
|
||||
else
|
||||
imap <c-p> <Plug>SuperTabBackward
|
||||
endif
|
||||
function! s:ForwardBack(command, map)
|
||||
exec "let map = \"" . escape(a:map, '<') . "\""
|
||||
return pumvisible() ? s:SuperTab(a:command) : map
|
||||
endfunction
|
||||
|
||||
if g:SuperTabCrMapping
|
||||
if maparg('<CR>','i') =~ '<CR>'
|
||||
let map = maparg('<cr>', 'i')
|
||||
let cr = (map =~? '\(^\|[^)]\)<cr>')
|
||||
let map = s:ExpandMap(map)
|
||||
exec "inoremap <script> <cr> <c-r>=<SID>SelectCompletion(" . cr . ")<cr>" . map
|
||||
else
|
||||
inoremap <cr> <c-r>=<SID>SelectCompletion(1)<cr>
|
||||
endif
|
||||
function! s:SelectCompletion(cr)
|
||||
" selecting a completion
|
||||
if pumvisible()
|
||||
" ugly hack to let other <cr> mappings for other plugins cooperate
|
||||
" with supertab
|
||||
let b:supertab_pumwasvisible = 1
|
||||
|
||||
" close the preview window if configured to do so
|
||||
if &completeopt =~ 'preview' && g:SuperTabCrClosePreview
|
||||
let preview = 0
|
||||
for bufnum in tabpagebuflist()
|
||||
if getwinvar(bufwinnr(bufnum), '&previewwindow')
|
||||
let preview = 1
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
if preview
|
||||
pclose
|
||||
endif
|
||||
endif
|
||||
|
||||
return "\<c-y>"
|
||||
endif
|
||||
|
||||
" only needed when chained with other mappings and one of them will
|
||||
" issue a <cr>.
|
||||
if exists('b:supertab_pumwasvisible') && !a:cr
|
||||
unlet b:supertab_pumwasvisible
|
||||
return ''
|
||||
endif
|
||||
|
||||
" not so pleasant hack to keep <cr> working for abbreviations
|
||||
let word = substitute(getline('.'), '^.*\s\+\(.*\%' . col('.') . 'c\).*', '\1', '')
|
||||
if maparg(word, 'i', 1) != ''
|
||||
call feedkeys("\<c-]>", 't')
|
||||
call feedkeys("\<cr>", 'n')
|
||||
return ''
|
||||
endif
|
||||
|
||||
" only return a cr if nothing else is mapped to it since we don't want
|
||||
" to duplicate a cr returned by another mapping.
|
||||
return a:cr ? "\<cr>" : ""
|
||||
endfunction
|
||||
endif
|
||||
" }}}
|
||||
|
||||
" Command Mappings {{{
|
||||
if !exists(":SuperTabHelp")
|
||||
command SuperTabHelp :call <SID>SuperTabHelp()
|
||||
endif
|
||||
" }}}
|
||||
|
||||
call s:Init()
|
||||
|
||||
let &cpo = s:save_cpo
|
||||
|
||||
" vim:ft=vim:fdm=marker
|
|
@ -0,0 +1 @@
|
|||
/doc/tags
|
|
@ -0,0 +1,149 @@
|
|||
fugitive.vim
|
||||
============
|
||||
|
||||
I'm not going to lie to you; fugitive.vim may very well be the best
|
||||
Git wrapper of all time. Check out these features:
|
||||
|
||||
View any blob, tree, commit, or tag in the repository with `:Gedit` (and
|
||||
`:Gsplit`, `:Gvsplit`, `:Gtabedit`, ...). Edit a file in the index and
|
||||
write to it to stage the changes. Use `:Gdiff` to bring up the staged
|
||||
version of the file side by side with the working tree version and use
|
||||
Vim's diff handling capabilities to stage a subset of the file's
|
||||
changes.
|
||||
|
||||
Bring up the output of `git status` with `:Gstatus`. Press `-` to
|
||||
`add`/`reset` a file's changes, or `p` to `add`/`reset` `--patch` that
|
||||
mofo. And guess what `:Gcommit` does!
|
||||
|
||||
`:Gblame` brings up an interactive vertical split with `git blame`
|
||||
output. Press enter on a line to reblame the file as it stood in that
|
||||
commit, or `o` to open that commit in a split. When you're done, use
|
||||
`:Gedit` in the historic buffer to go back to the work tree version.
|
||||
|
||||
`:Gmove` does a `git mv` on a file and simultaneously renames the
|
||||
buffer. `:Gremove` does a `git rm` on a file and simultaneously deletes
|
||||
the buffer.
|
||||
|
||||
Use `:Ggrep` to search the work tree (or any arbitrary commit) with
|
||||
`git grep`, skipping over that which is not tracked in the repository.
|
||||
`:Glog` loads all previous revisions of a file into the quickfix list so
|
||||
you can iterate over them and watch the file evolve!
|
||||
|
||||
`:Gread` is a variant of `git checkout -- filename` that operates on the
|
||||
buffer rather than the filename. This means you can use `u` to undo it
|
||||
and you never get any warnings about the file changing outside Vim.
|
||||
`:Gwrite` writes to both the work tree and index versions of a file,
|
||||
making it like `git add` when called from a work tree file and like
|
||||
`git checkout` when called from the index or a blob in history.
|
||||
|
||||
Use `:Gbrowse` to open the current file on GitHub, with optional line
|
||||
range (try it in visual mode!). If your current repository isn't on
|
||||
GitHub, `git instaweb` will be spun up instead.
|
||||
|
||||
Add `%{fugitive#statusline()}` to `'statusline'` to get an indicator
|
||||
with the current branch in (surprise!) your statusline.
|
||||
|
||||
Last but not least, there's `:Git` for running any arbitrary command,
|
||||
and `Git!` to open the output of a command in a temp file.
|
||||
|
||||
Screencasts
|
||||
-----------
|
||||
|
||||
* [A complement to command line git](http://vimcasts.org/e/31)
|
||||
* [Working with the git index](http://vimcasts.org/e/32)
|
||||
* [Resolving merge conflicts with vimdiff](http://vimcasts.org/e/33)
|
||||
* [Browsing the git object database](http://vimcasts.org/e/34)
|
||||
* [Exploring the history of a git repository](http://vimcasts.org/e/35)
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
If you don't have a preferred installation method, I recommend
|
||||
installing [pathogen.vim](https://github.com/tpope/vim-pathogen), and
|
||||
then simply copy and paste:
|
||||
|
||||
cd ~/.vim/bundle
|
||||
git clone git://github.com/tpope/vim-fugitive.git
|
||||
|
||||
Once help tags have been generated, you can view the manual with
|
||||
`:help fugitive`.
|
||||
|
||||
If your Vim version is below 7.2, I recommend also installing
|
||||
[vim-git](https://github.com/tpope/vim-git) for syntax highlighting and
|
||||
other Git niceties.
|
||||
|
||||
FAQ
|
||||
---
|
||||
|
||||
> I installed the plugin and started Vim. Why don't any of the commands
|
||||
> exist?
|
||||
|
||||
Fugitive cares about the current file, not the current working
|
||||
directory. Edit a file from the repository.
|
||||
|
||||
> I opened a new tab. Why don't any of the commands exist?
|
||||
|
||||
Fugitive cares about the current file, not the current working
|
||||
directory. Edit a file from the repository.
|
||||
|
||||
> Why is `:Gbrowse` not using my system default browser?
|
||||
|
||||
`:Gbrowse` delegates to `git web--browse`, which is less than perfect
|
||||
when it comes to finding the default browser on Linux. You can tell it
|
||||
the correct browser to use with `git config --global web.browser ...`.
|
||||
See `git web--browse --help` for details.
|
||||
|
||||
> Here's a patch that automatically opens the quickfix window after
|
||||
> `:Ggrep`.
|
||||
|
||||
This is a great example of why I recommend asking before patching.
|
||||
There are valid arguments to be made both for and against automatically
|
||||
opening the quickfix window. Whenever I have to make an arbitrary
|
||||
decision like this, I ask what Vim would do. And Vim does not open a
|
||||
quickfix window after `:grep`.
|
||||
|
||||
Luckily, it's easy to implement the desired behavior without changing
|
||||
fugitive.vim. The following autocommand will cause the quickfix window
|
||||
to open after any grep invocation:
|
||||
|
||||
autocmd QuickFixCmdPost *grep* cwindow
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
||||
Before reporting a bug, you should try stripping down your Vim
|
||||
configuration and removing other plugins. The sad nature of VimScript
|
||||
is that it is fraught with incompatibilities waiting to happen. I'm
|
||||
happy to work around them where I can, but it's up to you to isolate
|
||||
the conflict.
|
||||
|
||||
If your [commit message sucks](http://stopwritingramblingcommitmessages.com/),
|
||||
I'm not going to accept your pull request. I've explained very politely
|
||||
dozens of times that
|
||||
[my general guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)
|
||||
are absolute rules on my own repositories, so I may lack the energy to
|
||||
explain it to you yet another time. And please, if I ask you to change
|
||||
something, `git commit --amend`.
|
||||
|
||||
Beyond that, don't be shy about asking before patching. What takes you
|
||||
hours might take me minutes simply because I have both domain knowledge
|
||||
and a perverse knowledge of VimScript so vast that many would consider
|
||||
it a symptom of mental illness. On the flip side, some ideas I'll
|
||||
reject no matter how good the implementation is. "Send a patch" is an
|
||||
edge case answer in my book.
|
||||
|
||||
Self-Promotion
|
||||
--------------
|
||||
|
||||
Like fugitive.vim? Follow the repository on
|
||||
[GitHub](https://github.com/tpope/vim-fugitive) and vote for it on
|
||||
[vim.org](http://www.vim.org/scripts/script.php?script_id=2975). And if
|
||||
you're feeling especially charitable, follow [tpope](http://tpo.pe/) on
|
||||
[Twitter](http://twitter.com/tpope) and
|
||||
[GitHub](https://github.com/tpope).
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
Copyright (c) Tim Pope. Distributed under the same terms as Vim itself.
|
||||
See `:help license`.
|
|
@ -0,0 +1,271 @@
|
|||
*fugitive.txt* A Git wrapper so awesome, it should be illegal
|
||||
|
||||
Author: Tim Pope <http://tpo.pe/>
|
||||
License: Same terms as Vim itself (see |license|)
|
||||
|
||||
This plugin is only available if 'compatible' is not set.
|
||||
|
||||
INTRODUCTION *fugitive*
|
||||
|
||||
Whenever you edit a file from a Git repository, a set of commands is defined
|
||||
that serve as a gateway to Git.
|
||||
|
||||
COMMANDS *fugitive-commands*
|
||||
|
||||
These commands are local to the buffers in which they work (generally, buffers
|
||||
that are part of Git repositories).
|
||||
|
||||
*fugitive-:Git*
|
||||
:Git [args] Run an arbitrary git command. Similar to :!git [args]
|
||||
but chdir to the repository tree first.
|
||||
|
||||
*fugitive-:Git!*
|
||||
:Git! [args] Like |:Git|, but capture the output into a temp file,
|
||||
and edit that temp file.
|
||||
|
||||
*fugitive-:Gcd*
|
||||
:Gcd [directory] |:cd| relative to the repository.
|
||||
|
||||
*fugitive-:Glcd*
|
||||
:Glcd [directory] |:lcd| relative to the repository.
|
||||
|
||||
*fugitive-:Gstatus*
|
||||
:Gstatus Bring up the output of git-status in the preview
|
||||
window. The following maps, which work on the cursor
|
||||
line file where sensible, are provided:
|
||||
|
||||
<C-N> next file
|
||||
<C-P> previous file
|
||||
<CR> |:Gedit|
|
||||
- |:Git| add
|
||||
- |:Git| reset (staged files)
|
||||
C |:Gcommit|
|
||||
cA |Gcommit| --amend --reuse-message=HEAD
|
||||
ca |Gcommit| --amend
|
||||
D |:Gdiff|
|
||||
ds |:Gsdiff|
|
||||
dp |:Git!| diff (p for patch; use :Gw to apply)
|
||||
dp |:Git| add --intent-to-add (untracked files)
|
||||
dv |:Gvdiff|
|
||||
O |:Gtabedit|
|
||||
o |:Gsplit|
|
||||
p |:Git| add --patch
|
||||
p |:Git| reset --patch (staged files)
|
||||
q close status
|
||||
R reload status
|
||||
|
||||
*fugitive-:Gcommit*
|
||||
:Gcommit [args] A wrapper around git-commit. If there is nothing
|
||||
to commit, |:Gstatus| is called instead. Unless the
|
||||
arguments given would skip the invocation of an editor
|
||||
(e.g., -m), a split window will be used to obtain a
|
||||
commit message. Write and close that window (:wq or
|
||||
|:Gwrite|) to finish the commit. Unlike when running
|
||||
the actual git-commit command, it is possible (but
|
||||
unadvisable) to muck with the index with commands like
|
||||
git-add and git-reset while a commit message is
|
||||
pending.
|
||||
|
||||
*fugitive-:Ggrep*
|
||||
:Ggrep [args] |:grep| with git-grep as 'grepprg'.
|
||||
|
||||
*fugitive-:Glog*
|
||||
:Glog [args] Load all previous revisions of the current file into
|
||||
the quickfix list. Additional git-log arguments can
|
||||
be given (for example, --reverse). If "--" appears as
|
||||
an argument, no file specific filtering is done, and
|
||||
commits are loaded into the quickfix list.
|
||||
|
||||
*fugitive-:Gedit* *fugitive-:Ge*
|
||||
:Gedit [revision] |:edit| a |fugitive-revision|.
|
||||
|
||||
*fugitive-:Gsplit*
|
||||
:Gsplit [revision] |:split| a |fugitive-revision|.
|
||||
|
||||
*fugitive-:Gvsplit*
|
||||
:Gvsplit [revision] |:vsplit| a |fugitive-revision|.
|
||||
|
||||
*fugitive-:Gtabedit*
|
||||
:Gtabedit [revision] |:tabedit| a |fugitive-revision|.
|
||||
|
||||
*fugitive-:Gpedit*
|
||||
:Gpedit [revision] |:pedit| a |fugitive-revision|.
|
||||
|
||||
:Gsplit! [args] *fugitive-:Gsplit!* *fugitive-:Gvsplit!*
|
||||
:Gvsplit! [args] *fugitive-:Gtabedit!* *fugitive-:Gpedit!*
|
||||
:Gtabedit! [args] Like |:Git!|, but open the resulting temp file in a
|
||||
:Gpedit! [args] split, tab, or preview window.
|
||||
|
||||
*fugitive-:Gread*
|
||||
:Gread [revision] Empty the buffer and |:read| a |fugitive-revision|.
|
||||
When the argument is omitted, this is similar to
|
||||
git-checkout on a work tree file or git-add on a stage
|
||||
file, but without writing anything to disk.
|
||||
|
||||
:{range}Gread [revision]
|
||||
|:read| in a |fugitive-revision| after {range}.
|
||||
|
||||
*fugitive-:Gread!*
|
||||
:Gread! [args] Empty the buffer and |:read| the output of a Git
|
||||
command. For example, :Gread! show HEAD:%.
|
||||
|
||||
:{range}Gread! [args] |:read| the output of a Git command after {range}.
|
||||
|
||||
*fugitive-:Gwrite*
|
||||
:Gwrite Write to the current file's path and stage the results.
|
||||
When run in a work tree file, it is effectively git
|
||||
add. Elsewhere, it is effectively git-checkout. A
|
||||
great deal of effort is expended to behave sensibly
|
||||
when the work tree or index version of the file is
|
||||
open in another buffer.
|
||||
|
||||
:Gwrite {path} You can give |:Gwrite| an explicit path of where in
|
||||
the work tree to write. You can also give a path like
|
||||
:0:foo.txt or even :0 to write to just that stage in
|
||||
the index.
|
||||
|
||||
*fugitive-:Gwq*
|
||||
:Gwq [path] Like |:Gwrite| followed by |:quit| if the write
|
||||
succeeded.
|
||||
|
||||
:Gwq! [path] Like |:Gwrite|! followed by |:quit|! if the write
|
||||
succeeded.
|
||||
|
||||
*fugitive-:Gdiff*
|
||||
:Gdiff [revision] Perform a |vimdiff| against the current file in the
|
||||
given revision. With no argument, the version in the
|
||||
index is used (which means a three-way diff during a
|
||||
merge conflict, making it a git-mergetool
|
||||
alternative). The newer of the two files is placed
|
||||
to the right. Use |do| and |dp| and write to the
|
||||
index file to simulate "git add --patch".
|
||||
|
||||
*fugitive-:Gsdiff*
|
||||
:Gsdiff [revision] Like |:Gdiff|, but split horizontally.
|
||||
|
||||
*fugitive-:Gvdiff*
|
||||
:Gvdiff [revision] Identical to |:Gdiff|. For symmetry with |:Gsdiff|.
|
||||
|
||||
*fugitive-:Gmove*
|
||||
:Gmove {destination} Wrapper around git-mv that renames the buffer
|
||||
afterward. The destination is relative to the current
|
||||
directory except when started with a /, in which case
|
||||
it is relative to the work tree. Add a ! to pass -f.
|
||||
|
||||
*fugitive-:Gremove*
|
||||
:Gremove Wrapper around git-rm that deletes the buffer
|
||||
afterward. When invoked in an index file, --cached is
|
||||
passed. Add a ! to pass -f and forcefully discard the
|
||||
buffer.
|
||||
|
||||
*fugitive-:Gblame*
|
||||
:Gblame [flags] Run git-blame on the file and open the results in a
|
||||
scroll bound vertical split. Press enter on a line to
|
||||
reblame the file as it was in that commit. You can
|
||||
give any of ltwfsMC as flags and they will be passed
|
||||
along to git-blame. The following maps, which work on
|
||||
the cursor line commit where sensible, are provided:
|
||||
|
||||
q close blame and return to blamed window
|
||||
gq q, then |:Gedit| to return to work tree version
|
||||
i q, then open commit
|
||||
o open commit in horizontal split
|
||||
O open commit in new tab
|
||||
<CR> reblame at commit
|
||||
~ reblame at [count]th first grandparent
|
||||
P reblame at [count]th parent (like HEAD^[count])
|
||||
|
||||
:[range]Gblame [flags] Run git-blame on the given range.
|
||||
|
||||
*fugitive-:Gbrowse*
|
||||
:[range]Gbrowse If the remote for the current branch is on GitHub,
|
||||
open the current file, blob, tree, commit, or tag
|
||||
(with git-web--browse) on GitHub. Otherwise, open the
|
||||
current file, blob, tree, commit, or tag in
|
||||
git-instaweb (if you have issues, verify you can run
|
||||
"git instaweb" from a terminal). If a range is given,
|
||||
it is appropriately appended to the URL as an anchor.
|
||||
|
||||
:[range]Gbrowse! Like :Gbrowse, but put the URL on the clipboard rather
|
||||
than opening it.
|
||||
|
||||
:[range]Gbrowse {revision}
|
||||
Like :Gbrowse, but for a given |fugitive-revision|. A
|
||||
useful value here is -, which ties the URL to the
|
||||
latest commit rather than a volatile branch.
|
||||
|
||||
:[range]Gbrowse [...]@{remote}
|
||||
Force using the given remote rather than the remote
|
||||
for the current branch. The remote is used to
|
||||
determine which GitHub repository to link to.
|
||||
|
||||
MAPPINGS *fugitive-mappings*
|
||||
|
||||
These maps are available in Git objects.
|
||||
|
||||
*fugitive-<CR>*
|
||||
<CR> Jump to the revision under the cursor.
|
||||
|
||||
*fugitive-o*
|
||||
o Jump to the revision under the cursor in a new split.
|
||||
|
||||
*fugitive-O*
|
||||
O Jump to the revision under the cursor in a new tab.
|
||||
|
||||
*fugitive-~*
|
||||
~ Go to the current file in the [count]th first
|
||||
ancestor.
|
||||
|
||||
*fugitive-P*
|
||||
P Go to the current file in the [count]th parent.
|
||||
|
||||
*fugitive-C*
|
||||
C Go to the commit containing the current file.
|
||||
|
||||
*fugitive-a*
|
||||
a Show the current tag, commit, or tree in an alternate
|
||||
format.
|
||||
|
||||
SPECIFYING REVISIONS *fugitive-revision*
|
||||
|
||||
Fugitive revisions are similar to Git revisions as defined in the "SPECIFYING
|
||||
REVISIONS" section in the git-rev-parse man page. For commands that accept an
|
||||
optional revision, the default is the file in the index for work tree files
|
||||
and the work tree file for everything else. Example revisions follow.
|
||||
|
||||
Revision Meaning ~
|
||||
HEAD .git/HEAD
|
||||
master .git/refs/heads/master
|
||||
HEAD^{} The commit referenced by HEAD
|
||||
HEAD^ The parent of the commit referenced by HEAD
|
||||
HEAD: The tree referenced by HEAD
|
||||
/HEAD The file named HEAD in the work tree
|
||||
Makefile The file named Makefile in the work tree
|
||||
HEAD^:Makefile The file named Makefile in the parent of HEAD
|
||||
:Makefile The file named Makefile in the index (writable)
|
||||
- The current file in HEAD
|
||||
^ The current file in the previous commit
|
||||
~3 The current file 3 commits ago
|
||||
: .git/index (Same as |:Gstatus|)
|
||||
:0 The current file in the index
|
||||
:1 The current file's common ancestor during a conflict
|
||||
:2 The current file in the target branch during a conflict
|
||||
:3 The current file in the merged branch during a conflict
|
||||
:/foo The most recent commit with "foo" in the message
|
||||
|
||||
STATUSLINE *fugitive-statusline*
|
||||
|
||||
*fugitive#statusline()*
|
||||
Add %{fugitive#statusline()} to your statusline to get an indicator including
|
||||
the current branch and the currently edited file's commit. If you don't have
|
||||
a statusline, this one matches the default when 'ruler' is set:
|
||||
>
|
||||
set statusline=%<%f\ %h%m%r%{fugitive#statusline()}%=%-14.(%l,%c%V%)\ %P
|
||||
<
|
||||
ABOUT *fugitive-about*
|
||||
|
||||
Grab the latest version or report a bug on GitHub:
|
||||
|
||||
http://github.com/tpope/vim-fugitive
|
||||
|
||||
vim:tw=78:et:ft=help:norl:
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,2 @@
|
|||
doc/tags
|
||||
*.cache
|
|
@ -0,0 +1,100 @@
|
|||
=================
|
||||
Powerline for vim
|
||||
=================
|
||||
|
||||
:Author: Kim Silkebækken (kim.silkebaekken+vim@gmail.com)
|
||||
:Source: https://github.com/Lokaltog/vim-powerline
|
||||
:Version: β
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Powerline is a utility plugin which allows you to create better-looking,
|
||||
more functional vim statuslines. See the screenshots below for
|
||||
a demonstration of the plugin's capabilities.
|
||||
|
||||
It's recommended that you install the plugin using Pathogen_ or Vundle_.
|
||||
After the plugin is installed update your help tags and see ``:help
|
||||
Powerline`` for instructions on how to enable and configure the plugin.
|
||||
|
||||
See the `Troubleshooting`_ section below if you're having any issues with
|
||||
the plugin or the font patcher.
|
||||
|
||||
**Note:** You need a patched font to be able to use the symbols in the
|
||||
statusbar. An experimental Python/fontforge-based font patcher is included
|
||||
in the ``fontpatcher`` directory. See ``fontpatcher/README.rst`` for usage
|
||||
instructions.
|
||||
|
||||
.. _Pathogen: https://github.com/tpope/vim-pathogen
|
||||
.. _Vundle: https://github.com/gmarik/vundle
|
||||
|
||||
Screenshots
|
||||
-----------
|
||||
|
||||
**Normal mode**
|
||||
|
||||
.. image:: http://i.imgur.com/xFmOt.png
|
||||
|
||||
**Insert mode**
|
||||
|
||||
.. image:: http://i.imgur.com/5vDlB.png
|
||||
|
||||
**Command-T buffer** with custom color
|
||||
|
||||
.. image:: http://i.imgur.com/fDIhz.png
|
||||
|
||||
**Tagbar buffer** with custom color
|
||||
|
||||
.. image:: http://i.imgur.com/WZUvj.png
|
||||
|
||||
**Symbols when buffer is modified or read-only**
|
||||
|
||||
.. image:: http://i.imgur.com/dGJHZ.png
|
||||
|
||||
**Split window showing inactive buffer statusline**
|
||||
|
||||
.. image:: http://i.imgur.com/z18KU.png
|
||||
|
||||
**Normal mode without custom font**
|
||||
|
||||
.. image:: http://i.imgur.com/yCybn.png
|
||||
|
||||
Troubleshooting
|
||||
---------------
|
||||
|
||||
I can't see the fancy symbols, what's wrong?
|
||||
Make sure that you have ``let g:Powerline_symbols = 'fancy'`` in your
|
||||
``vimrc`` file. The settings may be loaded too late if you have this in
|
||||
``gvimrc``, so always put this in your ``vimrc``.
|
||||
|
||||
Clear the cache using ``:PowerlineClearCache`` and restart vim.
|
||||
|
||||
Make sure that you've configured gvim or your terminal emulator to use
|
||||
a patched font.
|
||||
|
||||
I'm unable to patch my font, what should I do?
|
||||
Font patching is only known to work on most Linux and OS X machines. If
|
||||
you have followed the instructions in the fontpatcher README and still
|
||||
have problems, please submit an issue on GitHub.
|
||||
|
||||
You can download some community-contributed patched fonts from the
|
||||
`Powerline wiki`_ if you don't want to mess around with the font
|
||||
patcher.
|
||||
|
||||
The Syntastic/Fugitive statusline flags don't work!
|
||||
These flags should work without any configuration. If you installed
|
||||
either plugin after Powerline, you'll have to clear the cache using
|
||||
``:PowerlineClearCache`` and restart vim.
|
||||
|
||||
The colors are weird in the default OS X Terminal app!
|
||||
The default OS X Terminal app is known to have some issues with the
|
||||
Powerline colors. Please use another terminal emulator. iTerm2 should
|
||||
work fine.
|
||||
|
||||
The statusbar is hidden/only appears in split windows!
|
||||
Make sure that you have ``set laststatus=2`` in your ``vimrc``.
|
||||
|
||||
If you have any other issues and you can't find the answer in the docs,
|
||||
please submit an issue on GitHub.
|
||||
|
||||
.. _`Powerline wiki`: https://github.com/Lokaltog/vim-powerline/wiki/Patched-fonts
|
|
@ -0,0 +1,121 @@
|
|||
" Powerline - The ultimate statusline utility
|
||||
"
|
||||
" Author: Kim Silkebækken <kim.silkebaekken+vim@gmail.com>
|
||||
" Source repository: https://github.com/Lokaltog/vim-powerline
|
||||
|
||||
" Commands {{{
|
||||
command! PowerlineClearCache call Pl#ClearCache()
|
||||
" }}}
|
||||
" Script variables {{{
|
||||
let g:Pl#OLD_STL = ''
|
||||
let g:Pl#THEME = []
|
||||
let g:Pl#HL = []
|
||||
|
||||
" Cache revision, this must be incremented whenever the cache format is changed
|
||||
let s:CACHE_REVISION = 2
|
||||
" }}}
|
||||
" Script initialization {{{
|
||||
function! Pl#LoadCache() " {{{
|
||||
if filereadable(g:Powerline_cache_file) && g:Powerline_cache_enabled
|
||||
exec 'source' escape(g:Powerline_cache_file, ' \')
|
||||
|
||||
if ! exists('g:Powerline_cache_revision') || g:Powerline_cache_revision != s:CACHE_REVISION
|
||||
" Cache revision differs, cache is invalid
|
||||
unlet! g:Powerline_cache_revision
|
||||
|
||||
return 0
|
||||
endif
|
||||
|
||||
" Create highlighting groups
|
||||
for hi_cmd in g:Pl#HL
|
||||
exec hi_cmd
|
||||
endfor
|
||||
|
||||
return 1
|
||||
endif
|
||||
|
||||
return 0
|
||||
endfunction " }}}
|
||||
function! Pl#ClearCache() " {{{
|
||||
if filereadable(g:Powerline_cache_file)
|
||||
" Delete the cache file
|
||||
call delete(g:Powerline_cache_file)
|
||||
endif
|
||||
|
||||
echo 'Powerline cache cleared. Please restart vim for the changes to take effect.'
|
||||
endfunction " }}}
|
||||
function! Pl#Load() " {{{
|
||||
if empty(g:Pl#OLD_STL)
|
||||
" Store old statusline
|
||||
let g:Pl#OLD_STL = &statusline
|
||||
endif
|
||||
|
||||
if ! Pl#LoadCache()
|
||||
try
|
||||
" Autoload the theme dict first
|
||||
let raw_theme = g:Powerline#Themes#{g:Powerline_theme}#theme
|
||||
catch
|
||||
echoe 'Invalid Powerline theme! Please check your theme and colorscheme settings.'
|
||||
|
||||
return
|
||||
endtry
|
||||
|
||||
" Create list with parsed statuslines
|
||||
for buffer_statusline in raw_theme
|
||||
call add(g:Pl#THEME, {
|
||||
\ 'matches': buffer_statusline.matches,
|
||||
\ 'mode_statuslines': Pl#Parser#GetStatusline(buffer_statusline.segments)
|
||||
\ })
|
||||
endfor
|
||||
|
||||
if ! g:Powerline_cache_enabled
|
||||
" Don't cache anything if caching is disabled or cache file isn't writeable
|
||||
return
|
||||
endif
|
||||
|
||||
" Prepare commands and statuslines for caching
|
||||
let cache = [
|
||||
\ 'let g:Powerline_cache_revision = '. string(s:CACHE_REVISION),
|
||||
\ 'let g:Pl#HL = '. string(g:Pl#HL),
|
||||
\ 'let g:Pl#THEME = '. string(g:Pl#THEME),
|
||||
\ ]
|
||||
|
||||
call writefile(cache, g:Powerline_cache_file)
|
||||
endif
|
||||
endfunction " }}}
|
||||
" }}}
|
||||
" Statusline updater {{{
|
||||
function! Pl#Statusline(statusline, current) " {{{
|
||||
let mode = mode()
|
||||
|
||||
if ! a:current
|
||||
let mode = 'N' " Normal (non-current)
|
||||
elseif mode =~# '\v(v|V|)'
|
||||
let mode = 'v' " Visual mode
|
||||
elseif mode =~# '\v(s|S|)'
|
||||
let mode = 's' " Select mode
|
||||
elseif mode =~# '\vi'
|
||||
let mode = 'i' " Insert mode
|
||||
elseif mode =~# '\v(R|Rv)'
|
||||
let mode = 'r' " Replace mode
|
||||
else
|
||||
" Fallback to normal mode
|
||||
let mode = 'n' " Normal (current)
|
||||
endif
|
||||
|
||||
return g:Pl#THEME[a:statusline].mode_statuslines[mode]
|
||||
endfunction " }}}
|
||||
function! Pl#UpdateStatusline(current) " {{{
|
||||
if empty(g:Pl#THEME)
|
||||
" Load statuslines if they aren't loaded yet
|
||||
call Pl#Load()
|
||||
endif
|
||||
|
||||
for i in range(0, len(g:Pl#THEME) - 1)
|
||||
if Pl#Match#Validate(g:Pl#THEME[i].matches)
|
||||
" Update window-local statusline
|
||||
let &l:statusline = '%!Pl#Statusline('. i .','. a:current .')'
|
||||
endif
|
||||
endfor
|
||||
endfunction " }}}
|
||||
" }}}
|
|
@ -0,0 +1,161 @@
|
|||
function! Pl#Colorscheme#Init(hi) " {{{
|
||||
let colorscheme = {}
|
||||
|
||||
for hi in a:hi
|
||||
" Ensure that the segments are a list
|
||||
let segments = type(hi[0]) == type('') ? [ hi[0] ] : hi[0]
|
||||
let mode_hi_dict = hi[1]
|
||||
|
||||
for segment in segments
|
||||
let colorscheme[segment] = mode_hi_dict
|
||||
endfor
|
||||
endfor
|
||||
|
||||
return colorscheme
|
||||
endfunction " }}}
|
||||
function! Pl#Colorscheme#Apply(colorscheme, buffer_segments) " {{{
|
||||
" Set color parameters for all segments in a:buffer_segments
|
||||
|
||||
" TODO This function should be recursive and work on both segments and groups
|
||||
" TODO We could probably handle the NS stuff here...
|
||||
|
||||
try
|
||||
let colorscheme = g:Powerline#Colorschemes#{a:colorscheme}#colorscheme
|
||||
catch
|
||||
echoe 'Color scheme "'. a:colorscheme .'" doesn''t exist!'
|
||||
|
||||
return
|
||||
endtry
|
||||
|
||||
let buffer_segments = a:buffer_segments
|
||||
|
||||
" This is a bit complex, I'll walk you through exactly what happens here...
|
||||
"
|
||||
" First of all we loop through the buffer_segments, which are the segments that
|
||||
" this specific buffer will have.
|
||||
for buffer_segment in buffer_segments
|
||||
" The buffer_segment consists of a 'matches' list and a 'segments' list.
|
||||
" The 'matches' list has conditions to limit this statusline to specific buffers/windows.
|
||||
" The 'segments' list has each segment and segment group for this buffer
|
||||
for segment in buffer_segment.segments
|
||||
let type = get(segment, 'type', '')
|
||||
|
||||
if type == 'segment_group'
|
||||
" We're going to handle segment groups different from single segments. Segment groups
|
||||
" have child segments which may have their own highlighting (e.g. fileinfo.flags),
|
||||
" and these child segments may be grouped (e.g. fileinfo.flags.ro) to provide very
|
||||
" specific highlighting. So here we'll handle all that:
|
||||
|
||||
" Set the default/fallback colors for this group
|
||||
for i in range(len(segment.variants), 0, -1)
|
||||
" Check for available highlighting for the main group segment
|
||||
"
|
||||
" This works like the segment highlighting below
|
||||
" TODO Create a function for this
|
||||
let seg_variants = join(segment.variants[0:i], '.')
|
||||
|
||||
let seg_name = i > 0 ? segment.name .'.'. seg_variants : segment.name
|
||||
let seg_ns_name = len(segment.ns) > 0 ? segment.ns .':'. seg_name : seg_name
|
||||
|
||||
if has_key(colorscheme, seg_ns_name)
|
||||
" We have a namespaced highlight group
|
||||
let segment.colors = colorscheme[seg_ns_name]
|
||||
break
|
||||
elseif has_key(colorscheme, seg_name)
|
||||
" We have a non-namespaced group
|
||||
let segment.colors = colorscheme[seg_name]
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
|
||||
" The reason why we need to deepcopy the group's segments is that the child segments
|
||||
" all point to the same base segments and that screws up highlighting if we highlight
|
||||
" some child segments with different namespaced colors
|
||||
let segment.segments = deepcopy(segment.segments)
|
||||
|
||||
" Apply colors to each child segment
|
||||
for child_segment in segment.segments
|
||||
" Check if this child segment is grouped (e.g. fileinfo.flags.group.subgroup)
|
||||
" We're going to prioritize the most specific grouping and then work back to the
|
||||
" most common group (e.g. fileinfo.flags)
|
||||
|
||||
" FIXME We don't have the variants from before because group children aren't run through Pl#Segment#Get
|
||||
let child_segment.variants = [seg_name] + split(child_segment.name, '\.')
|
||||
|
||||
" Use the parent group's namespace
|
||||
let child_segment.ns = segment.ns
|
||||
|
||||
for i in range(len(child_segment.variants), 0, -1)
|
||||
" Check for available highlighting for the main group segment
|
||||
let child_seg_name = join(child_segment.variants[0:i], '.')
|
||||
|
||||
let child_seg_ns_name = len(child_segment.ns) > 0 ? child_segment.ns .':'. child_seg_name : child_seg_name
|
||||
|
||||
if has_key(colorscheme, child_seg_ns_name)
|
||||
" We have a namespaced highlight group
|
||||
let child_segment.colors = colorscheme[child_seg_ns_name]
|
||||
break
|
||||
elseif has_key(colorscheme, child_seg_name)
|
||||
" We have a non-namespaced group
|
||||
let child_segment.colors = colorscheme[child_seg_name]
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
endfor
|
||||
elseif type == 'segment'
|
||||
for i in range(len(segment.variants), 0, -1)
|
||||
" Check for available highlighting
|
||||
"
|
||||
" This is done in the following manner, using the segment gundo:static_filename.text.buffer as an example:
|
||||
"
|
||||
" * Look for the hl group: gundo:static_filename.text.buffer
|
||||
" * Look for the hl group: static_filename.text.buffer
|
||||
" * Look for the hl group: gundo:static_filename.text
|
||||
" * Look for the hl group: static_filename.text
|
||||
" * Look for the hl group: gundo:static_filename
|
||||
" * Look for the hl group: static_filename
|
||||
" * Return the segment without highlighting, causing an error in the parser
|
||||
let seg_variants = join(segment.variants[0:i], '.')
|
||||
|
||||
let seg_name = i > 0 ? segment.name .'.'. seg_variants : segment.name
|
||||
let seg_ns_name = len(segment.ns) > 0 ? segment.ns .':'. seg_name : seg_name
|
||||
|
||||
if has_key(colorscheme, seg_ns_name)
|
||||
" We have a namespaced highlight group
|
||||
let segment.colors = colorscheme[seg_ns_name]
|
||||
break
|
||||
elseif has_key(colorscheme, seg_name)
|
||||
" We have a non-namespaced group
|
||||
let segment.colors = colorscheme[seg_name]
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
|
||||
unlet! segment
|
||||
endfor
|
||||
endfor
|
||||
|
||||
" Good luck parsing this return value
|
||||
"
|
||||
" It's a huge dict with all segments for all buffers with their respective syntax highlighting.
|
||||
" It will be parsed by the main Powerline code, where all the data will be shortened to a simple
|
||||
" array consiting of a statusline for each mode, with generated highlighting groups and dividers.
|
||||
return buffer_segments
|
||||
endfunction " }}}
|
||||
function! Pl#Colorscheme#HiSegment(segments, normal, ...) " {{{
|
||||
let mode_hi_dict = {
|
||||
\ 'n': a:normal
|
||||
\ }
|
||||
|
||||
if a:0 && type(a:1) == type({})
|
||||
for [modes, hl] in items(a:1)
|
||||
for mode in split(modes, '\zs')
|
||||
let mode_hi_dict[mode] = hl
|
||||
endfor
|
||||
endfor
|
||||
endif
|
||||
|
||||
" a:segments may be either a string or a list of strings to use this highlighting
|
||||
return [a:segments, mode_hi_dict]
|
||||
endfunction " }}}
|
|
@ -0,0 +1,104 @@
|
|||
" cterm -> gui color dict {{{
|
||||
let s:cterm2gui_dict = {
|
||||
\ 16: 0x000000, 17: 0x00005f, 18: 0x000087, 19: 0x0000af, 20: 0x0000d7, 21: 0x0000ff,
|
||||
\ 22: 0x005f00, 23: 0x005f5f, 24: 0x005f87, 25: 0x005faf, 26: 0x005fd7, 27: 0x005fff,
|
||||
\ 28: 0x008700, 29: 0x00875f, 30: 0x008787, 31: 0x0087af, 32: 0x0087d7, 33: 0x0087ff,
|
||||
\ 34: 0x00af00, 35: 0x00af5f, 36: 0x00af87, 37: 0x00afaf, 38: 0x00afd7, 39: 0x00afff,
|
||||
\ 40: 0x00d700, 41: 0x00d75f, 42: 0x00d787, 43: 0x00d7af, 44: 0x00d7d7, 45: 0x00d7ff,
|
||||
\ 46: 0x00ff00, 47: 0x00ff5f, 48: 0x00ff87, 49: 0x00ffaf, 50: 0x00ffd7, 51: 0x00ffff,
|
||||
\ 52: 0x5f0000, 53: 0x5f005f, 54: 0x5f0087, 55: 0x5f00af, 56: 0x5f00d7, 57: 0x5f00ff,
|
||||
\ 58: 0x5f5f00, 59: 0x5f5f5f, 60: 0x5f5f87, 61: 0x5f5faf, 62: 0x5f5fd7, 63: 0x5f5fff,
|
||||
\ 64: 0x5f8700, 65: 0x5f875f, 66: 0x5f8787, 67: 0x5f87af, 68: 0x5f87d7, 69: 0x5f87ff,
|
||||
\ 70: 0x5faf00, 71: 0x5faf5f, 72: 0x5faf87, 73: 0x5fafaf, 74: 0x5fafd7, 75: 0x5fafff,
|
||||
\ 76: 0x5fd700, 77: 0x5fd75f, 78: 0x5fd787, 79: 0x5fd7af, 80: 0x5fd7d7, 81: 0x5fd7ff,
|
||||
\ 82: 0x5fff00, 83: 0x5fff5f, 84: 0x5fff87, 85: 0x5fffaf, 86: 0x5fffd7, 87: 0x5fffff,
|
||||
\ 88: 0x870000, 89: 0x87005f, 90: 0x870087, 91: 0x8700af, 92: 0x8700d7, 93: 0x8700ff,
|
||||
\ 94: 0x875f00, 95: 0x875f5f, 96: 0x875f87, 97: 0x875faf, 98: 0x875fd7, 99: 0x875fff,
|
||||
\ 100: 0x878700, 101: 0x87875f, 102: 0x878787, 103: 0x8787af, 104: 0x8787d7, 105: 0x8787ff,
|
||||
\ 106: 0x87af00, 107: 0x87af5f, 108: 0x87af87, 109: 0x87afaf, 110: 0x87afd7, 111: 0x87afff,
|
||||
\ 112: 0x87d700, 113: 0x87d75f, 114: 0x87d787, 115: 0x87d7af, 116: 0x87d7d7, 117: 0x87d7ff,
|
||||
\ 118: 0x87ff00, 119: 0x87ff5f, 120: 0x87ff87, 121: 0x87ffaf, 122: 0x87ffd7, 123: 0x87ffff,
|
||||
\ 124: 0xaf0000, 125: 0xaf005f, 126: 0xaf0087, 127: 0xaf00af, 128: 0xaf00d7, 129: 0xaf00ff,
|
||||
\ 130: 0xaf5f00, 131: 0xaf5f5f, 132: 0xaf5f87, 133: 0xaf5faf, 134: 0xaf5fd7, 135: 0xaf5fff,
|
||||
\ 136: 0xaf8700, 137: 0xaf875f, 138: 0xaf8787, 139: 0xaf87af, 140: 0xaf87d7, 141: 0xaf87ff,
|
||||
\ 142: 0xafaf00, 143: 0xafaf5f, 144: 0xafaf87, 145: 0xafafaf, 146: 0xafafd7, 147: 0xafafff,
|
||||
\ 148: 0xafd700, 149: 0xafd75f, 150: 0xafd787, 151: 0xafd7af, 152: 0xafd7d7, 153: 0xafd7ff,
|
||||
\ 154: 0xafff00, 155: 0xafff5f, 156: 0xafff87, 157: 0xafffaf, 158: 0xafffd7, 159: 0xafffff,
|
||||
\ 160: 0xd70000, 161: 0xd7005f, 162: 0xd70087, 163: 0xd700af, 164: 0xd700d7, 165: 0xd700ff,
|
||||
\ 166: 0xd75f00, 167: 0xd75f5f, 168: 0xd75f87, 169: 0xd75faf, 170: 0xd75fd7, 171: 0xd75fff,
|
||||
\ 172: 0xd78700, 173: 0xd7875f, 174: 0xd78787, 175: 0xd787af, 176: 0xd787d7, 177: 0xd787ff,
|
||||
\ 178: 0xd7af00, 179: 0xd7af5f, 180: 0xd7af87, 181: 0xd7afaf, 182: 0xd7afd7, 183: 0xd7afff,
|
||||
\ 184: 0xd7d700, 185: 0xd7d75f, 186: 0xd7d787, 187: 0xd7d7af, 188: 0xd7d7d7, 189: 0xd7d7ff,
|
||||
\ 190: 0xd7ff00, 191: 0xd7ff5f, 192: 0xd7ff87, 193: 0xd7ffaf, 194: 0xd7ffd7, 195: 0xd7ffff,
|
||||
\ 196: 0xff0000, 197: 0xff005f, 198: 0xff0087, 199: 0xff00af, 200: 0xff00d7, 201: 0xff00ff,
|
||||
\ 202: 0xff5f00, 203: 0xff5f5f, 204: 0xff5f87, 205: 0xff5faf, 206: 0xff5fd7, 207: 0xff5fff,
|
||||
\ 208: 0xff8700, 209: 0xff875f, 210: 0xff8787, 211: 0xff87af, 212: 0xff87d7, 213: 0xff87ff,
|
||||
\ 214: 0xffaf00, 215: 0xffaf5f, 216: 0xffaf87, 217: 0xffafaf, 218: 0xffafd7, 219: 0xffafff,
|
||||
\ 220: 0xffd700, 221: 0xffd75f, 222: 0xffd787, 223: 0xffd7af, 224: 0xffd7d7, 225: 0xffd7ff,
|
||||
\ 226: 0xffff00, 227: 0xffff5f, 228: 0xffff87, 229: 0xffffaf, 230: 0xffffd7, 231: 0xffffff,
|
||||
\ 232: 0x080808, 233: 0x121212, 234: 0x1c1c1c, 235: 0x262626, 236: 0x303030, 237: 0x3a3a3a,
|
||||
\ 238: 0x444444, 239: 0x4e4e4e, 240: 0x585858, 241: 0x626262, 242: 0x6c6c6c, 243: 0x767676,
|
||||
\ 244: 0x808080, 245: 0x8a8a8a, 246: 0x949494, 247: 0x9e9e9e, 248: 0xa8a8a8, 249: 0xb2b2b2,
|
||||
\ 250: 0xbcbcbc, 251: 0xc6c6c6, 252: 0xd0d0d0, 253: 0xdadada, 254: 0xe4e4e4, 255: 0xeeeeee
|
||||
\ }
|
||||
" }}}
|
||||
function! s:Cterm2GUI(cterm) " {{{
|
||||
if toupper(a:cterm) == 'NONE'
|
||||
return 'NONE'
|
||||
endif
|
||||
|
||||
if ! has_key(s:cterm2gui_dict, a:cterm)
|
||||
return 0xff0000
|
||||
endif
|
||||
|
||||
return s:cterm2gui_dict[a:cterm]
|
||||
endfunction " }}}
|
||||
function! Pl#Hi#Create(...) " {{{
|
||||
let hi = {
|
||||
\ 'cterm': ['', ''],
|
||||
\ 'gui' : ['', ''],
|
||||
\ 'attr' : []
|
||||
\ }
|
||||
|
||||
" Fetch highlighting details from parameters
|
||||
for param in a:000
|
||||
" String parameters are always attributes
|
||||
if type(param) == type('')
|
||||
if tolower(param) == 'none'
|
||||
let param = 'NONE'
|
||||
endif
|
||||
|
||||
call add(hi['attr'], param)
|
||||
|
||||
continue
|
||||
endif
|
||||
|
||||
" Other parameters are either Pl#Hi#Cterm or Pl#Hi#GUI return values (lists)
|
||||
let hi[param[0]] = [toupper(param[1]), toupper(param[2])]
|
||||
|
||||
unlet! param
|
||||
endfor
|
||||
|
||||
" Fallback to term colors in gvim
|
||||
if empty(hi['gui'][0]) && ! empty(hi['cterm'][0])
|
||||
let hi['gui'][0] = s:Cterm2GUI(hi['cterm'][0])
|
||||
endif
|
||||
if empty(hi['gui'][1]) && ! empty(hi['cterm'][1])
|
||||
let hi['gui'][1] = s:Cterm2GUI(hi['cterm'][1])
|
||||
endif
|
||||
|
||||
" Return dict with properly formatted color values
|
||||
return {
|
||||
\ 'ctermfg': (empty(hi['cterm'][0]) ? '' : (string(hi['cterm'][0]) == 'NONE' ? 'NONE' : hi['cterm'][0])),
|
||||
\ 'ctermbg': (empty(hi['cterm'][1]) ? '' : (string(hi['cterm'][1]) == 'NONE' ? 'NONE' : hi['cterm'][1])),
|
||||
\ 'guifg': (empty(hi['gui'][0]) ? '' : (string(hi['gui'][0]) == 'NONE' ? 'NONE' : hi['gui'][0])),
|
||||
\ 'guibg': (empty(hi['gui'][1]) ? '' : (string(hi['gui'][1]) == 'NONE' ? 'NONE' : hi['gui'][1])),
|
||||
\ 'attr': (! len(hi['attr']) ? 'NONE' : join(hi['attr'], ','))
|
||||
\ }
|
||||
endfunction " }}}
|
||||
function! Pl#Hi#Cterm(fg, ...) " {{{
|
||||
return ['cterm', a:fg, (a:0 ? a:1 : '')]
|
||||
endfunction " }}}
|
||||
function! Pl#Hi#GUI(fg, ...) " {{{
|
||||
return ['gui', a:fg, (a:0 ? a:1 : '')]
|
||||
endfunction " }}}
|
|
@ -0,0 +1,39 @@
|
|||
function! Pl#Match#Add(pat, expr) " {{{
|
||||
return [a:pat, a:expr]
|
||||
endfunction " }}}
|
||||
function! Pl#Match#Any(...) " {{{
|
||||
let matches = []
|
||||
|
||||
for match_name in a:000
|
||||
if empty(match_name)
|
||||
" Skip empty match parameters
|
||||
continue
|
||||
endif
|
||||
|
||||
if has_key(g:Powerline#Matches#matches, match_name)
|
||||
call add(matches, g:Powerline#Matches#matches[match_name])
|
||||
endif
|
||||
|
||||
unlet! match_name
|
||||
endfor
|
||||
|
||||
return ['match', 'any', matches]
|
||||
endfunction " }}}
|
||||
function! Pl#Match#Validate(match) " {{{
|
||||
let [m, match, matches] = a:match
|
||||
|
||||
if ! len(matches)
|
||||
" Empty match array matches everything
|
||||
return 1
|
||||
endif
|
||||
|
||||
if match == 'any'
|
||||
for [eval, re] in matches
|
||||
if match(eval(eval), '\v'. re) != -1
|
||||
return 1
|
||||
endif
|
||||
endfor
|
||||
|
||||
return 0
|
||||
endif
|
||||
endfunction " }}}
|
|
@ -0,0 +1,40 @@
|
|||
let s:segment_mods = []
|
||||
|
||||
function! Pl#Mod#AddSegmentMod(action, properties) " {{{
|
||||
call add(s:segment_mods, [a:action, a:properties])
|
||||
endfunction " }}}
|
||||
function! Pl#Mod#ApplySegmentMods(theme) " {{{
|
||||
let theme = deepcopy(a:theme)
|
||||
|
||||
for mod in s:segment_mods
|
||||
let [action, properties] = mod
|
||||
|
||||
" We have to loop through the segments instead of using index() because some
|
||||
" segments are lists!
|
||||
let target_seg_idx = -1
|
||||
|
||||
for i in range(0, len(theme) - 1)
|
||||
unlet! segment
|
||||
let segment = theme[i]
|
||||
|
||||
if type(segment) == type(properties.target_segment) && segment == properties.target_segment
|
||||
let target_seg_idx = i
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
|
||||
if action == 'insert_segment'
|
||||
" Insert segment
|
||||
if target_seg_idx != -1
|
||||
call insert(theme, properties.new_segment, (properties.where == 'before' ? target_seg_idx : target_seg_idx + 1))
|
||||
endif
|
||||
elseif action == 'remove_segment'
|
||||
" Remove segment
|
||||
if target_seg_idx != -1
|
||||
call remove(theme, target_seg_idx)
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
|
||||
return theme
|
||||
endfunction " }}}
|
|
@ -0,0 +1,337 @@
|
|||
let g:Pl#Parser#Symbols = {
|
||||
\ 'compatible': {
|
||||
\ 'dividers': [ '', [0x2502], '', [0x2502] ]
|
||||
\ , 'symbols' : {
|
||||
\ 'BRANCH': 'BR:'
|
||||
\ , 'RO' : 'RO'
|
||||
\ , 'FT' : 'FT'
|
||||
\ , 'LINE' : 'LN'
|
||||
\ , 'COL' : 'C'
|
||||
\ }
|
||||
\ },
|
||||
\ 'unicode': {
|
||||
\ 'dividers': [ [0x25b6], [0x276f], [0x25c0], [0x276e] ]
|
||||
\ , 'symbols' : {
|
||||
\ 'BRANCH': [0x26a1]
|
||||
\ , 'RO' : [0x2613]
|
||||
\ , 'FT' : [0x2691]
|
||||
\ , 'LINE' : [0x204b]
|
||||
\ , 'COL' : [0x2551]
|
||||
\ },
|
||||
\ },
|
||||
\ 'fancy': {
|
||||
\ 'dividers': [ [0x2b80], [0x2b81], [0x2b82], [0x2b83] ]
|
||||
\ , 'symbols' : {
|
||||
\ 'BRANCH': [0x2b60]
|
||||
\ , 'RO' : [0x2b64]
|
||||
\ , 'FT' : [0x2b62, 0x2b63]
|
||||
\ , 'LINE' : [0x2b61]
|
||||
\ , 'COL' : [0x2551]
|
||||
\ }
|
||||
\ }
|
||||
\ }
|
||||
|
||||
let s:LEFT_SIDE = 0
|
||||
let s:RIGHT_SIDE = 2
|
||||
|
||||
let s:PADDING = 1
|
||||
|
||||
let s:EMPTY_SEGMENT = { 'type': 'empty' }
|
||||
|
||||
let s:HARD_DIVIDER = 0
|
||||
let s:SOFT_DIVIDER = 1
|
||||
|
||||
function! Pl#Parser#GetStatusline(segments) " {{{
|
||||
let statusline = {
|
||||
\ 'n': ''
|
||||
\ , 'N': ''
|
||||
\ , 'v': ''
|
||||
\ , 'i': ''
|
||||
\ , 'r': ''
|
||||
\ , 's': ''
|
||||
\ }
|
||||
|
||||
" Run through the different modes and create the statuslines
|
||||
for mode in keys(statusline)
|
||||
" Create an empty statusline list
|
||||
let stl = []
|
||||
|
||||
call extend(stl, s:ParseSegments(mode, s:LEFT_SIDE, a:segments))
|
||||
|
||||
let statusline[mode] .= join(stl, '')
|
||||
endfor
|
||||
|
||||
return statusline
|
||||
endfunction " }}}
|
||||
function! Pl#Parser#ParseChars(arg) " {{{
|
||||
" Handles symbol arrays which can be either an array of hex values,
|
||||
" or a string. Will convert the hex array to a string, or return the
|
||||
" string as-is.
|
||||
let arg = a:arg
|
||||
|
||||
if type(arg) == type([])
|
||||
" Hex array
|
||||
call map(arg, 'nr2char(v:val)')
|
||||
|
||||
return join(arg, '')
|
||||
endif
|
||||
|
||||
" Anything else, just return it as it is
|
||||
return arg
|
||||
endfunction " }}}
|
||||
function! s:ParseSegments(mode, side, segments, ...) " {{{
|
||||
let mode = a:mode
|
||||
let side = a:side
|
||||
let segments = a:segments
|
||||
|
||||
let level = exists('a:1') ? a:1 : 0
|
||||
let base_color = exists('a:2') ? a:2 : {}
|
||||
|
||||
let ret = []
|
||||
|
||||
for i in range(0, len(segments) - 1)
|
||||
unlet! seg_prev seg_curr seg_next
|
||||
|
||||
" Prepare some resources (fetch previous, current and next segment)
|
||||
let seg_curr = deepcopy(get(segments, i))
|
||||
|
||||
" Find previous segment
|
||||
let seg_prev = s:EMPTY_SEGMENT
|
||||
|
||||
" If we're currently at i = 0 we have to start on 0 or else we will start on the last segment (list[-1])
|
||||
let range_start = (i == 0 ? i : i - 1)
|
||||
for j in range(range_start, 0, -1)
|
||||
let seg = deepcopy(get(segments, j))
|
||||
if get(seg, 'name') ==# 'TRUNCATE'
|
||||
" Skip truncate segments
|
||||
continue
|
||||
endif
|
||||
|
||||
" Look ahead for another segment that's visible in this mode
|
||||
if index(get(seg, 'modes'), mode) != -1
|
||||
" Use this segment
|
||||
let seg_prev = seg
|
||||
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
|
||||
"" Find next segment
|
||||
let seg_next = s:EMPTY_SEGMENT
|
||||
|
||||
" If we're currently at i = len(segments) - 1 we have to start on i or else we will get an error because the index doesn't exist
|
||||
let range_start = (i == len(segments) - 1 ? i : i + 1)
|
||||
for j in range(range_start, len(segments) - 1, 1)
|
||||
let seg = deepcopy(get(segments, j))
|
||||
if get(seg, 'name') ==# 'TRUNCATE'
|
||||
" Skip truncate segments
|
||||
continue
|
||||
endif
|
||||
|
||||
" Look ahead for another segment that's visible in this mode
|
||||
if index(get(seg, 'modes'), mode) != -1
|
||||
" Use this segment
|
||||
let seg_next = seg
|
||||
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
|
||||
if index(get(seg_curr, 'modes', []), mode) == -1
|
||||
" The segment is invisible in this mode, skip it
|
||||
" FIXME When two segments after each other are hidden, a gap appears where the segments would be, this is probably due to segment padding
|
||||
continue
|
||||
endif
|
||||
|
||||
" Handle the different segment types
|
||||
if seg_curr.type == 'segment'
|
||||
if seg_curr.name ==# 'TRUNCATE'
|
||||
" Truncate statusline
|
||||
call add(ret, '%<')
|
||||
elseif seg_curr.name ==# 'SPLIT'
|
||||
" Split statusline
|
||||
|
||||
" Switch sides
|
||||
let side = s:RIGHT_SIDE
|
||||
|
||||
" Handle highlighting
|
||||
let mode_colors = get(seg_curr.colors, mode, seg_curr.colors['n'])
|
||||
let hl_group = s:HlCreate(mode_colors)
|
||||
|
||||
" Add segment text
|
||||
call add(ret, '%#'. hl_group .'#%=')
|
||||
else
|
||||
" Add segment text
|
||||
let text = seg_curr.text
|
||||
|
||||
" Decide on whether to use the group's colors or the segment's colors
|
||||
let colors = get(seg_curr, 'colors', base_color)
|
||||
|
||||
" Fallback to normal (current) highlighting if we don't have mode-specific highlighting
|
||||
let mode_colors = get(colors, mode, get(colors, 'n', {}))
|
||||
|
||||
if empty(mode_colors)
|
||||
echoe 'Segment doesn''t have any colors! NS: "'. seg_curr.ns .'" SEG: "'. seg_curr.name .'"'
|
||||
|
||||
continue
|
||||
endif
|
||||
|
||||
" Check if we're in a group (level > 0)
|
||||
if level > 0
|
||||
" If we're in a group we don't have dividers between segments, so we should only pad one side
|
||||
let padding_right = (side == s:LEFT_SIDE ? repeat(' ', s:PADDING) : '')
|
||||
let padding_left = (side == s:RIGHT_SIDE ? repeat(' ', s:PADDING) : '')
|
||||
|
||||
" Check if we lack a bg/fg color for this segment
|
||||
" If we do, use the bg/fg color from base_color
|
||||
let base_color_mode = ! has_key(base_color, mode) ? base_color['n'] : base_color[mode]
|
||||
|
||||
for col in ['ctermbg', 'ctermfg', 'guibg', 'guifg']
|
||||
if empty(mode_colors[col])
|
||||
let mode_colors[col] = base_color_mode[col]
|
||||
endif
|
||||
endfor
|
||||
else
|
||||
"" If we're outside a group we have dividers and must pad both sides
|
||||
let padding_left = repeat(' ', s:PADDING)
|
||||
let padding_right = repeat(' ', s:PADDING)
|
||||
endif
|
||||
|
||||
" Get main hl group for segment
|
||||
let hl_group = s:HlCreate(mode_colors)
|
||||
|
||||
" Prepare segment text
|
||||
let text = '%(%#'. hl_group .'#'. padding_left . text . padding_right . '%)'
|
||||
|
||||
if level == 0
|
||||
" Add divider to single segments
|
||||
let text = s:AddDivider(text, side, mode, colors, seg_prev, seg_curr, seg_next)
|
||||
endif
|
||||
|
||||
call add(ret, text)
|
||||
endif
|
||||
elseif seg_curr.type == 'segment_group'
|
||||
" Recursively parse segment group
|
||||
let func_params = [mode, side, seg_curr.segments, level + 1]
|
||||
|
||||
if has_key(seg_curr, 'colors')
|
||||
" Pass the base colors on to the child segments
|
||||
call add(func_params, seg_curr.colors)
|
||||
endif
|
||||
|
||||
" Get segment group string
|
||||
let text = join(call('s:ParseSegments', func_params), '')
|
||||
|
||||
" Pad on the opposite side of the divider
|
||||
let padding_right = (side == s:RIGHT_SIDE ? repeat(' ', s:PADDING) : '')
|
||||
let padding_left = (side == s:LEFT_SIDE ? repeat(' ', s:PADDING) : '')
|
||||
|
||||
let text = s:AddDivider(padding_left . text . padding_right, side, mode, seg_curr.colors, seg_prev, seg_curr, seg_next)
|
||||
|
||||
call add(ret, text)
|
||||
endif
|
||||
endfor
|
||||
|
||||
return ret
|
||||
endfunction " }}}
|
||||
function! s:HlCreate(hl) " {{{
|
||||
" Create a short and unique highlighting group name
|
||||
" It uses the hex values of all the color properties and an attribute flag at the end
|
||||
" NONE colors are translated to NN for cterm and NNNNNN for gui colors
|
||||
let hi_group = printf('Pl%s%s%s%s%s'
|
||||
\ , (a:hl['ctermfg'] == 'NONE' ? 'NN' : printf('%02x', a:hl['ctermfg']))
|
||||
\ , (a:hl['guifg'] == 'NONE' ? 'NNNNNN' : printf('%06x', a:hl['guifg'] ))
|
||||
\ , (a:hl['ctermbg'] == 'NONE' ? 'NN' : printf('%02x', a:hl['ctermbg']))
|
||||
\ , (a:hl['guibg'] == 'NONE' ? 'NNNNNN' : printf('%06x', a:hl['guibg'] ))
|
||||
\ , substitute(a:hl['attr'], '\v([a-zA-Z])[a-zA-Z]*,?', '\1', 'g')
|
||||
\ )
|
||||
|
||||
if ! s:HlExists(hi_group)
|
||||
let ctermbg = a:hl['ctermbg'] == 'NONE' ? 'NONE' : printf('%d', a:hl['ctermbg'])
|
||||
if (has('win32') || has('win64')) && !has('gui_running') && ctermbg != 'NONE' && ctermbg > 128
|
||||
let ctermbg -= 128
|
||||
endif
|
||||
let hi_cmd = printf('hi %s ctermfg=%s ctermbg=%s cterm=%s guifg=%s guibg=%s gui=%s'
|
||||
\ , hi_group
|
||||
\ , a:hl['ctermfg'] == 'NONE' ? 'NONE' : printf('%d', a:hl['ctermfg'])
|
||||
\ , ctermbg
|
||||
\ , a:hl['attr']
|
||||
\ , (a:hl['guifg'] == 'NONE' ? 'NONE' : printf('#%06x', a:hl['guifg']))
|
||||
\ , (a:hl['guibg'] == 'NONE' ? 'NONE' : printf('#%06x', a:hl['guibg']))
|
||||
\ , a:hl['attr']
|
||||
\ )
|
||||
|
||||
exec hi_cmd
|
||||
|
||||
" Add command to Pl#HL list for caching
|
||||
call add(g:Pl#HL, hi_cmd)
|
||||
endif
|
||||
|
||||
" Return only the highlighting group name
|
||||
return hi_group
|
||||
endfunction " }}}
|
||||
function! s:HlExists(hl) " {{{
|
||||
if ! hlexists(a:hl)
|
||||
return 0
|
||||
endif
|
||||
|
||||
redir => hlstatus
|
||||
silent exec 'hi' a:hl
|
||||
redir END
|
||||
|
||||
return (hlstatus !~ 'cleared')
|
||||
endfunction " }}}
|
||||
function! s:AddDivider(text, side, mode, colors, prev, curr, next) " {{{
|
||||
let seg_prev = a:prev
|
||||
let seg_curr = a:curr
|
||||
let seg_next = a:next
|
||||
|
||||
" Set default color/type for the divider
|
||||
let div_colors = get(a:colors, a:mode, a:colors['n'])
|
||||
let div_type = s:SOFT_DIVIDER
|
||||
|
||||
" Define segment to compare
|
||||
let cmp_seg = a:side == s:LEFT_SIDE ? seg_next : seg_prev
|
||||
|
||||
let cmp_all_colors = get(cmp_seg, 'colors', {})
|
||||
let cmp_colors = get(cmp_all_colors, a:mode, get(cmp_all_colors, 'n', {}))
|
||||
|
||||
if ! empty(cmp_colors)
|
||||
" Compare the highlighting groups
|
||||
"
|
||||
" If the background color for cterm is equal, use soft divider with the current segment's highlighting
|
||||
" If not, use hard divider with a new highlighting group
|
||||
"
|
||||
" Note that if the previous/next segment is the split, a hard divider is always used
|
||||
if get(div_colors, 'ctermbg') != get(cmp_colors, 'ctermbg') || get(seg_next, 'name') ==# 'SPLIT' || get(seg_prev, 'name') ==# 'SPLIT'
|
||||
let div_type = s:HARD_DIVIDER
|
||||
|
||||
" Create new highlighting group
|
||||
" Use FG = CURRENT BG, BG = CMP BG
|
||||
let div_colors['ctermfg'] = get(div_colors, 'ctermbg')
|
||||
let div_colors['guifg'] = get(div_colors, 'guibg')
|
||||
|
||||
let div_colors['ctermbg'] = get(cmp_colors, 'ctermbg')
|
||||
let div_colors['guibg'] = get(cmp_colors, 'guibg')
|
||||
endif
|
||||
endif
|
||||
|
||||
" Prepare divider
|
||||
let divider_raw = deepcopy(g:Pl#Parser#Symbols[g:Powerline_symbols].dividers[a:side + div_type])
|
||||
let divider = Pl#Parser#ParseChars(divider_raw)
|
||||
|
||||
" Don't add dividers for segments adjacent to split (unless it's a hard divider)
|
||||
if ((get(seg_next, 'name') ==# 'SPLIT' || get(seg_prev, 'name') ==# 'SPLIT') && div_type != s:HARD_DIVIDER)
|
||||
return ''
|
||||
endif
|
||||
|
||||
if a:side == s:LEFT_SIDE
|
||||
" Left side
|
||||
" Divider to the right
|
||||
return printf('%%(%s%%#%s#%s%%)', a:text, s:HlCreate(div_colors), divider)
|
||||
else
|
||||
" Right side
|
||||
" Divider to the left
|
||||
return printf('%%(%%#%s#%s%s%%)', s:HlCreate(div_colors), divider, a:text)
|
||||
endif
|
||||
endfunction " }}}
|
|
@ -0,0 +1,178 @@
|
|||
let s:default_modes = ['n', 'N', 'v', 'i', 'r', 's']
|
||||
|
||||
function! s:CheckConditions(params) " {{{
|
||||
" Check conditions for a segment/group
|
||||
" Integer parameters are always conditions
|
||||
for param in a:params
|
||||
if type(param) == type(0) && param == 0
|
||||
" Break here if it's an integer parameter and it's false (0)
|
||||
return 0
|
||||
endif
|
||||
unlet! param
|
||||
endfor
|
||||
|
||||
return 1
|
||||
endfunction " }}}
|
||||
function! Pl#Segment#Create(name, ...) " {{{
|
||||
" Check condition parameters
|
||||
if ! s:CheckConditions(a:000)
|
||||
return {}
|
||||
endif
|
||||
|
||||
let name = a:name
|
||||
let modes = s:default_modes
|
||||
let segments = []
|
||||
|
||||
for param in a:000
|
||||
" Lookup modes for this segment/group
|
||||
if type(param) == type([]) && param[0] == 'modes'
|
||||
let modes = param[1]
|
||||
elseif type(a:1) == type([]) && a:1[0] == 'segment'
|
||||
call add(segments, param[1])
|
||||
endif
|
||||
|
||||
unlet! param
|
||||
endfor
|
||||
|
||||
if type(a:1) == type([]) && a:1[0] == 'segment'
|
||||
" This is a segment group
|
||||
return ['segment_group', {
|
||||
\ 'type': 'segment_group'
|
||||
\ , 'name': name
|
||||
\ , 'segments': segments
|
||||
\ , 'modes': modes
|
||||
\ }]
|
||||
else
|
||||
" This is a single segment
|
||||
let text = a:1
|
||||
|
||||
" Search/replace symbols
|
||||
for [key, symbol] in items(g:Pl#Parser#Symbols[g:Powerline_symbols].symbols)
|
||||
let text = substitute(
|
||||
\ text,
|
||||
\ '\v\$('. key .')',
|
||||
\ '\=Pl#Parser#ParseChars(g:Pl#Parser#Symbols[g:Powerline_symbols].symbols[submatch(1)])',
|
||||
\ 'g')
|
||||
endfor
|
||||
|
||||
return ['segment', {
|
||||
\ 'type': 'segment'
|
||||
\ , 'name': name
|
||||
\ , 'text': text
|
||||
\ , 'modes': modes
|
||||
\ }]
|
||||
endif
|
||||
|
||||
endfunction " }}}
|
||||
function! Pl#Segment#Init(...) " {{{
|
||||
" Check condition parameters
|
||||
if ! s:CheckConditions(a:000)
|
||||
return {}
|
||||
endif
|
||||
|
||||
let segments = {}
|
||||
let ns = ''
|
||||
|
||||
for param in a:000
|
||||
if type(param) == type('')
|
||||
" String parameters is the namespace
|
||||
let ns = param
|
||||
elseif type(param) == type([])
|
||||
" The data dict is in param[1]
|
||||
" By default we don't have a namespace for the segment
|
||||
let segment = param[1]
|
||||
|
||||
if ! empty(ns)
|
||||
" Update segment so that it includes the namespace
|
||||
" Add the namespace to the segment dict key
|
||||
let segment.ns = ns
|
||||
let segment.name = join([segment.ns, segment.name], ':')
|
||||
endif
|
||||
|
||||
let key = segment.name
|
||||
|
||||
let segments[key] = segment
|
||||
endif
|
||||
|
||||
unlet! param
|
||||
endfor
|
||||
|
||||
return segments
|
||||
endfunction " }}}
|
||||
function! Pl#Segment#Modes(modes) " {{{
|
||||
" Handle modes for both segments and groups
|
||||
let modes = split(a:modes, '\zs')
|
||||
|
||||
if modes[0] == '!'
|
||||
" Filter modes (e.g. "!nr" will ignore the segment in normal and replace modes)
|
||||
let modes = filter(deepcopy(s:default_modes), 'v:val !~# "['. join(modes[1:]) .']"')
|
||||
endif
|
||||
|
||||
return ['modes', modes]
|
||||
endfunction " }}}
|
||||
function! Pl#Segment#Split(...) " {{{
|
||||
return a:0 ? a:1 .':SPLIT' : 'SPLIT'
|
||||
endfunction " }}}
|
||||
function! Pl#Segment#Truncate() " {{{
|
||||
return 'TRUNCATE'
|
||||
endfunction " }}}
|
||||
function! Pl#Segment#Get(name) " {{{
|
||||
" Return a segment data dict
|
||||
let args = []
|
||||
|
||||
" Check for printf segments (lists)
|
||||
if type(a:name) == type([])
|
||||
" We're dealing with a segment with printf arguments
|
||||
let seg_orig_name = a:name[0]
|
||||
let args = a:name[1:]
|
||||
else
|
||||
let seg_orig_name = a:name
|
||||
endif
|
||||
|
||||
" Fetch namespace and variants for storing in the segment dict
|
||||
let seg_ns = ''
|
||||
let seg_variants = []
|
||||
|
||||
" Retrieve color scheme variants
|
||||
let seg_name_split = split(seg_orig_name, '\v\.')
|
||||
if len(seg_name_split) > 1
|
||||
let seg_variants = seg_name_split[1:]
|
||||
endif
|
||||
|
||||
" Retrieve segment name and namespace
|
||||
" Use the first piece of the split string, we can't have variants in the final segment name
|
||||
let seg_name_split = split(seg_name_split[0], '\v:')
|
||||
let seg_name = seg_name_split[0]
|
||||
|
||||
if len(seg_name_split) > 1
|
||||
let seg_ns = seg_name_split[0]
|
||||
let seg_name = seg_name_split[-1]
|
||||
endif
|
||||
|
||||
try
|
||||
" If we have a namespace, try to use the namespaced segment first (i.e. search for the segment in the namespaced file first)
|
||||
let return_segment = deepcopy(g:Powerline#Segments#{seg_ns}#segments[seg_ns .':'. seg_name])
|
||||
catch
|
||||
try
|
||||
" We didn't find a namespaced segment, fall back to common segments
|
||||
let return_segment = deepcopy(g:Powerline#Segments#segments[seg_name])
|
||||
catch
|
||||
" Didn't find the segment among the common segments either, just skip it
|
||||
return {}
|
||||
endtry
|
||||
endtry
|
||||
|
||||
if len(args) && has_key(return_segment, 'text')
|
||||
" Handle segment printf arguments
|
||||
" printf doesn't accept lists as its second argument, so we have to work around that
|
||||
let return_segment.text = call('printf', [ return_segment.text ] + args)
|
||||
endif
|
||||
|
||||
" Assign namespace, name and variants
|
||||
let return_segment.ns = seg_ns
|
||||
let return_segment.name = seg_name
|
||||
let return_segment.orig_name = seg_orig_name
|
||||
let return_segment.variants = seg_variants
|
||||
|
||||
return return_segment
|
||||
endfunction " }}}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue