import modelbuilder
import phase
import modelize::modelize_class
-import model_utils
+import model::model_collect
redef class ToolContext
# Phase generating the files for the Vim plugin
do
super
option_context.add_option opt_vim_autocomplete
+ opt_vim_autocomplete.hidden = true
end
end
private fun field_separator: String do return "#====#"
private fun line_separator: String do return "#nnnn#"
- private fun write_to_stream(stream: OStream)
+ private fun write_doc(view: ModelView, stream: Writer)
do
# 1. Short name for autocompletion
stream.write complete_name
# 4. Full doc with extra
stream.write field_separator
+ stream.write "# "
+ stream.write full_name
+ write_signature_to_stream(stream)
if mdoc != null then
- stream.write "# "
- stream.write full_name
- write_signature_to_stream(stream)
for i in 2.times do stream.write line_separator
stream.write mdoc.content.join(line_separator)
end
+ write_location(view.mainmodule, stream)
+
+ write_extra_doc(view, stream)
+
stream.write "\n"
end
- private fun write_signature_to_stream(stream: OStream) do end
+ private fun write_signature_to_stream(stream: Writer) do end
# Actual name used in completion
private fun complete_name: String do return name
# Doc to use in completion
private fun complete_mdoc: nullable MDoc do return mdoc
+
+ # Extra auto documentation to append to the `stream`
+ private fun write_extra_doc(view: ModelView, stream: Writer) do end
+
+ # Location (file and line when available) of related declarations
+ private fun write_location(mainmodule: MModule, stream: Writer)
+ do
+ for i in 2.times do stream.write line_separator
+ stream.write "## Location"
+ stream.write line_separator
+ stream.write "* {location}"
+ end
end
redef class MMethodDef
stream.write msignature.to_s
end
end
+
+ redef fun write_location(mainmodule, stream)
+ do
+ for i in 2.times do stream.write line_separator
+ stream.write "## Location of introduction and refinements"
+
+ # Group locations in the same file
+ var file_to_location = new MultiHashMap[nullable SourceFile, Location]
+ for c in mproperty.mpropdefs do
+ file_to_location[c.location.file].add c.location
+ end
+
+ # Write one file per location
+ for file, locations in file_to_location do
+ var l = locations.first
+ stream.write line_separator
+ stream.write "* {l}"
+ if locations.length > 1 then stream.write " ({locations.length-1} more)"
+ end
+ end
end
redef class MAttributeDef
end
end
+redef class MClassType
+ redef fun write_extra_doc(view, stream)
+ do
+ # Super classes
+ stream.write line_separator*2
+ stream.write "## Class hierarchy"
+
+ var direct_supers = [for s in mclass.in_hierarchy(view.mainmodule).direct_greaters do s.name]
+ if not direct_supers.is_empty then
+ alpha_comparator.sort direct_supers
+ stream.write line_separator
+ stream.write "* Direct super classes: "
+ stream.write direct_supers.join(", ")
+ end
+
+ var supers = [for s in mclass.in_hierarchy(view.mainmodule).greaters do s.name]
+ supers.remove mclass.name
+ if not supers.is_empty then
+ alpha_comparator.sort supers
+ stream.write line_separator
+ stream.write "* All super classes: "
+ stream.write supers.join(", ")
+ end
+
+ var direct_subs = [for s in mclass.in_hierarchy(view.mainmodule).direct_smallers do s.name]
+ if not direct_subs.is_empty then
+ alpha_comparator.sort direct_subs
+ stream.write line_separator
+ stream.write "* Direct sub classes: "
+ stream.write direct_subs.join(", ")
+ end
+
+ var subs = [for s in mclass.in_hierarchy(view.mainmodule).smallers do s.name]
+ subs.remove mclass.name
+ if not subs.is_empty then
+ alpha_comparator.sort subs
+ stream.write line_separator
+ stream.write "* All sub classes: "
+ stream.write subs.join(", ")
+ end
+
+ # List other properties
+ stream.write line_separator*2
+ stream.write "## Properties"
+ stream.write line_separator
+ var props = mclass.collect_accessible_mproperties(view).to_a
+ alpha_comparator.sort props
+ for prop in props do
+ if mclass.name == "Object" or prop.intro.mclassdef.mclass.name != "Object" then
+ prop.write_synopsis(view.mainmodule, stream)
+ end
+ end
+ end
+
+ redef fun complete_mdoc do return mclass.intro.mdoc
+
+ redef fun write_location(mainmodule, stream)
+ do
+ for i in 2.times do stream.write line_separator
+ stream.write "## Location of introduction and refinements"
+ for c in mclass.mclassdefs do
+ stream.write line_separator
+ stream.write "* {c.location}"
+ end
+ end
+end
+
private class AutocompletePhase
super Phase
if compile_dir.is_empty then compile_dir = "HOME".environ / ".vim/nit"
compile_dir.mkdir
- var modules_stream = new OFStream.open(compile_dir / "modules.txt")
- var classes_stream = new OFStream.open(compile_dir / "classes.txt")
- var constructors_stream = new OFStream.open(compile_dir / "constructors.txt")
- var types_stream = new OFStream.open(compile_dir / "types.txt")
- var properties_stream = new OFStream.open(compile_dir / "properties.txt")
+ var modules_stream = new FileWriter.open(compile_dir / "modules.txt")
+ var classes_stream = new FileWriter.open(compile_dir / "classes.txt")
+ var constructors_stream = new FileWriter.open(compile_dir / "constructors.txt")
+ var types_stream = new FileWriter.open(compile_dir / "types.txt")
+ var properties_stream = new FileWriter.open(compile_dir / "properties.txt")
# Got all known modules
var model = mainmodule.model
+ var view = new ModelView(model, mainmodule)
for mmodule in model.mmodules do
- mmodule.write_to_stream modules_stream
+ mmodule.write_doc(view, modules_stream)
end
# TODO list other modules from the Nit lib
# Can it be instantiated?
if mclass.kind != interface_kind and mclass.kind != abstract_kind then
- for prop in mclass.all_mproperties(mainmodule, public_visibility) do
+ for prop in mclass.collect_accessible_mproperties(view) do
if prop isa MMethod and prop.is_init then
mclass_intro.target_constructor = prop.intro
- mclass_intro.write_to_stream constructors_stream
+ mclass_intro.write_doc(view, constructors_stream)
end
end
mclass_intro.target_constructor = null
end
# Always add to types and classes
- mclass.mclass_type.write_to_stream classes_stream
- mclass.mclass_type.write_to_stream types_stream
+ mclass.mclass_type.write_doc(view, classes_stream)
+ mclass.mclass_type.write_doc(view, types_stream)
end
# Get all known properties
# Is it a virtual type?
if mproperty isa MVirtualTypeProp then
- mproperty.intro.write_to_stream types_stream
+ mproperty.intro.write_doc(view, types_stream)
continue
end
var first_letter = mproperty.name.chars.first
if first_letter == '@' or first_letter == '_' then continue
- mproperty.intro.write_to_stream properties_stream
+ mproperty.intro.write_doc(view, properties_stream)
end
# Close streams
stream.close
var error = stream.last_error
if error != null then
- toolcontext.error(null, "Failed to write Vim autocomplete file: {error}")
+ toolcontext.error(null, "Error: failed to write Vim autocomplete file: {error}.")
+ end
+ end
+ end
+end
+
+redef class MModule
+ redef fun write_extra_doc(view, stream)
+ do
+ # Introduced classes
+ var class_intros = collect_intro_mclasses(view).to_a
+ if class_intros.not_empty then
+ alpha_comparator.sort class_intros
+ stream.write line_separator*2
+ stream.write "## Introduced classes"
+
+ for c in class_intros do
+ stream.write line_separator
+ stream.write "* {c.name}"
+ var doc = c.intro.mdoc
+ if doc != null then stream.write ": {doc.content.first}"
+ end
+ end
+
+ # Introduced properties
+ var prop_intros = new Array[MPropDef]
+ for c in mclassdefs do
+ prop_intros.add_all c.collect_intro_mpropdefs(view)
+ end
+
+ if prop_intros.not_empty then
+ alpha_comparator.sort prop_intros
+ stream.write line_separator*2
+ stream.write "## Introduced properties"
+ stream.write line_separator
+
+ for p in prop_intros do
+ p.mproperty.write_synopsis(view.mainmodule, stream)
end
end
end
end
+
+redef class MProperty
+ private fun write_synopsis(mainmodule: MModule, stream: Writer)
+ do
+ if visibility == public_visibility then
+ stream.write "+ "
+ else stream.write "~ " # protected_visibility
+
+ if self isa MMethod then
+ if is_new and name != "new" then
+ stream.write "new "
+ else if is_init and name != "init" then
+ stream.write "init "
+ end
+ end
+
+ stream.write name
+
+ if self isa MMethod then
+ var intro = intro
+ assert intro isa MMethodDef
+ var msignature = intro.msignature
+ if msignature != null then
+ stream.write msignature.to_s
+ end
+ end
+
+ var mdoc = intro.mdoc
+ if mdoc != null then
+ stream.write " # "
+ stream.write mdoc.content.first
+ end
+ stream.write line_separator
+ end
+end