Compare commits

..

No commits in common. "8402ff3a3cf035da660a6e53379f83ae6745cea5" and "27a169b30c6633b50f62d9e38677a4696da10c8c" have entirely different histories.

9 changed files with 143 additions and 310 deletions

View file

@ -13,8 +13,4 @@
<ProjectReference Include="..\FibLib\FibLib.fsproj" /> <ProjectReference Include="..\FibLib\FibLib.fsproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<PackageReference Update="FSharp.Core" Version="10.1.201" />
</ItemGroup>
</Project> </Project>

View file

@ -1,13 +1,9 @@
open System.Net open System.Net
open System.IO open System.IO
open System.Runtime.CompilerServices
open FSharp.Compiler.Text
open Fibble.FibLib open Fibble.FibLib
open Fibble.FibLib.Ast // Ger oss tillgång till Element, Text, RawHtml etc. open Fibble.FibLib.Ast // Ger oss tillgång till Element, Text, RawHtml etc.
open Fibble.FibLib.Pandoc open Fibble.FibLib.Pandoc
open Fibble.FibLib.HtmlPrinter
open Fibble.FibLib.Utils open Fibble.FibLib.Utils
open Fibble.FibLib.ConstructionHelpers
// ========================================== // ==========================================
// 1. Prelude (Dina egna taggar) // 1. Prelude (Dina egna taggar)
@ -16,25 +12,27 @@ open Fibble.FibLib.ConstructionHelpers
let myPrelude : Map<string, TagRenderer> = let myPrelude : Map<string, TagRenderer> =
Map [ Map [
"quotient", fun _ args _ _ -> "quotient", fun _ args _ ->
match args with match args with
| [one; two] -> | [_, one; _, two] ->
Text (sprintf "%d" (int one / int two)) Text (sprintf "%d" (int one / int two))
| _ -> | _ ->
Text "[Fel: quotient kräver två argument]" Text "[Fel: quotient kräver två argument]"
"bold", fun _ _ _ children -> "bold", fun _ args children ->
Strong(children) Element("b", args, children)
"kursiv", fun _ _ _ children -> Emph(children) "image", positional (fun _ args _ -> Element("img", [("src", args[0])], []))
"image", image "value", positional (fun meta args _ ->
"value", value match Map.tryFind args.Head meta with
"link", link | Some(v) -> Text v
"list", fun _ _ _ c -> System.Console.WriteLine(c) | None -> Text $"value {args.Head} not found in metadata")
RawHtml "hej" "link", positional (fun _ args children ->
let url = if args.Length > 0 then args.[0].Trim '"' else "#"
Element("a", [("href", args.Head)], children))
// @br har varken argument eller barn, vi returnerar bara HTML direkt // @br har varken argument eller barn, vi returnerar bara HTML direkt
"br", linebreak "br", nameToElement "br"
"table", fun _ _ _ children -> Text "hej" "table", fun _ _ children -> Text "hej"
"md", fun _ _ _ children -> RawHtml (mdToHtml (stringifyNodes children)) "md", fun meta args children -> RawHtml (mdToHtml (stringifyNodes children))
] ]
// ========================================== // ==========================================
@ -45,7 +43,7 @@ module File =
let readFile path = let readFile path =
match Path.Exists(path) with match Path.Exists(path) with
| true -> File.ReadAllText(path) | true -> File.ReadAllText(path)
| _ -> failwith $"{Path.GetFullPath path} does not exist" | _ -> failwith $"{path} does not exist"
let pageTemplate = File.readFile "_page-template" let pageTemplate = File.readFile "_page-template"
@ -69,12 +67,10 @@ let processDocument (source: string) =
| Section(l, a, children) -> | Section(l, a, children) ->
Section(l, a, children Section(l, a, children
|> List.map (Execution.transform metadata myPrelude evaluator)) |> List.map (Execution.transform metadata myPrelude evaluator))
| _ -> failwith "haha"
) )
// Steg 3: Be printern skriva ut trädet till HTML // Steg 3: Be printern skriva ut trädet till HTML
let bodyHtml = HtmlPrinter.render evaluatedBlocks let bodyHtml = HtmlPrinter.render (metadata, evaluatedBlocks)
// Steg 4: Fyll i din HTML-mall // Steg 4: Fyll i din HTML-mall
let mutable finalHtml = pageTemplate.Replace("{{body}}", bodyHtml) let mutable finalHtml = pageTemplate.Replace("{{body}}", bodyHtml)

View file

@ -20,7 +20,7 @@ let increment () =
Detta är en paragraf som har lite text i sig och lite @md{inbäddad *markdown* som kanske} funkar. Det är bra så. Detta är en paragraf som har lite text i sig och lite @md{inbäddad *markdown* som kanske} funkar. Det är bra så.
@md{ @md{
babeuoastnuhaoesn en tabell
hej hopp hej hopp
--- ---- --- ----
@ -32,18 +32,8 @@ ueo aoeu
elleR? elleR?
@list{
Första saken
Andra saken med @bold{text}
Tredje saken
}
@section{Användning} @section{Användning}
Första anropet: @(increment()) Första anropet: @(increment())
Andra anropet: @(increment()) Andra anropet: @(increment())
@bold{detta är ibdenrerat.
detta också.
hej}
Test av utskrift: @value[date] Test av utskrift: @value[date]

View file

@ -8,15 +8,12 @@
<ItemGroup> <ItemGroup>
<Compile Include="Pandoc.fs" /> <Compile Include="Pandoc.fs" />
<Compile Include="Library.fs" /> <Compile Include="Library.fs" />
<Compile Include="constructorHelpers.fs" />
<Compile Include="HtmlPrinter.fs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="FParsec" Version="1.1.1" /> <PackageReference Include="FParsec" Version="1.1.1" />
<PackageReference Include="FSharp.Compiler.Service" Version="43.12.201" /> <PackageReference Include="FSharp.Compiler.Service" Version="43.12.201" />
<PackageReference Include="YamlDotNet" Version="16.3.0" /> <PackageReference Include="YamlDotNet" Version="16.3.0" />
<PackageReference Update="FSharp.Core" Version="10.1.201" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -1,59 +0,0 @@
// ReSharper disable FSharpInterpolatedString
module Fibble.FibLib.HtmlPrinter
open System.Net
module HtmlPrinter =
open Ast
open System.Net
let renderAttributes (args: (string * string) list) =
args
|> List.map (fun k -> sprintf "%s=\"%s\"" (fst k) (snd k))
|> String.concat " "
let rec renderInline =
function
| Text t -> WebUtility.HtmlEncode t
| Strong(t) -> sprintf "<strong>%s</strong>" (renderInline t)
| RawHtml h ->
h
| _ -> ""
let renderFigure a c l =
failwith "haha"
let renderListItem item =
sprintf "<li>%s</li>" item
let renderList kind attributes nodesList =
let content = nodesList
|> List.map renderListItem
|> String.concat "\n"
$"<{kind} {(renderAttributes attributes)}>{content}</{kind}>"
let rec render blocks =
let doubleRender blocksblock =
List.map render blocksblock
let renderNode = function
| Paragraph [RawHtml html] ->
html
| Paragraph nodes when nodes |> List.forall (function
| RawHtml _ -> true
| Text t when System.String.IsNullOrWhiteSpace(t) -> true
| _ -> false) ->
nodes
|> List.choose (function RawHtml h -> Some h | _ -> None)
|> String.concat "\n"
| Paragraph c -> sprintf "<p>%s</p>" (c |> List.map renderInline |> String.concat "")
| Section(l, _, c) -> sprintf "<h%d>%s</h%d>" l (c |> List.map renderInline |> String.concat "") l
| CodeBlock(attributes, text) -> sprintf "<code>%s</code>" text
| Figure(attributes, caption, blocks) -> renderFigure attributes caption blocks
| ListBlock(l) -> match l with
| BulletList(attr, blocknodes) -> renderList "ul" attr.kvp (doubleRender blocknodes)
| Orderedlist(attr, start, blocknodes) -> renderList "ol" attr.kvp (doubleRender blocknodes)
| Plain nodes -> List.map renderInline nodes |> String.concat " "
blocks
|> List.map renderNode
|> String.concat "\n"

View file

@ -10,55 +10,32 @@ open System.Collections.Generic
// 1. AST & Utils // 1. AST & Utils
// ========================================== // ==========================================
module Ast = module Ast =
type Attr = { id: string; classes: string list; kvp: (string * string) list }
type InlineNode = type InlineNode =
| Text of string | Text of string
| RawHtml of string | RawHtml of string
| Emph of InlineNode list
| Underline of InlineNode list
| Strong of InlineNode list
| Strikeout of InlineNode list
| Superscript of InlineNode list
| Subscript of InlineNode list
| Link of attributes: Attr * target: Target
| Code of attributes: Attr * text: string
| Image of attributes: Attr * altText: InlineNode list * target: Url
| Note of BlockNode list
| SoftBreak
| LineBreak
| Expr of code: string * result: string option | Expr of code: string * result: string option
| Command of tag: string * args: string list * kwargs: Map<string, string> * children: InlineNode list | Element of tag: string * args: (string * string) list * children: InlineNode list
and BlockNode =
| CodeBlock of attributes: Attr * text: string type BlockNode =
| Figure of attributes: Attr * caption: InlineNode list * blocks: BlockNode list
| ListBlock of ListKind
| Plain of InlineNode list
| Paragraph of children: InlineNode list
| Section of level: int * args: (string * string) list * children: InlineNode list | Section of level: int * args: (string * string) list * children: InlineNode list
and ListKind = | Paragraph of children: InlineNode list
| Orderedlist of attributes: Attr * start: int * blocksList: (BlockNode list) list
| BulletList of attributes: Attr * blocksList: (BlockNode list) list
and Url = string
and Target = Url * InlineNode list
type Document = BlockNode list type Document = BlockNode list
type TagRenderer = Map<string,string> type TagRenderer = Map<string,string> -> (string * string) list -> InlineNode list -> InlineNode
-> string list
-> Map<string,string>
-> InlineNode list -> InlineNode
let rec stringifyNodes (nodes: InlineNode list) = let rec stringifyNodes (nodes: InlineNode list) =
let tupleToString (t: string * string) = sprintf "%s=\"%s\"" (fst t) (snd t)
nodes nodes
|> List.map (function |> List.map (function
| Text t -> t | Text t -> t
| RawHtml h -> h | RawHtml h -> h
| Element(tag, args, children) ->
// Omvandla inre taggar till HTML
let attrs = if args.IsEmpty then "" else " " + String.concat " " (List.map tupleToString args)
sprintf "<%s%s>%s</%s>" tag attrs (stringifyNodes children) tag
| Expr(_, Some res) -> res | Expr(_, Some res) -> res
| Expr(code, None) -> sprintf "@(%s)" code // Fallback om den inte evaluerats | Expr(code, None) -> sprintf "@(%s)" code // Fallback om den inte evaluerats
| _ -> failwith "haha"
) )
|> String.concat "" |> String.concat ""
@ -66,63 +43,32 @@ module Ast =
module Utils = module Utils =
open Ast open Ast
let dedentNodes (nodes: InlineNode list) = let smartDedent (input: string) =
let fullText = let lines = input.Replace("\r\n", "\n").Split '\n' |> List.ofArray
nodes |> List.choose (function Text t -> Some t | _ -> None) |> String.concat ""
let lines = fullText.Replace("\r\n", "\n").Split('\n') // 1. Hitta den minsta indenteringen bland alla rader som har text
// 1. Räkna BARA ut minIndent från rader som kommer efter en radbrytning (skippa rad 0)
let minIndent = let minIndent =
if lines.Length <= 1 then 0 lines
else |> List.filter (fun l -> not (System.String.IsNullOrWhiteSpace(l)))
lines |> Array.skip 1 |> List.map (fun l -> l.Length - l.TrimStart().Length)
|> Array.filter (fun l -> not (System.String.IsNullOrWhiteSpace(l))) |> function
|> Array.map (fun l -> l.Length - l.TrimStart().Length) | [] -> 0
|> function [||] -> 0 | arr -> Array.min arr | indents -> List.min indents
let mutable isFirstText = true // 2. Dra av exakt många mellanslag från alla rader
let indentStr = "\n" + String.replicate minIndent " " // för att dessa inte ska vara med i det slutgiltiga dokumentet.
// 2. Applicera formateringen
let dedented = let dedented =
nodes |> List.map (function lines
| Text t -> |> List.map (fun l ->
let t1 = t.Replace("\r\n", "\n") if System.String.IsNullOrWhiteSpace(l) then ""
else l.Substring(minIndent)
// Ta bort inledande mellanslag den allra första texten direkt efter '{'
let t2 =
if isFirstText then
isFirstText <- false
t1.TrimStart(' ', '\t')
else t1
// Ta bort minIndent antal mellanslag efter varje radbrytning i noden
let t3 = if minIndent > 0 then t2.Replace(indentStr, "\n") else t2
Text t3
| otherNode -> otherNode
) )
// 3. Städa bort överflödiga radbrytningar och blanksteg i ytterkanterna // 3. Slå ihop och städa bort överflödiga radbrytningar i början/slutet
let rec trimStart = function (String.concat "\n" dedented).Trim('\n', '\r')
| Text t :: rest ->
let trimmed = t.TrimStart('\n', '\r', ' ', '\t')
if trimmed = "" then trimStart rest else Text trimmed :: rest
| other -> other
let rec trimEnd = function
| Text t :: rest ->
let trimmed = t.TrimEnd('\n', '\r', ' ', '\t')
if trimmed = "" then trimEnd rest else Text trimmed :: rest
| other -> other
dedented |> trimStart |> List.rev |> trimEnd |> List.rev
let positional f: TagRenderer = let positional f: TagRenderer =
fun _ (args: string list) _ children -> f args children fun meta (args: (string*string) list) children -> f meta (List.map snd args) children
let onlyArgs f =
fun _ args kwargs children -> f args kwargs
let getArgIdx (args: (string*string) list) index defaultVal = let getArgIdx (args: (string*string) list) index defaultVal =
let unnamed = args |> List.filter (fun (k, _) -> k = "") let unnamed = args |> List.filter (fun (k, _) -> k = "")
@ -141,6 +87,10 @@ module Utils =
let withArg2 (k1: string) (d1: string) (k2: string) (d2: string) (f: string -> string -> InlineNode list -> InlineNode) = let withArg2 (k1: string) (d1: string) (k2: string) (d2: string) (f: string -> string -> InlineNode list -> InlineNode) =
fun _ args children -> f (getArg args k1 0 d1) (getArg args k2 1 d2) children fun _ args children -> f (getArg args k1 0 d1) (getArg args k2 1 d2) children
let nameToElement (n:string) : TagRenderer =
fun meta args children -> Element(n, args, children)
@ -162,49 +112,52 @@ module Parser =
let isSection (name: string) = name.EndsWith("section") let isSection (name: string) = name.EndsWith("section")
let pNewline = newline let pNewline = newline
let pArg =
spaces >>.
choice [
attempt (many1Chars (asciiLetter <|> digit <|> anyOf "-_")
.>> spaces .>> pchar '=' .>> spaces
.>>. manyChars (noneOf ",]"))
|>> fun (k, v) -> (k, v.Trim())
let pNamedArg = // Fallback: bara "värde" (ges en tom nyckel)
// Leta efter "nyckel=värde" manyChars (noneOf ",]") |>> fun v -> ("", v.Trim())
attempt (many1Chars (asciiLetter <|> digit <|> anyOf "-_") ] .>> spaces
.>> spaces .>> pchar '=' .>> spaces) let pArgs = between (pstring "[") (pstring "]") (sepBy pArg (pstring ","))
.>>. manyChars (noneOf ",]")
|>> fun (k, v) -> (k, v.Trim())
let pPositionalArg =
// Bara "värde"
manyChars (noneOf ",]") |>> fun v -> ("", v.Trim())
let pSingleArg = spaces >>. (pNamedArg <|> pPositionalArg) .>> spaces
let pArgs =
between (pstring "[") (pstring "]") (sepBy pSingleArg (pchar ','))
>>= fun args ->
// Validera att positionella argument alltid kommer först
let rec validate canBePositional = function
| [] -> preturn args // Allt är okej, returnera listan
| ("", _) :: tail ->
if not canBePositional then
fail "Syntaxfel: Positionella argument får inte komma efter namngivna argument."
else validate true tail
| _ :: tail ->
validate false tail
validate true args
// --- 1. Måsvinge-parser (för @kommandon) --- // --- 1. Måsvinge-parser (för @kommandon) ---
// Lägg till en referens för pBody högst upp bland dina referenser let pRawBody, pRawBodyRef = createParserForwardedToRef<string, unit>()
// (Bör ligga precis under let pInline, pInlineRef = ...) pRawBodyRef.Value <-
let pBody, pBodyRef = createParserForwardedToRef<InlineNode list, unit>() many (choice [
many1Chars (noneOf "{}")
pchar '{' >>. pRawBodyRef.Value .>> pchar '}' |>> sprintf "{%s}"
]) |>> String.concat ""
let pBody =
between (pstring "{") (pstring "}") pRawBodyRef.Value >>= fun raw ->
// En mer tillåtande parser isolerad för innehållet inuti {...}
let pInnerInline =
choice [
attempt pInline
// Fångar upp dubbla radbrytningar och måsvingar som pInline normalt blockerar
many1Chars (anyOf "\r\n{}") |>> Text
]
match run (many pInnerInline .>> eof) (Utils.smartDedent raw) with
| Success(n, _, _) -> preturn n
| Failure(m, _, _) -> fail m
// --- 2. Parentes-parser (för @(...) med sträng-stöd) --- // --- 2. Parentes-parser (för @(...) med sträng-stöd) ---
let pParenBody, pParenBodyRef = createParserForwardedToRef<string, unit>() let pParenBody, pParenBodyRef = createParserForwardedToRef<string, unit>()
// En inre parser som känner igen F#-strängar och escape-tecken (\")
let pFSharpString = let pFSharpString =
let normal = many1Chars (noneOf "\"\\") let normal = many1Chars (noneOf "\"\\")
let escaped = pstring "\\" >>. anyChar |>> sprintf "\\%c" let escaped = pstring "\\" >>. anyChar |>> sprintf "\\%c"
pstring "\"" .>>. manyStrings (normal <|> escaped) .>>. pstring "\"" pstring "\"" .>>. manyStrings (normal <|> escaped) .>>. pstring "\""
|>> fun ((start, inner), end_) -> start + inner + end_ |>> fun ((start, inner), end_) -> start + inner + end_
// Själva loopen letar nu efter strängar FÖRST, sen vanlig text, och sist inre parenteser
pParenBodyRef.Value <- pParenBodyRef.Value <-
manyStrings (choice [ manyStrings (choice [
pFSharpString pFSharpString
@ -219,38 +172,19 @@ module Parser =
// --- Övriga inline-parsers --- // --- Övriga inline-parsers ---
let pMultilineCode = let pMultilineCode =
pstring "@\"\"\"" >>. manyCharsTill anyChar (pstring "\"\"\"") pstring "@\"\"\"" >>. manyCharsTill anyChar (pstring "\"\"\"")
|>> fun c -> Expr(c, None) |>> fun c -> Expr(Utils.smartDedent c, None)
// pInlineCommand använder nu forward-referensen pBodyRef
let pInlineCommand = let pInlineCommand =
attempt (pchar '@' >>. many1Chars asciiLetter) attempt (
pchar '@' >>. many1Chars asciiLetter >>= fun name ->
if isSection name then fail "Sektioner är block-element."
else preturn name
)
.>>. opt pArgs .>>. opt pArgs
.>>. opt pBody .>>. opt pBody
|>> fun ((name, argsOpt), bodyOpt) -> |>> fun ((n, a), b) -> Element(n, defaultArg a [], defaultArg b [])
let rawArgs = defaultArg argsOpt []
let posArgs = rawArgs |> List.choose (fun (k, v) -> if k = "" then Some v else None)
let kwargs = rawArgs |> List.filter (fun (k, _) -> k <> "") |> Map.ofList
// dedentNodes anropas här från Utils // MÅSTE tilldelas efter att alla pExpr, pInlineCommand etc. är definierade
let children = defaultArg bodyOpt [] |> Utils.dedentNodes
Command(name, posArgs, kwargs, children)
// Nu när pInlineCommand, pExpr och pMultilineCode är definierade
// kan vi skapa pInnerInline
let pInnerInline =
choice [
attempt pInlineCommand
attempt pExpr
pMultilineCode
many1Chars (noneOf "@}") |>> Text
pchar '@' |>> fun _ -> Text "@"
]
// Tilldela värdet till pBodyRef
pBodyRef.Value <- between (pstring "{") (pstring "}") (many pInnerInline)
// Tilldela värdet till pInlineRef
pInlineRef.Value <- choice [ pInlineRef.Value <- choice [
pMultilineCode pMultilineCode
pExpr pExpr
@ -310,13 +244,47 @@ module Execution =
open Ast open Ast
let rec transform (metadata: Map<string, string>) (prelude: Map<string, TagRenderer>) (eval: IEvaluator) = function let rec transform (metadata: Map<string, string>) (prelude: Map<string, TagRenderer>) (eval: IEvaluator) = function
| Command(name, args, kwargs, children) when prelude.ContainsKey name -> | Element(n, a, c) when prelude.ContainsKey n ->
prelude.[name] metadata args kwargs (children |> List.map (transform metadata prelude eval)) prelude.[n] metadata a (c |> List.map (transform metadata prelude eval))
| Command(n, _, _ ,_) -> failwithf "%s is not a defined command" n | Element(n, a, c) ->
Element(n, a, c |> List.map (transform metadata prelude eval))
| Expr(c, _) -> RawHtml (eval.Evaluate c) | Expr(c, _) -> RawHtml (eval.Evaluate c)
| n -> n | n -> n
module HtmlPrinter =
open Ast
let voidElements = [ "area"; "base"; "br"; "col"; "command"; "embed"; "hr"; "img"; "input"; "keygen"; "link"; "meta"; "param"; "source"; "track"; "wbr"]
let renderAttributes args =
args
|> List.map (fun m -> sprintf "%s=\"%s\"" (fst m) (snd m))
|> String.concat " "
let rec renderInline =
function
| Text t -> WebUtility.HtmlEncode t
| RawHtml h -> h
| Element(t,a,c) when List.contains t voidElements -> sprintf "<%s %s />" t (renderAttributes a)
| Element(t, a, c) -> sprintf "<%s %s>%s</%s>" t (renderAttributes a) (c |> List.map renderInline |> String.concat "") t
| _ -> ""
let render (header, blocks) =
blocks
|> List.map (function
| Paragraph [RawHtml html] ->
html
// 2. (Frivillig) Mer robust guard om parsern råkar lämna kvar
// blanksteg (Text " ") runt ditt @md-block i samma paragraf
| Paragraph nodes when nodes |> List.forall (function
| RawHtml _ -> true
| Text t when System.String.IsNullOrWhiteSpace(t) -> true
| _ -> false) ->
nodes
|> List.choose (function RawHtml h -> Some h | _ -> None)
|> String.concat "\n"
| Paragraph c -> sprintf "<p>%s</p>" (c |> List.map renderInline |> String.concat "")
| Section(l, _, c) -> sprintf "<h%d>%s</h%d>" l (c |> List.map renderInline |> String.concat "") l)
|> String.concat "\n"
module Evaluators = module Evaluators =
@ -325,8 +293,8 @@ module Evaluators =
open FSharp.Compiler.Interactive.Shell open FSharp.Compiler.Interactive.Shell
type FsiEvaluator() = type FsiEvaluator() =
let sbOut = StringBuilder() let sbOut = new StringBuilder()
let sbErr = StringBuilder() let sbErr = new StringBuilder()
let inStream = new StringReader("") let inStream = new StringReader("")
let outStream = new StringWriter(sbOut) let outStream = new StringWriter(sbOut)
let errStream = new StringWriter(sbErr) let errStream = new StringWriter(sbErr)

View file

@ -1,8 +1,5 @@
namespace Fibble.FibLib namespace Fibble.FibLib
open System
open System.Xml.Schema
module Pandoc = module Pandoc =
open System.Diagnostics open System.Diagnostics
@ -20,16 +17,14 @@ module Pandoc =
use proc = Process.Start startInfo use proc = Process.Start startInfo
// Skriv markdown till Pandoc // Skriv markdown till Pandoc
use stdin = proc.StandardInput use stdin = proc.StandardInput
stdin.WriteLine markdownText stdin.Write markdownText
stdin.Close() // Måste stängas Pandoc vet att texten är slut stdin.Close() // Måste stängas Pandoc vet att texten är slut
// Läs ut resultatet // Läs ut resultatet
let htmlOutput = proc.StandardOutput.ReadToEnd() let htmlOutput = proc.StandardOutput.ReadToEnd()
let errorOutput = proc.StandardError.ReadToEnd() let errorOutput = proc.StandardError.ReadToEnd()
proc.WaitForExit() proc.WaitForExit()
Console.WriteLine(htmlOutput)
if proc.ExitCode = 0 then if proc.ExitCode = 0 then
htmlOutput.Trim() htmlOutput.Trim()
else else
@ -40,5 +35,4 @@ module Pandoc =
sprintf "\n<pre>%s</pre> and <pre>%s</pre>" ex.Message markdownText sprintf "\n<pre>%s</pre> and <pre>%s</pre>" ex.Message markdownText
let mdToHtml markdownText = let mdToHtml markdownText =
let res= toHtml "markdown" markdownText toHtml "markdown" markdownText
res

View file

@ -1,53 +0,0 @@
namespace Fibble.FibLib
open FSharp.Compiler.Text
open Fibble.FibLib.Ast
module Helpers =
let emptyAttr ={id=""; classes=[]; kvp=[]}
let ah cls kvp =
{id=""; classes = [cls]; kvp = Map.toList kvp }
let onlyChildren constructor : TagRenderer =
fun _ _ _ children -> constructor(children)
open Helpers
module ConstructionHelpers =
let linebreak _ _ _ _ = LineBreak
let softbreak _ _ _ _ = SoftBreak
let value : TagRenderer =
fun meta args _ _ ->
match Map.tryFind args.Head meta with
| Some(v) -> Text v
| None -> Text $"value {args.Head} not found in metadata"
let emph = onlyChildren Emph
let underline = onlyChildren Underline
let strong = onlyChildren Strong
let strikeout = onlyChildren Strikeout
let superscript = onlyChildren Superscript
let subscript = onlyChildren Subscript
let image : TagRenderer =
fun _ args kwargs children ->
let attributes = ah "inlineImage" kwargs
Image(attributes,children, args[0])
let code : TagRenderer =
fun _ _ kwargs children ->
let attributes = ah "inlineCode" kwargs
match children with
| [Text(c)] -> InlineNode.Code(attributes, c)
| _ -> failwith "Code tag was not Text,"
let link : TagRenderer =
fun _ args kwargs children ->
let attributes = ah "link" kwargs
Link(attributes,Target(args[0], children))
// blocks
let paragraph _ _ _ children = Paragraph(children)
let plain _ _ _ children = Plain(children)

View file

@ -127,6 +127,10 @@ let processDocument (source: string) =
// Hjälpfunktion: igenom trädet och byt ut @value{...} mot faktiskt data från YAML // Hjälpfunktion: igenom trädet och byt ut @value{...} mot faktiskt data från YAML
let rec resolveMeta = function let rec resolveMeta = function
| MetaRef key ->
match metadata.TryFind key with
| Some v -> Text v
| None -> Text (sprintf "[Saknad meta: %s]" key)
| Element(tag, args, children) -> | Element(tag, args, children) ->
Element(tag, args, children |> List.map resolveMeta) Element(tag, args, children |> List.map resolveMeta)
| other -> other | other -> other