Chuyển đến nội dung chính

Syntax highlighting trong Hugo

·4 phút· loading · loading · ·
Lập Trình Cms Ssg Jamstack Hugo
Duy Trung
Tác giả
Duy Trung
Thoughts run like the wind blows
Mục lục

Code hay dở chưa biết, nhìn phải đẹp đã.

Hugo là một bộ sinh trang web tĩnh (SSG - Static Site Generator) mã nguồn mở. Được xây dựng trên ngôn ngữ Go, Hugo nổi tiếng bởi tốc độ build siêu nhanh (< 1ms mỗi trang) và các tính năng hỗ trợ xây dựng nội dung mạnh mẽ. Từ blog cá nhân, trang quảng bá, trang tài liệu đến trang thương mại điện tử, Hugo đáp ứng được đa dạng nhu cầu về nội dung và lĩnh vực. Bài viết sau đây dành cho người mới bắt đầu sử dụng Hugo.

Các cách tiếp cận
#

Có 2 cách tiếp cận khi nói đến highlight code.

  1. Thực hiện ở phía browser, sử dụng Javascript ( Highlight.js, Prism.js).
  2. Thực hiện ở phía server, sinh sẵn mã HTML highlight bằng ngôn ngữ phía server.

Từ browser
#

Nhiều theme Hugo hỗ trợ cách tiếp cận đầu tiên, chẳng hạn, theme Paper cho phép cấu hình sử dụng Highlight.js.

Từ server
#

Cách tiếp cận số 2 trong Hugo sử dụng Chroma để highlight code. Chroma, viết bằng Go, thực hiện chuyển mã nguồn thành mã HTML có highlight cú pháp với hiệu năng cao. Chroma hỗ trợ nhiều ngôn ngữnhiều theme phổ biến. Thử nghiệm highlight code bằng Chroma tại đây.

Ưu điểm của cách tiếp cận này so với cách thứ nhất:

  • Sử dụng được với mọi theme, do được hỗ trợ mặc định bởi Hugo
  • Hiệu quả hơn, do mã HTML highlight được sinh sẵn ở build time, cũng như không cần tải thêm Javascript ở browser

Phần còn lại của bài viết tập trung hướng dẫn highlight code theo cách tiếp cận số 2.

Cấu hình mặc định
#

Ta có thể đặt cấu hình mặc định cho hightlight code trong file config.

# config.yml
markup:
  highlight:
    anchorLineNos: false  # Nếu true, sinh ra link cho từng dòng code
    guessSyntax: false
    hl_Lines: ""
    hl_inline: false      # Nếu true, highlight thẻ `code` markdown
    lineAnchors: ""
    codeFences: true  # Nếu true, cho phép truyền tham số vào code fence trong Markdown
    lineNos: false    # Nếu true, hiện số thứ tự dòng code
    lineNoStart: 1    # Số thứ tự bắt đầu của dòng code
    lineNumbersInTable: true
    noClasses: true   # Nếu false, sử dụng highlight bằng Javascript
    noHl: false
    style: monokai    # Theme
    tabWidth: 4       # Độ rộng tab

Sử dụng shortcode
#

Hugo hỗ trợ sẵn shortcode highlight để làm nhiệm vụ như tên gọi của nó.

{{< highlight go "linenos=true,hl_lines=11 20-26,linenostart=2" >}}
// ... code
{{< / highlight >}}
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package main

import (
    "fmt"
    "math/rand"
    "time"
)

type Moo struct {
    Cow   int
    Sound string
    Tube  chan bool
}

// A cow will moo until it is being fed
func cow(num int, mootube chan Moo) {
    tube := make(chan bool)
    for {
        select {
        case mootube <- Moo{num, "moo", tube}:
            fmt.Println("Cow number", num, "mooed through the mootube")
            <-tube
            fmt.Println("Cow number", num, "is being fed and stops mooing")
            mootube <- Moo{num, "mooh", nil}
            fmt.Println("Cow number", num, "moos one last time out of happyness")
            return
        default:
            fmt.Println("Cow number", num, "mooed through the mootube and was ignored")
            time.Sleep(time.Duration(rand.Int31n(1000)) * time.Millisecond)
        }
    }
}

Sử dụng code fence
#

Khi cấu hình codeFences: true trong file config, Hugo cho phép truyền tham số vào cú pháp code fence của Markdown.

```go {linenos=table,hl_lines=[11,"15-17"],linenostart=2}
// ... code
```
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package main

import (
    "fmt"
    "math/rand"
    "time"
)

type Moo struct {
    Cow   int
    Sound string
    Tube  chan bool
}

// A cow will moo until it is being fed
func cow(num int, mootube chan Moo) {
    tube := make(chan bool)
    for {
        select {
        case mootube <- Moo{num, "moo", tube}:
            fmt.Println("Cow number", num, "mooed through the mootube")
            <-tube
            fmt.Println("Cow number", num, "is being fed and stops mooing")
            mootube <- Moo{num, "mooh", nil}
            fmt.Println("Cow number", num, "moos one last time out of happyness")
            return
        default:
            fmt.Println("Cow number", num, "mooed through the mootube and was ignored")
            time.Sleep(time.Duration(rand.Int31n(1000)) * time.Millisecond)
        }
    }
}

Tham khảo
#

Bài liên quan

Ưu tiên undefined hơn null!
·4 phút· loading · loading
Lập Trình Javascript Best-Practices Eslint Linting

Lão Tử nói: “Đạo mà diễn tả được thì đó không còn là đạo bất biến nữa, tên mà gọi ra được thì đó không còn là tên bất biến nữa.”

Tree-shake Lodash trong Next.js
·5 phút· loading · loading
Lập Trình Javascript Node.js Next.js
Lý Tiểu Long nói đại ý: không sợ kẻ biết 1 vạn kiểu đá, chỉ sợ kẻ tập 1 kiểu 1 vạn lần.
Number trong Javascript: Dấu chấm động và IEEE 754
·10 phút· loading · loading
Lập Trình Javascript Floating-Point Ieee-754 Arithmetic
0.1 + 0.2 !== 0.3 (╯ ͡• ͜ʖ ͡•)╯┻━┻