ni_nitdoc: Generate dot file in overview page
[nit.git] / src / ni_nitdoc.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2008 Jean Privat <jean@pryen.org>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 module ni_nitdoc
18
19 import model_utils
20 import abstract_compiler
21 import html
22
23 class Nitdoc
24 private var toolcontext: ToolContext
25 private var model: Model
26 private var modelbuilder: ModelBuilder
27 private var mainmodule: MModule
28 private var arguments: Array[String]
29 private var destinationdir: nullable String
30 private var sharedir: nullable String
31
32 private var opt_dir = new OptionString("Directory where doc is generated", "-d", "--dir")
33 private var opt_source = new OptionString("What link for source (%f for filename, %l for first line, %L for last line)", "--source")
34 private var opt_sharedir = new OptionString("Directory containing the nitdoc files", "--sharedir")
35 private var opt_nodot = new OptionBool("Do not generate graphes with graphiviz", "--no-dot")
36
37 init(toolcontext: ToolContext) do
38 # We need a model to collect stufs
39 self.toolcontext = toolcontext
40 self.arguments = toolcontext.option_context.rest
41 toolcontext.option_context.add_option(opt_dir)
42 toolcontext.option_context.add_option(opt_source)
43 toolcontext.option_context.add_option(opt_sharedir)
44 toolcontext.option_context.add_option(opt_nodot)
45 process_options
46
47 if arguments.length < 1 then
48 toolcontext.option_context.usage
49 exit(1)
50 end
51
52 model = new Model
53 modelbuilder = new ModelBuilder(model, toolcontext)
54
55 # Here we load an process std modules
56 var mmodules = modelbuilder.parse_and_build([arguments.first])
57 if mmodules.is_empty then return
58 modelbuilder.full_propdef_semantic_analysis
59 assert mmodules.length == 1
60 self.mainmodule = mmodules.first
61 end
62
63 private fun process_options do
64 if not opt_dir.value is null then
65 destinationdir = opt_dir.value
66 else
67 destinationdir = "nitdoc_directory"
68 end
69 if not opt_sharedir.value is null then
70 sharedir = opt_sharedir.value
71 else
72 var dir = "NIT_DIR".environ
73 if dir.is_empty then
74 dir = "{sys.program_name.dirname}/../share/nitdoc"
75 else
76 dir = "{dir}/share/nitdoc"
77 end
78 sharedir = dir
79 if sharedir is null then
80 print "Error: Cannot locate nitdoc share files. Uses --sharedir or envvar NIT_DIR"
81 abort
82 end
83 dir = "{sharedir.to_s}/scripts/js-facilities.js"
84 if sharedir is null then
85 print "Error: Invalid nitdoc share files. Check --sharedir or envvar NIT_DIR"
86 abort
87 end
88 end
89 end
90
91 fun start do
92 if arguments.length == 1 then
93 # Create destination dir if it's necessary
94 if not destinationdir.file_exists then destinationdir.mkdir
95 sys.system("cp -r {sharedir.to_s}/* {destinationdir.to_s}/")
96 overview
97 end
98 end
99
100 fun overview do
101 var overviewpage = new NitdocOverview.with(modelbuilder.nmodules, self.opt_nodot.value, destinationdir.to_s)
102 overviewpage.save("{destinationdir.to_s}/index.html")
103 end
104
105 end
106
107 class NitdocOverview
108 super NitdocPage
109
110 var amodules: Array[AModule]
111
112 # Init with Array[AModule] to get all ifnormations about each MModule containt in a program
113 # opt_nodot to inform about the graph gen
114 # destination: to know where will be saved dot files
115 init with(modules: Array[AModule], opt_nodot: Bool, destination: String) do
116 self.amodules = modules
117 self.opt_nodot = opt_nodot
118 self.destinationdir = destination
119 end
120
121 redef fun head do
122 super
123 add("title").text("Overview | Nit Standard Library")
124 end
125
126 redef fun header do
127 open("header")
128 open("nav").add_class("main")
129 open("ul")
130 add("li").add_class("current").text("Overview")
131 open("li")
132 add_html("<a href=\"full-index.html\">Full Index</a>")
133 close("li")
134 open("li").attr("id", "liGitHub")
135 open("a").add_class("btn").attr("id", "logGitHub")
136 add("img").attr("id", "imgGitHub").attr("src", "resources/icons/github-icon.png")
137 close("a")
138 open("div").add_class("popover bottom")
139 add("div").add_class("arrow").text(" ")
140 open("div").add_class("githubTitle")
141 add("h3").text("Github Sign In")
142 close("div")
143 open("div")
144 add("label").attr("id", "lbloginGit").text("Username")
145 add("input").attr("id", "loginGit").attr("name", "login").attr("type", "text")
146 open("label").attr("id", "logginMessage").text("Hello ")
147 open("a").attr("id", "githubAccount")
148 add("strong").attr("id", "nickName").text(" ")
149 close("a")
150 close("label")
151 close("div")
152 open("div")
153 add("label").attr("id", "lbpasswordGit").text("Password")
154 add("input").attr("id", "passwordGit").attr("name", "password").attr("type", "password")
155 open("div").attr("id", "listBranches")
156 add("label").attr("id", "lbBranches").text("Branch")
157 add("select").add_class("dropdown").attr("id", "dropBranches").attr("name", "dropBranches").attr("tabindex", "1").text(" ")
158 close("div")
159 close("div")
160 open("div")
161 add("label").attr("id", "lbrepositoryGit").text("Repository")
162 add("input").attr("id", "repositoryGit").attr("name", "repository").attr("type", "text")
163 close("div")
164 open("div")
165 add("label").attr("id", "lbbranchGit").text("Branch")
166 add("input").attr("id", "branchGit").attr("name", "branch").attr("type", "text")
167 close("div")
168 open("div")
169 add("a").attr("id", "signIn").text("Sign In")
170 close("div")
171 close("div")
172 close("li")
173 close("ul")
174 close("nav")
175 close("header")
176 end
177
178 redef fun body do
179 super
180 open("div").add_class("page")
181 open("div").add_class("content fullpage")
182 add("h1").text("Nit Standard Library")
183 open("article").add_class("overview")
184 add_html("<p>Documentation for the standard library of Nit<br />Version jenkins-component=stdlib-19<br />Date: TODAY</p>")
185 close("article")
186 open("article").add_class("overview")
187 add("h2").text("Modules")
188 open("ul")
189 add_modules
190 close("ul")
191 process_generate_dot
192 close("article")
193 close("div")
194 close("div")
195 add("footer").text("Nit standard library. Version jenkins-component=stdlib-19.")
196 end
197
198 fun add_modules do
199 var ls = new List[nullable MModule]
200 for amodule in amodules do
201 var mmodule = amodule.mmodule.public_owner
202 if mmodule != null and not ls.has(mmodule) then
203 open("li")
204 add("a").attr("href", "{mmodule.name}.html").text("{mmodule.to_s} ")
205 add_html(amodule.comment)
206 close("li")
207 ls.add(mmodule)
208 end
209 end
210 end
211
212 fun process_generate_dot do
213 var op = new Buffer
214 op.append("digraph dep \{ rankdir=BT; node[shape=none,margin=0,width=0,height=0,fontsize=10]; edge[dir=none,color=gray]; ranksep=0.2; nodesep=0.1;\n")
215 for amodule in amodules do
216 op.append("\"{amodule.mmodule.name}\"[URL=\"{amodule.mmodule.name}.html\"];\n")
217 for mmodule2 in amodule.mmodule.in_importation.direct_greaters do
218 op.append("\"{amodule.mmodule.name}\"->\"{mmodule2.name}\";\n")
219 end
220 end
221 op.append("\}\n")
222 generate_dot(op.to_s, "dep", "Modules hierarchy")
223 end
224
225 end
226
227 class NitdocPage
228 super HTMLPage
229 var opt_nodot: Bool
230 var destinationdir : String
231
232 redef fun head do
233 add("meta").attr("charset", "utf-8")
234 add("script").attr("type", "text/javascript").attr("src", "scripts/jquery-1.7.1.min.js")
235 add("script").attr("type", "text/javascript").attr("src", "quicksearch-list.js")
236 add("script").attr("type", "text/javascript").attr("src", "scripts/js-facilities.js")
237 add("link").attr("rel", "stylesheet").attr("href", "styles/main.css").attr("type", "text/css").attr("media", "screen")
238 end
239
240 redef fun body do header
241 fun header do end
242
243 # Generate a clickable graphviz image using a dot content
244 fun generate_dot(dot: String, name: String, alt: String) do
245 if opt_nodot then return
246 var file = new OFStream.open("{self.destinationdir}/{name}.dot")
247 file.write(dot)
248 file.close
249 sys.system("\{ test -f {self.destinationdir}/{name}.png && test -f {self.destinationdir}/{name}.s.dot && diff {self.destinationdir}/{name}.dot {self.destinationdir}/{name}.s.dot >/dev/null 2>&1 ; \} || \{ cp {self.destinationdir}/{name}.dot {self.destinationdir}/{name}.s.dot && dot -Tpng -o{self.destinationdir}/{name}.png -Tcmapx -o{self.destinationdir}/{name}.map {self.destinationdir}/{name}.s.dot ; \}")
250 open("article").add_class("graph")
251 add("img").attr("src", "{name}.png").attr("usemap", "#{name}").attr("style", "margin:auto").attr("alt", "{alt}")
252 close("article")
253 var fmap = new IFStream.open("{self.destinationdir}/{name}.map")
254 add_html(fmap.read_all)
255 fmap.close
256 end
257
258 end
259
260 redef class AModule
261 private fun comment: String do
262 var ret = ""
263 if n_moduledecl is null or n_moduledecl.n_doc is null then ret
264 if n_moduledecl.n_doc is null then return ""
265 for t in n_moduledecl.n_doc.n_comment do
266 ret += "{t.text.replace("# ", "")}"
267 end
268 return ret
269 end
270
271 private fun short_comment: String do
272 var ret = ""
273 if n_moduledecl != null and n_moduledecl.n_doc != null then
274 var txt = n_moduledecl.n_doc.n_comment.first.text
275 txt = txt.replace("# ", "")
276 txt = txt.replace("\n", "")
277 ret += txt
278 end
279 return ret
280 end
281 end
282
283 # Create a tool context to handle options and paths
284 var toolcontext = new ToolContext
285 toolcontext.process_options
286
287 # Here we launch the nit index
288 var nitdoc = new Nitdoc(toolcontext)
289 nitdoc.start