DEV Community

ringabout
ringabout

Posted on

2 2

Implement a simple html syntax highlight using Nim

We introduce how to implement simple html syntax highlight using Nim. We use highlight in stdlib to parse syntax. Then we use karax and htmlgen to generate Html.

Preview

import module

We need karax which constructs DSL to generate Html file and use htmlgen to generate Html strings.

First you should use command nimble install karax to install karax.

karax can be used as server side rendering and also single page application. To be simple, karax can be used to generate Html and Javascript.

import karax / [karaxdsl, vdom]
import packages/docutils/highlite
from htmlgen import span
from xmltree import escape


## code block
const code = """
import hello

type  
  TreeObj* = object
    left*: ref TreeObj
    right*: ref TreeObj
    value*: char
    priority*: float
  Tree* = ref TreeObj

## escape `>=`
if a >= b:
  echo a + b
"""
Enter fullscreen mode Exit fullscreen mode

Generate HTML

karax supply text function accepting strings and verbatim function accepting raw Html strings.

We use link CSS to render keywords, comments, symbols, etc.

CSS looks like this.(highlight.css)

span.Keyword {
  color: blue;
  font-size: 18px;
}

span.Operator {
  color: purple;
  font-size: 18px;
}

span.Comment {
  color: green;
  font-size: 18px;
}
Enter fullscreen mode Exit fullscreen mode

List Nim code as below, buildLang function uses stdlib highlight to parse syntax information and generates Html strings.

proc buildPre*(code: string): string =
  let vnode = buildHtml(tdiv):
    pre(class = "text"): text code
  result = $vnode

proc buildVerbatimPre*(code: string, lang: string = "lang-Nim"): string =
  let vnode = buildHtml(tdiv):
    link(rel="stylesheet", `type`="text/css", href = "highlight.css")
    pre(class = lang): verbatim code
  result = $vnode

proc buildLang*(code: string): string =
  var toknizr: GeneralTokenizer
  initGeneralTokenizer(toknizr, code)
  while true:
    getNextToken(toknizr, langNim)
    case toknizr.kind
    of gtEof: break 
    of gtNone, gtWhitespace:
      result.add substr(code, toknizr.start, toknizr.length +
      toknizr.start - 1)
    else:
      result.add span(class=tokenClassToStr[toknizr.kind], escape(substr(code, toknizr.start, toknizr.length +
          toknizr.start - 1)))


proc buildCode*(code: string, lang: string = "Nim"): string =
  if getSourceLanguage(lang) != langNim:
    return buildPre(code)
  buildVerbatimPre(buildLang(code))
Enter fullscreen mode Exit fullscreen mode

Let’s test our results,use openDefaultBrowser to preview.

import browsers
let file = "highlight.html"
let f = open(file, fmWrite)
f.write buildCode(code)
f.close()
openDefaultBrowser(file)
Enter fullscreen mode Exit fullscreen mode

Speedy emails, satisfied customers

Postmark Image

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

Top comments (2)

Collapse
 
juancarlospaco profile image
Juan Carlos
import browsers
const file = "highlight.html"
writeFile(file, buildCode(code))
openDefaultBrowser(file)

:)

Collapse
 
ringabout profile image
ringabout

Nice catch!😄

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs