neo2vim 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/neo2vim.rb +169 -58
- 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
|
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
|
-
@
|
40
|
+
@state = :plugin_class_definiton
|
41
|
+
@in_plugin_class = true
|
9
42
|
else
|
10
|
-
@
|
11
|
-
|
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
|
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
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
@
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
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
|
-
@
|
40
|
-
@
|
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
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
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
|
-
|
58
|
-
|
59
|
-
@
|
60
|
-
|
61
|
-
|
62
|
-
@
|
63
|
-
|
64
|
-
|
65
|
-
|
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
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
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
|