├── .gitignore ├── .rspec ├── .ruby-gemset ├── .ruby-version ├── .vimrc-project ├── Gemfile ├── Gemfile.lock ├── Guardfile ├── LICENSE ├── README.md ├── plugin └── zshpathcompletion.vim └── spec ├── plugin_spec.rb ├── spec_helper.rb ├── support └── vim_helpers.rb └── unit ├── all_string_indexes_match_spec.rb ├── expand_path_component_spec.rb ├── expand_path_spec.rb ├── index_of_first_mismatch_spec.rb ├── longest_common_string_prefix_spec.rb └── shortest_string_in_list_spec.rb /.gitignore: -------------------------------------------------------------------------------- 1 | tags 2 | /tmp/* 3 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --drb 2 | --color 3 | --format documentation 4 | -------------------------------------------------------------------------------- /.ruby-gemset: -------------------------------------------------------------------------------- 1 | vim-zsh-path-completion 2 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | ruby-2.4.2 2 | -------------------------------------------------------------------------------- /.vimrc-project: -------------------------------------------------------------------------------- 1 | let g:tabber_predefined_labels = { 1: 'Plugin' } 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'vimrunner' 4 | gem 'rspec' 5 | gem 'rb-inotify', require: false # Linux 6 | gem 'rb-fsevent', require: false # OSX 7 | gem 'guard' 8 | gem 'guard-rspec' 9 | gem 'spork' 10 | gem 'guard-spork' 11 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | childprocess (3.0.0) 5 | coderay (1.1.2) 6 | diff-lcs (1.3) 7 | ffi (1.11.3) 8 | formatador (0.2.5) 9 | guard (2.16.1) 10 | formatador (>= 0.2.4) 11 | listen (>= 2.7, < 4.0) 12 | lumberjack (>= 1.0.12, < 2.0) 13 | nenv (~> 0.1) 14 | notiffany (~> 0.0) 15 | pry (>= 0.9.12) 16 | shellany (~> 0.0) 17 | thor (>= 0.18.1) 18 | guard-compat (1.2.1) 19 | guard-rspec (4.7.3) 20 | guard (~> 2.1) 21 | guard-compat (~> 1.1) 22 | rspec (>= 2.99.0, < 4.0) 23 | guard-spork (2.1.0) 24 | childprocess (>= 0.2.3) 25 | guard (~> 2.0) 26 | guard-compat (~> 1.0) 27 | spork (>= 0.8.4) 28 | listen (3.2.1) 29 | rb-fsevent (~> 0.10, >= 0.10.3) 30 | rb-inotify (~> 0.9, >= 0.9.10) 31 | lumberjack (1.0.13) 32 | method_source (0.9.2) 33 | nenv (0.3.0) 34 | notiffany (0.1.3) 35 | nenv (~> 0.1) 36 | shellany (~> 0.0) 37 | pry (0.12.2) 38 | coderay (~> 1.1.0) 39 | method_source (~> 0.9.0) 40 | rb-fsevent (0.10.3) 41 | rb-inotify (0.10.0) 42 | ffi (~> 1.0) 43 | rspec (3.9.0) 44 | rspec-core (~> 3.9.0) 45 | rspec-expectations (~> 3.9.0) 46 | rspec-mocks (~> 3.9.0) 47 | rspec-core (3.9.0) 48 | rspec-support (~> 3.9.0) 49 | rspec-expectations (3.9.0) 50 | diff-lcs (>= 1.2.0, < 2.0) 51 | rspec-support (~> 3.9.0) 52 | rspec-mocks (3.9.0) 53 | diff-lcs (>= 1.2.0, < 2.0) 54 | rspec-support (~> 3.9.0) 55 | rspec-support (3.9.0) 56 | shellany (0.0.1) 57 | spork (0.9.2) 58 | thor (0.20.3) 59 | vimrunner (0.3.4) 60 | 61 | PLATFORMS 62 | ruby 63 | 64 | DEPENDENCIES 65 | guard 66 | guard-rspec 67 | guard-spork 68 | rb-fsevent 69 | rb-inotify 70 | rspec 71 | spork 72 | vimrunner 73 | 74 | BUNDLED WITH 75 | 1.16.6 76 | -------------------------------------------------------------------------------- /Guardfile: -------------------------------------------------------------------------------- 1 | guard 'spork', cucumber: false do 2 | watch('Gemfile') 3 | watch('Gemfile.lock') 4 | watch('spec/spec_helper.rb') { :rspec } 5 | end 6 | 7 | guard 'rspec' do 8 | watch('spec/spec_helper.rb') { "spec" } 9 | watch(%r{^plugin/.+\.vim$}) { "spec" } 10 | watch(%r{^spec/.+_spec\.rb$}) 11 | end 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2013 Jim Stewart 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | vim-zsh-path-completion 2 | ======================= 3 | 4 | Provides Zsh-style pathname completion in the Vim command line. 5 | 6 | Specifically, it will complete each component of pathname independently 7 | up to the first ambiguous match. 8 | 9 | Here's an example: 10 | 11 | :edit s/m/a/c/s 12 | 13 | Will expand to: 14 | 15 | :edit src/myproject/app/controllers/something_controller.rb 16 | 17 | So long as there are no ambiguous matches along the way. You can 18 | provide as much of each component as you want. This also works: 19 | 20 | :edit sr/my/app/c/so 21 | 22 | If there are any ambiguous matches, it will complete as much as it can. 23 | 24 | You can freely intermingle `` and `` completion until you get 25 | the path you want. `` doesn't invoke any completion menus; it just 26 | completes what it can. 27 | 28 | Installation 29 | ------------ 30 | 31 | Via [pathogen.vim](https://github.com/tpope/vim-pathogen): 32 | 33 | cd ~/.vim/bundle 34 | git clone git://github.com/fweep/vim-zsh-path-completion.git 35 | 36 | Mappings 37 | -------- 38 | 39 | To suppress the key mapping: 40 | 41 | let g:zsh_path_completion_suppress_mappings = 1 42 | 43 | To provide your own mapping, bind to `ZshPathComplete`. The default 44 | is: 45 | 46 | cmap ZshPathComplete 47 | 48 | Limitations/Bugs 49 | ---------------- 50 | 51 | It doesn't understand context. Whereas Vim builtins like `:edit` know 52 | that they need a filename argument, and only do `` completion when 53 | appropriate, this will try to expand whatever token is there when you 54 | hit ``. 55 | 56 | It doesn't handle quotes/spaces/special characters. That should be fixable. 57 | 58 | If a component in the middle of the path is ambiguous, it will discard 59 | everything after the unambiguous prefix (zsh will expand the common 60 | portion and position the cursor at the first differing character, 61 | leaving the rest of the path string intact). 62 | 63 | `` only works on the end of the command line; if you move the 64 | cursor to the middle and invoke it, you won't get good results. 65 | 66 | I hope to address some of these issues. Soliciting feedback for now. 67 | 68 | Please file a [GitHub 69 | issue](https://github.com/fweep/vim-zsh-path-completion/issues) if you find bugs. 70 | 71 | A note on clutter 72 | ----------------- 73 | 74 | I'm not happy about all the Ruby stuff in the top-level directory. It's 75 | there because [Bundler](http://gembundler.com/) will not allow you to 76 | monitor paths above its root, so I can't use a relative path to 77 | `watch()` for changes in the `plugin` directory. Bundler also won't 78 | follow symlinks. If you install the plugin with 79 | [pathogen](https://github.com/tpope/vim-pathogen) (or another Vim package 80 | handler), it doesn't really matter that the directory is cluttered up. 81 | If you don't use pathogen, well...you should. I'll move everything to a 82 | single `test` directory once I figure out how to make Bundler happy. 83 | 84 | Acknowledgements 85 | ---------------- 86 | 87 | This was motivation by a [question on Stack 88 | Overflow](http://stackoverflow.com/questions/15581845/how-to-autocomplete-file-paths-in-vim-just-like-in-zsh) 89 | by Mykle Hansen. Thanks for the idea, Mykle! 90 | 91 | License 92 | ------- 93 | 94 | Copyright (C) 2013 Jim Stewart 95 | 96 | MIT License. See LICENSE file. 97 | -------------------------------------------------------------------------------- /plugin/zshpathcompletion.vim: -------------------------------------------------------------------------------- 1 | " zshpathcompletion.vim 2 | " 3 | " Author: Jim Stewart 4 | " Version: 0.1 5 | 6 | if exists('g:loaded_zsh_path_completion') || &cp || v:version < 700 7 | finish 8 | endif 9 | 10 | let g:loaded_zsh_path_completion = 1 11 | 12 | function! s:SID() 13 | let fullname = expand("") 14 | return matchstr(fullname, '\d\+_') 15 | endfunction 16 | 17 | let g:zsh_path_completion_SID = s:SID() 18 | 19 | function! s:expand_path_component(path_component) 20 | let matches = glob(a:path_component . '*') 21 | return split(matches, '\n') 22 | endfunction 23 | 24 | function! s:shortest_string_in_list(list) 25 | let shortest_string = a:list[0] 26 | for string in a:list[1:] 27 | if len(string) < len(shortest_string) 28 | let shortest_string = string 29 | endif 30 | endfor 31 | return shortest_string 32 | endfunction 33 | 34 | function! s:all_string_indexes_match(list, index) 35 | let character = a:list[0][a:index] 36 | for string in a:list[1:] 37 | if character != string[a:index] 38 | return 0 39 | endif 40 | endfor 41 | return 1 42 | endfunction 43 | 44 | function! s:longest_common_string_prefix(list) 45 | let shortest_string = s:shortest_string_in_list(a:list) 46 | let prefix = "" 47 | for idx in range(0, len(shortest_string) - 1) 48 | if !s:all_string_indexes_match(a:list, idx) 49 | break 50 | endif 51 | let prefix .= shortest_string[idx] 52 | endfor 53 | return prefix 54 | endfunction 55 | 56 | function s:index_of_first_mismatch(matches) 57 | return len(s:longest_common_string_prefix(a:matches)) 58 | endfunction 59 | 60 | function! s:expand_path(path_components) 61 | let current_path = '' 62 | for path_component in a:path_components 63 | let matches = s:expand_path_component(current_path . path_component) 64 | let number_of_matches = len(matches) 65 | if number_of_matches == 0 66 | break 67 | elseif number_of_matches > 1 68 | let index_of_first_mismatch = s:index_of_first_mismatch(matches) 69 | let current_path = matches[0][0:(index_of_first_mismatch - 1)] 70 | break 71 | " if path_component == 'p' 72 | " return [index_of_first_mismatch, current_path, matches, path_component] 73 | " endif 74 | else 75 | let current_path = matches[0] 76 | if isdirectory(current_path) 77 | let current_path .= '/' 78 | endif 79 | endif 80 | endfor 81 | return current_path 82 | endfunction 83 | 84 | function! s:ZshExpandPath() 85 | let command_line = getcmdline() 86 | let cursor_position = getcmdpos() 87 | let last_space_index = strridx(command_line, ' ') 88 | if last_space_index == -1 89 | return '' 90 | endif 91 | let last_word = command_line[(last_space_index + 1):] 92 | let path_components = split(last_word, '/') 93 | let full_path = s:expand_path(path_components) 94 | let new_command_line = command_line 95 | if strlen(full_path) != 0 96 | let command_prefix = command_line[0:last_space_index] 97 | let new_command_line = command_prefix . full_path 98 | call setcmdpos(strlen(new_command_line) + 1) 99 | endif 100 | return new_command_line 101 | endfunction 102 | 103 | function! s:has_key_map() 104 | return hasmapto('ZshPathComplete', 'c') || mapcheck('', 'c') != '' 105 | endfunction 106 | 107 | function! s:suppress_key_map() 108 | return exists('g:zsh_path_completion_suppress_mappings') && g:zsh_path_completion_suppress_mappings 109 | endfunction 110 | 111 | function! s:should_map_key() 112 | return !s:suppress_key_map() && !s:has_key_map() 113 | endfunction 114 | 115 | if s:should_map_key() 116 | cmap ZshPathComplete 117 | endif 118 | 119 | cmap ZshPathComplete eZshExpandPath() 120 | -------------------------------------------------------------------------------- /spec/plugin_spec.rb: -------------------------------------------------------------------------------- 1 | # NOTE: Tests require Vim with X11 and +clientserver. 2 | 3 | require 'spec_helper' 4 | 5 | describe "vim-zsh-path-completion" do 6 | 7 | it "meets requirements" do 8 | VIM.command("echo &cp").should == "0" 9 | VIM.command("echo v:version").to_i.should >= 700 10 | end 11 | 12 | it "sets a flag on load" do 13 | VIM.command("echo g:loaded_zsh_path_completion").should == "1" 14 | end 15 | 16 | end 17 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'rspec' 3 | require 'spork' 4 | 5 | Spork.prefork do 6 | require 'vimrunner' 7 | require 'tmpdir' 8 | 9 | # FIXME: why isn't RSpec finding VimHelpers? 10 | require 'support/vim_helpers' 11 | 12 | RSpec.configure do |config| 13 | config.treat_symbols_as_metadata_keys_with_true_values = true 14 | config.order = 'random' 15 | 16 | config.include VimHelpers 17 | 18 | # FIXME: if any of the tests leave Vim in a weird state, 19 | # spork will need to be restarted. it'd be better to bounce 20 | # it here, but mvim doesn't run headlessly and restarts suck. 21 | # config.before :suite do 22 | if /darwin/ =~ RUBY_PLATFORM 23 | # FIXME: forcing mvim due to problems with Vimrunner + vim in OSX 24 | VIM = Vimrunner::Server.new("mvim").start 25 | else 26 | VIM = Vimrunner.start 27 | end 28 | plugin_path = File.expand_path('../..', __FILE__) 29 | VIM.add_plugin(plugin_path, 'plugin/zshpathcompletion.vim') 30 | # end 31 | 32 | # config.after :suite do 33 | # VIM.kill 34 | # end 35 | 36 | config.around do |example| 37 | Dir.mktmpdir do |dir| 38 | Dir.chdir(dir) do 39 | VIM.command("cd #{dir}") 40 | example.call 41 | end 42 | end 43 | end 44 | end 45 | end 46 | 47 | Spork.each_run do 48 | end 49 | -------------------------------------------------------------------------------- /spec/support/vim_helpers.rb: -------------------------------------------------------------------------------- 1 | module VimHelpers 2 | 3 | def build_list(array) 4 | "[" + array.map {|a| "'#{a}'"}.join(', ') + "]" 5 | end 6 | 7 | end 8 | -------------------------------------------------------------------------------- /spec/unit/all_string_indexes_match_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "s:all_string_indexes_match" do 4 | 5 | let!(:sid) { VIM.command("echo g:zsh_path_completion_SID") } 6 | 7 | def all_string_indexes_match(list, index) 8 | VIM.command("echo #{sid}all_string_indexes_match(#{list}, #{index})") 9 | end 10 | 11 | it "when first characters match" do 12 | list = build_list(%w{then top truck}) 13 | all_string_indexes_match(list, 0).should == "1" 14 | end 15 | 16 | it "when second characters match" do 17 | list = build_list(%w{xhis that those}) 18 | all_string_indexes_match(list, 1).should == "1" 19 | end 20 | 21 | it "when first characters do not match" do 22 | list = build_list(%w{then top cow}) 23 | all_string_indexes_match(list, 0).should == "0" 24 | end 25 | 26 | end 27 | -------------------------------------------------------------------------------- /spec/unit/expand_path_component_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "s:expand_path_component" do 4 | 5 | let!(:sid) { VIM.command("echo g:zsh_path_completion_SID") } 6 | 7 | before do 8 | FileUtils.mkdir_p "foo/bar/b/blah" 9 | FileUtils.mkdir_p "foo/bar/baz/blah" 10 | FileUtils.mkdir_p "foo/bar/bzz/goat" 11 | end 12 | 13 | after do 14 | FileUtils.rm_rf "foo" 15 | end 16 | 17 | def expand_path_component(path_component) 18 | VIM.command("echo #{sid}expand_path_component('#{path_component}')") 19 | end 20 | 21 | it "expands unambiguous top-level directory" do 22 | expand_path_component("f").should == build_list(%w{foo}) 23 | end 24 | 25 | it "expands unambiguous nested directory" do 26 | expand_path_component("foo/b").should == build_list(%w{foo/bar}) 27 | end 28 | 29 | it "expands ambiguous nested directories" do 30 | dirs = %w{foo/bar/b foo/bar/baz foo/bar/bzz} 31 | expand_path_component("foo/bar/b").should == build_list(dirs) 32 | end 33 | 34 | it "descends with trailing /" do 35 | expand_path_component("foo/").should == build_list(%w{foo/bar}) 36 | end 37 | 38 | it "does not descend on full match" do 39 | expand_path_component("foo").should == build_list(%w{foo}) 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /spec/unit/expand_path_spec.rb: -------------------------------------------------------------------------------- 1 | describe "s:expand_path" do 2 | 3 | # FIXME: turn some of these into integration tests 4 | 5 | let!(:sid) { VIM.command("echo g:zsh_path_completion_SID") } 6 | 7 | def expand_path(path_components) 8 | VIM.command("echo #{sid}expand_path(#{path_components})") 9 | end 10 | 11 | describe "with an empty directory" do 12 | it "expands 's' to blank" do 13 | expand_path(["s"]).should == "" 14 | end 15 | end 16 | 17 | describe "with one file named 'stuff'" do 18 | before { FileUtils.touch("stuff") } 19 | it "expands 's'" do 20 | expand_path(["s"]).should == "stuff" 21 | end 22 | it "expands 'st'" do 23 | expand_path(["st"]).should == "stuff" 24 | end 25 | it "handles 'stuff'" do 26 | expand_path(["stuff"]).should == "stuff" 27 | end 28 | end 29 | 30 | describe "with a file extension" do 31 | before { FileUtils.touch("stuff.txt") } 32 | it "matches full filename" do 33 | expand_path(["st"]).should == "stuff.txt" 34 | end 35 | end 36 | 37 | describe "with a space in the filename" do 38 | before { FileUtils.touch("more stuff.txt") } 39 | it "matches full filename" do 40 | expand_path(["m"]).should == "more stuff.txt" 41 | end 42 | end 43 | 44 | describe "with two non-matching files" do 45 | let(:filenames) { ["stuff", "things"] } 46 | before { filenames.each {|f| FileUtils.touch(f) } } 47 | it "expands the first name" do 48 | expand_path(["st"]).should == "stuff" 49 | end 50 | it "expands the second name" do 51 | expand_path(["th"]).should == "things" 52 | end 53 | end 54 | 55 | describe "with two partially-matching files" do 56 | let(:filenames) { ["these", "those"] } 57 | before { filenames.each {|f| FileUtils.touch(f) } } 58 | it "expands the common prefix" do 59 | expand_path(["t"]).should == "th" 60 | end 61 | end 62 | 63 | describe "with one directory" do 64 | before { FileUtils.mkdir_p "mydir" } 65 | it "adds a trailing /" do 66 | expand_path(['m']).should == "mydir/" 67 | end 68 | 69 | describe "containing two similarly-named files" do 70 | let(:filenames) { ["golf", "goats"] } 71 | before { filenames.each {|f| FileUtils.touch("mydir/#{f}") } } 72 | it "expands the common prefix given a full directory name and partial filename" do 73 | path_components = build_list(%w{mydir g}) 74 | expand_path(path_components).should == "mydir/go" 75 | end 76 | it "expands the common prefix given a partial directory name and partial filename" do 77 | path_components = build_list(%w{m g}) 78 | expand_path(path_components).should == "mydir/go" 79 | end 80 | end 81 | 82 | describe "containing a subdirectory" do 83 | it "expands the subdirectory with a trailing /" do 84 | FileUtils.mkdir_p "mydir/subdir" 85 | path_components = build_list(%w{m s}) 86 | expand_path(path_components).should == "mydir/subdir/" 87 | end 88 | end 89 | end 90 | 91 | describe "with two partially-matching directories" do 92 | let(:dirnames) { ["these", "those"] } 93 | before { dirnames.each {|d| FileUtils.mkdir_p(d) } } 94 | it "expands the common prefix with no trailing /" do 95 | expand_path(['t']).should == "th" 96 | end 97 | describe "with a file in one directory" do 98 | before { FileUtils.touch("these/foo") } 99 | it "expands only the common prefix with an ambiguous directory match" do 100 | path_components = build_list(%w{t f}) 101 | expand_path(path_components).should == "th" 102 | end 103 | end 104 | end 105 | 106 | describe "with nested directories" do 107 | let(:top_dirnames) { ["src", "tmp"] } 108 | before { top_dirnames.each {|d| FileUtils.mkdir_p(d) } } 109 | describe "where the second partially matches" do 110 | let(:mid_dirnames) { ["pants", "parts"] } 111 | before { mid_dirnames.each {|d| FileUtils.mkdir_p("src/#{d}") } } 112 | it "expands the common prefix" do 113 | path_components = build_list(%w{s p}) 114 | expand_path(path_components).should == "src/pa" 115 | end 116 | it "expands the common prefix with a file" do 117 | FileUtils.touch("src/pants/foo") 118 | path_components = build_list(%w{s p f}) 119 | expand_path(path_components).should == "src/pa" 120 | end 121 | end 122 | end 123 | 124 | end 125 | -------------------------------------------------------------------------------- /spec/unit/index_of_first_mismatch_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "s:index_of_first_mismatch" do 4 | 5 | let!(:sid) { VIM.command("echo g:zsh_path_completion_SID") } 6 | 7 | def index_of_first_mismatch(list) 8 | VIM.command("echo #{sid}index_of_first_mismatch(#{list})") 9 | end 10 | 11 | it "returns 0 when first characters differ" do 12 | list = build_list(%w{this foo llamatron}) 13 | index_of_first_mismatch(list).should == "0" 14 | end 15 | 16 | 17 | it "returns 1 when second characters differ" do 18 | list = build_list(%w{cow crew clobber}) 19 | index_of_first_mismatch(list).should == "1" 20 | end 21 | 22 | it "returns strlen when no mismatch" do 23 | word = "llama" 24 | list = build_list([word] * 2) 25 | index_of_first_mismatch(list).should == "#{word.length}" 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /spec/unit/longest_common_string_prefix_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "s:longest_common_string_prefix" do 4 | 5 | let!(:sid) { VIM.command("echo g:zsh_path_completion_SID") } 6 | 7 | def longest_common_string_prefix(list) 8 | VIM.command("echo #{sid}longest_common_string_prefix(#{list})") 9 | end 10 | 11 | it "is blank when none match" do 12 | longest_common_string_prefix(%w{foo bar llama}).should == '' 13 | end 14 | 15 | it "is blank when first two of three match" do 16 | longest_common_string_prefix(%w{foo food baz}).should == '' 17 | end 18 | 19 | it "matches single character" do 20 | longest_common_string_prefix(%w{fee fie foe}).should == 'f' 21 | end 22 | 23 | it "matches multiple characters with no complete match" do 24 | longest_common_string_prefix(%w{fees feed feet}).should == 'fee' 25 | end 26 | 27 | it "matches multiple characters with one complete match" do 28 | longest_common_string_prefix(%w{bees bee beet}).should == 'bee' 29 | end 30 | 31 | it "matches multiple characters with all exact matches" do 32 | longest_common_string_prefix(%w{cow cow cow}).should == 'cow' 33 | end 34 | 35 | end 36 | -------------------------------------------------------------------------------- /spec/unit/shortest_string_in_list_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "s:shortest_string_in_list" do 4 | 5 | let!(:sid) { VIM.command("echo g:zsh_path_completion_SID") } 6 | 7 | def shortest_string_in_list(list) 8 | VIM.command("echo #{sid}shortest_string_in_list(#{list})") 9 | end 10 | 11 | it "finds the shortest when first" do 12 | list = build_list(%w{foo blammo something}) 13 | shortest_string_in_list(list).should == "foo" 14 | end 15 | 16 | it "finds the shortest when last" do 17 | list = build_list(%w{blammo something foo}) 18 | shortest_string_in_list(list).should == "foo" 19 | end 20 | 21 | end 22 | --------------------------------------------------------------------------------