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