neo2vim 0.0.1 → 0.0.2

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.
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: