all repos — hastyscribe @ 2a8679d3c257dee5f95f21289eaee56f5e42df4b

A professional markdown compiler.

hastyscribe.nim

 1
 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
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
import os, parseopt, strutils, times, markdown

let v = "1.0"
let usage = "  HastyScribe v" & v & " - Self-contained Markdown Compiler" & """

  (c) 2013 Fabio Cevasco
  
  Usage:
    hastyscribe markdown_file [--notoc]

  Arguments:
    markdown_file          The markdown file to compile into HTML.
  Options:
    --notoc                Do not generate a Table of Contents."""

var generate_toc = true
const src_css = "assets/hastyscribe.css".slurp
const src_headings_css = "assets/headings.css".slurp
const src_highlight_js = "assets/highlight.pack.js".slurp

# Procedures

proc parse_date(date: string, timeinfo: var TTimeInfo): bool = 
  var parts = date.split('-').map(proc(i:string): int = 
    try:
      i.parseInt
    except:
      0
  )
  try:
    timeinfo = TTimeInfo(year: parts[0], month: TMonth(parts[1]-1), monthday: parts[2])
    # Fix invalid dates (e.g. Feb 31st -> Mar 3rd)
    timeinfo = getLocalTime(timeinfo.TimeInfoToTime);
    return true
  except:
    return false


proc style_tag(css): string =
  result = "<style>$1</style>" % [css]


proc convert_file(input_file: string) =
  let inputsplit = input_file.splitFile

  # Output file name
  let output_file = inputsplit.dir/inputsplit.name & ".htm"
  let source = input_file.readFile

  # Document Variables
  var metadata = TMDMetaData(title:"", author:"", date:"")
  var body = source.md(MKD_DOTOC or MKD_EXTRA_FOOTNOTE, metadata)
  var main_css = src_css.style_tag
  var headings_css = src_headings_css.style_tag

  # Manage metadata
  if metadata.author != "":
    metadata.author = metadata.author & " &ndash;"

  var title_tag, header_tag, toc: string

  if metadata.title != "":
    title_tag = "<title>" & metadata.title & "</title>"
    header_tag = "<div id=\"header\"><h1>" & metadata.title & "</h1></div>"
  else:
    title_tag = ""
    header_tag = ""

  if generate_toc == true and metadata.toc != "":
    toc = "<div id=\"toc\">" & metadata.toc & "</div>"
  else:
    headings_css = ""
    toc = ""

  # Date parsing and validation
  var timeinfo: TTimeInfo

  if metadata.date == "":
    discard parse_date(getDateStr(), timeinfo)
  else:
    if parse_date(metadata.date, timeinfo) == false:
      discard parse_date(getDateStr(), timeinfo)

  let document = """<!doctype html>
<html lang="en">
<head>
  $title_tag
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta name="author" content="$author">
  <meta name="generator" content="HastyScribe">
  $main_css
  $headings_css
</head> 
<body>
  $header_tag
  $toc
  <div id="main">
$body
  </div>
  <div id="footer">
    <p>$author $date</p>
  </div>
  <script type="text/javascript">
    $highlight
    hljs.tabReplace = '  ';
    hljs.initHighlighting();
  </script>
</body>""" % ["title_tag", title_tag, "header_tag", header_tag, "author", metadata.author, "date", timeinfo.format("MMMM d, yyyy"), "toc", toc, "main_css", main_css, "headings_css", headings_css, "body", body, "highlight", src_highlight_js]
  output_file.writeFile(document)

 

### MAIN

var input = ""
var files = @[""]

discard files.pop

# Parse Parameters

for kind, key, val in getopt():
  case kind
  of cmdArgument:
    input = key
  of cmdLongOption:
    if key == "notoc":
      generate_toc = false
  else: nil

if input == "":
  quit(usage, 1)

for file in walkFiles(input):
  let filesplit = file.splitFile
  if (filesplit.ext == ".md" or filesplit.ext == ".markdown"):
    files.add(file)

if files.len == 0:
  quit("Error: \"$1\" does not match any markdown file" % [input], 2)
else:
  for file in files:
    convert_file(file)