vimdb 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require 'rubygems' unless Object.const_defined?(:Gem)
3
+ require File.dirname(__FILE__) + "/lib/vimdb/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "vimdb"
7
+ s.version = Vimdb::VERSION
8
+ s.authors = ["Gabriel Horner"]
9
+ s.email = "gabriel.horner@gmail.com"
10
+ s.homepage = "http://github.com/cldwalker/vimdb"
11
+ s.summary = "vim knowledge tabularized - search vim keys, options and more with great precision."
12
+ s.description = "Search your vim keybindings precisely by keystroke, mode, description or where they came from. Search vim options by name, alias and description."
13
+ s.required_rubygems_version = ">= 1.3.6"
14
+ s.executables = %w(vimdb)
15
+ s.add_dependency 'thor', '~> 0.14.6'
16
+ s.add_dependency 'hirb', '~> 0.5.0'
17
+ s.files = Dir.glob(%w[{lib,test}/**/*.rb bin/* [A-Z]*.{txt,rdoc,md} ext/**/*.{rb,c} **/deps.rip]) + %w{Rakefile .gemspec}
18
+ s.files += Dir.glob(['man/*', '*.gemspec'])
19
+ s.extra_rdoc_files = ["README.md", "LICENSE.txt"]
20
+ s.license = 'MIT'
21
+ end
@@ -0,0 +1,2 @@
1
+ = 0.1.0
2
+ * Finally a release!
@@ -0,0 +1,22 @@
1
+ The MIT LICENSE
2
+
3
+ Copyright (c) 2011 Gabriel Horner
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,93 @@
1
+ Description
2
+ ===========
3
+
4
+ Improve your knowledge of vim by tabularizing vim items: keybindings, options and more. This allows for
5
+ precise searching of items. Keys can be searched by keystroke, mode, description or where they came
6
+ from. This gem creates a vimdb database, ~/.vimdb.pstore, from your vim documentation. Tested with
7
+ vim >= 7.2 on a mac.
8
+
9
+ Usage
10
+ =====
11
+
12
+ # List keys with Ctrl
13
+ $ vimdb keys C-
14
+ +---------------+------+---------------------+------------------------------------------
15
+ | key | mode | from | desc |
16
+ +---------------+------+---------------------+-----------------------------------------|
17
+ | 0 C-d | i | default | delete all indent in the current line |
18
+ | <C-End> | i | default | cursor past end of fil |
19
+ | <C-End> | n | default | 1 same as "G" |
20
+ | <C-Home> | i | default | cursor to start of file |
21
+ | <C-Home> | n | default | 1 same as "gg" |
22
+ | <C-Left> | n | default | 1 same as "b" |
23
+ ...
24
+
25
+ # List keys with Ctrl-A combo
26
+ $ vimdb keys C-A
27
+
28
+ # List keys with Esc key
29
+ $ vimdb keys E-
30
+
31
+ # List keys with Leader
32
+ $ vimdb keys L-
33
+
34
+ # List insert mode keys
35
+ $ vimdb keys -m=i
36
+
37
+ # List keys I've defined in vimrc
38
+ $ vimdb keys user -f=from
39
+
40
+ # Plugins are assumed to be in ~/.vim/plugins/ directory
41
+ # Change with Vimdb::Keys.config[:plugins_dir]
42
+ # List keys from my plugins
43
+ $ vimdb keys plugin -f=from
44
+
45
+ # List keys from snipmate plugin
46
+ $ vimdb keys snipmate -f=from
47
+
48
+ # List keys that contain completion in description
49
+ $ vimdb keys completion -f=desc
50
+
51
+ # List options that contain window in description
52
+ $ vimdb opts window -f=desc
53
+
54
+ # Info about how vim items were made
55
+ $ vimdb info keys
56
+ $ vimdb info options
57
+
58
+ # For more
59
+ $ vimdb help
60
+
61
+ Key Modes
62
+ =========
63
+
64
+ Vim's key modes are represented as single letters
65
+
66
+ * n: normal
67
+ * c: commandline
68
+ * i: insert
69
+ * o: operation
70
+ * v: visual
71
+ * s: select
72
+
73
+ If you're unfamiliar with all these modes read about them in vim with ':h :map-modes'.
74
+
75
+ The following modes from :map were altered to fit into the above modes:
76
+
77
+ * ! -> ci
78
+ * l -> ci
79
+ * x -> v
80
+ * v -> vs
81
+
82
+ Motivation
83
+ ==========
84
+
85
+ Wanted to learn faster than :help would let me.
86
+
87
+ Todo
88
+ ====
89
+
90
+ * Tests!
91
+ * Add support for more vim items - commands, variables, functions
92
+ * Fix keys - index.txt edge cases
93
+ * Considering user annotation for vim items
@@ -0,0 +1,35 @@
1
+ require 'rake'
2
+ require 'fileutils'
3
+
4
+ def gemspec
5
+ @gemspec ||= eval(File.read('.gemspec'), binding, '.gemspec')
6
+ end
7
+
8
+ desc "Build the gem"
9
+ task :gem=>:gemspec do
10
+ sh "gem build .gemspec"
11
+ FileUtils.mkdir_p 'pkg'
12
+ FileUtils.mv "#{gemspec.name}-#{gemspec.version}.gem", 'pkg'
13
+ end
14
+
15
+ desc "Install the gem locally"
16
+ task :install => :gem do
17
+ sh %{gem install pkg/#{gemspec.name}-#{gemspec.version}}
18
+ end
19
+
20
+ desc "Generate the gemspec"
21
+ task :generate do
22
+ puts gemspec.to_ruby
23
+ end
24
+
25
+ desc "Validate the gemspec"
26
+ task :gemspec do
27
+ gemspec.validate
28
+ end
29
+
30
+ desc 'Run tests'
31
+ task :test do |t|
32
+ sh 'bacon -q -Ilib -I. test/*_test.rb'
33
+ end
34
+
35
+ task :default => :test
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'vimdb'
4
+ Vimdb::Runner.start
@@ -0,0 +1,2 @@
1
+ thor ~>0.14.6
2
+ hirb ~>0.5.0
@@ -0,0 +1,19 @@
1
+ module Vimdb
2
+ autoload :Runner, 'vimdb/runner'
3
+ autoload :User, 'vimdb/user'
4
+ autoload :DB, 'vimdb/db'
5
+ autoload :Item, 'vimdb/item'
6
+ autoload :Keys, 'vimdb/keys'
7
+
8
+ class << self; attr_accessor :default_item, :vim; end
9
+ self.default_item = ENV['VIMDB_ITEM'] || 'keys'
10
+ self.vim = 'vim'
11
+
12
+ def self.user(item_name = nil, db = DB.new)
13
+ @user ||= User.new(item(item_name), db)
14
+ end
15
+
16
+ def self.item(name = nil)
17
+ @item ||= Item.instance(name || default_item)
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ require 'pstore'
2
+
3
+ module Vimdb
4
+ class DB
5
+ attr_accessor :file
6
+ def initialize(file = Dir.home + '/.vimdb.pstore')
7
+ @file = file
8
+ @db = PStore.new(@file)
9
+ end
10
+
11
+ def get(key)
12
+ @db.transaction(true) { @db[key] }
13
+ end
14
+
15
+ def set(key, value)
16
+ @db.transaction { @db[key] = value }
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,55 @@
1
+ module Vimdb
2
+ class Item
3
+ def self.inherited(mod)
4
+ (@descendants ||= []) << mod
5
+ end
6
+
7
+ def self.load_item(name)
8
+ require "vimdb/#{name}"
9
+ rescue LoadError
10
+ end
11
+
12
+ def self.instance(name)
13
+ load_item(name)
14
+ item = @descendants.find {|e| e.item_name == name } or
15
+ abort "Item '#{name}' not found"
16
+ item.new
17
+ end
18
+
19
+ def self.item_name
20
+ name[/\w+$/].downcase
21
+ end
22
+
23
+ def search(items, query, options = {})
24
+ if query
25
+ query = Regexp.escape(query) unless options[:regexp]
26
+ regex = Regexp.new(query, options[:ignore_case])
27
+ items.select! {|e| e[options[:field].to_sym] =~ regex }
28
+ end
29
+ items
30
+ end
31
+
32
+ # key used to store item in DB
33
+ def key
34
+ self.class.item_name
35
+ end
36
+
37
+ def create
38
+ raise NotImplementedError
39
+ end
40
+
41
+ def info
42
+ raise NotImplementedError
43
+ end
44
+
45
+ def display_fields
46
+ raise NotImplementedError
47
+ end
48
+
49
+ private
50
+
51
+ def vim(*cmds)
52
+ system %[#{Vimdb.vim} -c 'colorscheme default | #{cmds.join(' | ')} | qa']
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,133 @@
1
+ require 'tempfile'
2
+
3
+ class Vimdb::Keys < Vimdb::Item
4
+ class << self; attr_accessor :config end
5
+ self.config = {
6
+ plugins_dir: 'plugins',
7
+ modifiers: {'<Esc>' => 'E'},
8
+ mode_map: {'!' => 'ci', 'v' => 'vs', 'x' => 'v', 'l' => 'ci'},
9
+ }
10
+
11
+ def initialize
12
+ @modifiers, @mode_map = self.class.config.values_at(:modifiers, :mode_map)
13
+ @plugins_dir = self.class.config[:plugins_dir]
14
+ end
15
+
16
+ def create
17
+ keys = parse_index_file create_index_file
18
+ @leader ||= get_leader
19
+ @modifiers[@leader] ||= 'L'
20
+ keys + parse_map_file(create_map_file)
21
+ end
22
+
23
+ def search(keys, query, options = {})
24
+ keys = super
25
+ if options[:mode]
26
+ keys.select! do |key|
27
+ options[:mode].split('').any? {|m| key[:mode].include?(m) }
28
+ end
29
+ end
30
+ keys
31
+ end
32
+
33
+ def info
34
+ "Created using index.txt and :map"
35
+ end
36
+
37
+ def display_fields
38
+ [:key, :mode, :from, :desc]
39
+ end
40
+
41
+ private
42
+
43
+ def get_leader
44
+ file = Tempfile.new('vim-leader').path
45
+ leader_cmd = %[silent! echo exists("mapleader") ? mapleader : ""]
46
+ vim "redir! > #{file}", leader_cmd, 'redir END'
47
+ leader = File.readlines(file).last.chomp
48
+ {' ' => '<Space>', '' => '\\'}[leader] || leader
49
+ end
50
+
51
+ def create_index_file
52
+ file = Tempfile.new('vim-index').path
53
+ vim 'silent help index.txt', "silent! w! #{file}"
54
+ file
55
+ end
56
+
57
+ def parse_index_file(file)
58
+ lines = File.read(file).split("\n")
59
+ sections = lines.slice_before(/^={10,}/).to_a
60
+ header_modes = [
61
+ ['1. Insert mode', 'i'], ['2.1', 'ovs'], ['2.', 'n'],
62
+ ['3. Visual mode', 'vs'], ['4. Command-line editing', 'c']
63
+ ]
64
+
65
+ keys = []
66
+ # skip intro and last Ex section
67
+ sections[1..-2].each do |section_lines|
68
+ mode = header_modes.find {|k,v|
69
+ section_lines[1] =~ Regexp.new('^' + Regexp.quote(k))
70
+ }.to_a[1] || '?'
71
+
72
+ #drop section header
73
+ section_lines = section_lines.drop_while {|e| e !~ /^\|/ }
74
+
75
+ section_lines.each do |e|
76
+ cols = e.split(/\t+/)
77
+ if cols.size >= 3
78
+ key = translate_index_key cols[-2]
79
+ keys << {mode: mode, key: key, desc: cols[-1].strip, :from => 'default'}
80
+ # add desc from following lines
81
+ elsif cols.size == 2 && cols[0] == ''
82
+ keys[-1][:desc] += ' ' + cols[1].strip
83
+ # else
84
+ # TODO: parse few edge cases
85
+ end
86
+ end
87
+ end
88
+ keys
89
+ end
90
+
91
+ def translate_index_key(key)
92
+ key.gsub(/CTRL-([A-Z])/) {|s| "C-#{$1.downcase}" }
93
+ end
94
+
95
+ def create_map_file
96
+ file = Tempfile.new('vim-map').path
97
+ vim "redir! > #{file}", "silent! verbose map", 'redir END'
98
+ file
99
+ end
100
+
101
+ def parse_map_file(file)
102
+ lines = File.read(file).strip.split("\n")
103
+ lines.slice_before {|e| e !~ /Last set/ }.map do |arr|
104
+ key = {}
105
+
106
+ key[:file] = arr[1].to_s[%r{Last set from (\S+)}, 1] or next
107
+ key[:from] = key[:file].to_s[%r{/#{@plugins_dir}/([^/]+)\S+}, 1] || 'user'
108
+ key[:from] += ' plugin' if key[:from] != 'user'
109
+
110
+ key[:key] = arr[0][/^\S*\s+(\S+)/, 1]
111
+ next if key[:key][/^(<Plug>|<SNR>)/]
112
+ key[:key] = translate_map_key(key[:key])
113
+
114
+ key[:desc] = arr[0][/^\S*\s+\S+\s+(.*)$/, 1]
115
+ key[:mode] = (mode = arr[0][/^[nvsxo!ilc]+/]) ?
116
+ @mode_map[mode] || mode : 'nvso'
117
+ key
118
+ end.compact
119
+ end
120
+
121
+ def translate_map_key(key)
122
+ if match = /^(?<modifier>#{Regexp.union(*@modifiers.keys)})(?<first>\S)(?<rest>.*$)/.match(key)
123
+ rest = match[:rest].empty? ? '' : ' ' + match[:rest]
124
+ "#{@modifiers[match[:modifier]]}-#{match[:first]}" + rest
125
+ elsif match = /^<(?<ctrl>C-[^>])>(?<rest>.*$)/.match(key)
126
+ rest = match[:rest].empty? ? '' :
127
+ ' ' + match[:rest].gsub(/<(C-[^>])>/, '\1')
128
+ (match[:ctrl] + rest).gsub(/C-([A-Z])/) {|s| "C-#{$1.downcase}" }
129
+ else
130
+ key
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,23 @@
1
+ class Vimdb::Options < Vimdb::Item
2
+ def display_fields
3
+ [:name, :alias, :desc]
4
+ end
5
+
6
+ def info
7
+ "Created using :help option-list"
8
+ end
9
+
10
+ def create
11
+ file = '.vimdb.temp'
12
+ # TODO: tempfile not working
13
+ #file = Tempfile.new('vim-options').path
14
+ vim 'silent help option-list', 'exe "normal 2_y}"', 'new', 'exe "normal p"',
15
+ "silent! w! #{file}"
16
+
17
+ opts = File.read(file).scan(/^'(\S+)'\s*('\S*')?\s*(.*$)/).map do |line|
18
+ { name: line[0], alias: line[1] ? line[1][1..-2] : '', desc: line[2] }
19
+ end
20
+ File.unlink file
21
+ opts
22
+ end
23
+ end
@@ -0,0 +1,51 @@
1
+ require 'thor'
2
+ require 'hirb'
3
+
4
+ class Vimdb::Runner < Thor
5
+ def self.start(*args)
6
+ rc = ENV['VIMDBRC'] || '~/.vimdbrc'
7
+ begin
8
+ load(rc) if File.exists?(File.expand_path(rc))
9
+ rescue StandardError, SyntaxError, LoadError => err
10
+ warn "Error while loading #{rc}:\n"+
11
+ "#{err.class}: #{err.message}\n #{err.backtrace.join("\n ")}"
12
+ end
13
+ super
14
+ end
15
+
16
+ def self.common_options
17
+ method_option :reload, :type => :boolean, :desc => 'reloads items'
18
+ method_option :sort, :type => :string, :desc => 'sort by field', :aliases => '-s'
19
+ method_option :reverse_sort, :type => :boolean, :aliases => '-R'
20
+ method_option :ignore_case, :type => :boolean, :aliases => '-i'
21
+ method_option :regexp, :type => :boolean, :aliases => '-r', :desc => 'query is a regexp'
22
+ end
23
+
24
+ common_options
25
+ method_option :field, :default => 'key', :desc => 'field to query', :aliases => '-f'
26
+ method_option :mode, :type => :string, :desc => 'search by mode, multiple modes are ORed', :aliases => '-m'
27
+ desc 'keys [QUERY]', 'List vim keys'
28
+ def keys(query = nil)
29
+ search_item(query)
30
+ end
31
+
32
+ common_options
33
+ method_option :field, :default => 'name', :desc => 'field to query', :aliases => '-f'
34
+ desc 'opts [QUERY]', 'List vim options'
35
+ def opts(query = nil)
36
+ Vimdb.item('options')
37
+ search_item(query)
38
+ end
39
+
40
+ desc 'info', 'Prints info about an item'
41
+ def info(item = nil)
42
+ puts Vimdb.item(item).info
43
+ end
44
+
45
+ private
46
+ def search_item(query = nil)
47
+ Vimdb.user.reload if options[:reload]
48
+ keys = Vimdb.user.search(query, options)
49
+ puts Hirb::Helpers::Table.render(keys, fields: Vimdb.item.display_fields)
50
+ end
51
+ end
@@ -0,0 +1,25 @@
1
+ module Vimdb
2
+ class User
3
+ def initialize(item, db)
4
+ @item, @db = item, db
5
+ @db_exists = File.exists?(@db.file)
6
+ end
7
+
8
+ def items
9
+ @db_exists ? @db.get(@item.key) :
10
+ @db.set(@item.key, @item.create).tap { @db_exists = true }
11
+ end
12
+
13
+ def search(query, options = {})
14
+ results = @item.search(items, query, options)
15
+ sort = options[:sort] || options[:field]
16
+ results.sort_by! {|e| e[sort.to_sym] || '' }
17
+ results.reverse! if options[:reverse_sort]
18
+ results
19
+ end
20
+
21
+ def reload
22
+ @db_exists = false
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,3 @@
1
+ module Vimdb
2
+ VERSION = '0.1.0'
3
+ end
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vimdb
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.1.0
6
+ platform: ruby
7
+ authors:
8
+ - Gabriel Horner
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-10-17 00:00:00 -04:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: thor
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ~>
23
+ - !ruby/object:Gem::Version
24
+ version: 0.14.6
25
+ type: :runtime
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: hirb
29
+ prerelease: false
30
+ requirement: &id002 !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - ~>
34
+ - !ruby/object:Gem::Version
35
+ version: 0.5.0
36
+ type: :runtime
37
+ version_requirements: *id002
38
+ description: Search your vim keybindings precisely by keystroke, mode, description or where they came from. Search vim options by name, alias and description.
39
+ email: gabriel.horner@gmail.com
40
+ executables:
41
+ - vimdb
42
+ extensions: []
43
+
44
+ extra_rdoc_files:
45
+ - README.md
46
+ - LICENSE.txt
47
+ files:
48
+ - lib/vimdb/db.rb
49
+ - lib/vimdb/item.rb
50
+ - lib/vimdb/keys.rb
51
+ - lib/vimdb/options.rb
52
+ - lib/vimdb/runner.rb
53
+ - lib/vimdb/user.rb
54
+ - lib/vimdb/version.rb
55
+ - lib/vimdb.rb
56
+ - bin/vimdb
57
+ - LICENSE.txt
58
+ - CHANGELOG.rdoc
59
+ - README.md
60
+ - deps.rip
61
+ - Rakefile
62
+ - .gemspec
63
+ has_rdoc: true
64
+ homepage: http://github.com/cldwalker/vimdb
65
+ licenses:
66
+ - MIT
67
+ post_install_message:
68
+ rdoc_options: []
69
+
70
+ require_paths:
71
+ - lib
72
+ required_ruby_version: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: "0"
78
+ required_rubygems_version: !ruby/object:Gem::Requirement
79
+ none: false
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: 1.3.6
84
+ requirements: []
85
+
86
+ rubyforge_project:
87
+ rubygems_version: 1.6.2
88
+ signing_key:
89
+ specification_version: 3
90
+ summary: vim knowledge tabularized - search vim keys, options and more with great precision.
91
+ test_files: []
92
+