├── .gitignore ├── LICENSE ├── README.md ├── html2karax.nim ├── html2karax.nimble ├── public ├── README.md ├── config.nims ├── dochack.nim ├── favicon.ico ├── fuzzysearch.nim ├── httpserver.nim ├── manual.html ├── manualkarax.html ├── manualkarax.nim ├── translations.nim ├── tut1.html ├── tut1.nim ├── tut1karax.html ├── tut1karax.nim ├── tut2.html ├── tut2karax.html ├── tut2karax.nim ├── tut3.html ├── tut3kararx.html └── tut3karax.nim └── tests ├── t1.html └── t1.nim /.gitignore: -------------------------------------------------------------------------------- 1 | html2karax 2 | *.js 3 | *.mp4 4 | httpserver 5 | *.exe -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Nim 中文社区 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # html2karax 2 | Converts static html to Karax single page application or server sider rendering. 3 | 4 | ## Installation 5 | 6 | ``` 7 | nimble install html2karax 8 | ``` 9 | 10 | ## Usage 11 | 12 | ``` 13 | html2karax yourHtmlFile.html 14 | ``` 15 | 16 | **yourHtmlFile.html** 17 | 18 | ```html 19 |
20 |
21 |       ___________________________
22 |   < I'm an expert in my field. >
23 |       ---------------------------
24 |           \   ^__^
25 |            \  (oo)\_______
26 |               (__)\       )\/\
27 |                   ||----w |
28 |                   ||     ||
29 |   
30 |
31 | A cow saying, "I'm an expert in my field." The cow is illustrated using preformatted text characters. 32 |
33 |
34 | ``` 35 | 36 | **yourHtmlFile.nim** 37 | 38 | ```nim 39 | include karax / prelude 40 | 41 | proc createDom(): VNode = 42 | result = buildHtml: 43 | figure(role = "img", aria-labelledby = "cow-caption"): 44 | pre: 45 | text """ 46 | ___________________________ 47 | < I'm an expert in my field. > 48 | --------------------------- 49 | \ ^__^ 50 | \ (oo)\_______ 51 | (__)\ )\/\ 52 | ||----w | 53 | || || 54 | """ 55 | figcaption(id = "cow-caption"): 56 | text "A cow saying, \"I'm an expert in my field.\" The cow is illustrated using " 57 | em: 58 | text "preformatted" 59 | text " text characters." 60 | 61 | setRenderer createDom 62 | ``` 63 | -------------------------------------------------------------------------------- /html2karax.nim: -------------------------------------------------------------------------------- 1 | import std / [algorithm, htmlparser, parseopt, strtabs, strutils, os, xmltree, wordwrap] 2 | 3 | const 4 | usage = """ 5 | html2karax - Convert static html to Karax DSL code. 6 | 7 | Usage: 8 | html2karax [options] htmlfile 9 | Options: 10 | --out:file set the output file (default: the same name as the input file, .nim extension) 11 | --help show this help 12 | --ssr output code appropriate for server side HTML rendering 13 | --indent:N[=2] set the number of spaces that is used for indentation 14 | --maxLineLen:N set the desired maximum line length (default: 80) 15 | """ 16 | 17 | karaxTmpl = """ 18 | include karax / prelude 19 | import karax / [vstyles] 20 | 21 | proc createDom(): VNode = 22 | result = buildHtml:$1 23 | 24 | setRenderer createDom 25 | """ 26 | 27 | karaxSsrTmpl = """ 28 | import karax / [karaxdsl, vdom, vstyles] 29 | 30 | proc render(): string = 31 | let vnode = buildHtml:$1 32 | result = $$vnode 33 | """ 34 | 35 | nimKeywords = ["addr", "and", "as", "asm", 36 | "bind", "block", "break", 37 | "case", "cast", "concept", "const", "continue", "converter", 38 | "defer", "discard", "distinct", "div", "do", 39 | "elif", "else", "end", "enum", "except", "export", 40 | "finally", "for", "from", "func", 41 | "if", "import", "in", "include", "interface", "is", "isnot", "iterator", 42 | "let", 43 | "macro", "method", "mixin", "mod", 44 | "nil", "not", "notin", 45 | "object", "of", "or", "out", 46 | "proc", "ptr", 47 | "raise", "ref", "return", 48 | "shl", "shr", "static", 49 | "template", "try", "tuple", "type", 50 | "using", 51 | "var", 52 | "when", "while", 53 | "xor", 54 | "yield"] 55 | 56 | proc isKeyword*(s: string): bool {.inline.} = 57 | binarySearch(nimKeywords, s) >= 0 # assumes sorted 58 | 59 | type 60 | Options = object # from command-line 61 | indWidth: Natural 62 | maxLineLen: Positive 63 | 64 | proc addVNode(result: var string; tag: string) = 65 | # Translates to karax VNode tags, most remain the same. 66 | case tag 67 | of "div": 68 | result.add "tdiv" 69 | of "s": 70 | result.add "strikethrough" 71 | of "var": 72 | result.add "`var`" 73 | of "i": 74 | result.add "italic" 75 | of "b": 76 | result.add "bold" 77 | of "u": 78 | result.add "underlined" 79 | of "object": 80 | result.add "`object`" 81 | of "discard": 82 | result.add "`discard`" 83 | of "set": 84 | result.add "`set`" 85 | of "text": 86 | result.add "stext" 87 | else: 88 | result.add tag 89 | 90 | proc addIndent(result: var string, indent: int) = 91 | result.add("\n") 92 | for i in 1..indent: 93 | result.add(' ') 94 | 95 | proc myRender(result: var string, b: string, escapeQuotes, stripSpaces: bool) = 96 | # Primarily used to remove spaces at line end. Also escapes '"' and 97 | # omits in-between multiple spaces when appropriate. 98 | let L = b.len 99 | var i = 0 100 | while i < L: 101 | let ch = b[i] 102 | if escapeQuotes and ch == '\"': 103 | result.add("\\\"") 104 | elif ch == ' ': 105 | let j = i 106 | while i < L and b[i] == ' ': inc i 107 | if i >= L: discard 108 | elif b[i] == '\n': 109 | result.add('\n') 110 | else: 111 | if stripSpaces: result.add(' ') 112 | else: 113 | for ii in j..i-1: 114 | result.add(' ') 115 | dec i 116 | elif ch == '\n': 117 | result.add('\n') 118 | else: 119 | result.add(ch) 120 | inc(i) 121 | 122 | proc renderText(result: var string, text: string; 123 | spaceInsensitive, leadingSpace, trailingSpace: bool) = 124 | let isSingleLine = countLines(text) == 1 125 | if isSingleLine: 126 | result.add('"') 127 | else: 128 | result.add("\"\"\"") 129 | if spaceInsensitive: result.add('\n') # verbatim multiline text that starts with a '\n' 130 | if leadingSpace: result.add(' ') 131 | myRender(result, text, isSingleLine, spaceInsensitive) 132 | if trailingSpace: result.add(' ') 133 | if isSingleLine: 134 | result.add('"') 135 | else: 136 | result.add("\"\"\"") 137 | 138 | proc renderBacklog(result: var string, text: string, indent: int, tags: set[HtmlTag]; 139 | last: bool; opt: Options) = 140 | if indent > 0: 141 | result.addIndent(indent) 142 | result.add("text ") 143 | var tmp = if tagPre notin tags: text.dedent else: text 144 | if tags * {tagScript, tagPre} != {}: 145 | renderText(result, tmp, spaceInsensitive = false, false, false) 146 | else: 147 | removePrefix(tmp, chars = Newlines) # fix leading \n replaced by ' ' 148 | var wrapped = wrapWords(tmp, opt.maxLineLen, splitLongWords = false) 149 | let leadingSpace = text.startsWith(' ') and not tmp.startsWith(' ') 150 | # Use that a block element can't be nested inside an inline element 151 | let trailingSpace = tmp.endsWith(' ') and (tags * InlineTags != {} or last) 152 | renderText(result, wrapped, true, leadingSpace, trailingSpace) # readd surrounding spaces 153 | 154 | proc renderImpl(result: var string, n: XmlNode, backlog: var string, indent: int; 155 | tags: set[HtmlTag]; opt: Options) = 156 | if n != nil: 157 | case n.kind 158 | of xnElement: 159 | let tag = htmlTag(n) 160 | let isDocRoot = tag == tagUnknown and n.tag == "document" # Hide document pseudo-tag 161 | if not isDocRoot: 162 | if indent > 0: 163 | result.addIndent(indent) 164 | result.addVNode(n.tag) 165 | if n.attrs != nil: 166 | result.add('(') 167 | var comma = false 168 | for key, val in pairs(n.attrs): 169 | if comma: result.add(", ") 170 | else: comma = true 171 | let isKeyword = isKeyword(key) 172 | if isKeyword: 173 | result.add('`') 174 | result.add(key) 175 | if isKeyword: 176 | result.add('`') 177 | result.add(" = \"") 178 | #myRender(result, val, true) 179 | result.add(val) 180 | result.add('"') 181 | if key == "style": 182 | result.add(".toCss") 183 | result.add(')') 184 | elif n.len == 0: # An empty element without attributes 185 | result.add("()") 186 | if n.len != 0: 187 | if not isDocRoot: result.add(':') 188 | let indent = if isDocRoot: indent else: indent+opt.indWidth 189 | for i in 0 ..< n.len: 190 | renderImpl(result, n[i], backlog, indent, tags + {tag}, opt) 191 | if i+1 >= n.len or n[i+1].kind != xnText: # Invalidate the backlog 192 | # Render grouped text nodes, without outputting empty text. 193 | if not isEmptyOrWhitespace(backlog): 194 | renderBacklog(result, backlog, indent, tags + {tag}, i+1 < n.len, opt) 195 | backlog.setLen(0) 196 | of xnText: 197 | backlog.add n.text 198 | of xnComment: 199 | if not isEmptyOrWhitespace(n.text): 200 | if indent > 0: # All comments are indented 201 | result.addIndent(indent) 202 | if countLines(n.text) == 1: 203 | result.add('#') 204 | myRender(result, n.text, escapeQuotes = false, stripSpaces = false) 205 | else: 206 | result.add("#[") 207 | # Unindent text before indenting it again! 208 | myRender(result, indent(n.text.dedent, indent), false, false) 209 | stripLineEnd(result) # comment end tag in the next line 210 | if indent > 0: 211 | result.addIndent(indent) 212 | result.add("]#") 213 | else: discard 214 | 215 | proc render(n: XmlNode, indent = 0, opt: Options): string = 216 | result = "" 217 | var backlog = "" 218 | renderImpl(result, n, backlog, indent, {}, opt) 219 | 220 | proc writeHelp() = 221 | stdout.write(usage) 222 | stdout.flushFile() 223 | quit(0) 224 | 225 | proc main = 226 | var infile, outfile: string 227 | var ssr = false 228 | var opt = Options(indWidth: 2, maxLineLen: 80) 229 | for kind, key, val in getopt(): 230 | case kind 231 | of cmdArgument: 232 | infile = key.addFileExt(".html") 233 | of cmdLongOption, cmdShortOption: 234 | case normalize(key) 235 | of "help", "h": writeHelp() 236 | of "output", "o", "out": outfile = val 237 | of "ssr": ssr = true 238 | of "indent": opt.indWidth = parseInt(val) 239 | of "maxlinelen": opt.maxLineLen = parseInt(val) 240 | else: writeHelp() 241 | of cmdEnd: assert false # cannot happen 242 | 243 | if infile.len == 0: 244 | quit "[Error] no input file." 245 | 246 | if outfile.len == 0: 247 | outfile = infile.changeFileExt(".nim") 248 | 249 | let parsed = loadHtml(infile) 250 | let result = render(parsed, 2*opt.indWidth, opt) # Templates start with the same indentation 251 | writeFile(outfile, if ssr: karaxSsrTmpl % result else: karaxTmpl % result) 252 | 253 | main() 254 | -------------------------------------------------------------------------------- /html2karax.nimble: -------------------------------------------------------------------------------- 1 | # Package 2 | 3 | version = "1.2.1" 4 | author = "nim-lang-cn" 5 | description = "Converts html to karax." 6 | license = "MIT" 7 | bin = @["html2karax"] 8 | skipDirs = @["public","tests"] 9 | 10 | # Dependencies 11 | 12 | requires "nim >= 1.6.4" 13 | requires "karax >= 1.2.1" 14 | -------------------------------------------------------------------------------- /public/README.md: -------------------------------------------------------------------------------- 1 | # html2karax 2 | Convert static html to Karax single page application or server sider rendering.Use https://github.com/gogolxdong/karax 3 | 4 | 把静态html转换为Karax单面应用或服务端渲染,使用https://github.com/gogolxdong/karax 5 | 6 | 7 | ## Usage 8 | nim c -r html2karax.nim tut1 9 | 把tut1.html转换成tut1karax.nim 10 | 11 | nim c -r html2karax.nim tut2 12 | 把tut2.html转换成tut2karax.nim 13 | 14 | nim c -r html2karax.nim tut3 15 | 把tut3.html转换成tut3karax.nim 16 | 17 | nim c -r html2karax.nim manual 18 | 把manual.html转换成manualkarax.nim 19 | 20 | nim js tut1karax.nim 21 | 把tut1karax.nim编译成js,以此类推。 22 | 23 | Open browser and access html accordingly. 24 | 通过浏览器访问相应的html文件 25 | -------------------------------------------------------------------------------- /public/config.nims: -------------------------------------------------------------------------------- 1 | --define:release 2 | --hints:off 3 | --warnings:off -------------------------------------------------------------------------------- /public/dochack.nim: -------------------------------------------------------------------------------- 1 | import dom 2 | import fuzzysearch 3 | 4 | proc textContent(e: Element): cstring {. 5 | importcpp: "#.textContent", nodecl.} 6 | 7 | proc textContent(e: Node): cstring {. 8 | importcpp: "#.textContent", nodecl.} 9 | 10 | proc tree(tag: string; kids: varargs[Element]): Element = 11 | result = document.createElement tag 12 | for k in kids: 13 | result.appendChild k 14 | 15 | proc add(parent, kid: Element) = 16 | if parent.nodeName == cstring"TR" and ( 17 | kid.nodeName == cstring"TD" or kid.nodeName == cstring"TH"): 18 | let k = document.createElement("TD") 19 | appendChild(k, kid) 20 | appendChild(parent, k) 21 | else: 22 | appendChild(parent, kid) 23 | 24 | proc setClass(e: Element; value: string) = 25 | e.setAttribute("class", value) 26 | proc text(s: string): Element = cast[Element](document.createTextNode(s)) 27 | proc text(s: cstring): Element = cast[Element](document.createTextNode(s)) 28 | 29 | proc getElementById(id: cstring): Element {.importc: "document.getElementById", nodecl.} 30 | 31 | proc replaceById(id: cstring; newTree: Node) = 32 | let x = getElementById(id) 33 | x.parentNode.replaceChild(newTree, x) 34 | newTree.id = id 35 | 36 | proc findNodeWith(x: Element; tag, content: cstring): Element = 37 | if x.nodeName == tag and x.textContent == content: 38 | return x 39 | for i in 0.. y: return 1 110 | return 0 111 | else: 112 | # ensure sorting is stable: 113 | return a.sortId - b.sortId 114 | ) 115 | for k in x.kids: 116 | let y = toHtml(k) 117 | if y != nil: 118 | ul.add tree("LI", y) 119 | if ul.len != 0: result.add ul 120 | if result.len == 0: result = nil 121 | 122 | #proc containsWord(a, b: cstring): bool {.asmNoStackFrame.} = 123 | #{.emit: """ 124 | #var escaped = `b`.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); 125 | #return new RegExp("\\b" + escaped + "\\b").test(`a`); 126 | #""".} 127 | 128 | proc isWhitespace(text: cstring): bool {.asmNoStackFrame.} = 129 | {.emit: """ 130 | return !/[^\s]/.test(`text`); 131 | """.} 132 | 133 | proc isWhitespace(x: Element): bool = 134 | x.nodeName == cstring"#text" and x.textContent.isWhitespace or 135 | x.nodeName == cstring"#comment" 136 | 137 | proc toToc(x: Element; father: TocEntry) = 138 | if x.nodeName == cstring"UL": 139 | let f = TocEntry(heading: nil, kids: @[], sortId: father.kids.len) 140 | var i = 0 141 | while i < x.len: 142 | var nxt = i+1 143 | while nxt < x.len and x[nxt].isWhitespace: 144 | inc nxt 145 | if nxt < x.len and x[i].nodeName == cstring"LI" and x[i].len == 1 and 146 | x[nxt].nodeName == cstring"UL": 147 | let e = TocEntry(heading: x[i][0], kids: @[], sortId: f.kids.len) 148 | let it = x[nxt] 149 | for j in 0..", "text/html"); 283 | 284 | `stuff` = doc.documentElement; 285 | """.} 286 | db = stuff.getElementsByClass"reference" 287 | contents = @[] 288 | for ahref in db: 289 | contents.add ahref.getAttribute("data-doc-search-tag") 290 | let ul = tree("UL") 291 | result = tree("DIV") 292 | result.setClass"search_results" 293 | var matches: seq[(Node, int)] = @[] 294 | for i in 0.. 2 | 3 | 4 | 19 | 21 | 43 | 45 | 46 | 48 | image/svg+xml 49 | 51 | 52 | 53 | 54 | 55 | 60 | 64 | 66 | 72 | 78 | 84 | 90 | 91 | 93 | 99 | 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /public/fuzzysearch.nim: -------------------------------------------------------------------------------- 1 | # A Fuzzy Match implementation inspired by the sublime text fuzzy match algorithm 2 | # as described here: https://blog.forrestthewoods.com/reverse-engineering-sublime-text-s-fuzzy-match-4cffeed33fdb 3 | # Heavily modified to provide more subjectively useful results 4 | # for on the Nim manual. 5 | # 6 | import strutils 7 | import math 8 | import macros 9 | 10 | 11 | const 12 | MaxUnmatchedLeadingChar = 3 13 | ## Maximum number of times the penalty for unmatched leading chars is applied. 14 | 15 | HeadingScaleFactor = 0.5 16 | ## The score from before the colon Char is multiplied by this. 17 | ## This is to weight function signatures and descriptions over module titles. 18 | 19 | 20 | type 21 | ScoreCard = enum 22 | StartMatch = -100 ## Start matching. 23 | LeadingCharDiff = -3 ## An unmatched, leading character was found. 24 | CharDiff = -1 ## An unmatched character was found. 25 | CharMatch = 0 ## A matched character was found. 26 | ConsecutiveMatch = 5 ## A consecutive match was found. 27 | LeadingCharMatch = 10 ## The character matches the beginning of the 28 | ## string or the first character of a word 29 | ## or camel case boundary. 30 | WordBoundryMatch = 20 ## The last ConsecutiveCharMatch that 31 | ## immediately precedes the end of the string, 32 | ## end of the pattern, or a LeadingCharMatch. 33 | 34 | 35 | proc fuzzyMatch*(pattern, str: cstring) : tuple[score: int, matched: bool] = 36 | var 37 | scoreState = StartMatch 38 | headerMatched = false 39 | unmatchedLeadingCharCount = 0 40 | consecutiveMatchCount = 0 41 | strIndex = 0 42 | patIndex = 0 43 | score = 0 44 | 45 | template transition(nextState) = 46 | scoreState = nextState 47 | score += ord(scoreState) 48 | 49 | while (strIndex < str.len) and (patIndex < pattern.len): 50 | var 51 | patternChar = pattern[patIndex].toLowerAscii 52 | strChar = str[strIndex].toLowerAscii 53 | 54 | # Ignore certain characters 55 | if patternChar in {'_', ' ', '.'}: 56 | patIndex += 1 57 | continue 58 | if strChar in {'_', ' ', '.'}: 59 | strIndex += 1 60 | continue 61 | 62 | # Since this algorithm will be used to search against Nim documentation, 63 | # the below logic prioritizes headers. 64 | if not headerMatched and strChar == ':': 65 | headerMatched = true 66 | scoreState = StartMatch 67 | score = int(floor(HeadingScaleFactor * float(score))) 68 | patIndex = 0 69 | strIndex += 1 70 | continue 71 | 72 | if strChar == patternChar: 73 | case scoreState 74 | of StartMatch, WordBoundryMatch: 75 | scoreState = LeadingCharMatch 76 | 77 | of CharMatch: 78 | transition(ConsecutiveMatch) 79 | 80 | of LeadingCharMatch, ConsecutiveMatch: 81 | consecutiveMatchCount += 1 82 | scoreState = ConsecutiveMatch 83 | score += ord(ConsecutiveMatch) * consecutiveMatchCount 84 | 85 | if scoreState == LeadingCharMatch: 86 | score += ord(LeadingCharMatch) 87 | 88 | var onBoundary = (patIndex == high(pattern)) 89 | if not onBoundary and strIndex < high(str): 90 | let 91 | nextPatternChar = toLowerAscii(pattern[patIndex + 1]) 92 | nextStrChar = toLowerAscii(str[strIndex + 1]) 93 | 94 | onBoundary = ( 95 | nextStrChar notin {'a'..'z'} and 96 | nextStrChar != nextPatternChar 97 | ) 98 | 99 | if onBoundary: 100 | transition(WordBoundryMatch) 101 | 102 | of CharDiff, LeadingCharDiff: 103 | var isLeadingChar = ( 104 | str[strIndex - 1] notin Letters or 105 | str[strIndex - 1] in {'a'..'z'} and 106 | str[strIndex] in {'A'..'Z'} 107 | ) 108 | 109 | if isLeadingChar: 110 | scoreState = LeadingCharMatch 111 | #a non alpha or a camel case transition counts as a leading char. 112 | # Transition the state, but don't give the bonus yet; wait until we verify a consecutive match. 113 | else: 114 | transition(CharMatch) 115 | patIndex += 1 116 | 117 | else: 118 | case scoreState 119 | of StartMatch: 120 | transition(LeadingCharDiff) 121 | 122 | of ConsecutiveMatch: 123 | transition(CharDiff) 124 | consecutiveMatchCount = 0 125 | 126 | of LeadingCharDiff: 127 | if unmatchedLeadingCharCount < MaxUnmatchedLeadingChar: 128 | transition(LeadingCharDiff) 129 | unmatchedLeadingCharCount += 1 130 | 131 | else: 132 | transition(CharDiff) 133 | 134 | strIndex += 1 135 | 136 | result = ( 137 | score: max(0, score), 138 | matched: (score > 0), 139 | ) 140 | -------------------------------------------------------------------------------- /public/httpserver.nim: -------------------------------------------------------------------------------- 1 | import jester, os, re, strutils, strformat 2 | import jester/private/utils 3 | 4 | settings: 5 | port = Port(8002) 6 | 7 | routes: 8 | get re"/(.*)": 9 | cond request.matches[0].splitFile.ext == "" 10 | resp(Http200, {"Access-Control-Allow-Origin": "*", "Content-Type":"text/html"}, readFile("public/tut1.html")) 11 | get "/@name": 12 | var name = @"name" 13 | echo name 14 | resp(Http200, {"Access-Control-Allow-Origin": "*"}, readFile(&"videos/{name}")) 15 | 16 | -------------------------------------------------------------------------------- /public/manualkarax.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | Nim Tutorial (Part I) 22 | 957 | 958 | 959 | 972 | 973 |
974 | 975 | 976 | 977 | -------------------------------------------------------------------------------- /public/translations.nim: -------------------------------------------------------------------------------- 1 | import karax / [kdom, jstrutils, kajax, vdom, jjson, karaxdsl,karax, vstyles,i18n, languages,kbase] 2 | 3 | proc textContent*(e: Element): cstring {. 4 | importcpp: "#.textContent", nodecl.} 5 | 6 | proc textContent*(e: Node): cstring {. 7 | importcpp: "#.textContent", nodecl.} 8 | 9 | proc zhCN*(e:Event,n:VNode) = 10 | setCurrentLanguage(Language.zhCN) 11 | 12 | proc enUS*(e:Event,n:VNode) = 13 | setCurrentLanguage(Language.enUS) 14 | 15 | proc t*(text: kstring): cstring = 16 | i18n($text).cstring 17 | 18 | var dict: seq[(string,string)] 19 | dict = @[ 20 | ("attachment:","附:"), 21 | ("Nim Tutorial (Part I)", "Nim中文教程(第一部分)"), 22 | ("Manual", "手册"), 23 | ("Index", "索引"), 24 | ("Search: ", "搜索:"), 25 | ("Standard library", "标准库"), 26 | ("Introduction", "序"), 27 | ("The first program", "第一个程序"), 28 | ("Lexical elements", "词汇元素"), 29 | ("String and character literals", "字符串和字符字面值"), 30 | ("Comments", "注释"), 31 | ("Numbers", "数字"), 32 | ("The var statement", "var语句"), 33 | ("The assignment statement", "赋值语句"), 34 | ("Constants", "常量"), 35 | ("The let statement", "let语句"), 36 | ("Control flow statements", "控制流语句"), 37 | ("If statement", "If语句"), 38 | ("Case statement", "Case语句"), 39 | ("While statement", "While语句"), 40 | ("For statement", "For语句"), 41 | ("Scopes and the block statement", "作用域和块语句"), 42 | ("Break statement", "Break语句"), 43 | ("Continue statement", "Continue语句"), 44 | ("When statement", "When语句"), 45 | ("Statements and indentation", "语句和缩进"), 46 | ("Procedures", "过程"), 47 | ("Result variable", "Result变量"), 48 | ("Parameters", "形参"), 49 | ("Discard statement", "Discard语句"), 50 | ("Named arguments", "命名形参"), 51 | ("Default arguments", "默认形参"), 52 | ("Overloaded procedures", "过程重载"), 53 | ("Operators", "运算符"), 54 | ("Forward declarations", "前向声明"), 55 | ("Iterators", "迭代器"), 56 | ("Basic types", "基本类型"), 57 | ("Booleans", "布尔"), 58 | ("Characters", "字符"), 59 | ("Strings", "字符串"), 60 | ("Integers", "整型"), 61 | ("Floats", "浮点"), 62 | ("Type Conversion", "类型转换"), 63 | ("Internal type representation", "内部类型表示"), 64 | ("Advanced types", "高级类型"), 65 | ("Enumerations", "枚举"), 66 | ("Ordinal types", "序数类型"), 67 | ("Subranges", "子范围"), 68 | ("Sets", "集合"), 69 | ("Bit fields", "位字段"), 70 | ("Arrays", "数组"), 71 | ("Sequences", "序列"), 72 | ("Open arrays", "开放数组"), 73 | ("Varargs", "可变形参"), 74 | ("Slices", "切片"), 75 | ("Objects", "对象"), 76 | ("Tuples", "元组"), 77 | ("Reference and pointer types", "引用和指针类型"), 78 | ("Procedural type", "过程类型"), 79 | ("Distinct type", "Distinct类型"), 80 | ("Modules", "模块"), 81 | ("Excluding symbols", "排除符号"), 82 | ("From statement", "From语句"), 83 | ("Include statement", "Include语句"), 84 | ("Part 2", "第二部分"), 85 | ("Author:", "作者:"), 86 | ("Version:", "版本:"), 87 | ("\"Der Mensch ist doch ein Augentier -- sch\xC3\xB6ne Dinge w\xC3\xBCnsch ich mir.\" ", "人是视觉动物——我渴望美好事物。"), 88 | ("This document is a tutorial for the programming language ", "本文档是编程语言"), 89 | (". This tutorial assumes that you are familiar with basic programming concepts like variables, types or statements but is kept very basic. The ", 90 | "的教程。本教程认为你熟悉基本的编程概念如变量、类型或语句。"), 91 | ("manual","手册"), 92 | ("contains many more examples of the advanced language features. All code examples in this tutorial, as well as the ones found in the rest of Nim\'s documentation, follow the ", 93 | "有更多高级语言特性示例。教程代码示例和其余Nim文档遵循"), 94 | ("Nim style guide","Nim风格指南"), 95 | ("The first program","第一个程序"), 96 | ("We start the tour with a modified \"hello world\" program:","我们用\"hello world\"程序开启教程之旅:"), 97 | ("# This is a comment","# 这里是注释"), 98 | ("Save this code to the file \"greetings.nim\". Now compile and run it: ","代码保存到\"greetings.nim\",编译运行:"), 99 | ("With the ","用"), 100 | ("switch","开关"), 101 | ("Nim executes the file automatically after compilation. You can give your program command line arguments by appending them after the filename: ", 102 | "Nim编译后自动执行文件。可以在文件名后加上程序的命令行参数:"), 103 | ("Commonly used commands and switches have abbreviations, so you can also use: ","常用命令和开关有简写,所以也可以用:"), 104 | ("To compile a release version use: ","编译发布版本使用:"), 105 | ("By default the Nim compiler generates a large amount of runtime checks aiming for your debugging pleasure. With ", 106 | "为了方便调试,Nim编译器默认生成大量运行时检查。用"), 107 | ("some checks are ","一些检查"), 108 | ("turned off and optimizations are turned on","被关闭并启用优化"), 109 | ("Though it should be pretty obvious what the program does, I will explain the syntax: statements which are not indented are executed when the program starts. Indentation is Nim\'s way of grouping statements. Indentation is done with spaces only, tabulators are not allowed.", 110 | "程序一目了然:没有缩进的语句在程序开始时执行。缩进是Nim划分语句的方式。缩进只能使用空格,不允许制表符。"), 111 | ("String literals are enclosed in double quotes. The ","字符串字面值用双引号括起来。"), 112 | ("statement declares a new variable named ","语句声明一个新的变量,名叫"), 113 | ("of type ",",属于"), 114 | ("with the value that is returned by the ",",值为被"), 115 | ("procedure. Since the compiler knows that ","过程返回的值。因为编译器知道"), 116 | ("returns a string, you can leave out the type in the declaration (this is called ","返回字符串,可以在声明中不写类型(这叫做"), 117 | ("local type inference","局部类型推导"), 118 | ("). So this will work too:",")。所以这也可以:"), 119 | ("Note that this is basically the only form of type inference that exists in Nim: it is a good compromise between brevity and readability.", 120 | "这基本是Nim中存在的唯一形式的类型推导:兼顾简洁和可读。"), 121 | ("The \"hello world\" program contains several identifiers that are already known to the compiler: ", 122 | "\"hello world\"程序包含几个编译器已知的标识符:"), 123 | (", etc. These built-ins are declared in the ","等。这些内置类型声明在"), 124 | ("module which is implicitly imported by any other module.","模块,其通过任意其它模块隐式导入。"), 125 | ("Let us look at Nim\'s lexical elements in more detail: like other programming languages Nim consists of (string) literals, identifiers, keywords, comments, operators, and other punctuation marks.", 126 | "我们来看下Nim的词汇元素的更多细节:和其它编程语言一样,Nim由(字符串)字面值、标识符、关键字、注释、运算符和其它标点符号构成。"), 127 | ("String literals are enclosed in double quotes; character literals in single quotes. Special characters are escaped with ", 128 | "字符串字面值括在双引号中;字符字面值在单引号中。特殊符号转义用"), 129 | ("means newline, ","意为换行"), 130 | ("means tabulator, etc. There are also ","意为制表符等。还有"), 131 | ("raw","原始"), 132 | ("string literals:","字符串字面值:"), 133 | ("In raw literals the backslash is not an escape character.","原始字面值中的反斜杠不是转义字符。"), 134 | ("The third and last way to write string literals are ","第三个也是最后一种写字符串字面值的方法是"), 135 | ("long string literals","长字符串字面值"), 136 | (". They are written with three quotes: ","。用三引号写:"), 137 | ("; they can span over multiple lines and the ","可以跨越多行并且"), 138 | ("is not an escape character either. They are very useful for embedding HTML code templates for example.","也不是转义字符。这对于例如嵌入HTML代码模板非常有用。"), 139 | ("Comments start anywhere outside a string or character literal with the hash character ","注释以字符串或字符字面值外的哈希字符开始"), 140 | (". Documentation comments start with ","。文档注释用"), 141 | ("## a documentation comment","## 文档注释"), 142 | ("Documentation comments are tokens; they are only allowed at certain places in the input file as they belong to the syntax tree! This feature enables simpler documentation generators.", 143 | "文档注释是符号,属于语法树,只允许出现在输入文件中的特定位置。这允许更简单的文档生成器。"), 144 | ("Multiline comments are started with ","多行注释用"), 145 | ("and terminated with ","结束用"), 146 | (". Multiline comments can also be nested.","。多行注释可以嵌套。"), 147 | ("#[\x0AYou can have any Nim code text commented\x0Aout inside this with no indentation restrictions. yes(\"May I ask a pointless question?\") #[ Note: these can be nested!! ]#\x0A]#", 148 | "#[\x0A你可以在这里注释任何Nim代码文本\x0A没有缩进限制。 yes(\"May I ask a pointless question?\") #[ 注意: 这些可以嵌套。 ]#\x0A]#"), 149 | ("Numerical literals are written as in most other languages. As a special twist, underscores are allowed for better readability: ", 150 | "数字字面值和大多数其它语言一样。用下划线做特殊调整以获取更好的可读性:"), 151 | ("(one million). A number that contains a dot (or \'e\' or \'E\') is a floating point literal: ", 152 | "(一百万)。 包含点 (或 \'e\' 或 \'E\') 的数字是浮点字面值:"), 153 | ("(one billion). Hexadecimal literals are prefixed with ","(十亿)。 十六进制字面值前缀用"), 154 | (", binary literals with ","二进制用"), 155 | ("and octal literals with ","八进制用"), 156 | (". A leading zero alone does not produce an octal.","。只有开头零的不是八进制。"), 157 | ("The var statement declares a new local or global variable:","var语句声明一个新的本地或全局变量:"), 158 | ("# declares x and y to have the type ``int``","# 声明x和y,具有类型``int``"), 159 | ("Indentation can be used after the ","缩进可用在"), 160 | ("keyword to list a whole section of variables:","关键字后来罗列一个变量段:"), 161 | ("# a comment can occur here too","# 注释也可以在这里"), 162 | ("The assignment statement assigns a new value to a variable or more generally to a storage location:", 163 | "赋值语句给变量或者说是更普遍的存储地址赋新值:"), 164 | ("# introduces a new variable `x` and assigns a value to it", 165 | "# 引入一个新变量`x`并赋值给它"), 166 | ("# assigns a new value to `x`","# 赋新值给`x`"), 167 | ("is the ","是"), 168 | ("assignment operator","赋值操作符"), 169 | (". The assignment operator can be overloaded. You can declare multiple variables with a single assignment statement and all the variables will have the same value:", 170 | "。赋值运算符可以重载。你可以用一个赋值语句声明多个变量,所有变量有同样的值:"), 171 | ("# assigns 3 to the variables `x` and `y`", 172 | "给变量`x`和`y`赋值为3"), 173 | ("# outputs \"x 3\"","# 输出 \"x 3\""), 174 | ("# changes `x` to 42 without changing `y`","# 不改变`y`,把`x`变为42"), 175 | ("# outputs \"x 42\"","# 输出 \"x 42\""), 176 | ("# outputs \"y 3\"","# 输出 \"y 3\""), 177 | ("Note that declaring multiple variables with a single assignment which calls a procedure can have unexpected results: the compiler will ", 178 | "注意用一个调用过程的赋值语句声明多个变量可能会有意外结果:编译器会"), 179 | ("unroll","展开"), 180 | ("the assignments and end up calling the procedure several times. If the result of the procedure depends on side effects, your variables may end up having different values! "& 181 | "For safety use side-effect free procedures if making multiple assignments.", 182 | "赋值并多次调用过程。如果过程结果取决于副作用,变量可能有不一样的值。为了安全考虑,如果要用多赋值,使用不含副作用的过程。"), 183 | ("Constants are symbols which are bound to a value. The constant\'s value cannot change. The compiler must be able to evaluate the expression in a constant declaration at compile time:", 184 | "常量是绑定了值的符号。常量值不可改变。编译器必需能够在编译期对表达式求值:"), 185 | ("# the constant x contains the string \"abc\"","# 常量x包含\"abc\"字符串"), 186 | ("keyword to list a whole section of constants:","关键字后用来罗列常量段:"), 187 | ("# computations are possible","# 计算是可能的"), 188 | ("statement works like the ","语句的作用类似"), 189 | ("statement but the declared symbols are ","语句但声明的符号是"), 190 | ("single assignment","单赋值"), 191 | ("variables: After the initialization their value cannot change:","变量:它们值在初始化后不可改变:"), 192 | ("# introduces a new variable `x` and binds a value to it","# 引入新变量`x`并绑定一个值"), 193 | ("# Illegal: assignment to `x`","# 无效:赋值给`x`"), 194 | ("and ","和"), 195 | ("is: ","是:"), 196 | ("introduces a variable that can not be re-assigned, ","引入不可再赋值的变量"), 197 | ("means \"enforce compile time evaluation and put it into a data section\":", 198 | "意味着\"强制编译期并放入数据段\":"), 199 | ("# Error: constant expression expected","# 错误:需要常量表达式"), 200 | ("# works","# 正常"), 201 | ("The greetings program consists of 3 statements that are executed sequentially. Only the most primitive programs can get away with that: branching and looping are needed too.", 202 | "问候程序由三个顺序执行语句组成。只有最原始的程序可以免于分支和循环。"), 203 | ("The if statement is one way to branch the control flow:","if语句是创建控制流分支的一种方法:"), 204 | ("There can be zero or more ","可以没有或多个"), 205 | ("parts, and the ","部分,并且"), 206 | ("part is optional. The keyword ","部分是可选的,关键字"), 207 | ("is short for ","是"), 208 | (", and is useful to avoid excessive indentation. (The ","的缩写,用于避免过度缩进。"), 209 | ("is the empty string. It contains no characters.)","是空字符串。不包含字符。"), 210 | ("Another way to branch is provided by the case statement. A case statement is a multi-branch:", 211 | "另一种创建分支的方法是case语句。case语句具有多个分支:"), 212 | ("As it can be seen, for an ","可以看到,对于一个"), 213 | ("branch a comma separated list of values is also allowed.","分支,逗号分隔的值列表也是允许的。"), 214 | ("The case statement can deal with integers, other ordinal types and strings. (What an ordinal type is will be explained soon.) For integers or other ordinal types value ranges are also possible:", 215 | "case语句可以处理整型,其它序数类型和字符串。(序数类型将在后面解释。)对于整型或其它序数类型还可以使用范围:"), 216 | ("# this statement will be explained later:","# 这个语句将在后面解释:"), 217 | ("However, the above code does not compile: the reason is that you have to cover every value that ", 218 | "上面的代码无法编译:原因是必需覆盖每个值"), 219 | ("may contain, but the code only handles the values ","可能含有的值,但代码只处理"), 220 | (". Since it is not very practical to list every other possible integer (though it is possible thanks to the range notation), we fix this by telling the compiler that for every other value nothing should be done:", 221 | "。因为列出来其它可能的值不是非常实际(尽管范围标记可以),告诉编译器不处理其它值即可:"), 222 | ("The empty ","空"), 223 | ("is a ","是"), 224 | ("do nothing","什么都不做"), 225 | ("statement. The compiler knows that a case statement with an else part cannot fail and thus the error disappears. Note that it is impossible to cover all possible string values: that is why string cases always need an ", 226 | "语句。编译器知道带有else部分的case语句不会出错,错误就此消除。注意不可能覆盖所有可能的字符串值:这是为什么字符串情况总需要"), 227 | ("branch.","分支"), 228 | ("In general the case statement is used for subrange types or enumerations where it is of great help that the compiler checks that you covered any possible value.", 229 | "通常case语句用于子范围类型或枚举,编译器检查覆盖任何可能值帮助很大。"), 230 | ("The while statement is a simple looping construct:","while语句是一个简单的循环构造:"), 231 | ("# no ``var``, because we do not declare a new variable here","# 没有``var``,因为我们没有声明新变量"), 232 | ("The example uses a while loop to keep asking the users for their name, as long as the user types in nothing (only presses RETURN).", 233 | "示例用while循环持续询问用户他们的名字,只要用户不输入(只按回车键)。"), 234 | ("statement is a construct to loop over any element an ","语句是一个构造,循环的任意元素由"), 235 | ("iterator","迭代器"), 236 | ("provides. The example uses the built-in ","提供。示例使用内置"), 237 | ("iterator:","迭代器:"), 238 | ("The variable ","变量"), 239 | ("is implicitly declared by the ","隐式声明通过"), 240 | ("loop and has the type ","循环并具有类型"), 241 | (", because that is what ",",因为这是"), 242 | ("returns. ","返回的"), 243 | ("runs through the values 1, 2, .., 10. Each value is ","遍历值1,2, ..,10。每个值被"), 244 | ("-ed. This code does the same:" ,"打印。下面代码功能相同"), 245 | ("Counting down can be achieved as easily (but is less often needed):" ,"倒数可以很容易做到(但不常用):"), 246 | ("Since counting up occurs so often in programs, Nim also has a " ,"因为正数在程序中比较常见,Nim也有"), 247 | ("iterator that does the same:" ,"相同功能的迭代器:"), 248 | ("Zero-indexed counting have two shortcuts " ,"零索引计数有两个快捷方式"), 249 | ("to simplify counting to one less than the higher index:" ,"简化计数到索引的前一个位置:"), 250 | ("Other useful iterators for collections (like arrays and sequences) are" ,"其它有用迭代器(如数组和序列)有"), 251 | (", which provides immutable and mutable elements respectively, and" ,",分别提供不可变和可变元素,还有"), 252 | ("which provides the element and an index number (immutable and mutable respectively)" , 253 | "分别提供可变和不可变的元素和索引数"), 254 | ("Control flow statements have a feature not covered yet: they open a new scope. This means that in the following example, " , 255 | "控制流语句还有个没有覆盖的特性:它们创建新的作用域。这意味着在下列示例中,"), 256 | ("is not accessible outside the loop:" ,"在循环外不可访问:"), 257 | ("A while (for) statement introduces an implicit block. Identifiers are only visible within the block they have been declared. The " , 258 | "while(for)语句引入一个隐式块。标识符只在声明的块中可见。"), 259 | ("statement can be used to open a new block explicitly:" ,"语句可以用于显式创建新块:"), 260 | ("# does not work either" ,"# 不对"), 261 | ("The block's " ,"块的"), 262 | ("in the example) is optional." ,"示例中)是可选的。"), 263 | ("A block can be left prematurely with a ","跳出块可以用"), 264 | ("statement. The break statement can leave a ","语句。break语句可以跳出"), 265 | (", or a ","或者"), 266 | ("statement. It leaves the innermost construct, unless a label of a block is given:", 267 | "语句。它跳出最内层的构造,除非给定块标签"), 268 | ("# leaves the loop, but not the block","# 跳出循环,但没有跳出块"), 269 | ("Like in many other programming languages, a ","像在许多其它编程语言,"), 270 | ("statement starts the next iteration immediately:","语句立刻开始下一个迭代:"), 271 | ("Example:","示例:"), 272 | ("statement is almost identical to the ","语句几乎等价于"), 273 | ("statement, but with these differences:","语句,但又不同:"), 274 | ("Each condition must be a constant expression since it is evaluated by the compiler.", 275 | "每个条件必须是常量表达式,因为编译器要对它求值。"), 276 | ("The statements within a branch do not open a new scope.","分支中的语句不创建新作用域。"), 277 | ("The compiler checks the semantics and produces code ","编译器检查语义并"), 278 | ("only","只"), 279 | ("for the statements that belong to the first condition that evaluates to ","为第一个语句生成代码,当其所属条件求值为"), 280 | (". ","。"), 281 | ("statement is useful for writing platform specific code, similar to the ", 282 | "语句对写平台特定代码很有用,类似于"), 283 | ("construct in the C programming language.", 284 | "C编程语言构造"), 285 | ("Now that we covered the basic control flow statements, let's return to Nim indentation rules.", 286 | "既然我们过完了基础的控制流语句,让我们回到Nim缩进规则。"), 287 | ("In Nim there is a distinction between ", 288 | "Nim中有区分在"), 289 | ("simple statements","简单语句"), 290 | ("complex statements","复杂语句"), 291 | ("Simple statements","简单语句"), 292 | ("cannot contain other statements: Assignment, procedure calls or the ", 293 | "不能包含其它语句:赋值、过程调用或"), 294 | ("statement belong to the simple statements. ","语句,它属于简单语句。"), 295 | ("Complex statements","复杂语句"), 296 | ("like ","像"), 297 | ("can contain other statements. To avoid ambiguities, complex statements must always be indented, but single simple statements do not:", 298 | "可以包含其它语句。为了避免歧义,复杂语句必须缩进,单个简单语句不需要:"), 299 | ("# no indentation needed for single assignment statement:","# 单个赋值语句不需要缩进"), 300 | ("# indentation needed for nested if statement:","# 嵌套if语句需要缩进:"), 301 | ("# indentation needed, because two statements follow the condition:","# 需要缩进,因为两个语句在条件之后:"), 302 | ("Expressions","表达式"), 303 | ("are parts of a statement which usually result in a value. The condition in an if statement is an example for an expression. Expressions can contain indentation at certain places for better readability:", 304 | "是通常结果为一个值的语句部分。if语句中的条件是一种表达式。表达式可以在特定的地方缩进以具有更好的可读性。"), 305 | ("As a rule of thumb, indentation within expressions is allowed after operators, an open parenthesis and after commas.", 306 | "一般来说,表达式中的缩进允许在运算符、开放的小括号和逗号后。"), 307 | ("With parenthesis and semicolons ","用小括号和分号"), 308 | ("you can use statements where only an expression is allowed:", 309 | "你可以在只允许表达式的地方使用语句:"), 310 | ("# computes fac(4) at compile time:","# 编译期计算fac(4):"), 311 | ("To define new commands like ","为了定义一个新命令如"), 312 | ("in the examples, the concept of a ","如在示例中,概念"), 313 | ("procedure","过程"), 314 | ("is needed. (Some languages call them ","是必要的。(一些语句叫做"), 315 | ("methods","方法"), 316 | ("functions","函数"), 317 | (".) In Nim new procedures are defined with the ","。)Nim中新方法定义用"), 318 | ("keyword:","关键字:"), 319 | ("This example shows a procedure named ","示例展示了一个过程,叫"), 320 | ("that asks the user a ","询问用户"), 321 | ("and returns true if they answered \"yes\" (or something similar) and returns false if they answered \"no\" (or something similar). A ", 322 | "并返回true如果回答\"yes\"(或类似的),返回false如果回答\"no\"或类似的)。"), 323 | ("statement leaves the procedure (and therefore the while loop) immediately. The ", 324 | "语句立刻离开过程(因此也离开了while循环)。"), 325 | ("syntax describes that the procedure expects a parameter named ","语法描述过程需要一个参数,名叫"), 326 | ("and returns a value of type ","并返回一个值类型为"), 327 | ("type is built-in: the only valid values for ","类型为内置:有效"), 328 | ("are ","为"), 329 | (". The conditions in if or while statements must be of type ", 330 | "。if或while语句中的条件必须属于类型"), 331 | ("Some terminology: in the example ","一些术语:在示例中"), 332 | ("is called a (formal) ","叫做形"), 333 | ("parameter","参"), 334 | ("is called an ","叫做"), 335 | ("argument","实参"), 336 | ("that is passed to this parameter.",",传递给这个参数。"), 337 | ("A procedure that returns a value has an implicit ","返回值的过程声明一个隐式的"), 338 | ("variable declared that represents the return value. A ","变量,代表返回值。"), 339 | ("statement with no expression is a shorthand for ","没有表达式的语句简化了"), 340 | (". The ","。"), 341 | ("value is always returned automatically at the end of a procedure if there is no ", 342 | "值总是在过程的结束前自动返回如果没有"), 343 | ("statement at the exit.","语句。"), 344 | ("variable is already implicitly declared at the start of the function, so declaring it again with \'var result\', for example, "& 345 | "would shadow it with a normal variable of the same name. The result variable is also already initialised with the type\'s default value. Note that referential data types will be ", 346 | "变量已经隐式声明在函数的开关,例如所以如果再次声明\'var result\',一个同名的普通变量会隐藏它。result变量也已经被类型的默认值初始化。注意引用数据类型将是"), 347 | ("at the start of the procedure, and thus may require manual initialisation. ","在过程的开头,因此需要手动初始化。"), 348 | ("Parameters are immutable in the procedure body. By default, their value cannot be changed because this allows the compiler to implement parameter passing in the most efficient way. If a mutable variable is needed inside the procedure, it has to be declared with ", 349 | "参数在过程体中不可修改。默认地,他们的值不能改变因为这允许编译器实现高效的参数传递。如果过程内需要可变变量,它必需声明为"), 350 | ("in the procedure body. Shadowing the parameter name is possible, and actually an idiom:","在过程体中。隐藏参数名是可能的,实际上这是一个习惯:"), 351 | ("If the procedure needs to modify the argument for the caller, a ","如果过程需要为调用者修改实参,"), 352 | ("parameter can be used:","形参可以实现:"), 353 | ("# integer division","# 整数除法"), 354 | ("# integer modulo operation","# 整数取模运算"), 355 | ("# modifies x and y","# 修改x和y"), 356 | ("In the example, ","示例中,"), 357 | ("var parameters","var形参"), 358 | (". Var parameters can be modified by the procedure and the changes are visible to the caller. Note that the above example would better make use of a tuple as a return value instead of using var parameters.", 359 | "。var形参可以被过程修改并且这些变化对调用者可见。注意上面的示例可以更好的利用元组作为返回值代替var形参。"), 360 | ("To call a procedure that returns a value just for its side effects and ignoring its return value, a ","只为副作用调用返回值的过程并忽略返回值,"), 361 | ("statement ","语句"), 362 | ("must","必须"), 363 | ("be used. Nim does not allow silently throwing away a return value:","使用。Nim不允许静默丢弃返回值:"), 364 | ("The return value can be ignored implicitly if the called proc/iterator has been declared with the ", 365 | "返回值可以被隐式忽略如果一个被调用的过程或迭代器声明为"), 366 | ("pragma:","编译指示:"), 367 | ("# now valid","# 现在可以了"), 368 | ("The ",""), 369 | ("statement can also be used to create block comments as described in the ", 370 | "也可以用于创建块注释,描述在"), 371 | ("section.","部分。"), 372 | ("Often a procedure has many parameters and it is not clear in which order the parameters appear. This is especially true for procedures that construct a complex data type. "& 373 | "Therefore the arguments to a procedure can be named, so that it is clear which argument belongs to which parameter:", 374 | "过程通常有多个形参,形参出现的顺序并不清楚。这对构造复杂的数据类型尤其适用。因此过程可以命名实参,以便于清楚地看到哪个实参属于哪个形参:"), 375 | ("Now that we use named arguments to call ","既然我们使用命名实参调用"), 376 | ("the argument order does not matter anymore. Mixing named arguments with ordered arguments is also possible, but not very readable:", 377 | "实参顺序不再重要。把有序实参和命名实参混合起来是可以的,但不是非常可读:"), 378 | ("The compiler checks that each parameter receives exactly one argument.","编译器检查每个形参只收到一个实参。"), 379 | ("To make the ","为了使"), 380 | ("proc easier to use it should provide ","proc更易于使用,应当提供"), 381 | ("default values","默认值"), 382 | ("; these are values that are used as arguments if the caller does not specify them:", 383 | ";这些是如果调用者没有指定而作为实参使用的值:"), 384 | ("Now the call to ","现在调用"), 385 | ("only needs to set the values that differ from the defaults.","只需要设置不同于默认值的实参值。"), 386 | ("Note that type inference works for parameters with default values; there is no need to write ", 387 | "注意类型推导适用于默认值;不需要写"), 388 | (", for example. ",",例如。"), 389 | ("Nim provides the ability to overload procedures similar to C++:","Nim提供类似C++的过程重载:"), 390 | ("# calls the toString(x: int) proc","# 调用toString(x: int) proc"), 391 | ("# calls the toString(x: bool) proc","# 调用toString(x: bool) proc"), 392 | ("(Note that ","(注意"), 393 | ("is usually the ","通常是"), 394 | ("operator in Nim.) The compiler chooses the most appropriate proc for the ","运算符在Nim中。)编译器选择最合适的过程"), 395 | ("calls. How this overloading resolution algorithm works exactly is not discussed here (it will be specified in the manual soon). "& 396 | "However, it does not lead to nasty surprises and is based on a quite simple unification algorithm. Ambiguous calls are reported as errors.", 397 | "调用。这种重载解析算法的工作原理不在这里讨论(将在手册中具体说明)。但它基于一个简单的统一算法,不会节外生枝,歧义调用将报错。"), 398 | ("The Nim library makes heavy use of overloading - one reason for this is that each operator like ", 399 | "Nim库重度使用重载- 一个原因是每个运算符如"), 400 | ("is just an overloaded proc. The parser lets you use operators in ","只是一个重载过程。解析器让你使用运算符在"), 401 | ("infix notation","中缀记号"), 402 | ("). An infix operator always receives two arguments, a prefix operator always one. (Postfix operators are not possible, because this would be ambiguous: does ", 403 | ")。中缀运算符总是需要两个实参,前缀运算符需要一个。(后缀运行符不可行,因为这有歧义:"), 404 | ("? It always means ","?它总意味着"), 405 | (", because there are no postfix operators in Nim.)",",因为Nim没有后缀运算符。)"), 406 | ("Apart from a few built-in keyword operators such as ","除了一些内置关键字运算符如"), 407 | (", operators always consist of these characters: ",",运算符问题由以下字符组成:"), 408 | ("User defined operators are allowed. Nothing stops you from defining your own ","用户定义运算符是允许的。没人阻止你定义自己的"), 409 | ("operator, but doing so may reduce readability.","运算符,但这么做降低了可读性。"), 410 | ("The operator\'s precedence is determined by its first character. The details can be found in the manual. ", 411 | "运算符优先级由第一个字符决定。可以在手册中看到更多细节。"), 412 | ("To define a new operator enclose the operator in backticks \"``\":","定义用\"``\"括起来的新运算符:"), 413 | ("# now the $ operator also works with myDataType, overloading resolution","# 现在$运算符也可以用于myDataType,重载解析"), 414 | ("# ensures that $ works for built-in types just like before","# 确保内置类型的$还像之前一样"), 415 | ("The \"``\" notation can also be used to call an operator just like any other procedure:","\"``\"记号也可用于调用像其它过程一样的运算符:"), 416 | ("Every variable, procedure, etc. needs to be declared before it can be used. (The reason for this is that it is non-trivial to avoid this need in a language that supports meta programming as extensively as Nim does.) However, this cannot be done for mutually recursive procedures:", 417 | "每个变量、过程等。需要在使用前声明。(这样做的原因是,使用像Nim一样广泛支持元编程的语言来避免这种需求并非易事。)但是,这对于相互递归的过程是无法做到的:"), 418 | ("# forward declaration:","# 前向声明"), 419 | ("# makes sure we don't run into negative recursion","# 确保我们不进入负递归"), 420 | ("Here ","这里"), 421 | ("depends on ","取决于"), 422 | ("and vice versa. Thus ","反之亦然。因此"), 423 | ("needs to be introduced to the compiler before it is completely defined. The syntax for such a forward declaration is simple: just omit the ", 424 | "需要在完全定义前引入编译器。每个前向声明的语法很简单:只忽略"), 425 | ("and the procedure's body. The ","和过程体。"), 426 | ("just adds border conditions, and will be covered later in ","只添加边界条件,将讲解在后续的"), 427 | ("Later versions of the language will weaken the requirements for forward declarations.","语言的后续版本将弱化前向声明。"), 428 | ("The example also shows that a proc\'s body can consist of a single expression whose value is then returned implicitly.","示例展示过程体由单个表达式组成,其值被隐式地返回。"), 429 | ("Let's return to the simple counting example:","让我们回到这个简单的计数示例:"), 430 | ("Can a ","可不可以用"), 431 | ("proc be written that supports this loop? Lets try:","过程支持这个循环?让我们试下:"), 432 | ("However, this does not work. The problem is that the procedure should not only ","不行。问题在于过程不应当只"), 433 | (", but return and ","而且要"), 434 | ("after an iteration has finished. This ",",在一次迭代完成后。这种"), 435 | ("return and continue","return并continue"), 436 | ("is called a ","叫做"), 437 | ("statement. Now the only thing left to do is to replace the ","语句。现在只剩下替换"), 438 | ("keyword by ","关键字用"), 439 | ("and here it is - our first iterator:","这是我们的第一个迭代器:"), 440 | ("Iterators look very similar to procedures, but there are several important differences:", 441 | "迭代器看起来很像过程,但有几点重要的区别:"), 442 | ("Iterators can only be called from for loops.","迭代器只能使用在循环中。"), 443 | ("Iterators cannot contain a ","迭代器不能包含"), 444 | ("statement (and procs cannot contain a " ,"语句(且procs不能包含"), 445 | ("statement). " ,"语句)。"), 446 | ("Iterators have no implicit " ,"迭代器没有隐式的"), 447 | ("variable. " ,"变量。"), 448 | ("Iterators do not support recursion." ,"迭代器不支持递归。"), 449 | ("Iterators cannot be forward declared, because the compiler must be able to inline an iterator. (This restriction will be gone in a future version of the compiler.)", 450 | "迭代器不能前向声明,因为编译器必须内联迭代器。(这个限制将在未来的编译器版本中消失。)"), 451 | ("However, you can also use a " ,"但是你也可以用"), 452 | ("iterator to get a different set of restrictions. See " ,"迭代器来获取限制集合。见"), 453 | ("first class iterators" ,"一类迭代器"), 454 | ("for details. Iterators can have the same name and parameters as a proc, since essentially they have their own namespaces. Therefore it is common practice to wrap iterators in procs of the same name which accumulate the result of the iterator and return it as a sequence, like ", 455 | "的更多细节。迭代器可以和proc一样有同样的名字和形参,因为实质上他们拥有自己的命名空间。因此这是一个普遍的实践,即把迭代器封装在同名的proc中,累计迭代器的结果并以序列返回,如"), 456 | ("from the " ,"来自"), 457 | ("strutils module" ,"strutils模块"), 458 | ("This section deals with the basic built-in types and the operations that are available for them in detail." , 459 | "这部分处理基本的内置类型和它们可用的运算符细节。"), 460 | ("Nim's boolean type is called " ,"Nim的布林类型叫做"), 461 | ("and consists of the two pre-defined values " ,"分为两个预定义的值"), 462 | (". Conditions in while, if, elif, and when statements must be of type bool." ,"。while,if,elif中的条件语句必须是bool类型。"), 463 | ("The operators " ,"运算符"), 464 | ("are defined for the bool type. The " ,"为bool类型定义。"), 465 | ("operators perform short-circuit evaluation. For example:" ,"运算执行短路求值。例如:"), 466 | ("# p.name is not evaluated if p == nil" ,"# 如果p == nil, p.name便不求值"), 467 | ("character type" ,"字符类型"), 468 | (". Its size is always one byte, so it cannot represent most UTF-8 characters; but it " ,"。它的大小总是1字节,它不能代表多数UTF-8字符;但它"), 469 | ("can" ,"可以"), 470 | ("represent one of the bytes that makes up a multi-byte UTF-8 character. The reason for this is efficiency: for the overwhelming majority of use-cases, the resulting programs will still handle UTF-8 properly as UTF-8 was specially designed for this. Character literals are enclosed in single quotes." , 471 | "代表组成多字节UTF-8字符的一个字节。这是出于效率:对绝大多数情况,结果程序仍将正确处理UTF-8,因为UTF-8正是为此而设计的,字符字面值被括在单引号中。"), 472 | ("Chars can be compared with the " ,"字符可以比较"), 473 | ("operators. The " ,"运算符。"), 474 | ("operator converts a " ,"运算符转换"), 475 | ("to a " ,"为"), 476 | (". Chars cannot be mixed with integers; to get the ordinal value of a " ,"。字符不能和整数混合;为了得到序数值代表的"), 477 | ("use the " ,"使用"), 478 | ("proc. Converting from an integer to a " ,"过程。从整数转换为"), 479 | ("is done with the " ,"使用"), 480 | ("proc." ,"过程。"), 481 | ("String variables are " ,"字符串变量是"), 482 | ("mutable" ,"可变的"), 483 | (", so appending to a string is possible, and quite efficient. Strings in Nim are both zero-terminated and have a length field. A string\'s length can be retrieved with the builtin " , 484 | ",所以可以追加字符串,并且这很高效。Nim中的字符串即是零结尾,也有一个长度字段。字符串长度获取可以通过内置"), 485 | ("procedure; the length never counts the terminating zero. Accessing the terminating zero is an error, it only exists so that a Nim string can be converted to a " , 486 | "过程;长度不计结尾的零。访问结尾零是一个错误,它存在只为Nim字符串可以转换成"), 487 | ("without doing a copy." ,",无需拷贝。"), 488 | ("The assignment operator for strings copies the string. You can use the " ,"字符串赋值运算符会拷贝。你可以使用"), 489 | ("operator to concatenate strings and " ,"运算符拼接字符串,"), 490 | ("to append to a string." ,"追加字符串"), 491 | ("Strings are compared using their lexicographical order. All the comparison operators are supported. By convention, all strings are UTF-8 encoded, but this is not enforced. For example, when reading strings from binary files, they are merely a sequence of bytes. The index operation " , 492 | "字符串使用词法序比较。支持所有比较运算符。按照惯例,所有字符串都是UTF-8编码,但这不是强制的。例如,当从二进制读取字符串时,他们只是字节序列。索引运算符"), 493 | ("means the i-th " ,"表示第i个"), 494 | ("char" ,"字符"), 495 | ("of " ,"在"), 496 | (", not the i-th " ,",不是第i个"), 497 | ("A string variable is initialized with the empty string " ,"字符串变量用空字符串初始化"), 498 | ("Nim has these integer types built-in: " ,"Nim有以下内置整数类型:"), 499 | ("The default integer type is " ,"默认的整数类型为"), 500 | (". Integer literals can have a " ,"。整数字面值可以有"), 501 | ("type suffix" ,"类型后缀"), 502 | ("to specify a non-default integer type:" ,"来指定非默认整数类型:"), 503 | ("# x is of type ``int``" ,"# x属于``int``类型"), 504 | ("# y is of type ``int8``" ,"# y属于``int8``类型"), 505 | ("# z is of type ``int64``" ,"# z属于``int64``类型"), 506 | ("# u is of type ``uint``" ,"# u属于``uint``类型"), 507 | ("Most often integers are used for counting objects that reside in memory, so " ,"多数整数用于计算内存中的对象个数,所以"), 508 | ("has the same size as a pointer." ,"具有指针的大小。"), 509 | ("The common operators " ,"通用运算符"), 510 | ("are defined for integers. The " ,"为整数定义。"), 511 | ("operators are also defined for integers, and provide " ,"也为整数定义,还提供"), 512 | ("bitwise","按位"), 513 | ("operations. Left bit shifting is done with the " ,"运算符。左移使用"), 514 | (", right shifting with the " ,",右移使用"), 515 | ("operator. Bit shifting operators always treat their arguments as " ,"运算符。位移运算总是把他们的实参作为"), 516 | ("unsigned" ,"无符号"), 517 | (". For " ,"。对于"), 518 | ("arithmetic bit shifts" ,"代数位移"), 519 | ("ordinary multiplication or division can be used." ,"平常的乘法或除法也可以使用。"), 520 | ("Unsigned operations all wrap around; they cannot lead to over- or under-flow errors." ,"所有无符号运算都被封装;它们不会引起上溢或下溢。"), 521 | ("Lossless " ,"无损"), 522 | ("Automatic type conversion " ,"自动类型转换"), 523 | ("is performed in expressions where different kinds of integer types are used. However, if the type conversion would cause loss of information, the " , 524 | "在表达式中使用不同整数类型时执行。但是如果类型转换会丢失信息,"), 525 | ("exception is raised (if the error cannot be detected at compile time)." ,"异常会被发起(如果错误在编译期检测到)。"), 526 | 527 | 528 | 529 | ] 530 | 531 | for i in dict: 532 | addTranslation(Language.zhCN, i[0],i[1]) 533 | 534 | -------------------------------------------------------------------------------- /public/tut1karax.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | Nim Tutorial (Part I) 22 | 957 | 958 | 959 | 972 | 973 |
974 | 975 | 976 | 977 | -------------------------------------------------------------------------------- /public/tut2karax.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | Nim Tutorial (Part I) 22 | 957 | 958 | 959 | 972 | 973 |
974 | 975 | 976 | 977 | -------------------------------------------------------------------------------- /public/tut3kararx.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | Nim Tutorial (Part I) 22 | 957 | 958 | 959 | 972 | 973 |
974 | 975 | 976 | 977 | -------------------------------------------------------------------------------- /tests/t1.html: -------------------------------------------------------------------------------- 1 |

Quick hummus recipe

2 | 3 |

This recipe makes quick, tasty hummus, with no messing. It has been adapted 4 | from a number of different recipes that I have read over the years.

5 | 6 |

Hummus is a delicious thick paste used heavily in Greek and Middle Eastern dishes. It is very tasty with salad, grilled meats and pitta breads.

7 | 8 |

Ingredients

9 | 10 |
    11 |
  • 1 can (400g) of chick peas (garbanzo beans)
  • 12 |
  • 175g of tahini
  • 13 |
  • 6 sundried tomatoes
  • 14 |
  • Half a red pepper
  • 15 |
  • A pinch of cayenne pepper
  • 16 |
  • 1 clove of garlic
  • 17 |
  • A dash of olive oil
  • 18 |
19 | 20 |

Instructions

21 | 22 |
    23 |
  1. Remove the skin from the garlic, and chop coarsely.
  2. 24 |
  3. Remove all the seeds and stalk from the pepper, and chop coarsely.
  4. 25 |
  5. Add all the ingredients into a food processor.
  6. 26 |
  7. Process all the ingredients into a paste.
  8. 27 |
  9. If you want a coarse "chunky" hummus, process it for a short time.
  10. 28 |
  11. If you want a smooth hummus, process it for a longer time.
  12. 29 |
30 | 31 |

For a different flavour, you could try blending in a small measure of lemon and coriander, chili pepper, lime and chipotle, harissa and mint, or spinach and feta cheese. Experiment and see what works for you.

32 | 33 |

Storage

34 | 35 |

Refrigerate the finished hummus in a sealed container. You should be able to use it for about a week after you've made it. If it starts to become fizzy, you should definitely discard it.

36 | 37 |

Hummus is suitable for freezing; you should thaw it and use it within a couple of months.

38 |

This liquid is highly toxic — 39 | if you drink it, 40 | you may die.

41 | 42 | 43 |

44 | The Ruby-throated Hummingbird (Archilochus colubris) 45 | is the most common hummingbird in Eastern North America. 46 |

47 | 48 | 49 |

50 | The menu was a sea of exotic words like vatrushka, 51 | nasi goreng and soupe à l'oignon. 52 |

53 | 54 | 55 |

56 | Someday I'll learn how to spel better. 57 |

58 | 59 |
60 | 61 |
    62 |
  1. 63 | Slice two pieces of bread off the loaf. 64 |
  2. 65 |
  3. 66 | Insert a tomato slice and a leaf of 67 | lettuce between the slices of bread. 68 |
  4. 69 |
70 |
71 | 72 | 73 | 74 | 75 | 79 | 80 | 90 | 91 | 92 | 93 | 94 | 98 | 99 |

Document content goes here.....

100 | 105 | 106 | 110 | 111 |

This is a paragraph.

112 | 113 |
114 |
115 |       ___________________________
116 |   < I'm an expert in my field. >
117 |       ---------------------------
118 |           \   ^__^
119 |            \  (oo)\_______
120 |               (__)\       )\/\
121 |                   ||----w |
122 |                   ||     ||
123 |   
124 |
125 | A cow saying, "I'm an expert in my field." The cow is illustrated using preformatted text characters. 126 |
127 |
128 | 129 |
130 |   L          TE
131 |     A       A
132 |       C    V
133 |        R A
134 |        DOU
135 |        LOU
136 |       REUSE
137 |       QUE TU
138 |       PORTES
139 |     ET QUI T'
140 |     ORNE O CI
141 |      VILISÉ
142 |     OTE-  TU VEUX
143 |      LA    BIEN
144 |     SI      RESPI
145 |             RER       - Apollinaire
146 | 
147 | 148 |

O’er all the hilltops
149 | Is quiet now,
150 | In all the treetops
151 | Hearest thou
152 | Hardly a breath;
153 | The birds are asleep in the trees:
154 | Wait, soon like these
155 | Thou too shalt rest. 156 |

157 | -------------------------------------------------------------------------------- /tests/t1.nim: -------------------------------------------------------------------------------- 1 | include karax / prelude 2 | 3 | proc createDom(): VNode = 4 | result = buildHtml: 5 | h1: 6 | text "Quick hummus recipe" 7 | p: 8 | text """ 9 | This recipe makes quick, tasty hummus, with no messing. It has been adapted from 10 | a number of different recipes that I have read over the years.""" 11 | p: 12 | text """ 13 | Hummus is a delicious thick paste used heavily in Greek and Middle Eastern 14 | dishes. It is very tasty with salad, grilled meats and pitta breads.""" 15 | h2: 16 | text "Ingredients" 17 | ul: 18 | li: 19 | text "1 can (400g) of chick peas (garbanzo beans)" 20 | li: 21 | text "175g of tahini" 22 | li: 23 | text "6 sundried tomatoes" 24 | li: 25 | text "Half a red pepper" 26 | li: 27 | text "A pinch of cayenne pepper" 28 | li: 29 | text "1 clove of garlic" 30 | li: 31 | text "A dash of olive oil" 32 | h2: 33 | text "Instructions" 34 | ol: 35 | li: 36 | text "Remove the skin from the garlic, and chop coarsely." 37 | li: 38 | text "Remove all the seeds and stalk from the pepper, and chop coarsely." 39 | li: 40 | text "Add all the ingredients into a food processor." 41 | li: 42 | text "Process all the ingredients into a paste." 43 | li: 44 | text "If you want a coarse \"chunky\" hummus, process it for a short time." 45 | li: 46 | text "If you want a smooth hummus, process it for a longer time." 47 | p: 48 | text """ 49 | For a different flavour, you could try blending in a small measure of lemon and 50 | coriander, chili pepper, lime and chipotle, harissa and mint, or spinach and 51 | feta cheese. Experiment and see what works for you.""" 52 | h2: 53 | text "Storage" 54 | p: 55 | text """ 56 | Refrigerate the finished hummus in a sealed container. You should be able to use 57 | it for about a week after you've made it. If it starts to become fizzy, you 58 | should definitely discard it.""" 59 | p: 60 | text """ 61 | Hummus is suitable for freezing; you should thaw it and use it within a couple 62 | of months.""" 63 | p: 64 | text "This liquid is " 65 | strong: 66 | text "highly toxic" 67 | text " — if you drink it, " 68 | strong: 69 | text "you may " 70 | em: 71 | text "die" 72 | text "." 73 | # scientific names 74 | p: 75 | text "The Ruby-throated Hummingbird ( " 76 | italic: 77 | text "Archilochus colubris" 78 | text ") is the most common hummingbird in Eastern North America." 79 | # foreign words 80 | p: 81 | text "The menu was a sea of exotic words like " 82 | italic(lang = "uk-latn"): 83 | text "vatrushka" 84 | text ", " 85 | italic(lang = "id"): 86 | text "nasi goreng" 87 | text " and " 88 | italic(lang = "fr"): 89 | text "soupe à l'oignon" 90 | text "." 91 | # a known misspelling 92 | p: 93 | text "Someday I'll learn how to " 94 | underlined(style = "text-decoration-line: underline; text-decoration-style: wavy;".toCss): 95 | text "spel" 96 | text " better." 97 | tdiv: 98 | # Highlight keywords in a set of instructions 99 | ol: 100 | li: 101 | bold: 102 | text "Slice" 103 | text " two pieces of bread off the loaf. " 104 | li: 105 | bold: 106 | text "Insert" 107 | text " a tomato slice and a leaf of lettuce between the slices of bread. " 108 | # Generated by the server 109 | script(`type` = "application/json", id = "data"): 110 | text "{\"userId\":1234,\"userName\":\"John Doe\",\"memberSince\":\"2000-01-01T00:00:00.000Z\"}" 111 | # Static 112 | script: 113 | text """ 114 | const userInfo = JSON.parse(document.getElementById("data").text); 115 | console.log("User information: %o", userInfo); 116 | """ 117 | script: 118 | text """ 119 | const a = 3; 120 | const b = -2; 121 | 122 | if (x > y) { 123 | alert("Hello World"); 124 | } 125 | console.log(a > 0 && b > 0); 126 | // expected output: false 127 | """ 128 | script(src = "javascript.js") 129 | body: 130 | #[ 131 | This is a multiline comment and it can 132 | span through as many as lines you like. 133 | ]# 134 | p: 135 | text "Document content goes here....." 136 | #[ I 137 | am 138 | a 139 | multiline 140 | comment 141 | ]# 142 | #[ 143 |

Look at this cool image:

144 | Trulli 145 | ]# 146 | p: 147 | text "This " 148 | # great text 149 | text " is a paragraph." 150 | figure(role = "img", aria-labelledby = "cow-caption"): 151 | pre: 152 | text """ 153 | ___________________________ 154 | < I'm an expert in my field. > 155 | --------------------------- 156 | \ ^__^ 157 | \ (oo)\_______ 158 | (__)\ )\/\ 159 | ||----w | 160 | || || 161 | """ 162 | figcaption(id = "cow-caption"): 163 | text """ 164 | A cow saying, "I'm an expert in my field." The cow is illustrated using 165 | preformatted text characters.""" 166 | pre: 167 | text """ 168 | L TE 169 | A A 170 | C V 171 | R A 172 | DOU 173 | LOU 174 | REUSE 175 | QUE TU 176 | PORTES 177 | ET QUI T' 178 | ORNE O CI 179 | VILISÉ 180 | OTE- TU VEUX 181 | LA BIEN 182 | SI RESPI 183 | RER - Apollinaire 184 | """ 185 | p: 186 | text " O’er all the hilltops " 187 | br() 188 | text "Is quiet now, " 189 | br() 190 | text "In all the treetops " 191 | br() 192 | text "Hearest thou " 193 | br() 194 | text "Hardly a breath; " 195 | br() 196 | text "The birds are asleep in the trees: " 197 | br() 198 | text "Wait, soon like these " 199 | br() 200 | text "Thou too shalt rest." 201 | 202 | setRenderer createDom 203 | --------------------------------------------------------------------------------