Merge: Nitiwiki next
[nit.git] / lib / markdown / decorators.nit
index 8db52c4..f33302f 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+# Decorators for `markdown` parsing.
+module decorators
+
 import markdown
 
+# `Decorator` that outputs markdown.
+class MdDecorator
+       super Decorator
+
+       redef var headlines = new ArrayMap[String, HeadLine]
+
+       redef fun add_ruler(v, block) do v.add "***\n"
+
+       redef fun add_headline(v, block) do
+               # save headline
+               var txt = block.block.first_line.value
+               var id = strip_id(txt)
+               var lvl = block.depth
+               headlines[id] = new HeadLine(id, txt, lvl)
+               v.add "{"#" * lvl} "
+               v.emit_in block
+               v.addn
+       end
+
+       redef fun add_paragraph(v, block) do
+               v.emit_in block
+               v.addn
+       end
+
+       redef fun add_code(v, block) do
+               if block isa BlockFence and block.meta != null then
+                       v.add "~~~{block.meta.to_s}"
+               else
+                       v.add "~~~"
+               end
+               v.addn
+               v.emit_in block
+               v.add "~~~"
+               v.addn
+       end
+
+       redef fun add_blockquote(v, block) do
+               v.add "> "
+               v.emit_in block
+               v.addn
+       end
+
+       redef fun add_unorderedlist(v, block) do
+               in_unorderedlist = true
+               v.emit_in block
+               in_unorderedlist = false
+       end
+       private var in_unorderedlist = false
+
+       redef fun add_orderedlist(v, block) do
+               in_orderedlist = true
+               current_li = 0
+               v.emit_in block
+               in_unorderedlist = false
+       end
+       private var in_orderedlist = false
+       private var current_li = 0
+
+       redef fun add_listitem(v, block) do
+               if in_unorderedlist then
+                       v.add "* "
+               else if in_orderedlist then
+                       current_li += 1
+                       v.add "{current_li} "
+               end
+               v.emit_in block
+               v.addn
+       end
+
+       redef fun add_em(v, text) do
+               v.add "*"
+               v.add text
+               v.add "*"
+       end
+
+       redef fun add_strong(v, text) do
+               v.add "**"
+               v.add text
+               v.add "**"
+       end
+
+       redef fun add_strike(v, text) do
+               v.add "~~"
+               v.add text
+               v.add "~~"
+       end
+
+       redef fun add_image(v, link, name, comment) do
+               v.add "!["
+               v.add name
+               v.add "]("
+               append_value(v, link)
+               if comment != null and not comment.is_empty then
+                       v.add " "
+                       append_value(v, comment)
+               end
+               v.add ")"
+       end
+
+       redef fun add_link(v, link, name, comment) do
+               v.add "["
+               v.add name
+               v.add "]("
+               append_value(v, link)
+               if comment != null and not comment.is_empty then
+                       v.add " "
+                       append_value(v, comment)
+               end
+               v.add ")"
+       end
+
+       redef fun add_abbr(v, name, comment) do
+               v.add "<abbr title=\""
+               append_value(v, comment)
+               v.add "\">"
+               v.emit_text(name)
+               v.add "</abbr>"
+       end
+
+       redef fun add_span_code(v, text, from, to) do
+               v.add "`"
+               append_code(v, text, from, to)
+               v.add "`"
+       end
+
+       redef fun add_line_break(v) do
+               v.add "\n"
+       end
+
+       redef fun append_value(v, text) do for c in text do escape_char(v, c)
+
+       redef fun escape_char(v, c) do v.addc(c)
+
+       redef fun append_code(v, buffer, from, to) do
+               for i in [from..to[ do
+                       v.addc buffer[i]
+               end
+       end
+
+       redef fun strip_id(txt) do
+               # strip id
+               var b = new FlatBuffer
+               for c in txt do
+                       if c == ' ' then
+                               b.add '_'
+                       else
+                               if not c.is_letter and
+                                  not c.is_digit and
+                                  not allowed_id_chars.has(c) then continue
+                               b.add c
+                       end
+               end
+               var res = b.to_s
+               var key = res
+               # check for multiple id definitions
+               if headlines.has_key(key) then
+                       var i = 1
+                       key = "{res}_{i}"
+                       while headlines.has_key(key) do
+                               i += 1
+                               key = "{res}_{i}"
+                       end
+               end
+               return key
+       end
+
+       private var allowed_id_chars: Array[Char] = ['-', '_', ':', '.']
+end
+
 # Decorator for span elements.
 #
 # InlineDecorator does not decorate things like paragraphs or headers.