Skip to content

Commit

Permalink
可運行首版 (#2)
Browse files Browse the repository at this point in the history
	標準以及常用的code-block顏色可以渲染(Monokai樣式)
  • Loading branch information
CarsonSlovoka committed Oct 1, 2022
1 parent 52b2d30 commit fa41260
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 4 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@
## 參考資料

- [github.com/yuin/goldmark-highlighting](https://github.com/yuin/goldmark-highlighting)
- [github.com/alecthomas/chroma](https://github.com/alecthomas/chroma) 掌管主題顏色的細節,例如{背景、數字、註解、字串...}[等相關屬性](https://github.com/alecthomas/chroma/blob/6138519d55582350e5dec0147cb8f5ddcb78f8cf/styles/swapoff.go#L8-L25)
- Style
- [Chroma Style Gallery](https://xyproto.github.io/splash/docs/)
- [Source](https://github.com/alecthomas/chroma/tree/3f86ac7/styles): 這邊每一個檔案都表示一種style
8 changes: 8 additions & 0 deletions v2/chroma.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package highlighting

import "github.com/alecthomas/chroma/v2/styles"

// DefaultStyle
// https://xyproto.github.io/splash/docs/
// https://github.com/alecthomas/chroma/tree/3f86ac7/styles
var DefaultStyle = styles.Monokai
7 changes: 6 additions & 1 deletion v2/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,9 @@ module github.com/CarsonSlovoka/goldmark-highlighting/v2

go 1.19

require github.com/yuin/goldmark v1.4.14
require (
github.com/alecthomas/chroma/v2 v2.3.0
github.com/yuin/goldmark v1.4.14
)

require github.com/dlclark/regexp2 v1.4.0 // indirect
11 changes: 11 additions & 0 deletions v2/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
github.com/alecthomas/chroma/v2 v2.3.0 h1:83xfxrnjv8eK+Cf8qZDzNo3PPF9IbTWHs7z28GY6D0U=
github.com/alecthomas/chroma/v2 v2.3.0/go.mod h1:mZxeWZlxP2Dy+/8cBob2PYd8O2DwNAzave5AY7A2eQw=
github.com/alecthomas/repr v0.1.0 h1:ENn2e1+J3k09gyj2shc0dHr/yjaWSHRlrJ4DPMevDqE=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/yuin/goldmark v1.4.14 h1:jwww1XQfhJN7Zm+/a1ZA/3WUiEBEroYFNTiV3dKwM8U=
github.com/yuin/goldmark v1.4.14/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
102 changes: 99 additions & 3 deletions v2/renderer.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package highlighting

import (
"bytes"
"fmt"
"github.com/alecthomas/chroma/v2"
chromahtml "github.com/alecthomas/chroma/v2/formatters/html"
"github.com/alecthomas/chroma/v2/lexers"
"github.com/yuin/goldmark/ast"
"github.com/yuin/goldmark/renderer"
"github.com/yuin/goldmark/util"
Expand All @@ -13,10 +18,101 @@ func NewHighlightingHTMLRenderer() renderer.NodeRenderer {
}

func (r *highlightingHTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
reg.Register(ast.KindFencedCodeBlock, r.nodeRendererFunc) // codeblock不需要再定義額外的ast去描述,基於原始的KindFencedCodeBlock增加額外的判斷即可
reg.Register(ast.KindFencedCodeBlock, r.nodeRendererFunc) // codeBlock不需要再定義額外的ast去描述,基於原始的KindFencedCodeBlock增加額外的判斷即可
}

// nodeRendererFunc 此函數可以把結果直接寫到writer之中,就能對輸出產生影響
func (r *highlightingHTMLRenderer) nodeRendererFunc(writer util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) {
return 0, nil
func (r *highlightingHTMLRenderer) nodeRendererFunc(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
if !entering {
return ast.WalkContinue, nil
}

n := node.(*ast.FencedCodeBlock) // 轉成對應的ast.Node

// Attributes, // parse ```go{hl_lines=["2-3",5], linenostart=5}
{
// TODO
}

noHighlight := false
guessLanguage := false

var codeBlockContent bytes.Buffer
l := n.Lines().Len()
for i := 0; i < l; i++ { // 把code-block的內容,一列一列的寫進去
line := n.Lines().At(i)
codeBlockContent.Write(line.Value(source)) // source是一個比較大的項目,可以包含code-block以外的內容
}

language := n.Language(source) // 當前code-block所用的語言 ```myLang

// 定義預設的code-block函數
defaultCodeBlockHandlerFunc := func() (ast.WalkStatus, error) {
// Header
{
if language != nil {
_, _ = w.WriteString(fmt.Sprintf("<pre>\n<code class=\"language-%s\">", language))
} else {
_, _ = w.WriteString("<pre>\n<code>")
}
}
// Body
{
_, _ = w.WriteString(codeBlockContent.String())
}
// Tail
{
_, _ = w.WriteString("</code>\n</pre>\n")
}
return ast.WalkContinue, nil
}

var lexer chroma.Lexer
if language != nil {
lexer = lexers.Get(string(language))
if lexer != nil {
return r.writeCodeBlock(
w, lexer, &codeBlockContent,
defaultCodeBlockHandlerFunc, // 如果錯誤就用預設的code-block取代
)
}
}

if !noHighlight && guessLanguage {
if lexer = lexers.Analyse(codeBlockContent.String()); lexer != nil {
return r.writeCodeBlock(w, lexer, &codeBlockContent, defaultCodeBlockHandlerFunc)
}
}

return defaultCodeBlockHandlerFunc()
}

func (r *highlightingHTMLRenderer) writeCodeBlock(
w util.BufWriter, lexer chroma.Lexer, codeBlockContent *bytes.Buffer,
defaultHandlerFunc func() (ast.WalkStatus, error),
) (ast.WalkStatus, error) {

if lexer == nil {
return ast.WalkContinue, nil
}
language := []byte(lexer.Config().Name)
lexer = chroma.Coalesce(lexer) // 常態化lexer。所得到的結果還是一個Laxer型別

iterator, err := lexer.Tokenise(nil, codeBlockContent.String()) // 這裡開始準備解析code-block的文本,他會把所有文本解析出個別的關鍵字,整理出一份token清單,可以被疊代
if err != nil {
return defaultHandlerFunc()
}

formatter := chromahtml.New()

// Head
_, _ = w.WriteString(fmt.Sprintf("<div class=\"highlight %s\">\n", language))

// Body
_ = formatter.Format(w, DefaultStyle, iterator) // chroma的核心,可以把該token渲染成指定的樣式

// Tail
_, _ = w.WriteString("\n</div>")

return ast.WalkContinue, nil
}

0 comments on commit fa41260

Please sign in to comment.