neo2vim 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. data/lib/neo2vim.rb +169 -58
  2. metadata +1 -1
data/lib/neo2vim.rb CHANGED
@@ -1,86 +1,197 @@
1
1
  #!/usr/bin/env ruby
2
+
3
+ require 'fileutils'
4
+ require 'stringio'
5
+
2
6
  class Neo2Vim
7
+ class PluginContent
8
+ attr_reader :plugin
9
+ attr_reader :autoload_py
10
+ attr_reader :autoload
11
+ def initialize
12
+ @plugin = StringIO.new
13
+ @autoload_py = StringIO.new
14
+ @autoload = StringIO.new
15
+ end
16
+ end
17
+
18
+
3
19
  def neovim_annotation line
4
- line.chomp.gsub(/^[^\(]*\('/, "").gsub(/'.*$/, "")
20
+ if line =~ /^\s*@neovim\.(\w+)\('(\w+)'.*/
21
+ {type: $1, name: $2}
22
+ else
23
+ nil
24
+ end
25
+ end
26
+ def method_info(line, annotation = nil)
27
+ {
28
+ name: method_name(line),
29
+ args: method_args(line),
30
+ annotation: annotation,
31
+ }
32
+ end
33
+ def method_args(line)
34
+ start = line.index('(') + 1
35
+ line[start..-1].scan(/\s*(\w+)(?:\s*=\s*[^,]+)?\s*(?:,|\))/).map(&:first)[1..-1]
5
36
  end
6
37
  def on_neovim_line line
38
+ @annotation = nil
7
39
  if line.include? "plugin"
8
- @plugin_name = true
40
+ @state = :plugin_class_definiton
41
+ @in_plugin_class = true
9
42
  else
10
- @names.each do |name|
11
- if line.include? name
12
- @store[name] = neovim_annotation line
13
- end
14
- end
43
+ @annotation = neovim_annotation line
44
+ @state = :plugin_method_definition
15
45
  end
16
46
  end
17
47
  def method_name line
18
48
  line.chomp.gsub(/^ *[^ ]* /, "").gsub(/\(.*/, "")
19
49
  end
20
- def on_line line
50
+ def to_snake name
51
+ name.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase
52
+ end
53
+ def on_line line, contents
21
54
  line.gsub!("import neovim", "import vim")
22
55
  line.gsub!(/.*if neovim$*/, "")
23
- @dst.write line
24
- if @plugin_name == true
25
- @plugin_name = line.chomp.gsub(/^[^ ]* /, "").gsub(/\(.*/, "")
26
- else
27
- @names.each do |name|
28
- if @store[name]
29
- @stores[name] ||= {}
30
- @stores[name][method_name(line)] = @store[name]
31
- @store[name] = nil
32
- end
56
+ contents.autoload_py.write line
57
+ case @state
58
+ when :plugin_class_definiton
59
+ @plugin_class_name = line.chomp.gsub(/^[^ ]* /, "").gsub(/\(.*/, "")
60
+ @plugin_id = to_snake(@plugin_class_name)
61
+ @state = :normal
62
+ when :plugin_method_definition
63
+ if @annotation && @names.include?(@annotation[:type])
64
+ @stores[@annotation[:type]][method_name(line)] = method_info(line, @annotation)
33
65
  end
66
+ @state = :normal
67
+ when :normal
68
+ if @in_plugin_class && line =~ /^[^#\s]/
69
+ # TODO: deal with multi-line string literal
70
+ @in_plugin_class = false
71
+ end
72
+ if @in_plugin_class && line =~ /^\s*def\s/ && method_name(line) !~ /^__/
73
+ @stores["autoload_function"][method_name(line)] = method_info(line)
74
+ end
34
75
  end
76
+ @annotation = nil
35
77
  end
36
78
  def initialize source, destination
37
- @names = ["function", "command", "autocmd"]
38
- @stores = {}
39
- @store = {}
40
- @plugin_name = nil
79
+ @names = ["autoload_function", "function", "command", "autocmd"]
80
+ @stores = @names.map {|name| [name, {}]}.to_h
81
+ @annotation = nil
82
+ @plugin_class_name = nil
83
+ @in_plugin_class = false
84
+ @plugin_id = nil
85
+ @state = :normal
41
86
  run source, destination
42
87
  end
43
- def declarations
44
- ["function", "autocmd", "command"].each do |what|
45
- @stores[what].each do |k, v|
46
- @dst.puts "fun! #{what == "function"?"":"En"}#{what == "function" ? v : k}(arg0, arg1)
47
- python <<EOF
48
- r = plugin.#{k}([vim.eval('a:arg0'), vim.eval('a:arg1')])
49
- vim.command('let g:__result = ' + json.dumps(([] if r == None else r)))
50
- EOF
51
- let res = g:__result
52
- unlet g:__result
53
- return res
54
- endfun"
55
- end
88
+ def write_declarations contents
89
+ ["autoload_function", "function", "autocmd", "command"].each do |what|
90
+ @stores[what].each do |k, v|
91
+ contents.autoload.puts <<-EOS
92
+ function! #{@plugin_id}\##{k}(#{v[:args].join(", ")}) abort
93
+ return s:call_plugin('#{k}', [#{v[:args].map {|a| "a:" + a}.join(", ")}])
94
+ endfunction
95
+ EOS
96
+ contents.autoload.puts
56
97
  end
57
- @dst.puts "augroup Poi
58
- autocmd!"
59
- @stores["autocmd"].each do |k, v|
60
- @dst.puts " autocmd #{v} * call En#{k}('', '')"
61
- end
62
- @dst.puts "augroup END"
63
- @stores["command"].each do |k, v|
64
- @dst.puts "command! -nargs=0 #{v} call En#{k}('', '')"
65
- end
98
+ end
99
+ contents.plugin.puts <<-EOS
100
+ augroup #{@plugin_id}
101
+ autocmd!
102
+ EOS
103
+ @stores["autocmd"].each do |k, v|
104
+ contents.plugin.puts <<-EOS
105
+ autocmd #{v[:annotation][:name]} * call #{@plugin_id}\##{k}(expand('<afile>'))
106
+ EOS
107
+ end
108
+ contents.plugin.puts "augroup END"
109
+ contents.plugin.puts
110
+
111
+ @stores["command"].each do |k, v|
112
+ contents.plugin.puts "command! -nargs=0 #{v[:annotation][:name]} call #{@plugin_id}\##{k}([])"
113
+ end
114
+ contents.plugin.puts
115
+
116
+ @stores["function"].each do |k, v|
117
+ contents.plugin.puts <<-EOS
118
+ function! #{v[:annotation][:name]}(#{v[:args].join(", ")}) abort
119
+ return #{@plugin_id}##{k}(#{v[:args].map{|a| "a:" + a}.join(", ")})
120
+ endfunction
121
+ EOS
122
+ end
66
123
  end
67
124
  def run source, destination
68
- File.open(destination, "w") do |dst|
69
- @dst = dst
70
- dst.puts "python <<EOF"
71
- File.open(source) do |src|
72
- @src = src
73
- src.each_line do |line|
74
- if line.include? "@neovim"
75
- on_neovim_line line
76
- else
77
- on_line line
78
- end
125
+ %w(plugin autoload).each do|dir|
126
+ FileUtils.mkdir_p(File.join(destination, dir))
127
+ end
128
+
129
+ contents = File.open(source) {|f| parse f }
130
+
131
+ File.open(File.join(destination, 'plugin', "#{@plugin_id}.vim"), "w") do |f|
132
+ f.print(contents.plugin.string)
133
+ end
134
+ File.open(File.join(destination, 'autoload', "#{@plugin_id}.vim"), "w") do |f|
135
+ f.print(contents.autoload.string)
136
+ end
137
+ File.open(File.join(destination, 'autoload', "#{@plugin_id}.vim.py"), "w") do |f|
138
+ f.print(contents.autoload_py.string)
139
+ end
140
+ end
141
+
142
+ def parse path
143
+ contents = PluginContent.new
144
+
145
+ nvim_guard = <<-EOS
146
+ if has('nvim')
147
+ finish
148
+ endif
149
+ EOS
150
+
151
+ contents.plugin.puts(nvim_guard)
152
+
153
+ contents.autoload.puts <<-EOS
154
+ if !has('nvim')
155
+ execute 'pyfile' expand('<sfile>:p').'.py'
156
+ endif
157
+ EOS
158
+ contents.autoload.puts
159
+
160
+ File.open(path) do |src|
161
+ src.each_line do |line|
162
+ if /^\s*@neovim/ =~ line
163
+ on_neovim_line line
164
+ else
165
+ on_line line, contents
79
166
  end
80
167
  end
81
- dst.puts "plugin = #{@plugin_name}(vim)"
82
- dst.puts "EOF"
83
- declarations
84
168
  end
169
+ contents.autoload_py.puts "#{@plugin_id}_plugin = #{@plugin_class_name}(vim)"
170
+ write_declarations(contents)
171
+
172
+ contents.autoload.puts <<-EOS
173
+ function! s:call_plugin(method_name, args) abort
174
+ " TODO: support nvim rpc
175
+ if has('nvim')
176
+ throw 'Call rplugin from vimscript: not supported yet'
177
+ endif
178
+ unlet! g:__error
179
+ python <<PY
180
+ try:
181
+ r = getattr(#{@plugin_id}_plugin, vim.eval('a:method_name'))(*vim.eval('a:args'))
182
+ vim.command('let g:__result = ' + json.dumps(([] if r == None else r)))
183
+ except:
184
+ vim.command('let g:__error = ' + json.dumps(str(sys.exc_info()[0]) + ':' + str(sys.exc_info()[1])))
185
+ PY
186
+ if exists('g:__error')
187
+ throw g:__error
188
+ endif
189
+ let res = g:__result
190
+ unlet g:__result
191
+ return res
192
+ endfunction
193
+ EOS
194
+
195
+ contents
85
196
  end
86
197
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: neo2vim
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors: