doc/commands: introduce docdown related commands
authorAlexandre Terrasa <alexandre@moz-code.org>
Tue, 24 Oct 2017 03:39:00 +0000 (23:39 -0400)
committerAlexandre Terrasa <alexandre@moz-code.org>
Thu, 23 Nov 2017 16:08:41 +0000 (11:08 -0500)
Signed-off-by: Alexandre Terrasa <alexandre@moz-code.org>

src/doc/commands/commands_docdown.nit [new file with mode: 0644]

diff --git a/src/doc/commands/commands_docdown.nit b/src/doc/commands/commands_docdown.nit
new file mode 100644 (file)
index 0000000..9ec8294
--- /dev/null
@@ -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 "<code>"
+                       v.emit_text mentity.html_link.write_to_string
+                       v.add "</code>"
+               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