Markdowner: a module to generate a gui from markdown

Markdowner generates Roblox guis to display markdown, supporting:

  • Paragraphs
  • Bullet point lists
  • Numbered lists
  • Nested lists
  • Code blocks
  • Syntax highlighting Lua code
  • Inline code
  • Horizontal rule (line)
  • Blockquotes
  • Images
  • Preserving original links while showing Roblox asset images only when viewed in Roblox i.e. markdown with images that can be viewed both in- and out-of Roblox
  • Doing a relayout of the markdown gui using the same data and some of the same gui objects.

Markdowner uses the following open-source modules:

Markdown is turned into html which is then turned into Roblox gui. This is not optimal. This project was hacked together with the intention of developing a documentation plugin, but I never got around to it! This would be a great inclusion to a documentation viewer plugin!

@ChipioIndustries suggested I open source this at RDC, so here it is! I included some minimal documentation for now – I’m still at RDC and don’t have time to write full docs.

Edit: At least a UIListLayout is required in your gui for Markdowner to display properly. Initially, this was not noted in the docs and no default UIListLayout was created. The module has been updated with relevant documentation and with default UI layouts.


Markdowner

Here is Markdowner rendering markdown.lua's README (+ an added list for example purposes):

MarkdownerPublic.rbxl (57.9 KB)

Source:


# markdown.lua

[![Build Status](https://travis-ci.org/mpeterv/markdown.png?branch=master)](https://travis-ci.org/mpeterv/markdown)
[![Coverage Status](https://coveralls.io/repos/mpeterv/markdown/badge.svg?branch=master)](https://coveralls.io/r/mpeterv/markdown?branch=master)

List

* Lista
* Listb
	1. List2a
	2. List2b
		1. List3a
		2. List3b

This is an implementation of the popular text markup language Markdown in pure Lua.
Markdown can convert documents written in a simple and easy to read text format
to well-formatted HTML. For a more thorough description of Markdown and the Markdown
syntax, see http://daringfireball.net/projects/markdown/.

The original Markdown source is written in Perl and makes heavy use of advanced
regular expression techniques (such as negative look-ahead, etc) which are not available
in Lua's simple regex engine. Therefore this Lua port has been rewritten from the ground
up. It is probably not completely bug free. If you notice any bugs, please report them using
GitHub issues. A unit test that exposes the error is helpful.

`markdown.lua` has been written by Niklas Frykholm ([original](http://www.frykholm.se/files/markdown.lua)).
This version has been updated to run under Lua 5.2 and Lua 5.3 in addition to Lua 5.1.

## Usage

```lua
local markdown = require "markdown"
markdown(source)
```

`markdown` module returns a single function which applies the Markdown transformation to the
specified string. For compatibility it is also set as a global.

`markdown.lua` can also be used directly from the command line:

```
lua markdown.lua test.md
```

Creates a file `test.html` with the converted content of `test.md`. Run:

```
lua markdown.lua -h
```

For a description of the command-line options.

## Installation

Simply copy `markdown.lua` into your directory for Lua libraries. Alternatively,
use [LuaRocks](https://luarocks.org/) and run `[sudo] luarocks install markdown`.

## Miscellaneous

`markdown.lua` uses the same license as Lua, the MIT license.

An alternative Markdown implementation is [lua-discount](http://asbradbury.org/projects/lua-discount/).
It is faster than `markdown.lua`, at the cost of being written in C.

[roblox https://travis-ci.org/mpeterv/markdown.png?branch=master]: rbxassetid://2651257779 "=90x20"
[roblox https://coveralls.io/repos/mpeterv/markdown/badge.svg?branch=master]: rbxassetid://2651258000 "=99x20"
74 Likes

This is almost exactly what I use in Lua Learning! You even used the Lexer that I worked on with Crazyman32! Mine uses the same method of MD>HTML>GUI as well. I’m pretty sure I also based mine off of that old markdown.lua from GitHub. Seems like we had the same idea here!

Tomorrow I’ll do some comparisons and tests with mine vs. yours. If yours is better, then I’ll be switching over to yours! I’ll probably have to modify it for backwards compatibility with my own image formatting for asset IDs, but other than that I presume it would be a simple change to make.

Thanks for sharing!

10 Likes

I will continuously edit this reply to add all my findings

I’d like to mention that despite these issues, this module is very well made and useful. You’ve done a great job, and these do not nullify that fact.

Lack of italics-bold

Your module does not have support for italic-bold. If you place italics inside of bold text or bold inside of italics, it becomes plain italics.

There is no italic-bold font, so this is understandable. However, I’d found a hacky method to do it anyway.

The way Roblox renders text is kinda janky, so we use that to our advantage. You render the same italic text in the same spot 3-4 times, and each time thickens it a little bit, resulting in “bolding” the italic text. Make sure the layers have BackgroundTransparency = 1 so that they can properly stack.
image

Poorly ported `markdown.lua`

You left a lot of things in the markdown.lua module that pertain to being run from a command line, and uses things like io and reading files. Roblox doesn’t need that part!

No newline support in blockquotes

If the quote has line breaks in it, the text is all forced to one line.
image

Strange lexer usage

Granted, I have the unfair advantage of being involved in its creation, but you’ve used it in extremely weird ways. You have an (incomplete) table of operators stored externally (external from the lexer) and then reference that after lexing operators already.

The proper way to do it:
Have textcolors have these keys:

textColors = {
	iden     = Color3.fromRGB(234, 234, 234),
	operator = Color3.fromRGB(255, 239, 148),
	keyword  = Color3.fromRGB(215, 174, 255),
	string   = Color3.fromRGB(196, 255, 193),
	number   = Color3.fromRGB(255, 125, 125),
	comment  = Color3.fromRGB(190, 190, 200),
	builtin  = Color3.fromRGB(131, 206, 255),
},

Then determine color like so:

for token, text in lexerScan(self.text) do
	local colorName = token
	local color = self.textColors[colorName] or self.textColors.operator
9 Likes

Any chance you’ll open-source the one you made?

1 Like

Mine has a lot of weirdly specific things made for Lua Learning.

  • When a user changes their script editor settings in game, it fires an event for the module to recolor all code blocks to match the new setting.
  • Uses my custom image format instead of just asset ids.
  • Supports GIFs through more weird custom formats
  • Code blocks are TextBoxes to allow copying to clipboard
  • Honestly really buggy in many cases
  • A bunch more minor things
6 Likes

I’ll have to check it out. Sounds pretty interesting.

I can’t for the life of me make it support Roblox RichText. It seems to ignore <font> and it’s properties. Any ideas?

Markdowner was created before Roblox added RichText, so you would have to modify the code yourself to support it.

I feel like I don’t fully understand it but at the same time it seems intuitive. I’ve added “font” to the protected data table but it still doesn’t ignore it… Are you at all familiar with the structure?

I haven’t looked too deep into the code so I can’t say, but from what I saw, Markdowner splits every word into its own TextLabel with RichText disabled. You would have to enable it somewhere.

I thought It would be a simple remove the split but it’s difficult to pinpoint since it uses OOP with Inheritance.