vimdb 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+