DEV Community

ringabout
ringabout

Posted on

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

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!😄