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