Skip to content

Commit

Permalink
looks like we finished it
Browse files Browse the repository at this point in the history
  • Loading branch information
songquanpeng committed Nov 15, 2020
1 parent f64b5ba commit 481bb9e
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 5 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Markdown to HTML

## TODO
- [ ] Support list.
- [x] Support list.
- [ ] Add style for code block.
- [ ] Support code block without triple backticks.

Expand Down
45 changes: 44 additions & 1 deletion converter/converter.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package converter
import (
"fmt"
"md2html/parser"
"strings"
)

var htmlTemplate = `<html>
Expand All @@ -20,7 +21,7 @@ max-width: 750px;

func Convert(markdown string, fullPage bool) (html string) {
ast := parser.Parse(markdown)
parser.PrintAST(ast)
//parser.PrintAST(ast)
html = processArticleNode(ast)
if fullPage {
html = fmt.Sprintf(htmlTemplate, html)
Expand Down Expand Up @@ -90,7 +91,49 @@ func processContentNode(node *parser.Node) (html string) {
}

func processListNode(node *parser.Node) (html string) {
if len(node.Children) == 0 {
return
}
if int(node.Children[0].Value[0])%2 == 0 {
// unordered list
html = "<ul>%s</ul>"
} else {
html = "<ol>%s</ol>"
}
content := ""
for _, child := range node.Children {
content += processSubListNode(child)
}
html = fmt.Sprintf(html, content)
return
}

func processSubListNode(node *parser.Node) (html string) {
content := processContentNode(node.Children[0])
i := strings.Index(content, ". ")
if i >= 0 && i < 5 {
i += 2
content = content[i:]
}
inputTag := ""
if int(node.Value[0]) == 2 {
inputTag = "<input disabled type='checkbox'>"
} else if int(node.Value[0]) == 3 {
inputTag = "<input checked disabled type='checkbox'>"
}
subListContent := ""
if len(node.Children) > 1 {
subList := ""
if int(node.Children[1].Value[0])%2 == 0 {
subList = "<ul>%s</ul>"
} else {
subList = "<ol>%s</ol>"
}
for _, child := range node.Children[1:] {
subListContent += fmt.Sprintf(subList, processSubListNode(child))
}
}
html += fmt.Sprintf("<li>%s%s%s</li>", inputTag, content, subListContent)
return
}

Expand Down
29 changes: 28 additions & 1 deletion parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ func (node Node) String() (str string) {
str += "Uncompleted Task"
case 3:
str += "Completed Task"
case -1:
str += "Placeholder List"
}
str += fmt.Sprintf(" (level %d)", int(node.Value[1]))
}
Expand Down Expand Up @@ -173,6 +175,31 @@ func preprocessAST(root *Node) {
}
}
root.Children = newChildren
// Then we have to combine those list items.
combineListNode(root)
}

func combineListNode(root *Node) {
var newChildren []*Node
var current *Node
for i := 0; i < len(root.Children); i++ {
if root.Children[i].Type == ListNode {
if current == nil {
current = &Node{
Type: ListNode,
Value: nil,
Children: nil,
}
current.Value = append(current.Value, rune(-1), rune(0))
newChildren = append(newChildren, current)
}
current.Children = append(current.Children, root.Children[i])
} else {
newChildren = append(newChildren, root.Children[i])
current = nil
}
}
root.Children = newChildren
}

func processListNode(nodes []*Node) {
Expand Down Expand Up @@ -434,7 +461,7 @@ func parseList() (root *Node) {
default:
log.Println("Warning: unexpected token detected when processing list.")
}
listLevel := tabCounter
listLevel := tabCounter + 1
tabCounter = 0
root.Value = append(root.Value, rune(listType), rune(listLevel))
// The first child of a list node is its content.
Expand Down
5 changes: 3 additions & 2 deletions test/test.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
首先,这个[博客](https://iamazing.cn/) 就是用 Node.js & Express.js 开发的,代码在此处:https://github.com/songquanpeng/express-react-blog
你可以拿来做参考,~~强烈建议 star~~
1. `req`:request,请求信息,这个是一个 JavaScript 对象,你可以打印出来看一下的,之后我们处理表单时,或者获取 url 参数的时候,数据就是从这个 req 对象里取的。
2. `res`:response,这个就是返回对象,我们可以调用它的一些方法,例如这里调用的是 `res.render('index', { title: 'Express' });`,告诉 Express 渲染 `/views/` 文件夹下的模板 `index.ejs`,并把渲染的结果返回给用户。
3. `next`:这是一个函数,当我们不想在当前函数中处理请求的话可以调用 `next()` 让后面的匹配的函数进行处理,不理解没关系,我们这里用不到。

0 comments on commit 481bb9e

Please sign in to comment.