From 481bb9e91b3b4b0e17237dcfb9661fda1342b0b2 Mon Sep 17 00:00:00 2001 From: Song Date: Sun, 15 Nov 2020 23:26:16 +0800 Subject: [PATCH] looks like we finished it --- README.md | 2 +- converter/converter.go | 45 +++++++++++++++++++++++++++++++++++++++++- parser/parser.go | 29 ++++++++++++++++++++++++++- test/test.md | 5 +++-- 4 files changed, 76 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 77f6abf..c25f317 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Markdown to HTML ## TODO -- [ ] Support list. +- [x] Support list. - [ ] Add style for code block. - [ ] Support code block without triple backticks. diff --git a/converter/converter.go b/converter/converter.go index a14dc6e..5379711 100644 --- a/converter/converter.go +++ b/converter/converter.go @@ -3,6 +3,7 @@ package converter import ( "fmt" "md2html/parser" + "strings" ) var htmlTemplate = ` @@ -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) @@ -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 = "" + } else { + html = "
    %s
" + } + 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 = "" + } else if int(node.Value[0]) == 3 { + inputTag = "" + } + subListContent := "" + if len(node.Children) > 1 { + subList := "" + if int(node.Children[1].Value[0])%2 == 0 { + subList = "" + } else { + subList = "
    %s
" + } + for _, child := range node.Children[1:] { + subListContent += fmt.Sprintf(subList, processSubListNode(child)) + } + } + html += fmt.Sprintf("
  • %s%s%s
  • ", inputTag, content, subListContent) return } diff --git a/parser/parser.go b/parser/parser.go index b831243..f4cdc44 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -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])) } @@ -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) { @@ -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. diff --git a/test/test.md b/test/test.md index 1b7af4b..7bf7221 100644 --- a/test/test.md +++ b/test/test.md @@ -1,2 +1,3 @@ -首先,这个[博客](https://iamazing.cn/) 就是用 Node.js & Express.js 开发的,代码在此处:https://github.com/songquanpeng/express-react-blog , -你可以拿来做参考,~~强烈建议 star~~。 \ No newline at end of file +1. `req`:request,请求信息,这个是一个 JavaScript 对象,你可以打印出来看一下的,之后我们处理表单时,或者获取 url 参数的时候,数据就是从这个 req 对象里取的。 +2. `res`:response,这个就是返回对象,我们可以调用它的一些方法,例如这里调用的是 `res.render('index', { title: 'Express' });`,告诉 Express 渲染 `/views/` 文件夹下的模板 `index.ejs`,并把渲染的结果返回给用户。 +3. `next`:这是一个函数,当我们不想在当前函数中处理请求的话可以调用 `next()` 让后面的匹配的函数进行处理,不理解没关系,我们这里用不到。