From: Alexandre Terrasa Date: Tue, 24 Oct 2017 03:39:00 +0000 (-0400) Subject: doc/commands: introduce docdown related commands X-Git-Url: http://nitlanguage.org doc/commands: introduce docdown related commands Signed-off-by: Alexandre Terrasa --- diff --git a/src/doc/commands/commands_docdown.nit b/src/doc/commands/commands_docdown.nit new file mode 100644 index 0000000..9ec8294 --- /dev/null +++ b/src/doc/commands/commands_docdown.nit @@ -0,0 +1,175 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Doc down related queries +module commands_docdown + +import commands::commands_parser +import commands::commands_html + +intrude import doc_down +intrude import markdown::wikilinks + +# Retrieve the MDoc summary +# +# List all MarkdownHeading found and their ids. +class CmdSummary + super CmdComment + + # Markdown processor used to parse the headlines + var markdown_processor: nullable MarkdownProcessor = null is optional, writable + + # Resulting summary + # + # Associates each headline to its id. + var summary: nullable ArrayMap[String, HeadLine] = null is optional, writable + + redef fun init_command do + var res = super + if not res isa CmdSuccess then return res + var mentity = self.mentity.as(not null) + + var markdown_processor = self.markdown_processor + if markdown_processor == null then + markdown_processor = new MarkdownProcessor + self.markdown_processor = markdown_processor + end + + var mdoc = self.mdoc + if mdoc == null then + mdoc = if fallback then mentity.mdoc_or_fallback else mentity.mdoc + self.mdoc = mdoc + end + if mdoc == null then return new WarningNoMDoc(mentity) + + markdown_processor.process(mdoc.md_documentation.write_to_string) + + var summary = new ArrayMap[String, HeadLine] + summary.add_all markdown_processor.decorator.headlines + self.summary = summary + return res + end +end + +# Custom Markdown processor able to process doc commands +class CmdDecorator + super NitdocDecorator + + redef type PROCESSOR: CmdMarkdownProcessor + + # View used by wikilink commands to find model entities + var view: ModelView + + redef fun add_span_code(v, buffer, from, to) do + var text = new FlatBuffer + buffer.read(text, from, to) + var name = text.write_to_string + name = name.replace("nullable ", "") + var mentity = try_find_mentity(view, name) + if mentity == null then + super + else + v.add "" + v.emit_text mentity.html_link.write_to_string + v.add "" + end + end + + private fun try_find_mentity(view: ModelView, text: String): nullable MEntity do + var mentity = view.mentity_by_full_name(text) + if mentity != null then return mentity + + var mentities = view.mentities_by_name(text) + if mentities.is_empty then + return null + else if mentities.length > 1 then + # TODO smart resolve conflicts + end + return mentities.first + end + + redef fun add_wikilink(v, token) do + v.render_wikilink(token, view) + end +end + +# Same as `InlineDecorator` but with wikilink commands handling +class CmdInlineDecorator + super InlineDecorator + + redef type PROCESSOR: CmdMarkdownProcessor + + # View used by wikilink commands to find model entities + var view: ModelView + + redef fun add_wikilink(v, token) do + v.render_wikilink(token, view) + end +end + +# Custom MarkdownEmitter for commands +class CmdMarkdownProcessor + super MarkdownProcessor + + # Parser used to process doc commands + var parser: CommandParser + + # Render a wikilink + fun render_wikilink(token: TokenWikiLink, model: ModelView) do + var link = token.link + if link == null then return + var name = token.name + if name != null then link = "{name} | {link}" + + var cmd = link.write_to_string + if cmd.is_empty then + var error = new CmdParserError("Empty wikilink") + emit_text error.to_html.write_to_string + return + end + + var command = parser.parse(cmd) + var error = parser.error + + # If not a command, try a comment command + if command == null and error isa CmdParserError then + error = null + command = new CmdEntity(parser.view, mentity_name = cmd) + var status = command.parser_init(cmd, new HashMap[String, String]) + if not status isa CmdSuccess then error = status + end + + if error isa CmdError then + emit_text error.to_html.write_to_string + return + end + if error isa CmdWarning then + emit_text error.to_html.write_to_string + end + add command.as(not null).to_html + end +end + +redef class Text + # Read `self` between `nstart` and `nend` (excluded) and writte chars to `out`. + private fun read(out: FlatBuffer, nstart, nend: Int): Int do + var pos = nstart + while pos < length and pos < nend do + out.add self[pos] + pos += 1 + end + if pos == length then return -1 + return pos + end +end