c05195b1f11dbd76e9d334511a9531cf7e69a751
[nit.git] / src / doc / commands / commands_docdown.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 # Doc down related queries
16 module commands_docdown
17
18 import commands::commands_parser
19 import commands::commands_html
20 import commands::commands_md
21
22 intrude import doc_down
23 intrude import markdown::wikilinks
24
25 # Retrieve the MDoc summary
26 #
27 # List all MarkdownHeading found and their ids.
28 class CmdSummary
29 super CmdComment
30
31 # Markdown processor used to parse the headlines
32 var markdown_processor: nullable MarkdownProcessor = null is optional, writable
33
34 # Resulting summary
35 #
36 # Associates each headline to its id.
37 var summary: nullable ArrayMap[String, HeadLine] = null is optional, writable
38
39 redef fun init_command do
40 var res = super
41 if not res isa CmdSuccess then return res
42 var mentity = self.mentity.as(not null)
43
44 var markdown_processor = self.markdown_processor
45 if markdown_processor == null then
46 markdown_processor = new MarkdownProcessor
47 self.markdown_processor = markdown_processor
48 end
49
50 var mdoc = self.mdoc
51 if mdoc == null then
52 mdoc = if fallback then mentity.mdoc_or_fallback else mentity.mdoc
53 self.mdoc = mdoc
54 end
55 if mdoc == null then return new WarningNoMDoc(mentity)
56
57 markdown_processor.process(mdoc.md_documentation.write_to_string)
58
59 var summary = new ArrayMap[String, HeadLine]
60 summary.add_all markdown_processor.decorator.headlines
61 self.summary = summary
62 return res
63 end
64 end
65
66 # Custom Markdown processor able to process doc commands
67 class CmdDecorator
68 super NitdocDecorator
69
70 redef type PROCESSOR: CmdMarkdownProcessor
71
72 # Model used by wikilink commands to find entities
73 var model: Model
74
75 # Filter to apply if any
76 var filter: nullable ModelFilter
77
78 redef fun add_span_code(v, buffer, from, to) do
79 var text = new FlatBuffer
80 buffer.read(text, from, to)
81 var name = text.write_to_string
82 name = name.replace("nullable ", "")
83 var mentity = try_find_mentity(name)
84 if mentity == null then
85 super
86 else
87 v.add "<code>"
88 v.emit_text mentity.html_link.write_to_string
89 v.add "</code>"
90 end
91 end
92
93 private fun try_find_mentity(text: String): nullable MEntity do
94 var mentity = model.mentity_by_full_name(text, filter)
95 if mentity != null then return mentity
96
97 var mentities = model.mentities_by_name(text, filter)
98 if mentities.is_empty then
99 return null
100 else if mentities.length > 1 then
101 # TODO smart resolve conflicts
102 end
103 return mentities.first
104 end
105
106 redef fun add_wikilink(v, token) do
107 v.render_wikilink(token, model)
108 end
109 end
110
111 # Same as `InlineDecorator` but with wikilink commands handling
112 class CmdInlineDecorator
113 super InlineDecorator
114
115 redef type PROCESSOR: CmdMarkdownProcessor
116
117 # Model used by wikilink commands to find entities
118 var model: Model
119
120 redef fun add_wikilink(v, token) do
121 v.render_wikilink(token, model)
122 end
123 end
124
125 # Custom MarkdownEmitter for commands
126 class CmdMarkdownProcessor
127 super MarkdownProcessor
128
129 # Parser used to process doc commands
130 var parser: CommandParser
131
132 # Render a wikilink
133 fun render_wikilink(token: TokenWikiLink, model: Model) do
134 var link = token.link
135 if link == null then return
136 var name = token.name
137 if name != null then link = "{name} | {link}"
138
139 var command = parser.parse(link.write_to_string)
140 var error = parser.error
141
142 if error isa CmdError then
143 emit_text error.to_html.write_to_string
144 return
145 end
146 if error isa CmdWarning then
147 emit_text error.to_html.write_to_string
148 end
149 add command.as(not null).to_html
150 end
151 end
152
153 redef class Text
154 # Read `self` between `nstart` and `nend` (excluded) and writte chars to `out`.
155 private fun read(out: FlatBuffer, nstart, nend: Int): Int do
156 var pos = nstart
157 while pos < length and pos < nend do
158 out.add self[pos]
159 pos += 1
160 end
161 if pos == length then return -1
162 return pos
163 end
164 end