gamnit: accept float values in `BMFont`
[nit.git] / src / doc / vim_autocomplete.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Generate files used by the Vim plugin to autocomplete with doc
16 #
17 # There is 3 files generated, each with a different target: modules, types,
18 # properties and constructors. Each line describe a different entity,
19 # with 4 values:
20 #
21 # 1. Short name to use in autocompletion
22 # 2. Full signature
23 # 3. Doc synopsis
24 # 4. Full doc with extra
25 #
26 # The priority with those files is for them to be analyzed efficiently, for
27 # this reason, the data is prepared in advance and some information may be
28 # duplicated.
29 module vim_autocomplete
30
31 import modelbuilder
32 import phase
33 import modelize::modelize_class
34 import model::model_collect
35
36 redef class ToolContext
37 # Phase generating the files for the Vim plugin
38 var autocomplete_phase: Phase = new AutocompletePhase(self, [modelize_class_phase])
39
40 # Shall we generate the files for the Vim plugin?
41 var opt_vim_autocomplete = new OptionBool(
42 "Generate metadata files used by the Vim plugin for autocompletion", "--vim-autocomplete")
43
44 init
45 do
46 super
47 option_context.add_option opt_vim_autocomplete
48 opt_vim_autocomplete.hidden = true
49 end
50 end
51
52 redef class Model
53
54 # Get a custom view for vimautocomplete.
55 private fun vim_view: ModelView do
56 var view = new ModelView(self)
57 view.min_visibility = protected_visibility
58 return view
59 end
60 end
61
62 redef class MEntity
63 private fun field_separator: String do return "#====#"
64 private fun line_separator: String do return "#nnnn#"
65
66 private fun write_doc(mainmodule: MModule, stream: Writer)
67 do
68 # 1. Short name for autocompletion
69 stream.write complete_name
70 stream.write field_separator
71
72 # 2. Full signature
73 stream.write complete_name
74 write_signature_to_stream(stream)
75 stream.write field_separator
76
77 # 3. Doc synopsis
78 var mdoc = complete_mdoc
79 if mdoc != null then
80 stream.write mdoc.content.first
81 end
82
83 # 4. Full doc with extra
84 stream.write field_separator
85 stream.write "# "
86 stream.write full_name
87 write_signature_to_stream(stream)
88 if mdoc != null then
89 for i in 2.times do stream.write line_separator
90 stream.write mdoc.content.join(line_separator)
91 end
92 write_extra_doc(mainmodule, stream)
93
94 stream.write "\n"
95 end
96
97 private fun write_signature_to_stream(stream: Writer) do end
98
99 # Actual name used in completion
100 private fun complete_name: String do return name
101
102 # Doc to use in completion
103 private fun complete_mdoc: nullable MDoc do return mdoc
104
105 # Extra auto documentation to append to the `stream`
106 private fun write_extra_doc(mainmodule: MModule, stream: Writer) do end
107 end
108
109 redef class MMethodDef
110 redef fun write_signature_to_stream(stream)
111 do
112 var msignature = msignature
113 if msignature != null then
114 stream.write msignature.to_s
115 end
116 end
117 end
118
119 redef class MAttributeDef
120 redef fun write_signature_to_stream(stream)
121 do
122 var static_mtype = static_mtype
123 if static_mtype != null then
124 stream.write stream.to_s
125 end
126 end
127 end
128
129 # Use `MClassDef` as anchor for its constructors only
130 redef class MClassDef
131 private var target_constructor: nullable MMethodDef = null
132
133 redef fun complete_name
134 do
135 var target_constructor = target_constructor
136 assert target_constructor != null
137
138 var params
139 var mparameters = mclass.mparameters
140 if not mparameters.is_empty then
141 params = "[{mparameters.join(", ")}]"
142 else
143 params = ""
144 end
145
146 if target_constructor.name != "init" and target_constructor.name != "new" then
147 return name + params + "." + target_constructor.name
148 end
149
150 return name + params
151 end
152
153 redef fun complete_mdoc
154 do
155 var target_constructor = target_constructor
156 assert target_constructor != null
157
158 if target_constructor.name != "init" and target_constructor.name != "new" then
159 return target_constructor.mdoc
160 end
161
162 return mdoc
163 end
164 end
165
166 redef class MClassType
167 redef fun write_extra_doc(mainmodule, stream)
168 do
169 # Super classes
170 stream.write line_separator*2
171 stream.write "## Class hierarchy"
172
173 var direct_supers = [for s in mclass.in_hierarchy(mainmodule).direct_greaters do s.name]
174 if not direct_supers.is_empty then
175 alpha_comparator.sort direct_supers
176 stream.write line_separator
177 stream.write "* Direct super classes: "
178 stream.write direct_supers.join(", ")
179 end
180
181 var supers = [for s in mclass.in_hierarchy(mainmodule).greaters do s.name]
182 supers.remove mclass.name
183 if not supers.is_empty then
184 alpha_comparator.sort supers
185 stream.write line_separator
186 stream.write "* All super classes: "
187 stream.write supers.join(", ")
188 end
189
190 var direct_subs = [for s in mclass.in_hierarchy(mainmodule).direct_smallers do s.name]
191 if not direct_subs.is_empty then
192 alpha_comparator.sort direct_subs
193 stream.write line_separator
194 stream.write "* Direct sub classes: "
195 stream.write direct_subs.join(", ")
196 end
197
198 var subs = [for s in mclass.in_hierarchy(mainmodule).smallers do s.name]
199 subs.remove mclass.name
200 if not subs.is_empty then
201 alpha_comparator.sort subs
202 stream.write line_separator
203 stream.write "* All sub classes: "
204 stream.write subs.join(", ")
205 end
206
207 # List other properties
208 stream.write line_separator*2
209 stream.write "## Properties"
210 stream.write line_separator
211 var props = mclass.collect_accessible_mproperties(model.protected_view).to_a
212 alpha_comparator.sort props
213 for prop in props do
214 if mclass.name == "Object" or prop.intro.mclassdef.mclass.name != "Object" then
215 prop.write_synopsis(mainmodule, stream)
216 end
217 end
218 end
219
220 redef fun complete_mdoc do return mclass.intro.mdoc
221 end
222
223 private class AutocompletePhase
224 super Phase
225
226 redef fun process_mainmodule(mainmodule, given_mmodules)
227 do
228 if not toolcontext.opt_vim_autocomplete.value then return
229
230 var compile_dir = "NIT_VIM_DIR".environ
231 if compile_dir.is_empty then compile_dir = "HOME".environ / ".vim/nit"
232 compile_dir.mkdir
233
234 var modules_stream = new FileWriter.open(compile_dir / "modules.txt")
235 var classes_stream = new FileWriter.open(compile_dir / "classes.txt")
236 var constructors_stream = new FileWriter.open(compile_dir / "constructors.txt")
237 var types_stream = new FileWriter.open(compile_dir / "types.txt")
238 var properties_stream = new FileWriter.open(compile_dir / "properties.txt")
239
240 # Got all known modules
241 var model = mainmodule.model
242 for mmodule in model.mmodules do
243 mmodule.write_doc(mainmodule, modules_stream)
244 end
245
246 # TODO list other modules from the Nit lib
247
248 # Get all known classes
249 for mclass in model.mclasses do
250 if not mainmodule.is_visible(mclass.intro_mmodule, public_visibility) then continue
251 var mclass_intro = mclass.intro
252
253 # Can it be instantiated?
254 if mclass.kind != interface_kind and mclass.kind != abstract_kind then
255
256 for prop in mclass.collect_accessible_mproperties(model.public_view) do
257 if prop isa MMethod and prop.is_init then
258 mclass_intro.target_constructor = prop.intro
259 mclass_intro.write_doc(mainmodule, constructors_stream)
260 end
261 end
262 mclass_intro.target_constructor = null
263 end
264
265 # Always add to types and classes
266 mclass.mclass_type.write_doc(mainmodule, classes_stream)
267 mclass.mclass_type.write_doc(mainmodule, types_stream)
268 end
269
270 # Get all known properties
271 for mproperty in model.mproperties do
272 var intro_mmodule = mproperty.intro_mclassdef.mmodule
273 if not mainmodule.is_visible(intro_mmodule, public_visibility) then continue
274
275 # Is it a virtual type?
276 if mproperty isa MVirtualTypeProp then
277 mproperty.intro.write_doc(mainmodule, types_stream)
278 continue
279 end
280
281 # Skip properties beginning with @ or _
282 var first_letter = mproperty.name.chars.first
283 if first_letter == '@' or first_letter == '_' then continue
284
285 mproperty.intro.write_doc(mainmodule, properties_stream)
286 end
287
288 # Close streams
289 for stream in [modules_stream, classes_stream, properties_stream,
290 types_stream, constructors_stream] do
291
292 stream.close
293 var error = stream.last_error
294 if error != null then
295 toolcontext.error(null, "Error: failed to write Vim autocomplete file: {error}.")
296 end
297 end
298 end
299 end
300
301 redef class MModule
302 redef fun write_extra_doc(mainmodule, stream)
303 do
304 # Introduced classes
305 var class_intros = collect_intro_mclasses(model.protected_view).to_a
306 if class_intros.not_empty then
307 alpha_comparator.sort class_intros
308 stream.write line_separator*2
309 stream.write "## Introduced classes"
310
311 for c in class_intros do
312 stream.write line_separator
313 stream.write "* {c.name}"
314 var doc = c.intro.mdoc
315 if doc != null then stream.write ": {doc.content.first}"
316 end
317 end
318
319 # Introduced properties
320 var prop_intros = new Array[MPropDef]
321 for c in mclassdefs do
322 prop_intros.add_all c.collect_intro_mpropdefs(model.protected_view)
323 end
324
325 if prop_intros.not_empty then
326 alpha_comparator.sort prop_intros
327 stream.write line_separator*2
328 stream.write "## Introduced properties"
329 stream.write line_separator
330
331 for p in prop_intros do
332 p.mproperty.write_synopsis(mainmodule, stream)
333 end
334 end
335 end
336 end
337
338 redef class MProperty
339 private fun write_synopsis(mainmodule: MModule, stream: Writer)
340 do
341 if visibility == public_visibility then
342 stream.write "+ "
343 else stream.write "~ " # protected_visibility
344
345 if self isa MMethod then
346 if is_new and name != "new" then
347 stream.write "new "
348 else if is_init and name != "init" then
349 stream.write "init "
350 end
351 end
352
353 stream.write name
354
355 if self isa MMethod then
356 var intro = intro
357 assert intro isa MMethodDef
358 var msignature = intro.msignature
359 if msignature != null then
360 stream.write msignature.to_s
361 end
362 end
363
364 var mdoc = intro.mdoc
365 if mdoc != null then
366 stream.write " # "
367 stream.write mdoc.content.first
368 end
369 stream.write line_separator
370 end
371 end