From 1a3186aa252bb91017e3da3e23e749c9b70d45dc Mon Sep 17 00:00:00 2001
From: Avi Avni
Date: Sun, 19 Jun 2016 06:16:17 +0300
Subject: [PATCH 001/108] add range to MarkdownParagraph and MarkdownSpan
---
src/Common/StringParsing.fs | 106 +++++++++---
src/FSharp.CodeFormat/CommentFilter.fs | 10 +-
src/FSharp.Literate/Document.fs | 2 +-
src/FSharp.Literate/Evaluator.fs | 8 +-
src/FSharp.Literate/Formatting.fs | 10 +-
src/FSharp.Literate/Main.fs | 4 +-
src/FSharp.Literate/ParseScript.fs | 24 +--
src/FSharp.Literate/Transformations.fs | 54 +++----
src/FSharp.Markdown/HtmlFormatting.fs | 64 ++++----
src/FSharp.Markdown/LatexFormatting.fs | 48 +++---
src/FSharp.Markdown/Main.fs | 10 +-
src/FSharp.Markdown/Markdown.fs | 96 +++++------
src/FSharp.Markdown/MarkdownParser.fs | 195 ++++++++++++-----------
src/FSharp.MetadataFormat/Main.fs | 14 +-
tests/FSharp.Literate.Tests/EvalTests.fs | 16 +-
tests/FSharp.Literate.Tests/Tests.fs | 26 +--
tests/FSharp.Markdown.Tests/Markdown.fs | 36 ++---
17 files changed, 394 insertions(+), 329 deletions(-)
diff --git a/src/Common/StringParsing.fs b/src/Common/StringParsing.fs
index 0f376562a..8d2ce0d8c 100644
--- a/src/Common/StringParsing.fs
+++ b/src/Common/StringParsing.fs
@@ -14,44 +14,57 @@ open FSharp.Collections
module String =
/// Matches when a string is a whitespace or null
- let (|WhiteSpace|_|) s =
+ let (|WhiteSpaceS|_|) (s) =
+ if String.IsNullOrWhiteSpace(s) then Some() else None
+
+ /// Matches when a string is a whitespace or null
+ let (|WhiteSpace|_|) (s, n: int) =
if String.IsNullOrWhiteSpace(s) then Some() else None
/// Matches when a string does starts with non-whitespace
- let (|Unindented|_|) (s:string) =
+ let (|Unindented|_|) (s:string, n:int) =
if not (String.IsNullOrWhiteSpace(s)) && s.TrimStart() = s then Some() else None
/// Returns a string trimmed from both start and end
- let (|TrimBoth|) (text:string) = text.Trim()
+ let (|TrimBothS|) (text:string) = text.Trim()
+ /// Returns a string trimmed from both start and end
+ let (|TrimBoth|) (text:string, n:int) = (text.Trim(), n)
/// Returns a string trimmed from the end
- let (|TrimEnd|) (text:string) = text.TrimEnd()
+ let (|TrimEnd|) (text:string, n:int) = (text.TrimEnd(), n)
/// Returns a string trimmed from the start
- let (|TrimStart|) (text:string) = text.TrimStart()
+ let (|TrimStart|) (text:string, n:int) = (text.TrimStart(), n)
/// Retrusn a string trimmed from the end using characters given as a parameter
- let (|TrimEndUsing|) chars (text:string) = text.TrimEnd(Array.ofSeq chars)
+ let (|TrimEndUsing|) chars (text:string, n:int) = text.TrimEnd(Array.ofSeq chars)
/// Returns a string trimmed from the start together with
/// the number of skipped whitespace characters
- let (|TrimStartAndCount|) (text:string) =
+ let (|TrimStartAndCount|) (text:string, n:int) =
let trimmed = text.TrimStart([|' '; '\t'|])
let len = text.Length - trimmed.Length
- len, text.Substring(0, len).Replace("\t", " ").Length, trimmed
+ len, text.Substring(0, len).Replace("\t", " ").Length, (trimmed, n)
/// Matches when a string starts with any of the specified sub-strings
- let (|StartsWithAny|_|) (starts:seq) (text:string) =
+ let (|StartsWithAny|_|) (starts:seq) (text:string, n:int) =
if starts |> Seq.exists (text.StartsWith) then Some() else None
/// Matches when a string starts with the specified sub-string
- let (|StartsWith|_|) (start:string) (text:string) =
+ let (|StartsWithS|_|) (start:string) (text:string) =
if text.StartsWith(start) then Some(text.Substring(start.Length)) else None
/// Matches when a string starts with the specified sub-string
+ let (|StartsWith|_|) (start:string) (text:string, n:int) =
+ if text.StartsWith(start) then Some(text.Substring(start.Length), n) else None
+ /// Matches when a string starts with the specified sub-string
/// The matched string is trimmed from all whitespace.
- let (|StartsWithTrim|_|) (start:string) (text:string) =
+ let (|StartsWithTrimS|_|) (start:string) (text:string) =
if text.StartsWith(start) then Some(text.Substring(start.Length).Trim()) else None
+ /// Matches when a string starts with the specified sub-string
+ /// The matched string is trimmed from all whitespace.
+ let (|StartsWithTrim|_|) (start:string) (text:string, n:int) =
+ if text.StartsWith(start) then Some(text.Substring(start.Length).Trim(), n) else None
/// Matches when a string starts with the specified sub-string (ignoring whitespace at the start)
/// The matched string is trimmed from all whitespace.
- let (|StartsWithNTimesTrimIgnoreStartWhitespace|_|) (start:string) (text:string) =
+ let (|StartsWithNTimesTrimIgnoreStartWhitespace|_|) (start:string) (text:string, n:int) =
if text.Contains(start) then
let beforeStart = text.Substring(0, text.IndexOf(start))
if String.IsNullOrWhiteSpace (beforeStart) then
@@ -67,12 +80,26 @@ module String =
/// Matches when a string starts with the given value and ends
/// with a given value (and returns the rest of it)
- let (|StartsAndEndsWith|_|) (starts, ends) (s:string) =
+ let (|StartsAndEndsWithS|_|) (starts, ends) (s:string) =
if s.StartsWith(starts) && s.EndsWith(ends) &&
s.Length >= starts.Length + ends.Length then
Some(s.Substring(starts.Length, s.Length - starts.Length - ends.Length))
else None
+ /// Matches when a string starts with the given value and ends
+ /// with a given value (and returns the rest of it)
+ let (|StartsAndEndsWith|_|) (starts, ends) (s:string, n:int) =
+ if s.StartsWith(starts) && s.EndsWith(ends) &&
+ s.Length >= starts.Length + ends.Length then
+ Some(s.Substring(starts.Length, s.Length - starts.Length - ends.Length), n)
+ else None
+
+ /// Matches when a string starts with the given value and ends
+ /// with a given value (and returns trimmed body)
+ let (|StartsAndEndsWithTrimS|_|) args = function
+ | StartsAndEndsWithS args (TrimBothS res) -> Some res
+ | _ -> None
+
/// Matches when a string starts with the given value and ends
/// with a given value (and returns trimmed body)
let (|StartsAndEndsWithTrim|_|) args = function
@@ -85,7 +112,7 @@ module String =
///
/// let (StartsWithRepeated "/\" (2, " abc")) = "/\/\ abc"
///
- let (|StartsWithRepeated|_|) (repeated:string) (text:string) =
+ let (|StartsWithRepeated|_|) (repeated:string) (text:string, ln:int) =
let rec loop i =
if i = text.Length then i
elif text.[i] <> repeated.[i % repeated.Length] then i
@@ -93,7 +120,7 @@ module String =
let n = loop 0
if n = 0 || n % repeated.Length <> 0 then None
- else Some(n/repeated.Length, text.Substring(n, text.Length - n))
+ else Some(n/repeated.Length, (text.Substring(n, text.Length - n), ln))
/// Ignores everything until a end-line character is detected, returns the remaining string.
let (|SkipSingleLine|) (text:string) =
@@ -114,12 +141,11 @@ module String =
FSharp.Formatting.Common.Log.warnf "could not skip a line of %s, because no line-ending character was found!" text
result
-
/// Matches when a string starts with a sub-string wrapped using the
/// opening and closing sub-string specified in the parameter.
/// For example "[aa]bc" is wrapped in [ and ] pair. Returns the wrapped
/// text together with the rest.
- let (|StartsWithWrapped|_|) (starts:string, ends:string) (text:string) =
+ let (|StartsWithWrappedS|_|) (starts:string, ends:string) (text:string) =
if text.StartsWith(starts) then
let id = text.IndexOf(ends, starts.Length)
if id >= 0 then
@@ -129,10 +155,24 @@ module String =
else None
else None
+ /// Matches when a string starts with a sub-string wrapped using the
+ /// opening and closing sub-string specified in the parameter.
+ /// For example "[aa]bc" is wrapped in [ and ] pair. Returns the wrapped
+ /// text together with the rest.
+ let (|StartsWithWrapped|_|) (starts:string, ends:string) (text:string, n:int) =
+ if text.StartsWith(starts) then
+ let id = text.IndexOf(ends, starts.Length)
+ if id >= 0 then
+ let wrapped = text.Substring(starts.Length, id - starts.Length)
+ let rest = text.Substring(id + ends.Length, text.Length - id - ends.Length)
+ Some(wrapped, (rest, n))
+ else None
+ else None
+
/// Matches when a string consists of some number of
/// complete repetitions of a specified sub-string.
- let (|EqualsRepeated|_|) repeated = function
- | StartsWithRepeated repeated (n, "") -> Some()
+ let (|EqualsRepeated|_|) (repeated, n:int) = function
+ | StartsWithRepeated repeated (n, ("", _)) -> Some()
| _ -> None
/// Given a list of lines indented with certan number of whitespace
@@ -197,8 +237,8 @@ module Lines =
/// Removes blank lines from the start and the end of a list
let (|TrimBlank|) lines =
lines
- |> List.skipWhile String.IsNullOrWhiteSpace |> List.rev
- |> List.skipWhile String.IsNullOrWhiteSpace |> List.rev
+ |> List.skipWhile (fun (s, n) -> String.IsNullOrWhiteSpace s) |> List.rev
+ |> List.skipWhile (fun (s, n) -> String.IsNullOrWhiteSpace s) |> List.rev
/// Matches when there are some lines at the beginning that are
/// either empty (or whitespace) or start with the specified string.
@@ -213,7 +253,7 @@ module Lines =
/// either empty (or whitespace) or start with at least 4 spaces (a tab counts as 4 spaces here).
/// Returns all such lines from the beginning until a different line and
/// the number of spaces the first line started with.
- let (|TakeCodeBlock|_|) (input:string list) =
+ let (|TakeCodeBlock|_|) (input:(string * int) list) =
let spaceNum = 4
//match input with
//| h :: _ ->
@@ -225,20 +265,20 @@ module Lines =
let normalized = s.Replace("\t", " ")
normalized.Length >= spaceNum &&
normalized.Substring(0, spaceNum) = System.String(' ', spaceNum)
- match List.partitionWhile (fun s ->
+ match List.partitionWhile (fun (s, n) ->
String.IsNullOrWhiteSpace s || startsWithSpaces s) input with
| matching, rest when matching <> [] && spaceNum >= 4 ->
Some(spaceNum, matching, rest)
| _ -> None
/// Removes whitespace lines from the beginning of the list
- let (|TrimBlankStart|) = List.skipWhile (String.IsNullOrWhiteSpace)
+ let (|TrimBlankStart|) = List.skipWhile (fun (s:string, n:int) -> String.IsNullOrWhiteSpace s)
/// Trims all lines of the current paragraph
let (|TrimParagraphLines|) lines =
lines
// first remove all whitespace on the beginning of the line
- |> List.map (fun (s:string) -> s.TrimStart())
+ |> List.map (fun (s:string, n:int) -> s.TrimStart())
// Now remove all additional spaces at the end, but keep two spaces if existent
|> List.map (fun s ->
let endsWithTwoSpaces = s.EndsWith(" ")
@@ -258,7 +298,21 @@ open System.Collections.Generic
/// recognize `key1=value, key2=value` and also `key1:value, key2:value`
/// The key of the command should be identifier with just
/// characters in it - otherwise, the parsing fails.
-let (|ParseCommands|_|) (str:string) =
+let (|ParseCommandsS|_|) (str:string) =
+ let kvs =
+ [ for cmd in str.Split(',') do
+ let kv = cmd.Split([| '='; ':' |])
+ if kv.Length = 2 then yield kv.[0].Trim(), kv.[1].Trim()
+ elif kv.Length = 1 then yield kv.[0].Trim(), "" ]
+ let allKeysValid =
+ kvs |> Seq.forall (fst >> Seq.forall (fun c -> Char.IsLetter c || c = '_' || c = '-'))
+ if allKeysValid && kvs <> [] then Some(dict kvs) else None
+
+/// Utility for parsing commands. Commands can be used in different places. We
+/// recognize `key1=value, key2=value` and also `key1:value, key2:value`
+/// The key of the command should be identifier with just
+/// characters in it - otherwise, the parsing fails.
+let (|ParseCommands|_|) (str:string, n:int) =
let kvs =
[ for cmd in str.Split(',') do
let kv = cmd.Split([| '='; ':' |])
diff --git a/src/FSharp.CodeFormat/CommentFilter.fs b/src/FSharp.CodeFormat/CommentFilter.fs
index 279f5e176..8364862e2 100644
--- a/src/FSharp.CodeFormat/CommentFilter.fs
+++ b/src/FSharp.CodeFormat/CommentFilter.fs
@@ -49,12 +49,12 @@ let rec getSnippets (state:NamedSnippet option) (snippets:NamedSnippet list)
match source with
| [] -> snippets
| (line, tokens)::rest ->
- let text = lines.[line].Trim()
+ let text = lines.[line].Trim(), line
match state, text with
// We're not inside a snippet and we found a beginning of one
| None, String.StartsWithTrim "//" (String.StartsWithTrim "[snippet:" title) ->
- let title = title.Substring(0, title.IndexOf(']'))
+ let title = (fst title).Substring(0, (fst title).IndexOf(']'))
getSnippets (Some(title, [])) snippets rest lines
// Not inside a snippet and there is a usual line
| None, _ ->
@@ -92,7 +92,7 @@ let rec shrinkOmittedCode (text:StringBuilder) line content (source:Snippet) =
// Take the next line, merge comments and continue looking for end
| [], (line, content)::source ->
shrinkOmittedCode (text.Append("\n")) line (mergeComments content None []) source
- | (String.StartsAndEndsWithTrim ("(*", "*)") "[/omit]", tok)::rest, source
+ | (String.StartsAndEndsWithTrimS ("(*", "*)") "[/omit]", tok)::rest, source
when tok.TokenName = "COMMENT" ->
line, rest, source, text
| (str, tok)::rest, _ ->
@@ -105,13 +105,13 @@ let rec shrinkOmittedCode (text:StringBuilder) line content (source:Snippet) =
let rec shrinkLine line (content:SnippetLine) (source:Snippet) =
match content with
| [] -> [], source
- | (String.StartsAndEndsWithTrim ("(*", "*)") (String.StartsAndEndsWithTrim ("[omit:", "]") body), (tok:FSharpTokenInfo))::rest
+ | (String.StartsAndEndsWithTrimS ("(*", "*)") (String.StartsAndEndsWithTrimS ("[omit:", "]") body), (tok:FSharpTokenInfo))::rest
when tok.TokenName = "COMMENT" ->
let line, remcontent, source, text =
shrinkOmittedCode (StringBuilder()) line rest source
let line, source = shrinkLine line remcontent source
(body, { tok with TokenName = "OMIT" + (text.ToString()) })::line, source
- | (String.StartsWithTrim "//" (String.StartsAndEndsWith ("[fsi:", "]") fsi), (tok:FSharpTokenInfo))::rest ->
+ | (String.StartsWithTrimS "//" (String.StartsAndEndsWithS ("[fsi:", "]") fsi), (tok:FSharpTokenInfo))::rest ->
let line, source = shrinkLine line rest source
(fsi, { tok with TokenName = "FSI"})::line, source
| (str, tok)::rest ->
diff --git a/src/FSharp.Literate/Document.fs b/src/FSharp.Literate/Document.fs
index 0441373d4..e7bc9323b 100644
--- a/src/FSharp.Literate/Document.fs
+++ b/src/FSharp.Literate/Document.fs
@@ -112,4 +112,4 @@ type LiterateDocument(paragraphs, formattedTips, links, source, sourceFile, erro
/// Markdown documents.
module Matching =
let (|LiterateParagraph|_|) = function
- | EmbedParagraphs(:? LiterateParagraph as lp) -> Some lp | _ -> None
\ No newline at end of file
+ | EmbedParagraphs(:? LiterateParagraph as lp, _) -> Some lp | _ -> None
\ No newline at end of file
diff --git a/src/FSharp.Literate/Evaluator.fs b/src/FSharp.Literate/Evaluator.fs
index 27a87486f..2241114d5 100644
--- a/src/FSharp.Literate/Evaluator.fs
+++ b/src/FSharp.Literate/Evaluator.fs
@@ -111,7 +111,7 @@ type FsiEvaluator(?options:string[], ?fsiObj) =
/// Registered transformations for pretty printing values
/// (the default formats value as a string and emits single CodeBlock)
let mutable valueTransformations =
- [ (fun (o:obj, t:Type) ->Some([CodeBlock (sprintf "%A" o, "", "")]) ) ]
+ [ (fun (o:obj, t:Type) ->Some([CodeBlock (sprintf "%A" o, "", "", None)]) ) ]
/// Register a function that formats (some) values that are produced by the evaluator.
/// The specified function should return 'Some' when it knows how to format a value
@@ -130,12 +130,12 @@ type FsiEvaluator(?options:string[], ?fsiObj) =
match result :?> FsiEvaluationResult, kind with
| result, FsiEmbedKind.Output ->
let s = defaultArg result.Output "No output has been produced."
- [ CodeBlock(s.Trim(), "", "") ]
+ [ CodeBlock(s.Trim(), "", "", None) ]
| { ItValue = Some v }, FsiEmbedKind.ItValue
| { Result = Some v }, FsiEmbedKind.Value ->
valueTransformations |> Seq.pick (fun f -> lock lockObj (fun () -> f v))
- | _, FsiEmbedKind.ItValue -> [ CodeBlock ("No value has been returned", "", "") ]
- | _, FsiEmbedKind.Value -> [ CodeBlock ("No value has been returned", "", "") ]
+ | _, FsiEmbedKind.ItValue -> [ CodeBlock ("No value has been returned", "", "", None) ]
+ | _, FsiEmbedKind.Value -> [ CodeBlock ("No value has been returned", "", "", None) ]
/// Evaluates the given text in an fsi session and returns
/// an FsiEvaluationResult.
diff --git a/src/FSharp.Literate/Formatting.fs b/src/FSharp.Literate/Formatting.fs
index 9d02c7c23..93bbad5a3 100644
--- a/src/FSharp.Literate/Formatting.fs
+++ b/src/FSharp.Literate/Formatting.fs
@@ -27,8 +27,8 @@ module Formatting =
/// Try find first-level heading in the paragraph collection
let findHeadings paragraphs generateAnchors (outputKind:OutputKind) =
paragraphs |> Seq.tryPick (function
- | (Heading(1, text)) ->
- let doc = MarkdownDocument([Span(text)], dict [])
+ | Heading(1, text, r) ->
+ let doc = MarkdownDocument([Span(text, r)], dict [])
Some(format doc generateAnchors outputKind)
| _ -> None)
@@ -37,13 +37,13 @@ module Formatting =
let getSourceDocument (doc:LiterateDocument) =
match doc.Source with
| LiterateSource.Markdown text ->
- doc.With(paragraphs = [CodeBlock (text, "", "")])
+ doc.With(paragraphs = [CodeBlock (text, "", "", None)])
| LiterateSource.Script snippets ->
let paragraphs =
[ for Snippet(name, lines) in snippets do
if snippets.Length > 1 then
- yield Heading(3, [Literal name])
- yield EmbedParagraphs(FormattedCode(lines)) ]
+ yield Heading(3, [Literal(name, None)], None)
+ yield EmbedParagraphs(FormattedCode(lines), None) ]
doc.With(paragraphs = paragraphs)
// --------------------------------------------------------------------------------------
diff --git a/src/FSharp.Literate/Main.fs b/src/FSharp.Literate/Main.fs
index bc7b0cef0..37a7314ac 100644
--- a/src/FSharp.Literate/Main.fs
+++ b/src/FSharp.Literate/Main.fs
@@ -104,7 +104,7 @@ type Literate private () =
static member WriteHtml(doc:LiterateDocument, ?prefix, ?lineNumbers, ?generateAnchors) =
let ctx = formattingContext None (Some OutputKind.Html) prefix lineNumbers None generateAnchors None None
let doc = Transformations.replaceLiterateParagraphs ctx doc
- let doc = MarkdownDocument(doc.Paragraphs @ [InlineBlock doc.FormattedTips], doc.DefinedLinks)
+ let doc = MarkdownDocument(doc.Paragraphs @ [InlineBlock(doc.FormattedTips, None)], doc.DefinedLinks)
let sb = new System.Text.StringBuilder()
use wr = new StringWriter(sb)
Html.formatMarkdown wr ctx.GenerateHeaderAnchors Environment.NewLine true doc.DefinedLinks doc.Paragraphs
@@ -113,7 +113,7 @@ type Literate private () =
static member WriteHtml(doc:LiterateDocument, writer:TextWriter, ?prefix, ?lineNumbers, ?generateAnchors) =
let ctx = formattingContext None (Some OutputKind.Html) prefix lineNumbers None generateAnchors None None
let doc = Transformations.replaceLiterateParagraphs ctx doc
- let doc = MarkdownDocument(doc.Paragraphs @ [InlineBlock doc.FormattedTips], doc.DefinedLinks)
+ let doc = MarkdownDocument(doc.Paragraphs @ [InlineBlock(doc.FormattedTips, None)], doc.DefinedLinks)
Html.formatMarkdown writer ctx.GenerateHeaderAnchors Environment.NewLine true doc.DefinedLinks doc.Paragraphs
static member WriteLatex(doc:LiterateDocument, ?prefix, ?lineNumbers, ?generateAnchors) =
diff --git a/src/FSharp.Literate/ParseScript.fs b/src/FSharp.Literate/ParseScript.fs
index 70edf8308..af7fefc81 100644
--- a/src/FSharp.Literate/ParseScript.fs
+++ b/src/FSharp.Literate/ParseScript.fs
@@ -35,7 +35,7 @@ module internal CodeBlockUtils =
let rec readComments inWhite acc = function
| Token(TokenKind.Comment, text, _)::tokens when not inWhite->
readComments false (text::acc) tokens
- | Token(TokenKind.Default, String.WhiteSpace _, _)::tokens ->
+ | Token(TokenKind.Default, String.WhiteSpaceS _, _)::tokens ->
readComments true acc tokens
| [] -> Some(String.concat "" (List.rev acc))
| _ -> None
@@ -54,7 +54,7 @@ module internal CodeBlockUtils =
cend
match lines with
- | (ConcatenatedComments(String.StartsAndEndsWith ("(***", "***)") (ParseCommands cmds)))::lines ->
+ | (ConcatenatedComments(String.StartsAndEndsWithS ("(***", "***)") (ParseCommandsS cmds)))::lines ->
// Ended with a command, yield comment, command & parse the next as a snippet
let cend = findCommentEnd comment
yield BlockComment (comment.Substring(0, cend))
@@ -68,7 +68,7 @@ module internal CodeBlockUtils =
yield BlockComment (comment.Substring(0, cend))
yield! collectSnippet [] lines
- | (Line[Token(TokenKind.Comment, String.StartsWith "(**" text, _)])::lines ->
+ | (Line[Token(TokenKind.Comment, String.StartsWithS "(**" text, _)])::lines ->
// Another block of Markdown comment starting...
// Yield the previous snippet block and continue parsing more comments
let cend = findCommentEnd comment
@@ -94,13 +94,13 @@ module internal CodeBlockUtils =
BlockSnippet res
seq {
match lines with
- | (ConcatenatedComments(String.StartsAndEndsWith ("(***", "***)") (ParseCommands cmds)))::lines ->
+ | (ConcatenatedComments(String.StartsAndEndsWithS ("(***", "***)") (ParseCommandsS cmds)))::lines ->
// Found a special command, yield snippet, command and parse another snippet
if acc <> [] then yield blockSnippet acc
yield BlockCommand cmds
yield! collectSnippet [] lines
- | (Line[Token(TokenKind.Comment, String.StartsWith "(**" text, _)])::lines ->
+ | (Line[Token(TokenKind.Comment, String.StartsWithS "(**" text, _)])::lines ->
// Found a comment - yield snippet & switch to parsing comment state
// (Also trim leading spaces to support e.g.: `(** ## Hello **)`)
if acc <> [] then yield blockSnippet acc
@@ -132,19 +132,19 @@ module internal ParseScript =
// Reference to code snippet defined later
| BlockCommand(Command "include" ref)::blocks ->
- let p = EmbedParagraphs(CodeReference(ref))
+ let p = EmbedParagraphs(CodeReference(ref), None)
transformBlocks noEval (p::acc) defs blocks
| BlockCommand(Command "include-output" ref)::blocks ->
- let p = EmbedParagraphs(OutputReference(ref))
+ let p = EmbedParagraphs(OutputReference(ref), None)
transformBlocks noEval (p::acc) defs blocks
| BlockCommand(Command "include-it" ref)::blocks ->
- let p = EmbedParagraphs(ItValueReference(ref))
+ let p = EmbedParagraphs(ItValueReference(ref), None)
transformBlocks noEval (p::acc) defs blocks
| BlockCommand(Command "include-value" ref)::blocks ->
- let p = EmbedParagraphs(ValueReference(ref))
+ let p = EmbedParagraphs(ValueReference(ref), None)
transformBlocks noEval (p::acc) defs blocks
| BlockCommand(Command "raw" _) ::BlockSnippet(snip):: blocks ->
- let p = EmbedParagraphs(RawBlock(snip))
+ let p = EmbedParagraphs(RawBlock(snip), None)
transformBlocks noEval (p::acc) defs blocks
// Parse commands in [foo=bar,zoo], followed by a source code snippet
@@ -166,7 +166,7 @@ module internal ParseScript =
{ Evaluate = not (noEval || cmds.ContainsKey("do-not-eval"))
OutputName = outputName
Visibility = visibility }
- let code = EmbedParagraphs(LiterateCode(snip, opts))
+ let code = EmbedParagraphs(LiterateCode(snip, opts), None)
transformBlocks noEval (code::acc) defs blocks
// Unknown command
@@ -178,7 +178,7 @@ module internal ParseScript =
transformBlocks noEval acc defs blocks
// Ordinary F# code snippet
| BlockSnippet(snip)::blocks ->
- let p = EmbedParagraphs(FormattedCode(snip))
+ let p = EmbedParagraphs(FormattedCode(snip), None)
transformBlocks noEval (p::acc) defs blocks
// Markdown documentation block
| BlockComment(text)::blocks ->
diff --git a/src/FSharp.Literate/Transformations.fs b/src/FSharp.Literate/Transformations.fs
index 141a42ca0..daba38a90 100644
--- a/src/FSharp.Literate/Transformations.fs
+++ b/src/FSharp.Literate/Transformations.fs
@@ -21,10 +21,10 @@ module Transformations =
/// to colorize. We skip snippets that specify non-fsharp langauge e.g. [lang=csharp].
let rec collectCodeSnippets par = seq {
match par with
- | CodeBlock((String.StartsWithWrapped ("[", "]") (ParseCommands cmds, String.SkipSingleLine code)), language, _)
+ | CodeBlock((String.StartsWithWrappedS ("[", "]") (ParseCommandsS cmds, String.SkipSingleLine code)), language, _, _)
when (not (String.IsNullOrWhiteSpace(language)) && language <> "fsharp") || (cmds.ContainsKey("lang") && cmds.["lang"] <> "fsharp") -> ()
- | CodeBlock((String.StartsWithWrapped ("[", "]") (ParseCommands cmds, String.SkipSingleLine code)), _, _)
- | CodeBlock(Let (dict []) (cmds, code), _, _) ->
+ | CodeBlock((String.StartsWithWrappedS ("[", "]") (ParseCommandsS cmds, String.SkipSingleLine code)), _, _, _)
+ | CodeBlock(Let (dict []) (cmds, code), _, _, _) ->
let modul =
match cmds.TryGetValue("module") with
| true, v -> Some v | _ -> None
@@ -39,8 +39,8 @@ module Transformations =
/// Replace CodeBlock elements with formatted HTML that was processed by the F# snippets tool
/// (The dictionary argument is a map from original code snippets to formatted HTML snippets.)
let rec replaceCodeSnippets path (codeLookup:IDictionary<_, _>) = function
- | CodeBlock ((String.StartsWithWrapped ("[", "]") (ParseCommands cmds, String.SkipSingleLine code)), language, _)
- | CodeBlock(Let (dict []) (cmds, code), language, _) ->
+ | CodeBlock ((String.StartsWithWrappedS ("[", "]") (ParseCommandsS cmds, String.SkipSingleLine code)), language, _, r)
+ | CodeBlock(Let (dict []) (cmds, code), language, _, r) ->
if cmds.ContainsKey("hide") then None else
let code =
if cmds.ContainsKey("file") && cmds.ContainsKey("key") then
@@ -56,12 +56,12 @@ module Transformations =
else code
let lang =
match language with
- | String.WhiteSpace when cmds.ContainsKey("lang") -> cmds.["lang"]
+ | String.WhiteSpaceS when cmds.ContainsKey("lang") -> cmds.["lang"]
| language -> language
if not (String.IsNullOrWhiteSpace(lang)) && lang <> "fsharp" then
- Some (EmbedParagraphs(LanguageTaggedCode(lang, code)))
+ Some (EmbedParagraphs(LanguageTaggedCode(lang, code), r))
else
- Some (EmbedParagraphs(FormattedCode(codeLookup.[code])))
+ Some (EmbedParagraphs(FormattedCode(codeLookup.[code]), r))
// Recursively process nested paragraphs, other nodes return without change
| Matching.ParagraphNested(pn, nested) ->
@@ -116,7 +116,7 @@ module Transformations =
// Collect IndirectLinks in a span
let rec collectSpanReferences span = seq {
match span with
- | IndirectLink(_, _, key) -> yield key
+ | IndirectLink(_, _, key, _) -> yield key
| Matching.SpanLeaf _ -> ()
| Matching.SpanNode(_, spans) ->
for s in spans do yield! collectSpanReferences s }
@@ -137,13 +137,13 @@ module Transformations =
let replaceReferences (refIndex:IDictionary) =
// Replace IndirectLinks with a nice link given a single span element
let rec replaceSpans = function
- | IndirectLink(body, original, key) ->
- [ yield IndirectLink(body, original, key)
+ | IndirectLink(body, original, key, r) ->
+ [ yield IndirectLink(body, original, key, r)
match refIndex.TryGetValue(key) with
| true, i ->
- yield Literal " ["
- yield DirectLink([Literal (string i)], ("#rf" + DateTime.Now.ToString("yyMMddhh"), None))
- yield Literal "]"
+ yield Literal(" [", r)
+ yield DirectLink([Literal (string i, r)], ("#rf" + DateTime.Now.ToString("yyMMddhh"), None), r)
+ yield Literal("]", r)
| _ -> () ]
| Matching.SpanLeaf(sl) -> [Matching.SpanLeaf(sl)]
| Matching.SpanNode(nd, spans) ->
@@ -179,18 +179,18 @@ module Transformations =
if colon > 0 then
let auth = title.Substring(0, colon)
let name = title.Substring(colon + 1, title.Length - 1 - colon)
- yield [Span [ Literal (sprintf "[%d] " i)
- DirectLink([Literal (name.Trim())], (link, Some title))
- Literal (" - " + auth)] ]
+ yield [Span([ Literal (sprintf "[%d] " i, None)
+ DirectLink([Literal (name.Trim(), None)], (link, Some title), None)
+ Literal (" - " + auth, None)], None) ]
else
- yield [Span [ Literal (sprintf "[%d] " i)
- DirectLink([Literal title], (link, Some title))]] ]
+ yield [Span([ Literal (sprintf "[%d] " i, None)
+ DirectLink([Literal(title, None)], (link, Some title), None)], None)] ]
// Return the document together with dictionary for looking up indices
let id = DateTime.Now.ToString("yyMMddhh")
- [ Paragraph [AnchorLink id];
- Heading(3, [Literal "References"])
- ListBlock(MarkdownListKind.Unordered, refList) ], refLookup
+ [ Paragraph([AnchorLink(id, None)], None)
+ Heading(3, [Literal("References", None)], None)
+ ListBlock(MarkdownListKind.Unordered, refList, None) ], refLookup
/// Turn all indirect links into a references
/// and add paragraph to the document
@@ -270,8 +270,8 @@ module Transformations =
| _ -> None
match special with
| EvalFormat(Some result, _, kind) -> ctx.Evaluator.Value.Format(result, kind)
- | EvalFormat(None, ref, _) -> [ CodeBlock("Could not find reference '" + ref + "'", "", "") ]
- | other -> [ EmbedParagraphs(other) ]
+ | EvalFormat(None, ref, _) -> [ CodeBlock("Could not find reference '" + ref + "'", "", "", None) ]
+ | other -> [ EmbedParagraphs(other, None) ]
// Traverse all other structrues recursively
| Matching.ParagraphNested(pn, nested) ->
@@ -311,7 +311,7 @@ module Transformations =
let rec replaceSpecialCodes ctx (formatted:IDictionary<_, _>) = function
| Matching.LiterateParagraph(special) ->
match special with
- | RawBlock lines -> Some (InlineBlock (unparse lines))
+ | RawBlock lines -> Some (InlineBlock(unparse lines, None))
| LiterateCode(_, { Visibility = (HiddenCode | NamedCode _) }) -> None
| FormattedCode lines
| LiterateCode(lines, _) -> Some (formatted.[Choice1Of2 lines])
@@ -352,7 +352,7 @@ module Transformations =
| OutputKind.Latex ->
sprintf "\\begin{lstlisting}\n%s\n\\end{lstlisting}" code
- Some(InlineBlock(inlined))
+ Some(InlineBlock(inlined, None))
// Traverse all other structures recursively
| Matching.ParagraphNested(pn, nested) ->
let nested = List.map (List.choose (replaceSpecialCodes ctx formatted)) nested
@@ -379,7 +379,7 @@ module Transformations =
| OutputKind.Latex -> CodeFormat.FormatLatex(snippets, ctx.GenerateLineNumbers)
let lookup =
[ for (key, _), fmtd in Seq.zip replacements formatted.Snippets ->
- key, InlineBlock(fmtd.Content) ] |> dict
+ key, InlineBlock(fmtd.Content, None) ] |> dict
// Replace original snippets with formatted HTML/Latex and return document
let newParagraphs = List.choose (replaceSpecialCodes ctx lookup) doc.Paragraphs
diff --git a/src/FSharp.Markdown/HtmlFormatting.fs b/src/FSharp.Markdown/HtmlFormatting.fs
index a256cd19c..02bcb978b 100644
--- a/src/FSharp.Markdown/HtmlFormatting.fs
+++ b/src/FSharp.Markdown/HtmlFormatting.fs
@@ -67,19 +67,19 @@ let noBreak (ctx:FormattingContext) () = ()
/// Write MarkdownSpan value to a TextWriter
let rec formatSpan (ctx:FormattingContext) = function
- | LatexDisplayMath(body) ->
+ | LatexDisplayMath(body, _) ->
// use mathjax grammar, for detail, check: http://www.mathjax.org/
ctx.Writer.Write("\\[" + (htmlEncode body) + "\\]")
- | LatexInlineMath(body) ->
+ | LatexInlineMath(body, _) ->
// use mathjax grammar, for detail, check: http://www.mathjax.org/
ctx.Writer.Write("\\(" + (htmlEncode body) + "\\)")
- | AnchorLink(id) -> ctx.Writer.Write("")
- | EmbedSpans(cmd) -> formatSpans ctx (cmd.Render())
- | Literal(str) -> ctx.Writer.Write(str)
- | HardLineBreak -> ctx.Writer.Write(" " + ctx.Newline)
- | IndirectLink(body, _, LookupKey ctx.Links (link, title))
- | DirectLink(body, (link, title)) ->
+ | AnchorLink(id, _) -> ctx.Writer.Write("")
+ | EmbedSpans(cmd, _) -> formatSpans ctx (cmd.Render())
+ | Literal(str, _) -> ctx.Writer.Write(str)
+ | HardLineBreak(_) -> ctx.Writer.Write(" " + ctx.Newline)
+ | IndirectLink(body, _, LookupKey ctx.Links (link, title), _)
+ | DirectLink(body, (link, title), _) ->
ctx.Writer.Write("")
- | IndirectLink(body, original, _) ->
+ | IndirectLink(body, original, _, _) ->
ctx.Writer.Write("[")
formatSpans ctx body
ctx.Writer.Write("]")
ctx.Writer.Write(original)
- | IndirectImage(body, _, LookupKey ctx.Links (link, title))
- | DirectImage(body, (link, title)) ->
+ | IndirectImage(body, _, LookupKey ctx.Links (link, title), _)
+ | DirectImage(body, (link, title), _) ->
ctx.Writer.Write(" ()
ctx.Writer.Write("\" />")
- | IndirectImage(body, original, _) ->
+ | IndirectImage(body, original, _, _) ->
ctx.Writer.Write("[")
ctx.Writer.Write(body)
ctx.Writer.Write("]")
ctx.Writer.Write(original)
- | Strong(body) ->
+ | Strong(body, _) ->
ctx.Writer.Write("")
formatSpans ctx body
ctx.Writer.Write("")
- | InlineCode(body) ->
+ | InlineCode(body, _) ->
ctx.Writer.Write("")
ctx.Writer.Write(htmlEncode body)
ctx.Writer.Write("")
- | Emphasis(body) ->
+ | Emphasis(body, _) ->
ctx.Writer.Write("")
formatSpans ctx body
ctx.Writer.Write("")
@@ -141,10 +141,10 @@ let formatAnchor (ctx:FormattingContext) (spans:MarkdownSpans) =
let rec gather (span:MarkdownSpan) : seq =
seq {
match span with
- | Literal str -> yield! extractWords str
- | Strong body -> yield! gathers body
- | Emphasis body -> yield! gathers body
- | DirectLink (body,_) -> yield! gathers body
+ | Literal(str, _) -> yield! extractWords str
+ | Strong(body, _) -> yield! gathers body
+ | Emphasis(body, _) -> yield! gathers body
+ | DirectLink(body, _, _) -> yield! gathers body
| _ -> ()
}
@@ -163,13 +163,13 @@ let withInner ctx f =
/// Write a MarkdownParagraph value to a TextWriter
let rec formatParagraph (ctx:FormattingContext) paragraph =
match paragraph with
- | LatexBlock(lines) ->
+ | LatexBlock(lines, _) ->
// use mathjax grammar, for detail, check: http://www.mathjax.org/
let body = String.concat ctx.Newline lines
ctx.Writer.Write("
")
ctx.Writer.Write(htmlEncode code)
diff --git a/src/FSharp.Markdown/MarkdownParser.fs b/src/FSharp.Markdown/MarkdownParser.fs
index 373b531ac..ecac2f16d 100644
--- a/src/FSharp.Markdown/MarkdownParser.fs
+++ b/src/FSharp.Markdown/MarkdownParser.fs
@@ -18,7 +18,7 @@ open FSharp.Collections
/// Splits a link formatted as `http://link "title"` into a link part
/// and an optional title part (may be wrapped using quote or double-quotes)
-let getLinkAndTitle (String.TrimBoth(input, n)) =
+let getLinkAndTitle (StringPosition.TrimBoth(input, n)) =
let url, title =
if input.Length = 0 then "", None else
let c = input.[input.Length - 1]
@@ -250,7 +250,7 @@ let rec parseChars acc input (ctx:ParsingContext) = seq {
yield! accLiterals.Value }
/// Parse body of a paragraph into a list of Markdown inline spans
-let parseSpans (String.TrimBoth(s, n)) ctx =
+let parseSpans (StringPosition.TrimBoth(s, n)) ctx =
parseChars [] (s.ToCharArray() |> List.ofArray) ctx |> List.ofSeq
let rec trimSpaces numSpaces (s:string) =
@@ -265,11 +265,11 @@ let rec trimSpaces numSpaces (s:string) =
/// Recognizes heading, either prefixed with #s or followed by === or --- line
let (|Heading|_|) = function
- | (String.TrimBoth header) :: (String.TrimEnd (String.EqualsRepeated("=", 0))) :: rest ->
+ | (StringPosition.TrimBoth header) :: (StringPosition.TrimEnd (StringPosition.EqualsRepeated("=", 0))) :: rest ->
Some(1, header, rest)
- | (String.TrimBoth header) :: (String.TrimEnd (String.EqualsRepeated("-", 0))) :: rest ->
+ | (StringPosition.TrimBoth header) :: (StringPosition.TrimEnd (StringPosition.EqualsRepeated("-", 0))) :: rest ->
Some(2, header, rest)
- | String.StartsWithRepeated "#" (n, (header, ln)) :: rest ->
+ | StringPosition.StartsWithRepeated "#" (n, (header, ln)) :: rest ->
let header =
// Drop "##" at the end, but only when it is preceded by some whitespace
// (For example "## Hello F#" should be "Hello F#")
@@ -306,9 +306,9 @@ let (|NestedCodeBlock|_|) = function
/// Recognizes a fenced code block - starting and ending with at least ``` or ~~~
let (|FencedCodeBlock|_|) = function
- | String.StartsWithNTimesTrimIgnoreStartWhitespace "~" (Let "~" (start,num), indent, header) :: lines
+ | StringPosition.StartsWithNTimesTrimIgnoreStartWhitespace "~" (Let "~" (start,num), indent, header) :: lines
// when num > 2
- | String.StartsWithNTimesTrimIgnoreStartWhitespace "`" (Let "`" (start,num), indent, header) :: lines
+ | StringPosition.StartsWithNTimesTrimIgnoreStartWhitespace "`" (Let "`" (start,num), indent, header) :: lines
when num > 2 ->
let mutable endStr = String.replicate num start
if header.Contains (start) then None // info string cannot contain backspaces
@@ -317,7 +317,7 @@ let (|FencedCodeBlock|_|) = function
match [line] with
// end cannot contain info string afterwards (see http://spec.commonmark.org/0.23/#example-104)
// end must be indended with less then 4 spaces: http://spec.commonmark.org/0.23/#example-95
- | String.StartsWithNTimesTrimIgnoreStartWhitespace start (n, i, h) :: _ when n >= num && i < 4 && String.IsNullOrWhiteSpace h ->
+ | StringPosition.StartsWithNTimesTrimIgnoreStartWhitespace start (n, i, h) :: _ when n >= num && i < 4 && String.IsNullOrWhiteSpace h ->
endStr <- String.replicate n start
true
| _ -> false)
@@ -365,23 +365,23 @@ let (|SkipSomeNumbers|_|) (input:string, n:int) =
/// Recognizes a staring of a list (either 1. or +, *, -).
/// Returns the rest of the line, together with the indent.
let (|ListStart|_|) = function
- | String.TrimStartAndCount
+ | StringPosition.TrimStartAndCount
(startIndent, spaces,
// NOTE: a tab character after +, * or - isn't supported by the reference implementation
// (it will be parsed as paragraph for 0.22)
- (String.StartsWithAny ["+ "; "* "; "- " (*; "+\t"; "*\t"; "-\t"*)] as item)) ->
+ (StringPosition.StartsWithAny ["+ "; "* "; "- " (*; "+\t"; "*\t"; "-\t"*)] as item)) ->
let li = ((fst item).Substring(2), snd item)
- let (String.TrimStartAndCount (startIndent2, spaces2, _)) = li
+ let (StringPosition.TrimStartAndCount (startIndent2, spaces2, _)) = li
let endIndent =
startIndent + 2 +
// Handle case of code block
if startIndent2 >= 5 then 1 else startIndent2
Some(Unordered, startIndent, endIndent, li)
- | String.TrimStartAndCount // Remove leading spaces
+ | StringPosition.TrimStartAndCount // Remove leading spaces
(startIndent, spaces,
(SkipSomeNumbers // read a number
(skipNumCount, '.' :: ' ' :: List.AsString item))) ->
- let (String.TrimStartAndCount (startIndent2, spaces2, _)) = (item, 0)
+ let (StringPosition.TrimStartAndCount (startIndent2, spaces2, _)) = (item, 0)
let endIndent =
startIndent + 2 + skipNumCount +
// Handle case of code block
@@ -392,13 +392,13 @@ let (|ListStart|_|) = function
/// Splits input into lines until whitespace or starting of a list and the rest.
let (|LinesUntilListOrWhite|) =
List.partitionUntil (function
- | ListStart _ | String.WhiteSpace -> true | _ -> false)
+ | ListStart _ | StringPosition.WhiteSpace -> true | _ -> false)
/// Splits input into lines until not-indented line or starting of a list and the rest.
let (|LinesUntilListOrUnindented|) =
List.partitionUntilLookahead (function
- | (ListStart _ | String.Unindented)::_
- | String.WhiteSpace::String.WhiteSpace::_ -> true | _ -> false)
+ | (ListStart _ | StringPosition.Unindented)::_
+ | StringPosition.WhiteSpace::StringPosition.WhiteSpace::_ -> true | _ -> false)
/// Recognizes a list item until the next list item (possibly nested) or end of a list.
/// The parameter specifies whether the previous line was simple (single-line not
@@ -414,17 +414,17 @@ let (|ListItem|_|) prevSimple = function
(LinesUntilListOrUnindented (more, rest) as next)) ->
let simple =
match item with
- | String.TrimStartAndCount (_, spaces, _) when spaces >= 4->
+ | StringPosition.TrimStartAndCount (_, spaces, _) when spaces >= 4->
// Code Block
false
| _ ->
match next, rest with
- | String.WhiteSpace::_, (ListStart _)::_ -> false
+ | StringPosition.WhiteSpace::_, (ListStart _)::_ -> false
| (ListStart _)::_, _ -> true
| [], _ -> true
- | [ String.WhiteSpace ], _ -> true
- | String.WhiteSpace::String.WhiteSpace::_, _ -> true
- | _, String.Unindented::_ -> prevSimple
+ | [ StringPosition.WhiteSpace ], _ -> true
+ | StringPosition.WhiteSpace::StringPosition.WhiteSpace::_, _ -> true
+ | _, StringPosition.Unindented::_ -> prevSimple
| _, _ -> false
let lines =
@@ -486,10 +486,10 @@ let rec pipeTableFindSplits (delim : char array) (line : char list) =
/// Recognizes alignment specified in the passed separator line.
let (|TableCellSeparator|_|) = function
- | String.StartsAndEndsWith (":", ":") (String.EqualsRepeated("-", 0)) -> Some(AlignCenter)
- | String.StartsWith ":" (String.EqualsRepeated("-", 0)) -> Some(AlignLeft)
- | String.StartsAndEndsWith ("", ":") (String.EqualsRepeated("-", 0)) -> Some(AlignRight)
- | String.EqualsRepeated("-", 0) -> Some(AlignDefault)
+ | StringPosition.StartsAndEndsWith (":", ":") (StringPosition.EqualsRepeated("-", 0)) -> Some(AlignCenter)
+ | StringPosition.StartsWith ":" (StringPosition.EqualsRepeated("-", 0)) -> Some(AlignLeft)
+ | StringPosition.StartsAndEndsWith ("", ":") (StringPosition.EqualsRepeated("-", 0)) -> Some(AlignRight)
+ | StringPosition.EqualsRepeated("-", 0) -> Some(AlignDefault)
| _ -> None
/// Recognizes row of pipe table.
@@ -562,9 +562,9 @@ let (|EmacsTableLine|_|) (grid:option) (c:char) (check:string * int -> b
/// Recognizes emacs table
let (|EmacsTableBlock|_|) (input) =
- let isCellSep = String.(|EqualsRepeated|_|)("-", 0) >> Option.isSome
+ let isCellSep = StringPosition.(|EqualsRepeated|_|)("-", 0) >> Option.isSome
let isAlignedCellSep = ( |TableCellSeparator|_| ) >> Option.isSome
- let isHeadCellSep = String.(|EqualsRepeated|_|)("=", 0) >> Option.isSome
+ let isHeadCellSep = StringPosition.(|EqualsRepeated|_|)("=", 0) >> Option.isSome
let isText (s:string, n:int) = true
match input with
| (EmacsTableLine None '+' isAlignedCellSep (grid, parts)) :: rest ->
@@ -605,7 +605,7 @@ let (|TakeParagraphLines|_|) input =
| Heading _ -> false
| FencedCodeBlock _ -> false
| BlockquoteStart _::_ -> false
- | String.WhiteSpace::_ -> false
+ | StringPosition.WhiteSpace::_ -> false
| _ -> true) input with
| matching, rest when matching <> [] -> Some(matching, rest)
| _ -> None
@@ -623,7 +623,7 @@ let (|LinesUntilBlockquoteEnds|) input =
match next with
| BlockquoteStart _ :: _
| Heading _
- | String.WhiteSpace :: _ -> true
+ | StringPosition.WhiteSpace :: _ -> true
| _ ->
false) input
@@ -643,8 +643,8 @@ let rec (|Blockquote|_|) = function
/// Recognizes a special case: an empty blockquote line should terminate
/// the blockquote if the next line is not a blockquote
and (|EmptyBlockquote|_|) = function
- | BlockquoteStart(String.WhiteSpace) :: Blockquote(_) -> None
- | BlockquoteStart(String.WhiteSpace) :: rest -> Some rest
+ | BlockquoteStart(StringPosition.WhiteSpace) :: Blockquote(_) -> None
+ | BlockquoteStart(StringPosition.WhiteSpace) :: rest -> Some rest
| _ -> None
/// Recognizes Latex block - start with "$$$"
@@ -656,10 +656,10 @@ let (|LatexBlock|_|) (lines:(string * int) list) = lines |> function
/// Recognize a definition of a link as in `[key]: http://url ...`
let (|LinkDefinition|_|) = function
- | ( String.StartsWithWrapped ("[", "]:") (wrapped, String.TrimBoth link)
- | String.StartsWithWrapped (" [", "]:") (wrapped, String.TrimBoth link)
- | String.StartsWithWrapped (" [", "]:") (wrapped, String.TrimBoth link)
- | String.StartsWithWrapped (" [", "]:") (wrapped, String.TrimBoth link) ) :: rest ->
+ | ( StringPosition.StartsWithWrapped ("[", "]:") (wrapped, StringPosition.TrimBoth link)
+ | StringPosition.StartsWithWrapped (" [", "]:") (wrapped, StringPosition.TrimBoth link)
+ | StringPosition.StartsWithWrapped (" [", "]:") (wrapped, StringPosition.TrimBoth link)
+ | StringPosition.StartsWithWrapped (" [", "]:") (wrapped, StringPosition.TrimBoth link) ) :: rest ->
Some((wrapped, link), rest)
| _ -> None
diff --git a/src/FSharp.MetadataFormat/Main.fs b/src/FSharp.MetadataFormat/Main.fs
index 238d35972..16ad5d774 100755
--- a/src/FSharp.MetadataFormat/Main.fs
+++ b/src/FSharp.MetadataFormat/Main.fs
@@ -535,7 +535,7 @@ module Reader =
Comment.Create(blurb, full, sections)
let findCommand = (function
- | String.StartsWithWrapped ("[", "]") (ParseCommand(k, v), rest) ->
+ | StringPosition.StartsWithWrapped ("[", "]") (ParseCommand(k, v), rest) ->
Some (k, v)
| _ -> None)
From c7f78e7a9d80acf2d2b237b01928d763feda5554 Mon Sep 17 00:00:00 2001
From: Avi Avni
Date: Wed, 6 Jul 2016 20:28:06 +0300
Subject: [PATCH 003/108] fix naming
---
src/Common/StringParsing.fs | 16 +---------------
src/FSharp.Literate/ParseScript.fs | 4 ++--
src/FSharp.Literate/Transformations.fs | 6 +++---
3 files changed, 6 insertions(+), 20 deletions(-)
diff --git a/src/Common/StringParsing.fs b/src/Common/StringParsing.fs
index cd8b0ba72..72cd7f34e 100644
--- a/src/Common/StringParsing.fs
+++ b/src/Common/StringParsing.fs
@@ -303,21 +303,7 @@ open System.Collections.Generic
/// recognize `key1=value, key2=value` and also `key1:value, key2:value`
/// The key of the command should be identifier with just
/// characters in it - otherwise, the parsing fails.
-let (|ParseCommandsS|_|) (str:string) =
- let kvs =
- [ for cmd in str.Split(',') do
- let kv = cmd.Split([| '='; ':' |])
- if kv.Length = 2 then yield kv.[0].Trim(), kv.[1].Trim()
- elif kv.Length = 1 then yield kv.[0].Trim(), "" ]
- let allKeysValid =
- kvs |> Seq.forall (fst >> Seq.forall (fun c -> Char.IsLetter c || c = '_' || c = '-'))
- if allKeysValid && kvs <> [] then Some(dict kvs) else None
-
-/// Utility for parsing commands. Commands can be used in different places. We
-/// recognize `key1=value, key2=value` and also `key1:value, key2:value`
-/// The key of the command should be identifier with just
-/// characters in it - otherwise, the parsing fails.
-let (|ParseCommands|_|) (str:string, n:int) =
+let (|ParseCommands|_|) (str:string) =
let kvs =
[ for cmd in str.Split(',') do
let kv = cmd.Split([| '='; ':' |])
diff --git a/src/FSharp.Literate/ParseScript.fs b/src/FSharp.Literate/ParseScript.fs
index 9e767d962..34e2c4076 100644
--- a/src/FSharp.Literate/ParseScript.fs
+++ b/src/FSharp.Literate/ParseScript.fs
@@ -54,7 +54,7 @@ module internal CodeBlockUtils =
cend
match lines with
- | (ConcatenatedComments(String.StartsAndEndsWith ("(***", "***)") (ParseCommandsS cmds)))::lines ->
+ | (ConcatenatedComments(String.StartsAndEndsWith ("(***", "***)") (ParseCommands cmds)))::lines ->
// Ended with a command, yield comment, command & parse the next as a snippet
let cend = findCommentEnd comment
yield BlockComment (comment.Substring(0, cend))
@@ -94,7 +94,7 @@ module internal CodeBlockUtils =
BlockSnippet res
seq {
match lines with
- | (ConcatenatedComments(String.StartsAndEndsWith ("(***", "***)") (ParseCommandsS cmds)))::lines ->
+ | (ConcatenatedComments(String.StartsAndEndsWith ("(***", "***)") (ParseCommands cmds)))::lines ->
// Found a special command, yield snippet, command and parse another snippet
if acc <> [] then yield blockSnippet acc
yield BlockCommand cmds
diff --git a/src/FSharp.Literate/Transformations.fs b/src/FSharp.Literate/Transformations.fs
index 77f91751d..d5253e096 100644
--- a/src/FSharp.Literate/Transformations.fs
+++ b/src/FSharp.Literate/Transformations.fs
@@ -21,9 +21,9 @@ module Transformations =
/// to colorize. We skip snippets that specify non-fsharp langauge e.g. [lang=csharp].
let rec collectCodeSnippets par = seq {
match par with
- | CodeBlock((String.StartsWithWrapped ("[", "]") (ParseCommandsS cmds, String.SkipSingleLine code)), language, _, _)
+ | CodeBlock((String.StartsWithWrapped ("[", "]") (ParseCommands cmds, String.SkipSingleLine code)), language, _, _)
when (not (String.IsNullOrWhiteSpace(language)) && language <> "fsharp") || (cmds.ContainsKey("lang") && cmds.["lang"] <> "fsharp") -> ()
- | CodeBlock((String.StartsWithWrapped ("[", "]") (ParseCommandsS cmds, String.SkipSingleLine code)), _, _, _)
+ | CodeBlock((String.StartsWithWrapped ("[", "]") (ParseCommands cmds, String.SkipSingleLine code)), _, _, _)
| CodeBlock(Let (dict []) (cmds, code), _, _, _) ->
let modul =
match cmds.TryGetValue("module") with
@@ -39,7 +39,7 @@ module Transformations =
/// Replace CodeBlock elements with formatted HTML that was processed by the F# snippets tool
/// (The dictionary argument is a map from original code snippets to formatted HTML snippets.)
let rec replaceCodeSnippets path (codeLookup:IDictionary<_, _>) = function
- | CodeBlock ((String.StartsWithWrapped ("[", "]") (ParseCommandsS cmds, String.SkipSingleLine code)), language, _, r)
+ | CodeBlock ((String.StartsWithWrapped ("[", "]") (ParseCommands cmds, String.SkipSingleLine code)), language, _, r)
| CodeBlock(Let (dict []) (cmds, code), language, _, r) ->
if cmds.ContainsKey("hide") then None else
let code =
From 377f5b1f3cf0e9dcf1e9fdc518a703e7b98c613b Mon Sep 17 00:00:00 2001
From: Avi Avni
Date: Wed, 6 Jul 2016 21:17:50 +0300
Subject: [PATCH 004/108] add names to DUs parameters
---
src/FSharp.Markdown/Markdown.fs | 48 ++++++++++++++++-----------------
1 file changed, 24 insertions(+), 24 deletions(-)
diff --git a/src/FSharp.Markdown/Markdown.fs b/src/FSharp.Markdown/Markdown.fs
index afd942d4d..e2d760295 100644
--- a/src/FSharp.Markdown/Markdown.fs
+++ b/src/FSharp.Markdown/Markdown.fs
@@ -30,19 +30,19 @@ type MarkdownColumnAlignment =
/// Represents inline formatting inside a paragraph. This can be literal (with text), various
/// formattings (string, emphasis, etc.), hyperlinks, images, inline maths etc.
type MarkdownSpan =
- | Literal of string * MarkdownRange option
- | InlineCode of string * MarkdownRange option
- | Strong of MarkdownSpans * MarkdownRange option
- | Emphasis of MarkdownSpans * MarkdownRange option
- | AnchorLink of string * MarkdownRange option
- | DirectLink of MarkdownSpans * (string * option) * MarkdownRange option
- | IndirectLink of MarkdownSpans * string * string * MarkdownRange option
- | DirectImage of string * (string * option) * MarkdownRange option
- | IndirectImage of string * string * string * MarkdownRange option
- | HardLineBreak of MarkdownRange option
- | LatexInlineMath of string * MarkdownRange option
- | LatexDisplayMath of string * MarkdownRange option
- | EmbedSpans of MarkdownEmbedSpans * MarkdownRange option
+ | Literal of text:string * range:MarkdownRange option
+ | InlineCode of code:string * range:MarkdownRange option
+ | Strong of spans:MarkdownSpans * range:MarkdownRange option
+ | Emphasis of spans:MarkdownSpans * range:MarkdownRange option
+ | AnchorLink of link:string * range:MarkdownRange option
+ | DirectLink of spans:MarkdownSpans * linkAndTitle:(string * option) * range:MarkdownRange option
+ | IndirectLink of spans:MarkdownSpans * link:string * key:string * range:MarkdownRange option
+ | DirectImage of body:string * linkAndTitle:(string * option) * range:MarkdownRange option
+ | IndirectImage of body:string * link:string * key:string * range:MarkdownRange option
+ | HardLineBreak of range:MarkdownRange option
+ | LatexInlineMath of string * range:MarkdownRange option
+ | LatexDisplayMath of string * range:MarkdownRange option
+ | EmbedSpans of customSpans:MarkdownEmbedSpans * range:MarkdownRange option
/// A type alias for a list of `MarkdownSpan` values
and MarkdownSpans = list
@@ -56,17 +56,17 @@ and MarkdownEmbedSpans =
/// Paragraphs are headings, inline paragraphs, code blocks, lists, quotations, tables and
/// also embedded LaTeX blocks.
type MarkdownParagraph =
- | Heading of int * MarkdownSpans * MarkdownRange option
- | Paragraph of MarkdownSpans * MarkdownRange option
- | CodeBlock of string * string * string * MarkdownRange option
- | InlineBlock of string * MarkdownRange option
- | ListBlock of MarkdownListKind * list * MarkdownRange option
- | QuotedBlock of MarkdownParagraphs * MarkdownRange option
- | Span of MarkdownSpans * MarkdownRange option
- | LatexBlock of list * MarkdownRange option
- | HorizontalRule of char * MarkdownRange option
- | TableBlock of option * list * list * MarkdownRange option
- | EmbedParagraphs of MarkdownEmbedParagraphs * MarkdownRange option
+ | Heading of n:int * spans:MarkdownSpans * range:MarkdownRange option
+ | Paragraph of spans:MarkdownSpans * range:MarkdownRange option
+ | CodeBlock of code:string * language:string * ignoredLine:string * range:MarkdownRange option
+ | InlineBlock of code:string * range:MarkdownRange option
+ | ListBlock of kind:MarkdownListKind * items:list * range:MarkdownRange option
+ | QuotedBlock of paragraphs:MarkdownParagraphs * range:MarkdownRange option
+ | Span of spans:MarkdownSpans * range:MarkdownRange option
+ | LatexBlock of body:list * range:MarkdownRange option
+ | HorizontalRule of c:char * range:MarkdownRange option
+ | TableBlock of headers:option * alignments:list * rows:list * range:MarkdownRange option
+ | EmbedParagraphs of customParagraphs:MarkdownEmbedParagraphs * range:MarkdownRange option
/// A type alias for a list of paragraphs
and MarkdownParagraphs = list
From 16383d8894bef27d0d273b7775bda703a6238072 Mon Sep 17 00:00:00 2001
From: Avi Avni
Date: Fri, 8 Jul 2016 18:25:15 +0300
Subject: [PATCH 005/108] add start/end line/column to markdown range
---
docs/content/codeformat.fsx | 2 +-
docs/content/markdown.fsx | 9 +-
src/Common/StringParsing.fs | 67 +++++----
src/FSharp.CodeFormat/CodeFormatAgent.fs | 6 +-
src/FSharp.CodeFormat/CommentFilter.fs | 5 +-
.../FSharp.Formatting.Common.fsproj | 1 +
src/FSharp.Formatting.Common/Range.fs | 11 ++
src/FSharp.Markdown/Main.fs | 7 +-
src/FSharp.Markdown/Markdown.fs | 7 +-
src/FSharp.Markdown/MarkdownParser.fs | 135 ++++++++++--------
src/FSharp.MetadataFormat/Main.fs | 4 +-
tests/FSharp.Literate.Tests/Tests.fs | 20 +--
.../FSharp.Markdown.Tests.fsproj | 5 +
tests/FSharp.Markdown.Tests/Markdown.fs | 37 ++---
14 files changed, 184 insertions(+), 132 deletions(-)
create mode 100644 src/FSharp.Formatting.Common/Range.fs
diff --git a/docs/content/codeformat.fsx b/docs/content/codeformat.fsx
index 570c84e12..12ae4d9bb 100644
--- a/docs/content/codeformat.fsx
+++ b/docs/content/codeformat.fsx
@@ -24,7 +24,7 @@ can be called to format snippets repeatedly:
*)
let fsharpCompiler = Assembly.Load("FSharp.Compiler")
-let formattingAgent = CodeFormat.CreateAgent(fsharpCompiler)
+let formattingAgent = CodeFormat.CreateAgent()
(**
If you want to process multiple snippets, it is a good idea to keep the
diff --git a/docs/content/markdown.fsx b/docs/content/markdown.fsx
index 87b1593d7..133127bda 100644
--- a/docs/content/markdown.fsx
+++ b/docs/content/markdown.fsx
@@ -10,7 +10,10 @@ First, we need to load the assembly and open necessary namespaces:
*)
#r "../../bin/FSharp.Markdown.dll"
+#r "../../bin/FSharp.Formatting.Common.dll"
open FSharp.Markdown
+open FSharp.Formatting.Common
+
(**
Parsing documents
@@ -64,7 +67,7 @@ The following snippet prints the heading of the document:
// Iterate over all the paragraph elements
for par in parsed.Paragraphs do
match par with
- | Heading(1, [Literal text]) ->
+ | Heading(1, [Literal(text, _)], _) ->
// Recognize heading that has a simple content
// containing just a literal (no other formatting)
printfn "%s" text
@@ -92,8 +95,8 @@ to recognize any paragraph or span that can contain child elements:
/// Returns all links in a specified span node
let rec collectSpanLinks span = seq {
match span with
- | DirectLink(_, (url, _)) -> yield url
- | IndirectLink(_, _, key) -> yield fst (parsed.DefinedLinks.[key])
+ | DirectLink(_, (url, _), _) -> yield url
+ | IndirectLink(_, _, key, _) -> yield fst (parsed.DefinedLinks.[key])
| Matching.SpanLeaf _ -> ()
| Matching.SpanNode(_, spans) ->
for s in spans do yield! collectSpanLinks s }
diff --git a/src/Common/StringParsing.fs b/src/Common/StringParsing.fs
index 72cd7f34e..e33c38c92 100644
--- a/src/Common/StringParsing.fs
+++ b/src/Common/StringParsing.fs
@@ -7,6 +7,7 @@ module internal FSharp.Patterns
open System
open FSharp.Collections
+open FSharp.Formatting.Common
// --------------------------------------------------------------------------------------
// Active patterns that simplify parsing of strings and lists of strings (lines)
@@ -92,46 +93,55 @@ module String =
module StringPosition =
/// Matches when a string is a whitespace or null
- let (|WhiteSpace|_|) (s, n: int) =
+ let (|WhiteSpace|_|) (s, n: MarkdownRange) =
if String.IsNullOrWhiteSpace(s) then Some() else None
/// Matches when a string does starts with non-whitespace
- let (|Unindented|_|) (s:string, n:int) =
+ let (|Unindented|_|) (s:string, n:MarkdownRange) =
if not (String.IsNullOrWhiteSpace(s)) && s.TrimStart() = s then Some() else None
/// Returns a string trimmed from both start and end
- let (|TrimBoth|) (text:string, n:int) = (text.Trim(), n)
+ let (|TrimBoth|) (text:string, n:MarkdownRange) =
+ let trimmedStart = text.TrimStart()
+ let trimmed = trimmedStart.TrimEnd()
+ (trimmed, { n with StartColumn = n.StartColumn + text.Length - trimmedStart.Length; EndColumn = n.EndColumn - trimmedStart.Length + trimmed.Length })
/// Returns a string trimmed from the end
- let (|TrimEnd|) (text:string, n:int) = (text.TrimEnd(), n)
+ let (|TrimEnd|) (text:string, n:MarkdownRange) =
+ let trimmed = text.TrimEnd()
+ (trimmed, { n with EndColumn = n.EndColumn - text.Length + trimmed.Length })
/// Returns a string trimmed from the start
- let (|TrimStart|) (text:string, n:int) = (text.TrimStart(), n)
+ let (|TrimStart|) (text:string, n:MarkdownRange) =
+ let trimmed = text.TrimStart()
+ (trimmed, { n with StartColumn = n.StartColumn + text.Length - trimmed.Length })
- /// Retrusn a string trimmed from the end using characters given as a parameter
- let (|TrimEndUsing|) chars (text:string, n:int) = text.TrimEnd(Array.ofSeq chars)
+ /// Returns a string trimmed from the end using characters given as a parameter
+ let (|TrimEndUsing|) chars (text:string, n:MarkdownRange) =
+ let trimmed = text.TrimEnd(Array.ofSeq chars)
+ (trimmed, { n with EndColumn = n.EndColumn - text.Length + trimmed.Length })
/// Returns a string trimmed from the start together with
/// the number of skipped whitespace characters
- let (|TrimStartAndCount|) (text:string, n:int) =
+ let (|TrimStartAndCount|) (text:string, n:MarkdownRange) =
let trimmed = text.TrimStart([|' '; '\t'|])
let len = text.Length - trimmed.Length
- len, text.Substring(0, len).Replace("\t", " ").Length, (trimmed, n)
+ len, text.Substring(0, len).Replace("\t", " ").Length, (trimmed, { n with StartColumn = n.StartColumn + text.Length - trimmed.Length })
/// Matches when a string starts with any of the specified sub-strings
- let (|StartsWithAny|_|) (starts:seq) (text:string, n:int) =
+ let (|StartsWithAny|_|) (starts:seq) (text:string, n:MarkdownRange) =
if starts |> Seq.exists (text.StartsWith) then Some() else None
/// Matches when a string starts with the specified sub-string
- let (|StartsWith|_|) (start:string) (text:string, n:int) =
- if text.StartsWith(start) then Some(text.Substring(start.Length), n) else None
+ let (|StartsWith|_|) (start:string) (text:string, n:MarkdownRange) =
+ if text.StartsWith(start) then Some(text.Substring(start.Length), { n with StartColumn = n.StartColumn + text.Length - start.Length }) else None
/// Matches when a string starts with the specified sub-string
/// The matched string is trimmed from all whitespace.
- let (|StartsWithTrim|_|) (start:string) (text:string, n:int) =
- if text.StartsWith(start) then Some(text.Substring(start.Length).Trim(), n) else None
+ let (|StartsWithTrim|_|) (start:string) (text:string, n:MarkdownRange) =
+ if text.StartsWith(start) then Some(text.Substring(start.Length).Trim(), { n with StartColumn = n.StartColumn + text.Length - start.Length }) else None
/// Matches when a string starts with the specified sub-string (ignoring whitespace at the start)
/// The matched string is trimmed from all whitespace.
- let (|StartsWithNTimesTrimIgnoreStartWhitespace|_|) (start:string) (text:string, n:int) =
+ let (|StartsWithNTimesTrimIgnoreStartWhitespace|_|) (start:string) (text:string, n:MarkdownRange) =
if text.Contains(start) then
let beforeStart = text.Substring(0, text.IndexOf(start))
if String.IsNullOrWhiteSpace (beforeStart) then
@@ -147,10 +157,10 @@ module StringPosition =
/// Matches when a string starts with the given value and ends
/// with a given value (and returns the rest of it)
- let (|StartsAndEndsWith|_|) (starts, ends) (s:string, n:int) =
+ let (|StartsAndEndsWith|_|) (starts, ends) (s:string, n:MarkdownRange) =
if s.StartsWith(starts) && s.EndsWith(ends) &&
s.Length >= starts.Length + ends.Length then
- Some(s.Substring(starts.Length, s.Length - starts.Length - ends.Length), n)
+ Some(s.Substring(starts.Length, s.Length - starts.Length - ends.Length), { n with StartColumn = n.StartColumn + s.Length - starts.Length; EndColumn = n.EndColumn - s.Length + ends.Length })
else None
/// Matches when a string starts with the given value and ends
@@ -165,7 +175,7 @@ module StringPosition =
///
/// let (StartsWithRepeated "/\" (2, " abc")) = "/\/\ abc"
///
- let (|StartsWithRepeated|_|) (repeated:string) (text:string, ln:int) =
+ let (|StartsWithRepeated|_|) (repeated:string) (text:string, ln:MarkdownRange) =
let rec loop i =
if i = text.Length then i
elif text.[i] <> repeated.[i % repeated.Length] then i
@@ -173,25 +183,25 @@ module StringPosition =
let n = loop 0
if n = 0 || n % repeated.Length <> 0 then None
- else Some(n/repeated.Length, (text.Substring(n, text.Length - n), ln))
+ else Some(n/repeated.Length, (text.Substring(n, text.Length - n), { ln with StartColumn = n }))
/// Matches when a string starts with a sub-string wrapped using the
/// opening and closing sub-string specified in the parameter.
/// For example "[aa]bc" is wrapped in [ and ] pair. Returns the wrapped
/// text together with the rest.
- let (|StartsWithWrapped|_|) (starts:string, ends:string) (text:string, n:int) =
+ let (|StartsWithWrapped|_|) (starts:string, ends:string) (text:string, n:MarkdownRange) =
if text.StartsWith(starts) then
let id = text.IndexOf(ends, starts.Length)
if id >= 0 then
let wrapped = text.Substring(starts.Length, id - starts.Length)
let rest = text.Substring(id + ends.Length, text.Length - id - ends.Length)
- Some(wrapped, (rest, n))
+ Some(wrapped, (rest, { n with StartColumn = id + ends.Length }))
else None
else None
/// Matches when a string consists of some number of
/// complete repetitions of a specified sub-string.
- let (|EqualsRepeated|_|) (repeated, n:int) = function
+ let (|EqualsRepeated|_|) (repeated, n:MarkdownRange) = function
| StartsWithRepeated repeated (n, ("", _)) -> Some()
| _ -> None
@@ -201,7 +211,7 @@ module List =
let inline (|DelimitedWith|_|) startl endl input =
if List.startsWith startl input then
match List.partitionUntilEquals endl (List.skip startl.Length input) with
- | Some(pre, post) -> Some(pre, List.skip endl.Length post)
+ | Some(pre, post) -> Some(pre, List.skip endl.Length post, startl.Length, endl.Length)
| None -> None
else None
@@ -258,7 +268,7 @@ module Lines =
/// either empty (or whitespace) or start with at least 4 spaces (a tab counts as 4 spaces here).
/// Returns all such lines from the beginning until a different line and
/// the number of spaces the first line started with.
- let (|TakeCodeBlock|_|) (input:(string * int) list) =
+ let (|TakeCodeBlock|_|) (input:(string * MarkdownRange) list) =
let spaceNum = 4
//match input with
//| h :: _ ->
@@ -277,17 +287,18 @@ module Lines =
| _ -> None
/// Removes whitespace lines from the beginning of the list
- let (|TrimBlankStart|) = List.skipWhile (fun (s:string, n:int) -> String.IsNullOrWhiteSpace s)
+ let (|TrimBlankStart|) = List.skipWhile (fun (s:string, n:MarkdownRange) -> String.IsNullOrWhiteSpace s)
/// Trims all lines of the current paragraph
let (|TrimParagraphLines|) lines =
lines
// first remove all whitespace on the beginning of the line
- |> List.map (fun (s:string, n:int) -> s.TrimStart())
+ |> List.map StringPosition.(|TrimStart|)
// Now remove all additional spaces at the end, but keep two spaces if existent
- |> List.map (fun s ->
+ |> List.map (fun (s, n) ->
let endsWithTwoSpaces = s.EndsWith(" ")
- s.TrimEnd([|' '|]) + if endsWithTwoSpaces then " " else "")
+ let trimmed = s.TrimEnd([|' '|]) + if endsWithTwoSpaces then " " else ""
+ (trimmed, { n with EndColumn = n.EndColumn - s.Length + trimmed.Length }))
/// Parameterized pattern that assigns the specified value to the
/// first component of a tuple. Usage:
diff --git a/src/FSharp.CodeFormat/CodeFormatAgent.fs b/src/FSharp.CodeFormat/CodeFormatAgent.fs
index 1c7dfb1e0..29c3e291e 100644
--- a/src/FSharp.CodeFormat/CodeFormatAgent.fs
+++ b/src/FSharp.CodeFormat/CodeFormatAgent.fs
@@ -73,7 +73,7 @@ module private Helpers =
state := nstate
yield! parseLine()
| None, nstate -> state := nstate }
- yield n, parseLine() |> List.ofSeq ]
+ yield { StartLine = n; StartColumn = 0; EndLine = n; EndColumn = 0 }, parseLine() |> List.ofSeq ]
// Count the minimal number of spaces at the beginning of lines
// (so that we can remove spaces for indented text)
@@ -238,10 +238,10 @@ type CodeFormatAgent() =
processSnippetLine
checkResults
(categorizedSpans
- |> Map.tryFind ((fst snippetLine) + 1)
+ |> Map.tryFind ((fst snippetLine).StartLine + 1)
|> function None -> [] | Some spans -> List.ofSeq spans)
lines
- snippetLine)
+ ((fst snippetLine).StartLine, snd snippetLine))
// --------------------------------------------------------------------------------------
diff --git a/src/FSharp.CodeFormat/CommentFilter.fs b/src/FSharp.CodeFormat/CommentFilter.fs
index 0a9e5d303..52043ba92 100644
--- a/src/FSharp.CodeFormat/CommentFilter.fs
+++ b/src/FSharp.CodeFormat/CommentFilter.fs
@@ -11,6 +11,7 @@ open System.Web
open FSharp.Patterns
open FSharp.Collections
+open FSharp.Formatting.Common
open Microsoft.FSharp.Compiler
open Microsoft.FSharp.Compiler.SourceCodeServices
@@ -34,7 +35,7 @@ open Microsoft.FSharp.Compiler.SourceCodeServices
type Token = string * FSharpTokenInfo
type SnippetLine = Token list
-type IndexedSnippetLine = int * SnippetLine
+type IndexedSnippetLine = MarkdownRange * SnippetLine
type Snippet = IndexedSnippetLine list
type NamedSnippet = string * Snippet
@@ -49,7 +50,7 @@ let rec getSnippets (state:NamedSnippet option) (snippets:NamedSnippet list)
match source with
| [] -> snippets
| (line, tokens)::rest ->
- let text = lines.[line].Trim(), line
+ let text = lines.[line.StartLine].Trim(), line
match state, text with
// We're not inside a snippet and we found a beginning of one
diff --git a/src/FSharp.Formatting.Common/FSharp.Formatting.Common.fsproj b/src/FSharp.Formatting.Common/FSharp.Formatting.Common.fsproj
index 07fc84a1c..33e7125c9 100644
--- a/src/FSharp.Formatting.Common/FSharp.Formatting.Common.fsproj
+++ b/src/FSharp.Formatting.Common/FSharp.Formatting.Common.fsproj
@@ -69,6 +69,7 @@
Common\AssemblyInfo.fs
+
diff --git a/src/FSharp.Formatting.Common/Range.fs b/src/FSharp.Formatting.Common/Range.fs
new file mode 100644
index 000000000..bdb58b434
--- /dev/null
+++ b/src/FSharp.Formatting.Common/Range.fs
@@ -0,0 +1,11 @@
+namespace FSharp.Formatting.Common
+
+type MarkdownRange = { StartLine : int; StartColumn : int; EndLine : int; EndColumn : int }
+
+module MRange =
+ let Zero = { StartLine = 0; StartColumn = 0; EndLine = 0; EndColumn = 0 }
+
+ let MergeRanges (ranges:MarkdownRange list) =
+ let startRange = ranges |> List.minBy (fun r -> r.StartLine * 10 + r.StartColumn)
+ let endRange = ranges |> List.maxBy (fun r -> r.EndLine * 10 + r.EndColumn)
+ { StartLine = startRange.StartLine; StartColumn = startRange.StartColumn; EndLine = endRange.EndLine; EndColumn = endRange.EndColumn }
\ No newline at end of file
diff --git a/src/FSharp.Markdown/Main.fs b/src/FSharp.Markdown/Main.fs
index 21fc0bc8d..1b79fdda8 100644
--- a/src/FSharp.Markdown/Main.fs
+++ b/src/FSharp.Markdown/Main.fs
@@ -12,6 +12,7 @@ open System.Collections.Generic
open FSharp.Patterns
open FSharp.Markdown.Parser
open FSharp.Markdown.Html
+open FSharp.Formatting.Common
module private Utils =
/// Replace tabs with four spaces - tab will end at the
@@ -50,14 +51,14 @@ type Markdown =
[ let line = ref ""
let mutable lineNo = 1
while (line := reader.ReadLine(); line.Value <> null) do
- yield (line.Value, lineNo)
+ yield (line.Value, { StartLine = lineNo; StartColumn = 0; EndLine = lineNo; EndColumn = line.Value.Length })
lineNo <- lineNo + 1
if text.EndsWith(newline) then
- yield ("", lineNo) ]
+ yield ("", { StartLine = lineNo; StartColumn = 0; EndLine = lineNo; EndColumn = 0 }) ]
//|> Utils.replaceTabs 4
let links = Dictionary<_, _>()
//let (Lines.TrimBlank lines) = lines
- let ctx : ParsingContext = { Newline = newline; Links = links; CurrentRange = Some({ Line = 1 }) }
+ let ctx : ParsingContext = { Newline = newline; Links = links; CurrentRange = Some(MRange.Zero) }
let paragraphs =
lines
|> FSharp.Collections.List.skipWhile (fun (s, n) -> String.IsNullOrWhiteSpace s)
diff --git a/src/FSharp.Markdown/Markdown.fs b/src/FSharp.Markdown/Markdown.fs
index e2d760295..969477017 100644
--- a/src/FSharp.Markdown/Markdown.fs
+++ b/src/FSharp.Markdown/Markdown.fs
@@ -8,13 +8,12 @@ namespace FSharp.Markdown
open System
open System.IO
open System.Collections.Generic
+open FSharp.Formatting.Common
// --------------------------------------------------------------------------------------
// Definition of the Markdown format
// --------------------------------------------------------------------------------------
-type MarkdownRange = { Line : int }
-
/// A list kind can be `Ordered` or `Unordered` corresponding to `` and `
` elements
type MarkdownListKind =
| Ordered
@@ -40,8 +39,8 @@ type MarkdownSpan =
| DirectImage of body:string * linkAndTitle:(string * option) * range:MarkdownRange option
| IndirectImage of body:string * link:string * key:string * range:MarkdownRange option
| HardLineBreak of range:MarkdownRange option
- | LatexInlineMath of string * range:MarkdownRange option
- | LatexDisplayMath of string * range:MarkdownRange option
+ | LatexInlineMath of code:string * range:MarkdownRange option
+ | LatexDisplayMath of code:string * range:MarkdownRange option
| EmbedSpans of customSpans:MarkdownEmbedSpans * range:MarkdownRange option
/// A type alias for a list of `MarkdownSpan` values
diff --git a/src/FSharp.Markdown/MarkdownParser.fs b/src/FSharp.Markdown/MarkdownParser.fs
index ecac2f16d..0eb376db4 100644
--- a/src/FSharp.Markdown/MarkdownParser.fs
+++ b/src/FSharp.Markdown/MarkdownParser.fs
@@ -11,6 +11,7 @@ open System.Text.RegularExpressions
open FSharp.Patterns
open FSharp.Collections
+open FSharp.Formatting.Common
// --------------------------------------------------------------------------------------
// Parsing of Markdown - first part handles inline formatting
@@ -118,7 +119,7 @@ let (|AutoLink|_|) input =
let linkFor (scheme:string) =
let prefix = scheme.ToCharArray() |> Array.toList
match input with
- | List.DelimitedWith prefix [' '] (List.AsString link, rest) ->
+ | List.DelimitedWith prefix [' '] (List.AsString link, rest, s, e) ->
Some(scheme + link, ' '::rest)
| List.StartsWith prefix (List.AsString link) ->
Some(link, [])
@@ -156,14 +157,15 @@ let rec parseChars acc input (ctx:ParsingContext) = seq {
// Zero or one literals, depending whether there is some accumulated input
let accLiterals = Lazy.Create(fun () ->
- if List.isEmpty acc then []
- else [Literal(String(List.rev acc |> Array.ofList), ctx.CurrentRange)] )
+ if List.isEmpty acc then ([], ctx)
+ else ([Literal(String(List.rev acc |> Array.ofList), match ctx.CurrentRange with | Some(n) -> Some({ n with EndColumn = n.StartColumn + acc.Length }) | None -> None)], { ctx with CurrentRange = match ctx.CurrentRange with | Some(n) -> Some({ n with StartColumn = n.StartColumn + acc.Length }) | None -> None }) )
match input with
// Recognizes explicit line-break at the end of line
| ' '::' '::'\r'::'\n'::rest
| ' '::' '::('\n' | '\r')::rest ->
- yield! accLiterals.Value
+ let (value, ctx) = accLiterals.Value
+ yield! value
yield HardLineBreak(ctx.CurrentRange)
yield! parseChars [] rest ctx
@@ -178,64 +180,76 @@ let rec parseChars acc input (ctx:ParsingContext) = seq {
// Inline code delimited either using double `` or single `
// (if there are spaces around, then body can contain more backticks)
- | List.DelimitedWith ['`'; ' '] [' '; '`'] (body, rest)
- | List.DelimitedNTimes '`' (body, rest) ->
- yield! accLiterals.Value
- yield InlineCode(String(Array.ofList body).Trim(), ctx.CurrentRange)
+ | List.DelimitedWith ['`'; ' '] [' '; '`'] (body, rest, s, e)
+ | List.DelimitedNTimes '`' (body, rest, s, e) ->
+ let (value, ctx) = accLiterals.Value
+ yield! value
+ yield InlineCode(String(Array.ofList body).Trim(), match ctx.CurrentRange with Some(n) -> Some({ n with StartColumn = n.StartColumn + s; EndColumn = n.EndColumn - e }) | None -> None)
yield! parseChars [] rest ctx
// Display Latex inline math mode
| DelimitedLatexDisplayMath ['$';'$'] (body, rest) ->
- yield! accLiterals.Value
+ let (value, ctx) = accLiterals.Value
+ yield! value
yield LatexDisplayMath(String(Array.ofList body).Trim(), ctx.CurrentRange)
yield! parseChars [] rest ctx
// Inline Latex inline math mode
| DelimitedLatexInlineMath ['$'] (body, rest) ->
- yield! accLiterals.Value
- yield LatexInlineMath(String(Array.ofList body).Trim(), ctx.CurrentRange)
+ let (value, ctx) = accLiterals.Value
+ let ctx = { ctx with CurrentRange = match ctx.CurrentRange with | Some(n) -> Some({ n with StartColumn = n.StartColumn + 1 }) | None -> None }
+ yield! value
+ let code = String(Array.ofList body).Trim()
+ yield LatexInlineMath(code, match ctx.CurrentRange with | Some(n) -> Some({ n with EndColumn = n.StartColumn + code.Length }) | None -> None)
yield! parseChars [] rest ctx
// Inline link wrapped as
- | List.DelimitedWith ['<'] ['>'] (List.AsString link, rest)
+ | List.DelimitedWith ['<'] ['>'] (List.AsString link, rest, s, e)
when Seq.forall (Char.IsWhiteSpace >> not) link && (link.Contains("@") || link.Contains("://")) ->
- yield! accLiterals.Value
+ let (value, ctx) = accLiterals.Value
+ yield! value
yield DirectLink([Literal(link, ctx.CurrentRange)], (link, None), ctx.CurrentRange)
yield! parseChars [] rest ctx
// Not an inline link - leave as an inline HTML tag
- | List.DelimitedWith ['<'] ['>'] (tag, rest) ->
+ | List.DelimitedWith ['<'] ['>'] (tag, rest, s, e) ->
yield! parseChars ('>'::(List.rev tag) @ '<' :: acc) rest ctx
// Recognize direct link [foo](http://bar) or indirect link [foo][bar] or auto link http://bar
| DirectLink (body, link, rest) ->
- yield! accLiterals.Value
- let info = getLinkAndTitle (String(Array.ofList link), 0)
+ let (value, ctx) = accLiterals.Value
+ yield! value
+ let info = getLinkAndTitle (String(Array.ofList link), MRange.Zero)
yield DirectLink(parseChars [] body ctx |> List.ofSeq, info, ctx.CurrentRange)
yield! parseChars [] rest ctx
| IndirectLink(body, link, original, rest) ->
- yield! accLiterals.Value
+ let (value, ctx) = accLiterals.Value
+ yield! value
let key = if String.IsNullOrEmpty(link) then String(body |> Array.ofSeq) else link
yield IndirectLink(parseChars [] body ctx |> List.ofSeq, original, key, ctx.CurrentRange)
yield! parseChars [] rest ctx
| AutoLink (link, rest) ->
- yield! accLiterals.Value
+ let (value, ctx) = accLiterals.Value
+ yield! value
yield DirectLink([Literal(link, ctx.CurrentRange)], (link, None), ctx.CurrentRange)
yield! parseChars [] rest ctx
// Recognize image - this is a link prefixed with the '!' symbol
| '!'::DirectLink (body, link, rest) ->
- yield! accLiterals.Value
- yield DirectImage(String(Array.ofList body), getLinkAndTitle (String(Array.ofList link), 0), ctx.CurrentRange)
+ let (value, ctx) = accLiterals.Value
+ yield! value
+ yield DirectImage(String(Array.ofList body), getLinkAndTitle (String(Array.ofList link), MRange.Zero), ctx.CurrentRange)
yield! parseChars [] rest ctx
| '!'::IndirectLink(body, link, original, rest) ->
- yield! accLiterals.Value
+ let (value, ctx) = accLiterals.Value
+ yield! value
let key = if String.IsNullOrEmpty(link) then String(body |> Array.ofSeq) else link
yield IndirectImage(String(Array.ofList body), original, key, ctx.CurrentRange)
yield! parseChars [] rest ctx
// Handle emphasised text
| Emphasised (body, f, rest) ->
- yield! accLiterals.Value
+ let (value, ctx) = accLiterals.Value
+ yield! value
let body = parseChars [] body ctx |> List.ofSeq
yield f(body, ctx.CurrentRange)
yield! parseChars [] rest ctx
@@ -247,10 +261,12 @@ let rec parseChars acc input (ctx:ParsingContext) = seq {
| x::xs ->
yield! parseChars (x::acc) xs ctx
| [] ->
- yield! accLiterals.Value }
+ let (value, ctx) = accLiterals.Value
+ yield! value }
/// Parse body of a paragraph into a list of Markdown inline spans
let parseSpans (StringPosition.TrimBoth(s, n)) ctx =
+ let ctx = { ctx with CurrentRange = Some(n) }
parseChars [] (s.ToCharArray() |> List.ofArray) ctx |> List.ofSeq
let rec trimSpaces numSpaces (s:string) =
@@ -265,11 +281,11 @@ let rec trimSpaces numSpaces (s:string) =
/// Recognizes heading, either prefixed with #s or followed by === or --- line
let (|Heading|_|) = function
- | (StringPosition.TrimBoth header) :: (StringPosition.TrimEnd (StringPosition.EqualsRepeated("=", 0))) :: rest ->
+ | (StringPosition.TrimBoth header) :: (StringPosition.TrimEnd (StringPosition.EqualsRepeated("=", MRange.Zero))) :: rest ->
Some(1, header, rest)
- | (StringPosition.TrimBoth header) :: (StringPosition.TrimEnd (StringPosition.EqualsRepeated("-", 0))) :: rest ->
+ | (StringPosition.TrimBoth header) :: (StringPosition.TrimEnd (StringPosition.EqualsRepeated("-", MRange.Zero))) :: rest ->
Some(2, header, rest)
- | StringPosition.StartsWithRepeated "#" (n, (header, ln)) :: rest ->
+ | StringPosition.StartsWithRepeated "#" (n, StringPosition.TrimBoth(header, ln)) :: rest ->
let header =
// Drop "##" at the end, but only when it is preceded by some whitespace
// (For example "## Hello F#" should be "Hello F#")
@@ -278,12 +294,12 @@ let (|Heading|_|) = function
if noHash.Length > 0 && Char.IsWhiteSpace(noHash.Chars(noHash.Length - 1))
then noHash else header
else header
- Some(n, (header.Trim(), ln), rest)
+ Some(n, (header, ln), rest)
| rest ->
None
/// Recognizes a horizontal rule written using *, _ or -
-let (|HorizontalRule|_|) (line:string, n:int) =
+let (|HorizontalRule|_|) (line:string, n:MarkdownRange) =
let rec loop ((h, a, u) as arg) i =
if (h >= 3 || a >= 3 || u >= 3) && i = line.Length then Some(line.[0])
elif i = line.Length then None
@@ -355,7 +371,7 @@ let (|FencedCodeBlock|_|) = function
/// Matches when the input starts with a number. Returns the
/// rest of the input, following the last number.
-let (|SkipSomeNumbers|_|) (input:string, n:int) =
+let (|SkipSomeNumbers|_|) (input:string, n:MarkdownRange) =
match List.ofSeq input with
| x::xs when Char.IsDigit x ->
let _, rest = List.partitionUntil (Char.IsDigit >> not) xs
@@ -370,7 +386,8 @@ let (|ListStart|_|) = function
// NOTE: a tab character after +, * or - isn't supported by the reference implementation
// (it will be parsed as paragraph for 0.22)
(StringPosition.StartsWithAny ["+ "; "* "; "- " (*; "+\t"; "*\t"; "-\t"*)] as item)) ->
- let li = ((fst item).Substring(2), snd item)
+ let range = snd item
+ let li = ((fst item).Substring(2), { range with StartColumn = range.StartColumn + 2 })
let (StringPosition.TrimStartAndCount (startIndent2, spaces2, _)) = li
let endIndent =
startIndent + 2 +
@@ -381,12 +398,12 @@ let (|ListStart|_|) = function
(startIndent, spaces,
(SkipSomeNumbers // read a number
(skipNumCount, '.' :: ' ' :: List.AsString item))) ->
- let (StringPosition.TrimStartAndCount (startIndent2, spaces2, _)) = (item, 0)
+ let (StringPosition.TrimStartAndCount (startIndent2, spaces2, _)) = (item, MRange.Zero)
let endIndent =
startIndent + 2 + skipNumCount +
// Handle case of code block
if startIndent2 >= 5 then 1 else startIndent2
- Some(Ordered, startIndent, endIndent, (item, 0))
+ Some(Ordered, startIndent, endIndent, (item, MRange.Zero))
| _ -> None
/// Splits input into lines until whitespace or starting of a list and the rest.
@@ -433,7 +450,7 @@ let (|ListItem|_|) prevSimple = function
yield (line.Trim(), n)
for (line, n) in more do
let trimmed = trimSpaces endIndent line
- yield (trimmed, n) ]
+ yield (trimmed, { n with StartColumn = n.StartColumn + line.Length - trimmed.Length }) ]
//let trimmed = line.TrimStart()
//if trimmed.Length >= line.Length - endIndent then yield trimmed
//else yield line.Substring(endIndent) ]
@@ -466,8 +483,8 @@ let rec pipeTableFindSplits (delim : char array) (line : char list) =
match line with
| DelimitedLatexDisplayMath [ '$'; '$' ] (body, rest) -> ptfs delim rest
| DelimitedLatexInlineMath [ '$' ] (body, rest) -> ptfs delim rest
- | List.DelimitedWith [ '`'; ' ' ] [ ' '; '`' ] (body, rest) -> ptfs delim rest
- | List.DelimitedNTimes '`' (body, rest) -> ptfs delim rest
+ | List.DelimitedWith [ '`'; ' ' ] [ ' '; '`' ] (body, rest, s, e) -> ptfs delim rest
+ | List.DelimitedNTimes '`' (body, rest, s, e) -> ptfs delim rest
| x :: rest when Array.exists ((=) x) delim -> Some rest
| '\\' :: _ :: rest | _ :: rest -> ptfs delim rest
| [] -> None
@@ -486,16 +503,16 @@ let rec pipeTableFindSplits (delim : char array) (line : char list) =
/// Recognizes alignment specified in the passed separator line.
let (|TableCellSeparator|_|) = function
- | StringPosition.StartsAndEndsWith (":", ":") (StringPosition.EqualsRepeated("-", 0)) -> Some(AlignCenter)
- | StringPosition.StartsWith ":" (StringPosition.EqualsRepeated("-", 0)) -> Some(AlignLeft)
- | StringPosition.StartsAndEndsWith ("", ":") (StringPosition.EqualsRepeated("-", 0)) -> Some(AlignRight)
- | StringPosition.EqualsRepeated("-", 0) -> Some(AlignDefault)
+ | StringPosition.StartsAndEndsWith (":", ":") (StringPosition.EqualsRepeated("-", MRange.Zero)) -> Some(AlignCenter)
+ | StringPosition.StartsWith ":" (StringPosition.EqualsRepeated("-", MRange.Zero)) -> Some(AlignLeft)
+ | StringPosition.StartsAndEndsWith ("", ":") (StringPosition.EqualsRepeated("-", MRange.Zero)) -> Some(AlignRight)
+ | StringPosition.EqualsRepeated("-", MRange.Zero) -> Some(AlignDefault)
| _ -> None
/// Recognizes row of pipe table.
/// The function takes number of expected columns and array of delimiters.
/// Returns list of strings between delimiters.
-let (|PipeTableRow|_|) (size : option) delimiters (line : string, n:int) =
+let (|PipeTableRow|_|) (size : option) delimiters (line : string, n:MarkdownRange) =
let parts =
pipeTableFindSplits delimiters (line.ToCharArray() |> Array.toList)
|> List.toArray
@@ -552,20 +569,20 @@ let (|PipeTableBlock|_|) input =
/// The function takes positions of grid columns (if known) and expected grid separator.
/// Passed function is used to check whether all parts within grid are valid.
/// Retuns tuple (position of grid columns, text between grid columns).
-let (|EmacsTableLine|_|) (grid:option) (c:char) (check:string * int -> bool) (line:string, n:int) =
+let (|EmacsTableLine|_|) (grid:option) (c:char) (check:string * MarkdownRange -> bool) (line:string, n:MarkdownRange) =
let p = if grid.IsSome then grid.Value else Array.FindAll([|0..line.Length - 1|], fun i -> line.[i] = c)
let n = p.Length - 1
if n < 2 || line.Length <= p.[n] || Array.exists (fun i -> line.[i] <> c) p then None
else
- let parts = [1..n] |> List.map (fun i -> line.Substring(p.[i - 1] + 1, p.[i] - p.[i - 1] - 1), i)
+ let parts = [1..n] |> List.map (fun i -> line.Substring(p.[i - 1] + 1, p.[i] - p.[i - 1] - 1), { StartLine = n; StartColumn = 0; EndLine = n; EndColumn = p.[i] - p.[i - 1] - 1 })
if List.forall check parts then Some(p, parts) else None
/// Recognizes emacs table
let (|EmacsTableBlock|_|) (input) =
- let isCellSep = StringPosition.(|EqualsRepeated|_|)("-", 0) >> Option.isSome
+ let isCellSep = StringPosition.(|EqualsRepeated|_|)("-", MRange.Zero) >> Option.isSome
let isAlignedCellSep = ( |TableCellSeparator|_| ) >> Option.isSome
- let isHeadCellSep = StringPosition.(|EqualsRepeated|_|)("=", 0) >> Option.isSome
- let isText (s:string, n:int) = true
+ let isHeadCellSep = StringPosition.(|EqualsRepeated|_|)("=", MRange.Zero) >> Option.isSome
+ let isText (s:string, n:MarkdownRange) = true
match input with
| (EmacsTableLine None '+' isAlignedCellSep (grid, parts)) :: rest ->
let alignments = List.choose ( |TableCellSeparator|_| ) parts
@@ -574,8 +591,8 @@ let (|EmacsTableBlock|_|) (input) =
// prevRow - content of the processed rows
// cur - list of paragraphs in the current row (list of empty lists after each separator line)
// flag indicates whether current row is empty (similar to List.forall (List.isEmpty) cur)
- let emptyCur = List.replicate<(string * int) list> (grid.Length - 1) []
- let rec loop flag headers (prevRows:(string * int) list list list) (cur:(string * int) list list) = function
+ let emptyCur = List.replicate<(string * MarkdownRange) list> (grid.Length - 1) []
+ let rec loop flag headers (prevRows:(string * MarkdownRange) list list list) (cur:(string * MarkdownRange) list list) = function
| (EmacsTableLine (Some grid) '|' isText (_, parts)) :: others ->
loop false headers prevRows (List.zip parts cur |> List.map (fun ((h, n), t) -> (h.TrimEnd(), n) :: t)) others
| (EmacsTableLine (Some grid) '+' isCellSep _) :: others ->
@@ -588,14 +605,16 @@ let (|EmacsTableBlock|_|) (input) =
| _ -> None
/// Recognizes a start of a blockquote
-let (|BlockquoteStart|_|) (line:string, n:int) =
+let (|BlockquoteStart|_|) (line:string, n:MarkdownRange) =
let regex =
"^ {0,3}" // Up to three leading spaces
+ ">" // Blockquote character
+ "\s?" // Maybe one whitespace character
+ "(.*)" // Capture everything else
let match' = Regex.Match(line, regex)
- if match'.Success then Some ((match'.Groups.Item(1)).Value, n)
+ if match'.Success then
+ let group = match'.Groups.Item(1)
+ Some (group.Value, { n with StartColumn = n.StartColumn + group.Index; EndColumn = n.StartColumn + group.Index + group.Length })
else None
/// Takes lines that belong to a continuing paragraph until
@@ -631,7 +650,7 @@ let (|LinesUntilBlockquoteEnds|) input =
/// starting with '>' until there is something else
let rec (|Blockquote|_|) = function
| EmptyBlockquote(Lines.TrimBlankStart rest) ->
- Some ([("", 0)], rest)
+ Some ([("", MRange.Zero)], rest)
| BlockquoteStart(line)::LinesUntilBlockquoteEnds(continued, Lines.TrimBlankStart rest) ->
let moreLines, rest =
match rest with
@@ -648,7 +667,7 @@ and (|EmptyBlockquote|_|) = function
| _ -> None
/// Recognizes Latex block - start with "$$$"
-let (|LatexBlock|_|) (lines:(string * int) list) = lines |> function
+let (|LatexBlock|_|) (lines:(string * MarkdownRange) list) = lines |> function
| (first, n)::rest when (first.TrimEnd()) = "$$$" -> rest |> function
| TakeParagraphLines(body, rest) -> Some(body, rest)
| _ -> None
@@ -666,10 +685,10 @@ let (|LinkDefinition|_|) = function
let updateCurrentRange lines =
match lines with
| [] -> None
- | (_, l)::_ -> Some({ Line = l })
+ | (_, l)::_ -> Some(l)
/// Parse a list of lines into a sequence of markdown paragraphs
-let rec parseParagraphs (ctx:ParsingContext) lines = seq {
+let rec parseParagraphs (ctx:ParsingContext) (lines:(string * MarkdownRange) list) = seq {
let ctx = { ctx with CurrentRange = updateCurrentRange lines }
match lines with
// Recognize various kinds of standard paragraphs
@@ -681,7 +700,7 @@ let rec parseParagraphs (ctx:ParsingContext) lines = seq {
yield CodeBlock(code |> String.concat ctx.Newline, langString, ignoredLine, ctx.CurrentRange)
yield! parseParagraphs ctx lines
| Blockquote(body, Lines.TrimBlankStart rest) ->
- yield QuotedBlock(parseParagraphs ctx (body @ [("", 0)]) |> List.ofSeq, ctx.CurrentRange)
+ yield QuotedBlock(parseParagraphs ctx (body @ [("", MRange.Zero)]) |> List.ofSeq, ctx.CurrentRange)
yield! parseParagraphs ctx rest
| EmacsTableBlock((headers, alignments, rows), Lines.TrimBlankStart rest)
| PipeTableBlock((headers, alignments, rows), Lines.TrimBlankStart rest) ->
@@ -715,18 +734,18 @@ let rec parseParagraphs (ctx:ParsingContext) lines = seq {
| [] -> []
// Turn tree into nested list definitions
- let rec formatTree (nodes:Tree list) =
+ let rec formatTree (nodes:Tree list) =
let kind = match nodes with Node((_, kind, _), _)::_ -> kind | _ -> Unordered
let items =
[ for (Node((simple, _, body), nested)) in nodes ->
[ if not simple then yield! parseParagraphs ctx body
- else yield Span(parseSpans(String.concat ctx.Newline (body |> List.map fst), 0) ctx, ctx.CurrentRange)
+ else yield Span(parseSpans(String.concat ctx.Newline (body |> List.map fst), body |> List.map snd |> MRange.MergeRanges) ctx, ctx.CurrentRange)
if nested <> [] then
yield formatTree nested ] ]
ListBlock(kind, items, ctx.CurrentRange)
// Make sure all items of the list have are either simple or not.
- let rec unifySimpleProperty (nodes:Tree list) =
+ let rec unifySimpleProperty (nodes:Tree list) =
let containsNonSimple =
tree |> Seq.exists (function
| Node ((false, _, _), _) -> true
@@ -750,7 +769,7 @@ let rec parseParagraphs (ctx:ParsingContext) lines = seq {
yield InlineBlock(all, ctx.CurrentRange)
yield! parseParagraphs ctx lines
| TakeParagraphLines(Lines.TrimParagraphLines lines, Lines.TrimBlankStart rest) ->
- yield Paragraph (parseSpans (String.concat ctx.Newline lines, 0) ctx, ctx.CurrentRange)
+ yield Paragraph (parseSpans (lines |> List.map fst |> String.concat ctx.Newline, lines |> List.map snd |> MRange.MergeRanges) ctx, ctx.CurrentRange)
yield! parseParagraphs ctx rest
| Lines.TrimBlankStart [] -> ()
diff --git a/src/FSharp.MetadataFormat/Main.fs b/src/FSharp.MetadataFormat/Main.fs
index 16ad5d774..25f9fd2d6 100755
--- a/src/FSharp.MetadataFormat/Main.fs
+++ b/src/FSharp.MetadataFormat/Main.fs
@@ -546,7 +546,7 @@ module Reader =
Seq.iter (fun (x : XNode) ->
if x.NodeType = XmlNodeType.Text then
let text = (x :?> XText).Value
- match findCommand (text, 0) with
+ match findCommand (text, MRange.Zero) with
| Some (k,v) -> cmds.Add(k,v)
| None -> full.Append(text) |> ignore
elif x.NodeType = XmlNodeType.Element then
@@ -713,7 +713,7 @@ module Reader =
| null ->
dict[], (Comment.Create ("", el.Value, []))
| sum ->
- let lines = removeSpaces sum.Value |> Seq.map (fun s -> (s, 0))
+ let lines = removeSpaces sum.Value |> Seq.map (fun s -> (s, MRange.Zero))
let cmds = new System.Collections.Generic.Dictionary<_, _>()
if ctx.MarkdownComments then
diff --git a/tests/FSharp.Literate.Tests/Tests.fs b/tests/FSharp.Literate.Tests/Tests.fs
index 3ca09336c..75432718a 100644
--- a/tests/FSharp.Literate.Tests/Tests.fs
+++ b/tests/FSharp.Literate.Tests/Tests.fs
@@ -61,10 +61,10 @@ a
b""", __SOURCE_DIRECTORY__ @@ "Test.fsx")
//[/test]
- doc.Paragraphs |> shouldMatchPar (function Paragraph([Literal("a", Some({ Line = 2 }))], Some({ Line = 2 })) -> true | _ -> false)
- doc.Paragraphs |> shouldMatchPar (function Paragraph([Literal("b", Some({ Line = 6 }))], Some({ Line = 6 })) -> true | _ -> false)
+ doc.Paragraphs |> shouldMatchPar (function Paragraph([Literal("a", Some({ StartLine = 2 }))], Some({ StartLine = 2 })) -> true | _ -> false)
+ doc.Paragraphs |> shouldMatchPar (function Paragraph([Literal("b", Some({ StartLine = 6 }))], Some({ StartLine = 6 })) -> true | _ -> false)
doc.Paragraphs |> shouldMatchPar (function
- | EmbedParagraphs(:? LiterateParagraph as cd, Some({ Line = 4 })) ->
+ | EmbedParagraphs(:? LiterateParagraph as cd, Some({ StartLine = 4 })) ->
match cd with LanguageTaggedCode("csharp", text) -> text.Contains "magic" | _ -> false
| _ -> false)
@@ -82,7 +82,7 @@ let test = 42"""
doc.Paragraphs |> shouldMatchPar (function
| Matching.LiterateParagraph(FormattedCode(_)) -> true | _ -> false)
doc.Paragraphs |> shouldMatchPar (function
- | Paragraph([Strong([Literal("hello", Some({ Line = 1 }))], Some({ Line = 1 }))], Some({ Line = 1 })) -> true | _ -> false)
+ | Paragraph([Strong([Literal("hello", Some({ StartLine = 1 }))], Some({ StartLine = 1 }))], Some({ StartLine = 1 })) -> true | _ -> false)
[]
let ``Can parse heading on the same line as opnening comment (#147)`` () =
@@ -92,7 +92,7 @@ content *)
let test = 42"""
let doc = Literate.ParseScriptString(content, "C" @@ "A.fsx", getFormatAgent())
doc.Paragraphs |> shouldMatchPar (function
- | Heading(2, [Literal("Heading", Some({ Line = 1 }))], Some({ Line = 1 })) -> true | _ -> false)
+ | Heading(2, [Literal("Heading", Some({ StartLine = 1 }))], Some({ StartLine = 1 })) -> true | _ -> false)
[]
let ``Can parse and format markdown with F# snippet`` () =
@@ -105,7 +105,7 @@ let ``Can parse and format markdown with F# snippet`` () =
doc.Paragraphs |> shouldMatchPar (function
| Matching.LiterateParagraph(FormattedCode(_)) -> true | _ -> false)
doc.Paragraphs |> shouldMatchPar (function
- | Paragraph([Strong([Literal("hello", Some({ Line = 2 }))], Some({ Line = 2 }))], Some({ Line = 2 })) -> true | _ -> false)
+ | Paragraph([Strong([Literal("hello", Some({ StartLine = 2 }))], Some({ StartLine = 2 }))], Some({ StartLine = 2 })) -> true | _ -> false)
[]
let ``Can parse and format markdown with Github-flavoured F# snippet`` () =
@@ -120,7 +120,7 @@ let test = 42
doc.Paragraphs |> shouldMatchPar (function
| Matching.LiterateParagraph(FormattedCode(_)) -> true | _ -> false)
doc.Paragraphs |> shouldMatchPar (function
- | Paragraph([Strong([Literal("hello", Some({ Line = 2 }))], Some({ Line = 2 }))], Some({ Line = 2 })) -> true | _ -> false)
+ | Paragraph([Strong([Literal("hello", Some({ StartLine = 2 }))], Some({ StartLine = 2 }))], Some({ StartLine = 2 })) -> true | _ -> false)
[]
let ``Can parse and format markdown with Github-flavoured F# snippet starting and ending with empty lines`` () =
@@ -581,7 +581,7 @@ let ``Can format single snippet with label using literate parser`` () =
let add a b = a + b
// [/snippet]"""
let doc = Literate.ParseScriptString(source, "/somewhere/test.fsx", getFormatAgent())
- doc.Paragraphs |> shouldMatchPar (function Heading(_, [Literal("demo", Some({ Line = 1 }))], Some({ Line = 1 })) -> true | _ -> false)
+ doc.Paragraphs |> shouldMatchPar (function Heading(_, [Literal("demo", Some({ StartLine = 1 }))], Some({ StartLine = 1 })) -> true | _ -> false)
[]
@@ -594,8 +594,8 @@ let add a b = a + b
let mul a b = a * b
// [/snippet]"""
let doc = Literate.ParseScriptString(source, "/somewhere/test.fsx", getFormatAgent())
- doc.Paragraphs |> shouldMatchPar (function Heading(_, [Literal("demo1", Some({ Line = 1 }))], Some({ Line = 1 })) -> true | _ -> false)
- doc.Paragraphs |> shouldMatchPar (function Heading(_, [Literal("demo2", Some({ Line = 1 }))], Some({ Line = 1 })) -> true | _ -> false)
+ doc.Paragraphs |> shouldMatchPar (function Heading(_, [Literal("demo1", Some({ StartLine = 1 }))], Some({ StartLine = 1 })) -> true | _ -> false)
+ doc.Paragraphs |> shouldMatchPar (function Heading(_, [Literal("demo2", Some({ StartLine = 1 }))], Some({ StartLine = 1 })) -> true | _ -> false)
[]
let ``Formatter does not crash on source that contains invalid string`` () =
diff --git a/tests/FSharp.Markdown.Tests/FSharp.Markdown.Tests.fsproj b/tests/FSharp.Markdown.Tests/FSharp.Markdown.Tests.fsproj
index cdebb63c3..01ed64dc6 100644
--- a/tests/FSharp.Markdown.Tests/FSharp.Markdown.Tests.fsproj
+++ b/tests/FSharp.Markdown.Tests/FSharp.Markdown.Tests.fsproj
@@ -95,6 +95,11 @@
-->
+
+ FSharp.Formatting.Common
+ {91bad90e-bf3b-4646-a1a7-1568f8f25075}
+ True
+ FSharp.Markdown{c44c1c05-599a-40dd-9590-465eab8960c5}
diff --git a/tests/FSharp.Markdown.Tests/Markdown.fs b/tests/FSharp.Markdown.Tests/Markdown.fs
index 093777632..8d90faf69 100644
--- a/tests/FSharp.Markdown.Tests/Markdown.fs
+++ b/tests/FSharp.Markdown.Tests/Markdown.fs
@@ -9,6 +9,7 @@ module FSharp.Markdown.Tests.Parsing
open FsUnit
open NUnit.Framework
open FSharp.Markdown
+open FSharp.Formatting.Common
let properNewLines (text: string) = text.Replace("\r\n", System.Environment.NewLine)
@@ -19,7 +20,7 @@ let shouldEqualNoWhiteSpace (x:string) (y:string) =
let ``Inline HTML tag containing 'at' is not turned into hyperlink`` () =
let doc = """hi""" |> Markdown.Parse
doc.Paragraphs
- |> shouldEqual [ Paragraph([Literal("""hi""", Some({ Line = 1 })) ], Some({ Line = 1 }))]
+ |> shouldEqual [ Paragraph([Literal("""hi""", Some({ StartLine = 1; StartColumn = 0; EndLine = 1; EndColumn = 29 })) ], Some({ StartLine = 1; StartColumn = 0; EndLine = 1; EndColumn = 29 }))]
[]
let ``Encode '<' and '>' characters as HTML entities`` () =
@@ -36,8 +37,8 @@ Some more""" |> Markdown.Parse
doc.Paragraphs
|> shouldEqual [
- Heading(2, [Literal("Hello F#", Some({ Line = 2 }))], Some({ Line = 2 }))
- Paragraph([Literal("Some more", Some({ Line = 3 }))], Some({ Line = 3 }))]
+ Heading(2, [Literal("Hello F#", Some({ StartLine = 2; StartColumn = 3; EndLine = 2; EndColumn = 11 }))], Some({ StartLine = 2; StartColumn = 0; EndLine = 2; EndColumn = 11 }))
+ Paragraph([Literal("Some more", Some({ StartLine = 3; StartColumn = 0; EndLine = 3; EndColumn = 9 }))], Some({ StartLine = 3; StartColumn = 0; EndLine = 3; EndColumn = 9 }))]
[]
let ``Headings ending with spaces followed by # are parsed correctly`` () =
@@ -47,8 +48,8 @@ Some more""" |> Markdown.Parse
doc.Paragraphs
|> shouldEqual [
- Heading(2, [Literal("Hello", Some({ Line = 2 }))], Some({ Line = 2 }))
- Paragraph([Literal("Some more", Some({ Line = 3 }))], Some({ Line = 3 }))]
+ Heading(2, [Literal("Hello", Some({ StartLine = 2; StartColumn = 3; EndLine = 2; EndColumn = 8 }))], Some({ StartLine = 2; StartColumn = 0; EndLine = 2; EndColumn = 13 }))
+ Paragraph([Literal("Some more", Some({ StartLine = 3; StartColumn = 0; EndLine = 3; EndColumn = 9 }))], Some({ StartLine = 3; StartColumn = 0; EndLine = 3; EndColumn = 9 }))]
[]
let ``Should be able to create nested list item with two paragraphs`` () =
@@ -59,38 +60,38 @@ let ``Should be able to create nested list item with two paragraphs`` () =
c""" |> Markdown.Parse
let expectedBody =
- [ Paragraph([Literal("b", Some({ Line = 3 }))] , Some({ Line = 3 }))
- Paragraph([Literal("c", Some({ Line = 5 }))], Some({ Line = 5 })) ]
+ [ Paragraph([Literal("b", Some({ StartLine = 3; StartColumn = 4; EndLine = 3; EndColumn = 5 }))] , Some({ StartLine = 3; StartColumn = 4; EndLine = 3; EndColumn = 5 }))
+ Paragraph([Literal("c", Some({ StartLine = 5; StartColumn = 4; EndLine = 5; EndColumn = 5 }))], Some({ StartLine = 5; StartColumn = 4; EndLine = 5; EndColumn = 5 })) ]
match doc.Paragraphs.Head with
- | ListBlock(Unordered, [ [Span([Literal("a", Some({ Line = 2 }))], _); ListBlock(Unordered, [ body ], _)] ], _) ->
+ | ListBlock(Unordered, [ [Span([Literal("a", Some({ StartLine = 2; StartColumn = 2; EndLine = 2; EndColumn = 3 }))], _); ListBlock(Unordered, [ body ], _)] ], _) ->
body |> shouldEqual expectedBody
| _ -> Assert.Fail "Expected list block with a nested list block"
[]
let ``Can escape special characters such as "*" in emphasis`` () =
let doc = """*foo\*\*bar*""" |> Markdown.Parse
- let expected = Paragraph([Emphasis([Literal("foo**bar", Some({ Line = 1 }))], Some({ Line = 1 }))], Some({ Line = 1 }))
+ let expected = Paragraph([Emphasis([Literal("foo**bar", Some({ StartLine = 1; StartColumn = 0; EndLine = 1; EndColumn = 8 }))], Some({ StartLine = 1; StartColumn = 0; EndLine = 1; EndColumn = 12 }))], Some({ StartLine = 1; StartColumn = 0; EndLine = 1; EndColumn = 12 }))
doc.Paragraphs.Head
|> shouldEqual expected
[]
let ``Can escape special characters in LaTex inline math`` () =
let doc = """test \$ is: $foo\$\$bar<>\$\&\%\$\#\_\{\}$""" |> Markdown.Parse
- let expected = Paragraph([Literal("test $ is: ", Some({ Line = 1 })); LatexInlineMath("foo\$\$bar<>\$\&\%\$\#\_\{\}", Some({ Line = 1 }))], Some({ Line = 1 }))
+ let expected = Paragraph([Literal("test $ is: ", Some({ StartLine = 1; StartColumn = 0; EndLine = 1; EndColumn = 11 })); LatexInlineMath("foo\$\$bar<>\$\&\%\$\#\_\{\}", Some({ StartLine = 1; StartColumn = 12; EndLine = 1; EndColumn = 40 }))], Some({ StartLine = 1; StartColumn = 0; EndLine = 1; EndColumn = 42 }))
doc.Paragraphs.Head
|> shouldEqual expected
[]
let ``Test special character _ in LaTex inline math`` () =
let doc = """$\bigcap_{x \in A} p_{x}A$""" |> Markdown.Parse
- let expected = Paragraph([ LatexInlineMath("\\bigcap_{x \\in A} p_{x}A", Some({ Line = 1 })) ], Some({ Line = 1 }))
+ let expected = Paragraph([ LatexInlineMath("\\bigcap_{x \\in A} p_{x}A", Some({ StartLine = 1; StartColumn = 1; EndLine = 1; EndColumn = 25 })) ], Some({ StartLine = 1; StartColumn = 0; EndLine = 1; EndColumn = 26 }))
doc.Paragraphs.Head
|> shouldEqual expected
[]
let ``Inline code can contain backticks when wrapped with spaces`` () =
let doc = """` ``h`` `""" |> Markdown.Parse
- let expected = Paragraph([InlineCode("``h``", Some({ Line = 1 }))], Some({ Line = 1 }))
+ let expected = Paragraph([InlineCode("``h``", Some({ StartLine = 1; StartColumn = 2; EndLine = 1; EndColumn = 7 }))], Some({ StartLine = 1; StartColumn = 0; EndLine = 1; EndColumn = 9 }))
doc.Paragraphs.Head
|> shouldEqual expected
@@ -284,7 +285,7 @@ let ``Transform horizontal rules correctly``() =
let doc = "* * *\r\n\r\n***\r\n\r\n*****\r\n\r\n- - -\r\n\r\n---------------------------------------\r\n\r\n";
let expected = "\r\n\r\n\r\n\r\n\r\n" |> properNewLines
Markdown.Parse(doc).Paragraphs
- |> shouldEqual [ HorizontalRule('*', Some({ Line = 1 })); HorizontalRule('*', Some({ Line = 3 })); HorizontalRule('*', Some({ Line = 5 })); HorizontalRule('-', Some({ Line = 7 })); HorizontalRule('-', Some({ Line = 9 })) ]
+ |> shouldEqual [ HorizontalRule('*', Some({ StartLine = 1; StartColumn = 0; EndLine = 1; EndColumn = 5 })); HorizontalRule('*', Some({ StartLine = 3; StartColumn = 0; EndLine = 3; EndColumn = 3 })); HorizontalRule('*', Some({ StartLine = 5; StartColumn = 0; EndLine = 5; EndColumn = 5 })); HorizontalRule('-', Some({ StartLine = 7; StartColumn = 0; EndLine = 7; EndColumn = 5 })); HorizontalRule('-', Some({ StartLine = 9; StartColumn = 0; EndLine = 9; EndColumn = 39 })) ]
Markdown.TransformHtml doc
|> shouldEqual expected
@@ -326,8 +327,8 @@ let ``Transform tables with delimiters in code or math correctly``() =
let ``Parse empty blockquote followed by content``() =
let doc = ">
a"
- let expected = [ QuotedBlock([], Some({ Line = 1 }))
- Paragraph([ Literal("a", Some({ Line = 2 })) ], Some({ Line = 2 })) ]
+ let expected = [ QuotedBlock([], Some({ StartLine = 1; StartColumn = 0; EndLine = 1; EndColumn = 1 }))
+ Paragraph([ Literal("a", Some({ StartLine = 2; StartColumn = 0; EndLine = 2; EndColumn = 1 })) ], Some({ StartLine = 2; StartColumn = 0; EndLine = 2; EndColumn = 1 })) ]
(Markdown.Parse doc).Paragraphs
|> shouldEqual expected
@@ -337,8 +338,8 @@ let ``Parse blockquote teriminated by empty blockquote line and followed by cont
let doc = ">a
>
a"
- let expected = [ QuotedBlock([ Paragraph([ Literal("a", Some({ Line = 1 })) ], Some({ Line = 1 })) ], Some({ Line = 1 }))
- Paragraph([ Literal("a", Some({ Line = 3 })) ], Some({ Line = 3 })) ]
+ let expected = [ QuotedBlock([ Paragraph([ Literal("a", Some({ StartLine = 1; StartColumn = 1; EndLine = 1; EndColumn = 2 })) ], Some({ StartLine = 1; StartColumn = 1; EndLine = 1; EndColumn = 2 })) ], Some({ StartLine = 1; StartColumn = 0; EndLine = 1; EndColumn = 2 }))
+ Paragraph([ Literal("a", Some({ StartLine = 3; StartColumn = 0; EndLine = 3; EndColumn = 1 })) ], Some({ StartLine = 3; StartColumn = 0; EndLine = 3; EndColumn = 1 })) ]
(Markdown.Parse doc).Paragraphs
|> shouldEqual expected
@@ -346,7 +347,7 @@ a"
[]
let ``Parse blockquote with three leading spaces``() =
let doc = " >a"
- let expected = [ QuotedBlock([ Paragraph([ Literal("a", Some({ Line = 1 })) ], Some({ Line = 1 })) ], Some({ Line = 1 })) ]
+ let expected = [ QuotedBlock([ Paragraph([ Literal("a", Some({ StartLine = 1; StartColumn = 4; EndLine = 1; EndColumn = 5 })) ], Some({ StartLine = 1; StartColumn = 4; EndLine = 1; EndColumn = 5 })) ], Some({ StartLine = 1; StartColumn = 0; EndLine = 1; EndColumn = 5 })) ]
(Markdown.Parse doc).Paragraphs
|> shouldEqual expected
\ No newline at end of file
From 2b6f7bb2535cd1445d33ef8064600a07ba1e82f4 Mon Sep 17 00:00:00 2001
From: Avi Avni
Date: Tue, 12 Jul 2016 09:22:25 +0300
Subject: [PATCH 006/108] fixes from tomas code review
---
docs/content/markdown.fsx | 2 +-
src/FSharp.Formatting.Common/Range.fs | 3 +-
src/FSharp.Markdown/HtmlFormatting.fs | 2 +-
src/FSharp.Markdown/LatexFormatting.fs | 2 +-
src/FSharp.Markdown/Main.fs | 2 +-
src/FSharp.Markdown/Markdown.fs | 18 +++++------
src/FSharp.Markdown/MarkdownParser.fs | 45 +++++++++++++++-----------
src/FSharp.MetadataFormat/Main.fs | 4 +--
8 files changed, 44 insertions(+), 34 deletions(-)
diff --git a/docs/content/markdown.fsx b/docs/content/markdown.fsx
index 133127bda..3818c6bcd 100644
--- a/docs/content/markdown.fsx
+++ b/docs/content/markdown.fsx
@@ -67,7 +67,7 @@ The following snippet prints the heading of the document:
// Iterate over all the paragraph elements
for par in parsed.Paragraphs do
match par with
- | Heading(1, [Literal(text, _)], _) ->
+ | Heading(size=1; body=[Literal(text=text)]) ->
// Recognize heading that has a simple content
// containing just a literal (no other formatting)
printfn "%s" text
diff --git a/src/FSharp.Formatting.Common/Range.fs b/src/FSharp.Formatting.Common/Range.fs
index bdb58b434..f0946edad 100644
--- a/src/FSharp.Formatting.Common/Range.fs
+++ b/src/FSharp.Formatting.Common/Range.fs
@@ -2,7 +2,8 @@
type MarkdownRange = { StartLine : int; StartColumn : int; EndLine : int; EndColumn : int }
-module MRange =
+[]
+module MarkdownRange =
let Zero = { StartLine = 0; StartColumn = 0; EndLine = 0; EndColumn = 0 }
let MergeRanges (ranges:MarkdownRange list) =
diff --git a/src/FSharp.Markdown/HtmlFormatting.fs b/src/FSharp.Markdown/HtmlFormatting.fs
index b84808ee5..45badc162 100644
--- a/src/FSharp.Markdown/HtmlFormatting.fs
+++ b/src/FSharp.Markdown/HtmlFormatting.fs
@@ -98,7 +98,7 @@ let rec formatSpan (ctx:FormattingContext) = function
ctx.Writer.Write(original)
| IndirectImage(body, _, LookupKey ctx.Links (link, title), _)
- | DirectImage(body, (link, title), _) ->
+ | DirectImage(body, link, title, _) ->
ctx.Writer.Write("
// Use the technique introduced at
// http://stackoverflow.com/q/14014827
diff --git a/src/FSharp.Markdown/Main.fs b/src/FSharp.Markdown/Main.fs
index 1b79fdda8..155a729ce 100644
--- a/src/FSharp.Markdown/Main.fs
+++ b/src/FSharp.Markdown/Main.fs
@@ -58,7 +58,7 @@ type Markdown =
//|> Utils.replaceTabs 4
let links = Dictionary<_, _>()
//let (Lines.TrimBlank lines) = lines
- let ctx : ParsingContext = { Newline = newline; Links = links; CurrentRange = Some(MRange.Zero) }
+ let ctx : ParsingContext = { Newline = newline; Links = links; CurrentRange = Some(MarkdownRange.Zero) }
let paragraphs =
lines
|> FSharp.Collections.List.skipWhile (fun (s, n) -> String.IsNullOrWhiteSpace s)
diff --git a/src/FSharp.Markdown/Markdown.fs b/src/FSharp.Markdown/Markdown.fs
index 969477017..11e06f149 100644
--- a/src/FSharp.Markdown/Markdown.fs
+++ b/src/FSharp.Markdown/Markdown.fs
@@ -31,12 +31,12 @@ type MarkdownColumnAlignment =
type MarkdownSpan =
| Literal of text:string * range:MarkdownRange option
| InlineCode of code:string * range:MarkdownRange option
- | Strong of spans:MarkdownSpans * range:MarkdownRange option
- | Emphasis of spans:MarkdownSpans * range:MarkdownRange option
+ | Strong of body:MarkdownSpans * range:MarkdownRange option
+ | Emphasis of body:MarkdownSpans * range:MarkdownRange option
| AnchorLink of link:string * range:MarkdownRange option
- | DirectLink of spans:MarkdownSpans * linkAndTitle:(string * option) * range:MarkdownRange option
- | IndirectLink of spans:MarkdownSpans * link:string * key:string * range:MarkdownRange option
- | DirectImage of body:string * linkAndTitle:(string * option) * range:MarkdownRange option
+ | DirectLink of body:MarkdownSpans * linkAndTitle:(string * option) * range:MarkdownRange option
+ | IndirectLink of body:MarkdownSpans * link:string * key:string * range:MarkdownRange option
+ | DirectImage of body:string * link:string * title:option * range:MarkdownRange option
| IndirectImage of body:string * link:string * key:string * range:MarkdownRange option
| HardLineBreak of range:MarkdownRange option
| LatexInlineMath of code:string * range:MarkdownRange option
@@ -55,15 +55,15 @@ and MarkdownEmbedSpans =
/// Paragraphs are headings, inline paragraphs, code blocks, lists, quotations, tables and
/// also embedded LaTeX blocks.
type MarkdownParagraph =
- | Heading of n:int * spans:MarkdownSpans * range:MarkdownRange option
- | Paragraph of spans:MarkdownSpans * range:MarkdownRange option
+ | Heading of size:int * body:MarkdownSpans * range:MarkdownRange option
+ | Paragraph of body:MarkdownSpans * range:MarkdownRange option
| CodeBlock of code:string * language:string * ignoredLine:string * range:MarkdownRange option
| InlineBlock of code:string * range:MarkdownRange option
| ListBlock of kind:MarkdownListKind * items:list * range:MarkdownRange option
| QuotedBlock of paragraphs:MarkdownParagraphs * range:MarkdownRange option
- | Span of spans:MarkdownSpans * range:MarkdownRange option
+ | Span of body:MarkdownSpans * range:MarkdownRange option
| LatexBlock of body:list * range:MarkdownRange option
- | HorizontalRule of c:char * range:MarkdownRange option
+ | HorizontalRule of character:char * range:MarkdownRange option
| TableBlock of headers:option * alignments:list * rows:list * range:MarkdownRange option
| EmbedParagraphs of customParagraphs:MarkdownEmbedParagraphs * range:MarkdownRange option
diff --git a/src/FSharp.Markdown/MarkdownParser.fs b/src/FSharp.Markdown/MarkdownParser.fs
index 0eb376db4..97a808d25 100644
--- a/src/FSharp.Markdown/MarkdownParser.fs
+++ b/src/FSharp.Markdown/MarkdownParser.fs
@@ -155,10 +155,18 @@ type ParsingContext =
/// Parses a body of a paragraph and recognizes all inline tags.
let rec parseChars acc input (ctx:ParsingContext) = seq {
- // Zero or one literals, depending whether there is some accumulated input
+ // Zero or one literals, depending whether there is some accumulated input and update the ctx
let accLiterals = Lazy.Create(fun () ->
if List.isEmpty acc then ([], ctx)
- else ([Literal(String(List.rev acc |> Array.ofList), match ctx.CurrentRange with | Some(n) -> Some({ n with EndColumn = n.StartColumn + acc.Length }) | None -> None)], { ctx with CurrentRange = match ctx.CurrentRange with | Some(n) -> Some({ n with StartColumn = n.StartColumn + acc.Length }) | None -> None }) )
+ else
+ let range = match ctx.CurrentRange with
+ | Some(n) -> Some({ n with EndColumn = n.StartColumn + acc.Length })
+ | None -> None
+ let ctx = { ctx with CurrentRange = match ctx.CurrentRange with
+ | Some(n) -> Some({ n with StartColumn = n.StartColumn + acc.Length })
+ | None -> None }
+ let text = String(List.rev acc |> Array.ofList)
+ ([Literal(text, range)], ctx) )
match input with
// Recognizes explicit line-break at the end of line
@@ -218,7 +226,7 @@ let rec parseChars acc input (ctx:ParsingContext) = seq {
| DirectLink (body, link, rest) ->
let (value, ctx) = accLiterals.Value
yield! value
- let info = getLinkAndTitle (String(Array.ofList link), MRange.Zero)
+ let info = getLinkAndTitle (String(Array.ofList link), MarkdownRange.Zero)
yield DirectLink(parseChars [] body ctx |> List.ofSeq, info, ctx.CurrentRange)
yield! parseChars [] rest ctx
| IndirectLink(body, link, original, rest) ->
@@ -237,7 +245,8 @@ let rec parseChars acc input (ctx:ParsingContext) = seq {
| '!'::DirectLink (body, link, rest) ->
let (value, ctx) = accLiterals.Value
yield! value
- yield DirectImage(String(Array.ofList body), getLinkAndTitle (String(Array.ofList link), MRange.Zero), ctx.CurrentRange)
+ let link, title = getLinkAndTitle (String(Array.ofList link), MarkdownRange.Zero)
+ yield DirectImage(String(Array.ofList body), link, title, ctx.CurrentRange)
yield! parseChars [] rest ctx
| '!'::IndirectLink(body, link, original, rest) ->
let (value, ctx) = accLiterals.Value
@@ -281,9 +290,9 @@ let rec trimSpaces numSpaces (s:string) =
/// Recognizes heading, either prefixed with #s or followed by === or --- line
let (|Heading|_|) = function
- | (StringPosition.TrimBoth header) :: (StringPosition.TrimEnd (StringPosition.EqualsRepeated("=", MRange.Zero))) :: rest ->
+ | (StringPosition.TrimBoth header) :: (StringPosition.TrimEnd (StringPosition.EqualsRepeated("=", MarkdownRange.Zero))) :: rest ->
Some(1, header, rest)
- | (StringPosition.TrimBoth header) :: (StringPosition.TrimEnd (StringPosition.EqualsRepeated("-", MRange.Zero))) :: rest ->
+ | (StringPosition.TrimBoth header) :: (StringPosition.TrimEnd (StringPosition.EqualsRepeated("-", MarkdownRange.Zero))) :: rest ->
Some(2, header, rest)
| StringPosition.StartsWithRepeated "#" (n, StringPosition.TrimBoth(header, ln)) :: rest ->
let header =
@@ -398,12 +407,12 @@ let (|ListStart|_|) = function
(startIndent, spaces,
(SkipSomeNumbers // read a number
(skipNumCount, '.' :: ' ' :: List.AsString item))) ->
- let (StringPosition.TrimStartAndCount (startIndent2, spaces2, _)) = (item, MRange.Zero)
+ let (StringPosition.TrimStartAndCount (startIndent2, spaces2, _)) = (item, MarkdownRange.Zero)
let endIndent =
startIndent + 2 + skipNumCount +
// Handle case of code block
if startIndent2 >= 5 then 1 else startIndent2
- Some(Ordered, startIndent, endIndent, (item, MRange.Zero))
+ Some(Ordered, startIndent, endIndent, (item, MarkdownRange.Zero))
| _ -> None
/// Splits input into lines until whitespace or starting of a list and the rest.
@@ -503,10 +512,10 @@ let rec pipeTableFindSplits (delim : char array) (line : char list) =
/// Recognizes alignment specified in the passed separator line.
let (|TableCellSeparator|_|) = function
- | StringPosition.StartsAndEndsWith (":", ":") (StringPosition.EqualsRepeated("-", MRange.Zero)) -> Some(AlignCenter)
- | StringPosition.StartsWith ":" (StringPosition.EqualsRepeated("-", MRange.Zero)) -> Some(AlignLeft)
- | StringPosition.StartsAndEndsWith ("", ":") (StringPosition.EqualsRepeated("-", MRange.Zero)) -> Some(AlignRight)
- | StringPosition.EqualsRepeated("-", MRange.Zero) -> Some(AlignDefault)
+ | StringPosition.StartsAndEndsWith (":", ":") (StringPosition.EqualsRepeated("-", MarkdownRange.Zero)) -> Some(AlignCenter)
+ | StringPosition.StartsWith ":" (StringPosition.EqualsRepeated("-", MarkdownRange.Zero)) -> Some(AlignLeft)
+ | StringPosition.StartsAndEndsWith ("", ":") (StringPosition.EqualsRepeated("-", MarkdownRange.Zero)) -> Some(AlignRight)
+ | StringPosition.EqualsRepeated("-", MarkdownRange.Zero) -> Some(AlignDefault)
| _ -> None
/// Recognizes row of pipe table.
@@ -579,9 +588,9 @@ let (|EmacsTableLine|_|) (grid:option) (c:char) (check:string * Markdown
/// Recognizes emacs table
let (|EmacsTableBlock|_|) (input) =
- let isCellSep = StringPosition.(|EqualsRepeated|_|)("-", MRange.Zero) >> Option.isSome
+ let isCellSep = StringPosition.(|EqualsRepeated|_|)("-", MarkdownRange.Zero) >> Option.isSome
let isAlignedCellSep = ( |TableCellSeparator|_| ) >> Option.isSome
- let isHeadCellSep = StringPosition.(|EqualsRepeated|_|)("=", MRange.Zero) >> Option.isSome
+ let isHeadCellSep = StringPosition.(|EqualsRepeated|_|)("=", MarkdownRange.Zero) >> Option.isSome
let isText (s:string, n:MarkdownRange) = true
match input with
| (EmacsTableLine None '+' isAlignedCellSep (grid, parts)) :: rest ->
@@ -650,7 +659,7 @@ let (|LinesUntilBlockquoteEnds|) input =
/// starting with '>' until there is something else
let rec (|Blockquote|_|) = function
| EmptyBlockquote(Lines.TrimBlankStart rest) ->
- Some ([("", MRange.Zero)], rest)
+ Some ([("", MarkdownRange.Zero)], rest)
| BlockquoteStart(line)::LinesUntilBlockquoteEnds(continued, Lines.TrimBlankStart rest) ->
let moreLines, rest =
match rest with
@@ -700,7 +709,7 @@ let rec parseParagraphs (ctx:ParsingContext) (lines:(string * MarkdownRange) lis
yield CodeBlock(code |> String.concat ctx.Newline, langString, ignoredLine, ctx.CurrentRange)
yield! parseParagraphs ctx lines
| Blockquote(body, Lines.TrimBlankStart rest) ->
- yield QuotedBlock(parseParagraphs ctx (body @ [("", MRange.Zero)]) |> List.ofSeq, ctx.CurrentRange)
+ yield QuotedBlock(parseParagraphs ctx (body @ [("", MarkdownRange.Zero)]) |> List.ofSeq, ctx.CurrentRange)
yield! parseParagraphs ctx rest
| EmacsTableBlock((headers, alignments, rows), Lines.TrimBlankStart rest)
| PipeTableBlock((headers, alignments, rows), Lines.TrimBlankStart rest) ->
@@ -739,7 +748,7 @@ let rec parseParagraphs (ctx:ParsingContext) (lines:(string * MarkdownRange) lis
let items =
[ for (Node((simple, _, body), nested)) in nodes ->
[ if not simple then yield! parseParagraphs ctx body
- else yield Span(parseSpans(String.concat ctx.Newline (body |> List.map fst), body |> List.map snd |> MRange.MergeRanges) ctx, ctx.CurrentRange)
+ else yield Span(parseSpans(String.concat ctx.Newline (body |> List.map fst), body |> List.map snd |> MarkdownRange.MergeRanges) ctx, ctx.CurrentRange)
if nested <> [] then
yield formatTree nested ] ]
ListBlock(kind, items, ctx.CurrentRange)
@@ -769,7 +778,7 @@ let rec parseParagraphs (ctx:ParsingContext) (lines:(string * MarkdownRange) lis
yield InlineBlock(all, ctx.CurrentRange)
yield! parseParagraphs ctx lines
| TakeParagraphLines(Lines.TrimParagraphLines lines, Lines.TrimBlankStart rest) ->
- yield Paragraph (parseSpans (lines |> List.map fst |> String.concat ctx.Newline, lines |> List.map snd |> MRange.MergeRanges) ctx, ctx.CurrentRange)
+ yield Paragraph (parseSpans (lines |> List.map fst |> String.concat ctx.Newline, lines |> List.map snd |> MarkdownRange.MergeRanges) ctx, ctx.CurrentRange)
yield! parseParagraphs ctx rest
| Lines.TrimBlankStart [] -> ()
diff --git a/src/FSharp.MetadataFormat/Main.fs b/src/FSharp.MetadataFormat/Main.fs
index 25f9fd2d6..ce1d74f99 100755
--- a/src/FSharp.MetadataFormat/Main.fs
+++ b/src/FSharp.MetadataFormat/Main.fs
@@ -546,7 +546,7 @@ module Reader =
Seq.iter (fun (x : XNode) ->
if x.NodeType = XmlNodeType.Text then
let text = (x :?> XText).Value
- match findCommand (text, MRange.Zero) with
+ match findCommand (text, MarkdownRange.Zero) with
| Some (k,v) -> cmds.Add(k,v)
| None -> full.Append(text) |> ignore
elif x.NodeType = XmlNodeType.Element then
@@ -713,7 +713,7 @@ module Reader =
| null ->
dict[], (Comment.Create ("", el.Value, []))
| sum ->
- let lines = removeSpaces sum.Value |> Seq.map (fun s -> (s, MRange.Zero))
+ let lines = removeSpaces sum.Value |> Seq.map (fun s -> (s, MarkdownRange.Zero))
let cmds = new System.Collections.Generic.Dictionary<_, _>()
if ctx.MarkdownComments then
From 6ca4b3feab21551fcc8346607a870f94127dadcb Mon Sep 17 00:00:00 2001
From: Tomas Petricek
Date: Mon, 1 Aug 2016 15:25:24 +0100
Subject: [PATCH 007/108] Minor styling and naming tweaks
---
FSharp.Formatting.sln | 10 ++---
RELEASE_NOTES.md | 4 ++
docs/content/codeformat.fsx | 1 -
docs/content/evaluation.fsx | 9 ++---
docs/content/literate.fsx | 8 ++--
docs/content/markdown.fsx | 8 ++--
src/FSharp.Formatting.Common/Range.fs | 11 +++---
src/FSharp.Literate/Transformations.fs | 6 +--
src/FSharp.Markdown/HtmlFormatting.fs | 4 +-
src/FSharp.Markdown/LatexFormatting.fs | 2 +-
src/FSharp.Markdown/Main.fs | 2 +-
src/FSharp.Markdown/Markdown.fs | 8 ++--
src/FSharp.Markdown/MarkdownParser.fs | 51 +++++++++++++++-----------
src/FSharp.MetadataFormat/Main.fs | 4 +-
14 files changed, 67 insertions(+), 61 deletions(-)
diff --git a/FSharp.Formatting.sln b/FSharp.Formatting.sln
index 33b68a751..2bc714b96 100644
--- a/FSharp.Formatting.sln
+++ b/FSharp.Formatting.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
-VisualStudioVersion = 14.0.25123.0
+VisualStudioVersion = 14.0.23107.0
MinimumVisualStudioVersion = 12.0.31101.0
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "project", "project", "{194BD478-0DB5-44F3-A6C2-1FC75D3F3294}"
ProjectSection(SolutionItems) = preProject
@@ -74,6 +74,9 @@ EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.Formatting.CommandTool", "src\FSharp.Formatting.CommandTool\FSharp.Formatting.CommandTool.fsproj", "{D30F7F2B-A4E3-4A07-A1BD-ED3EB21768F8}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{8D44B659-E9F7-4CE4-B5DA-D37CDDCD2525}"
+ ProjectSection(SolutionItems) = preProject
+ tests\commonmark_spec.json = tests\commonmark_spec.json
+ EndProjectSection
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.CodeFormat.Tests", "tests\FSharp.CodeFormat.Tests\FSharp.CodeFormat.Tests.fsproj", "{5DEBD769-D86E-4E14-ABF1-373CA91BFAA2}"
EndProject
@@ -105,11 +108,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "crefLib4", "tests\FSharp.Me
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.Formatting.Common", "src\FSharp.Formatting.Common\FSharp.Formatting.Common.fsproj", "{91BAD90E-BF3B-4646-A1A7-1568F8F25075}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{AFB9168D-4763-472D-B895-F61A049B75BF}"
- ProjectSection(SolutionItems) = preProject
- tests\commonmark_spec.json = tests\commonmark_spec.json
- EndProjectSection
-EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 551d8c750..186d185ee 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,3 +1,7 @@
+## 3.0.0-beta01 (1 August, 2016)
+ - MarkdownSpan and MarkdownParagraph now use named DUs
+ - Add range to MarkdownParagraph and MarkdownSpan (#411)
+
## 2.14.3 (26 May, 2016)
- Fixes issues with comments and keywords in Paket highlighter (#408)
- Fix tooltip flickering in CSS (#406)
diff --git a/docs/content/codeformat.fsx b/docs/content/codeformat.fsx
index 12ae4d9bb..de3733732 100644
--- a/docs/content/codeformat.fsx
+++ b/docs/content/codeformat.fsx
@@ -23,7 +23,6 @@ entry point. The static method `CreateAgent` starts a background worker that
can be called to format snippets repeatedly:
*)
-let fsharpCompiler = Assembly.Load("FSharp.Compiler")
let formattingAgent = CodeFormat.CreateAgent()
(**
diff --git a/docs/content/evaluation.fsx b/docs/content/evaluation.fsx
index 53b3efd2f..99e94820d 100644
--- a/docs/content/evaluation.fsx
+++ b/docs/content/evaluation.fsx
@@ -78,10 +78,7 @@ Specifying the evaluator and formatting
(*** hide ***)
#nowarn "211"
-#I "../../bin"
-#r "FSharp.CodeFormat.dll"
-#r "FSharp.Literate.dll"
-#r "FSharp.Markdown.dll"
+#load "../../packages/FSharp.Formatting/FSharp.Formatting.fsx"
(**
The embedding of F# output requires specifying an additional parameter to the
parsing functions discussed in [literate programming documentation](literate.html).
@@ -159,9 +156,9 @@ fsiOl.RegisterTransformation(fun (o, ty) ->
let items =
// Get items as objects and create paragraph for each item
[ for it in Seq.cast (unbox o) ->
- [ Paragraph[Literal (it.ToString())] ] ]
+ [ Paragraph([Literal(it.ToString(), None)], None) ] ]
// Return option value (success) with ordered list
- Some [ ListBlock(MarkdownListKind.Ordered, items) ]
+ Some [ ListBlock(MarkdownListKind.Ordered, items, None) ]
else None)
(**
diff --git a/docs/content/literate.fsx b/docs/content/literate.fsx
index 21a7f2bf2..1cfa45b6d 100644
--- a/docs/content/literate.fsx
+++ b/docs/content/literate.fsx
@@ -110,18 +110,18 @@ Typical literate setup
(*** hide ***)
#nowarn "211"
-#I "../../bin"
(**
For literate programming support in your project, install the `FSharp.Formatting` nuget package.
HTML (or LaTeX) is generated by including a simple script file similar to [`build.fsx`](https://github.com/tpetricek/FSharp.Formatting/blob/master/misc/literate/build.fsx) in your project.
-You can find this file in the installed nuget package folder: `/packages/FSharp.Formatting.2.8.0/literate/`
+You can find this file in the installed nuget package folder: `/packages/FSharp.Formatting/literate/`
-Assuming you are using *FSharp.Formatting 2.8.0* typical `build.fsx` looks like this:
+Assuming you are using [Paket](http://fsprojects.github.io/Paket/) to reference F# Formatting and you
+do not have version number in the directory name, typical `build.fsx` looks like this:
*)
-#load @"../packages/FSharp.Formatting.2.8.0/FSharp.Formatting.fsx"
+#load "../../packages/FSharp.Formatting/FSharp.Formatting.fsx"
open FSharp.Literate
open System.IO
diff --git a/docs/content/markdown.fsx b/docs/content/markdown.fsx
index 3818c6bcd..cae50e50a 100644
--- a/docs/content/markdown.fsx
+++ b/docs/content/markdown.fsx
@@ -9,8 +9,8 @@ how to turn the code into a nicely formatted HTML.
First, we need to load the assembly and open necessary namespaces:
*)
-#r "../../bin/FSharp.Markdown.dll"
#r "../../bin/FSharp.Formatting.Common.dll"
+#r "../../bin/FSharp.Markdown.dll"
open FSharp.Markdown
open FSharp.Formatting.Common
@@ -95,12 +95,12 @@ to recognize any paragraph or span that can contain child elements:
/// Returns all links in a specified span node
let rec collectSpanLinks span = seq {
match span with
- | DirectLink(_, (url, _), _) -> yield url
- | IndirectLink(_, _, key, _) -> yield fst (parsed.DefinedLinks.[key])
+ | DirectLink(link=url) -> yield url
+ | IndirectLink(key=key) -> yield fst (parsed.DefinedLinks.[key])
| Matching.SpanLeaf _ -> ()
| Matching.SpanNode(_, spans) ->
for s in spans do yield! collectSpanLinks s }
-
+
/// Returns all links in the specified paragraph node
let rec collectParLinks par = seq {
match par with
diff --git a/src/FSharp.Formatting.Common/Range.fs b/src/FSharp.Formatting.Common/Range.fs
index f0946edad..059151fe8 100644
--- a/src/FSharp.Formatting.Common/Range.fs
+++ b/src/FSharp.Formatting.Common/Range.fs
@@ -4,9 +4,10 @@ type MarkdownRange = { StartLine : int; StartColumn : int; EndLine : int; EndCol
[]
module MarkdownRange =
- let Zero = { StartLine = 0; StartColumn = 0; EndLine = 0; EndColumn = 0 }
+ let zero = { StartLine = 0; StartColumn = 0; EndLine = 0; EndColumn = 0 }
- let MergeRanges (ranges:MarkdownRange list) =
- let startRange = ranges |> List.minBy (fun r -> r.StartLine * 10 + r.StartColumn)
- let endRange = ranges |> List.maxBy (fun r -> r.EndLine * 10 + r.EndColumn)
- { StartLine = startRange.StartLine; StartColumn = startRange.StartColumn; EndLine = endRange.EndLine; EndColumn = endRange.EndColumn }
\ No newline at end of file
+ let mergeRanges (ranges:MarkdownRange list) =
+ let startRange = ranges |> List.minBy (fun r -> r.StartLine, r.StartColumn)
+ let endRange = ranges |> List.maxBy (fun r -> r.EndLine, r.EndColumn)
+ { StartLine = startRange.StartLine; StartColumn = startRange.StartColumn;
+ EndLine = endRange.EndLine; EndColumn = endRange.EndColumn }
\ No newline at end of file
diff --git a/src/FSharp.Literate/Transformations.fs b/src/FSharp.Literate/Transformations.fs
index d5253e096..7ab01cc5b 100644
--- a/src/FSharp.Literate/Transformations.fs
+++ b/src/FSharp.Literate/Transformations.fs
@@ -142,7 +142,7 @@ module Transformations =
match refIndex.TryGetValue(key) with
| true, i ->
yield Literal(" [", r)
- yield DirectLink([Literal (string i, r)], ("#rf" + DateTime.Now.ToString("yyMMddhh"), None), r)
+ yield DirectLink([Literal (string i, r)], "#rf" + DateTime.Now.ToString("yyMMddhh"), None, r)
yield Literal("]", r)
| _ -> () ]
| Matching.SpanLeaf(sl) -> [Matching.SpanLeaf(sl)]
@@ -180,11 +180,11 @@ module Transformations =
let auth = title.Substring(0, colon)
let name = title.Substring(colon + 1, title.Length - 1 - colon)
yield [Span([ Literal (sprintf "[%d] " i, None)
- DirectLink([Literal (name.Trim(), None)], (link, Some title), None)
+ DirectLink([Literal (name.Trim(), None)], link, Some title, None)
Literal (" - " + auth, None)], None) ]
else
yield [Span([ Literal (sprintf "[%d] " i, None)
- DirectLink([Literal(title, None)], (link, Some title), None)], None)] ]
+ DirectLink([Literal(title, None)], link, Some title, None)], None)] ]
// Return the document together with dictionary for looking up indices
let id = DateTime.Now.ToString("yyMMddhh")
diff --git a/src/FSharp.Markdown/HtmlFormatting.fs b/src/FSharp.Markdown/HtmlFormatting.fs
index 45badc162..dc7588989 100644
--- a/src/FSharp.Markdown/HtmlFormatting.fs
+++ b/src/FSharp.Markdown/HtmlFormatting.fs
@@ -79,7 +79,7 @@ let rec formatSpan (ctx:FormattingContext) = function
| Literal(str, _) -> ctx.Writer.Write(str)
| HardLineBreak(_) -> ctx.Writer.Write(" " + ctx.Newline)
| IndirectLink(body, _, LookupKey ctx.Links (link, title), _)
- | DirectLink(body, (link, title), _) ->
+ | DirectLink(body, link, title, _) ->
ctx.Writer.Write(" yield! extractWords str
| Strong(body, _) -> yield! gathers body
| Emphasis(body, _) -> yield! gathers body
- | DirectLink(body, _, _) -> yield! gathers body
+ | DirectLink(body, _, _, _) -> yield! gathers body
| _ -> ()
}
diff --git a/src/FSharp.Markdown/LatexFormatting.fs b/src/FSharp.Markdown/LatexFormatting.fs
index 5b58e79e3..788084d11 100644
--- a/src/FSharp.Markdown/LatexFormatting.fs
+++ b/src/FSharp.Markdown/LatexFormatting.fs
@@ -63,7 +63,7 @@ let rec formatSpan (ctx:FormattingContext) = function
| AnchorLink _ -> ()
| IndirectLink(body, _, LookupKey ctx.Links (link, _), _)
- | DirectLink(body, (link, _), _)
+ | DirectLink(body, link, _, _)
| IndirectLink(body, link, _, _) ->
ctx.Writer.Write(@"\href{")
ctx.Writer.Write(latexEncode link)
diff --git a/src/FSharp.Markdown/Main.fs b/src/FSharp.Markdown/Main.fs
index 155a729ce..75c9df0c7 100644
--- a/src/FSharp.Markdown/Main.fs
+++ b/src/FSharp.Markdown/Main.fs
@@ -58,7 +58,7 @@ type Markdown =
//|> Utils.replaceTabs 4
let links = Dictionary<_, _>()
//let (Lines.TrimBlank lines) = lines
- let ctx : ParsingContext = { Newline = newline; Links = links; CurrentRange = Some(MarkdownRange.Zero) }
+ let ctx : ParsingContext = { Newline = newline; Links = links; CurrentRange = Some(MarkdownRange.zero) }
let paragraphs =
lines
|> FSharp.Collections.List.skipWhile (fun (s, n) -> String.IsNullOrWhiteSpace s)
diff --git a/src/FSharp.Markdown/Markdown.fs b/src/FSharp.Markdown/Markdown.fs
index 11e06f149..903cadbbb 100644
--- a/src/FSharp.Markdown/Markdown.fs
+++ b/src/FSharp.Markdown/Markdown.fs
@@ -34,8 +34,8 @@ type MarkdownSpan =
| Strong of body:MarkdownSpans * range:MarkdownRange option
| Emphasis of body:MarkdownSpans * range:MarkdownRange option
| AnchorLink of link:string * range:MarkdownRange option
- | DirectLink of body:MarkdownSpans * linkAndTitle:(string * option) * range:MarkdownRange option
- | IndirectLink of body:MarkdownSpans * link:string * key:string * range:MarkdownRange option
+ | DirectLink of body:MarkdownSpans * link:string * title:option * range:MarkdownRange option
+ | IndirectLink of body:MarkdownSpans * original:string * key:string * range:MarkdownRange option
| DirectImage of body:string * link:string * title:option * range:MarkdownRange option
| IndirectImage of body:string * link:string * key:string * range:MarkdownRange option
| HardLineBreak of range:MarkdownRange option
@@ -102,7 +102,7 @@ module Matching =
SpanLeaf(SL span)
| Strong(spans, _)
| Emphasis(spans , _)
- | DirectLink(spans, _, _)
+ | DirectLink(spans, _, _, _)
| IndirectLink(spans, _, _, _) ->
SpanNode(SN span, spans)
@@ -111,7 +111,7 @@ module Matching =
match span with
| Strong(_, r) -> Strong(spans , r)
| Emphasis(_, r) -> Emphasis(spans, r)
- | DirectLink(_, a, r) -> DirectLink(spans, a, r)
+ | DirectLink(_, l, t, r) -> DirectLink(spans, l, t, r)
| IndirectLink(_, a, b, r) -> IndirectLink(spans, a, b, r)
| _ -> invalidArg "" "Incorrect SpanNodeInfo"
diff --git a/src/FSharp.Markdown/MarkdownParser.fs b/src/FSharp.Markdown/MarkdownParser.fs
index 97a808d25..3d894f26d 100644
--- a/src/FSharp.Markdown/MarkdownParser.fs
+++ b/src/FSharp.Markdown/MarkdownParser.fs
@@ -192,7 +192,11 @@ let rec parseChars acc input (ctx:ParsingContext) = seq {
| List.DelimitedNTimes '`' (body, rest, s, e) ->
let (value, ctx) = accLiterals.Value
yield! value
- yield InlineCode(String(Array.ofList body).Trim(), match ctx.CurrentRange with Some(n) -> Some({ n with StartColumn = n.StartColumn + s; EndColumn = n.EndColumn - e }) | None -> None)
+ let rng =
+ match ctx.CurrentRange with
+ | Some(n) -> Some { n with StartColumn = n.StartColumn + s; EndColumn = n.EndColumn - e }
+ | None -> None
+ yield InlineCode(String(Array.ofList body).Trim(), rng)
yield! parseChars [] rest ctx
// Display Latex inline math mode
@@ -216,7 +220,7 @@ let rec parseChars acc input (ctx:ParsingContext) = seq {
when Seq.forall (Char.IsWhiteSpace >> not) link && (link.Contains("@") || link.Contains("://")) ->
let (value, ctx) = accLiterals.Value
yield! value
- yield DirectLink([Literal(link, ctx.CurrentRange)], (link, None), ctx.CurrentRange)
+ yield DirectLink([Literal(link, ctx.CurrentRange)], link, None, ctx.CurrentRange)
yield! parseChars [] rest ctx
// Not an inline link - leave as an inline HTML tag
| List.DelimitedWith ['<'] ['>'] (tag, rest, s, e) ->
@@ -226,8 +230,8 @@ let rec parseChars acc input (ctx:ParsingContext) = seq {
| DirectLink (body, link, rest) ->
let (value, ctx) = accLiterals.Value
yield! value
- let info = getLinkAndTitle (String(Array.ofList link), MarkdownRange.Zero)
- yield DirectLink(parseChars [] body ctx |> List.ofSeq, info, ctx.CurrentRange)
+ let link, title = getLinkAndTitle (String(Array.ofList link), MarkdownRange.zero)
+ yield DirectLink(parseChars [] body ctx |> List.ofSeq, link, title, ctx.CurrentRange)
yield! parseChars [] rest ctx
| IndirectLink(body, link, original, rest) ->
let (value, ctx) = accLiterals.Value
@@ -238,14 +242,14 @@ let rec parseChars acc input (ctx:ParsingContext) = seq {
| AutoLink (link, rest) ->
let (value, ctx) = accLiterals.Value
yield! value
- yield DirectLink([Literal(link, ctx.CurrentRange)], (link, None), ctx.CurrentRange)
+ yield DirectLink([Literal(link, ctx.CurrentRange)], link, None, ctx.CurrentRange)
yield! parseChars [] rest ctx
// Recognize image - this is a link prefixed with the '!' symbol
| '!'::DirectLink (body, link, rest) ->
let (value, ctx) = accLiterals.Value
yield! value
- let link, title = getLinkAndTitle (String(Array.ofList link), MarkdownRange.Zero)
+ let link, title = getLinkAndTitle (String(Array.ofList link), MarkdownRange.zero)
yield DirectImage(String(Array.ofList body), link, title, ctx.CurrentRange)
yield! parseChars [] rest ctx
| '!'::IndirectLink(body, link, original, rest) ->
@@ -290,9 +294,9 @@ let rec trimSpaces numSpaces (s:string) =
/// Recognizes heading, either prefixed with #s or followed by === or --- line
let (|Heading|_|) = function
- | (StringPosition.TrimBoth header) :: (StringPosition.TrimEnd (StringPosition.EqualsRepeated("=", MarkdownRange.Zero))) :: rest ->
+ | (StringPosition.TrimBoth header) :: (StringPosition.TrimEnd (StringPosition.EqualsRepeated("=", MarkdownRange.zero))) :: rest ->
Some(1, header, rest)
- | (StringPosition.TrimBoth header) :: (StringPosition.TrimEnd (StringPosition.EqualsRepeated("-", MarkdownRange.Zero))) :: rest ->
+ | (StringPosition.TrimBoth header) :: (StringPosition.TrimEnd (StringPosition.EqualsRepeated("-", MarkdownRange.zero))) :: rest ->
Some(2, header, rest)
| StringPosition.StartsWithRepeated "#" (n, StringPosition.TrimBoth(header, ln)) :: rest ->
let header =
@@ -407,12 +411,12 @@ let (|ListStart|_|) = function
(startIndent, spaces,
(SkipSomeNumbers // read a number
(skipNumCount, '.' :: ' ' :: List.AsString item))) ->
- let (StringPosition.TrimStartAndCount (startIndent2, spaces2, _)) = (item, MarkdownRange.Zero)
+ let (StringPosition.TrimStartAndCount (startIndent2, spaces2, _)) = (item, MarkdownRange.zero)
let endIndent =
startIndent + 2 + skipNumCount +
// Handle case of code block
if startIndent2 >= 5 then 1 else startIndent2
- Some(Ordered, startIndent, endIndent, (item, MarkdownRange.Zero))
+ Some(Ordered, startIndent, endIndent, (item, MarkdownRange.zero))
| _ -> None
/// Splits input into lines until whitespace or starting of a list and the rest.
@@ -512,10 +516,10 @@ let rec pipeTableFindSplits (delim : char array) (line : char list) =
/// Recognizes alignment specified in the passed separator line.
let (|TableCellSeparator|_|) = function
- | StringPosition.StartsAndEndsWith (":", ":") (StringPosition.EqualsRepeated("-", MarkdownRange.Zero)) -> Some(AlignCenter)
- | StringPosition.StartsWith ":" (StringPosition.EqualsRepeated("-", MarkdownRange.Zero)) -> Some(AlignLeft)
- | StringPosition.StartsAndEndsWith ("", ":") (StringPosition.EqualsRepeated("-", MarkdownRange.Zero)) -> Some(AlignRight)
- | StringPosition.EqualsRepeated("-", MarkdownRange.Zero) -> Some(AlignDefault)
+ | StringPosition.StartsAndEndsWith (":", ":") (StringPosition.EqualsRepeated("-", MarkdownRange.zero)) -> Some(AlignCenter)
+ | StringPosition.StartsWith ":" (StringPosition.EqualsRepeated("-", MarkdownRange.zero)) -> Some(AlignLeft)
+ | StringPosition.StartsAndEndsWith ("", ":") (StringPosition.EqualsRepeated("-", MarkdownRange.zero)) -> Some(AlignRight)
+ | StringPosition.EqualsRepeated("-", MarkdownRange.zero) -> Some(AlignDefault)
| _ -> None
/// Recognizes row of pipe table.
@@ -583,14 +587,16 @@ let (|EmacsTableLine|_|) (grid:option) (c:char) (check:string * Markdown
let n = p.Length - 1
if n < 2 || line.Length <= p.[n] || Array.exists (fun i -> line.[i] <> c) p then None
else
- let parts = [1..n] |> List.map (fun i -> line.Substring(p.[i - 1] + 1, p.[i] - p.[i - 1] - 1), { StartLine = n; StartColumn = 0; EndLine = n; EndColumn = p.[i] - p.[i - 1] - 1 })
+ let parts = [1..n] |> List.map (fun i ->
+ let rng = { StartLine = n; StartColumn = 0; EndLine = n; EndColumn = p.[i] - p.[i - 1] - 1 }
+ line.Substring(p.[i - 1] + 1, p.[i] - p.[i - 1] - 1), rng)
if List.forall check parts then Some(p, parts) else None
/// Recognizes emacs table
let (|EmacsTableBlock|_|) (input) =
- let isCellSep = StringPosition.(|EqualsRepeated|_|)("-", MarkdownRange.Zero) >> Option.isSome
+ let isCellSep = StringPosition.(|EqualsRepeated|_|)("-", MarkdownRange.zero) >> Option.isSome
let isAlignedCellSep = ( |TableCellSeparator|_| ) >> Option.isSome
- let isHeadCellSep = StringPosition.(|EqualsRepeated|_|)("=", MarkdownRange.Zero) >> Option.isSome
+ let isHeadCellSep = StringPosition.(|EqualsRepeated|_|)("=", MarkdownRange.zero) >> Option.isSome
let isText (s:string, n:MarkdownRange) = true
match input with
| (EmacsTableLine None '+' isAlignedCellSep (grid, parts)) :: rest ->
@@ -659,7 +665,7 @@ let (|LinesUntilBlockquoteEnds|) input =
/// starting with '>' until there is something else
let rec (|Blockquote|_|) = function
| EmptyBlockquote(Lines.TrimBlankStart rest) ->
- Some ([("", MarkdownRange.Zero)], rest)
+ Some ([("", MarkdownRange.zero)], rest)
| BlockquoteStart(line)::LinesUntilBlockquoteEnds(continued, Lines.TrimBlankStart rest) ->
let moreLines, rest =
match rest with
@@ -709,7 +715,7 @@ let rec parseParagraphs (ctx:ParsingContext) (lines:(string * MarkdownRange) lis
yield CodeBlock(code |> String.concat ctx.Newline, langString, ignoredLine, ctx.CurrentRange)
yield! parseParagraphs ctx lines
| Blockquote(body, Lines.TrimBlankStart rest) ->
- yield QuotedBlock(parseParagraphs ctx (body @ [("", MarkdownRange.Zero)]) |> List.ofSeq, ctx.CurrentRange)
+ yield QuotedBlock(parseParagraphs ctx (body @ [("", MarkdownRange.zero)]) |> List.ofSeq, ctx.CurrentRange)
yield! parseParagraphs ctx rest
| EmacsTableBlock((headers, alignments, rows), Lines.TrimBlankStart rest)
| PipeTableBlock((headers, alignments, rows), Lines.TrimBlankStart rest) ->
@@ -747,8 +753,9 @@ let rec parseParagraphs (ctx:ParsingContext) (lines:(string * MarkdownRange) lis
let kind = match nodes with Node((_, kind, _), _)::_ -> kind | _ -> Unordered
let items =
[ for (Node((simple, _, body), nested)) in nodes ->
- [ if not simple then yield! parseParagraphs ctx body
- else yield Span(parseSpans(String.concat ctx.Newline (body |> List.map fst), body |> List.map snd |> MarkdownRange.MergeRanges) ctx, ctx.CurrentRange)
+ [ let rng = body |> List.map snd |> MarkdownRange.mergeRanges
+ if not simple then yield! parseParagraphs ctx body
+ else yield Span(parseSpans(body |> List.map fst |> String.concat ctx.Newline, rng) ctx, ctx.CurrentRange)
if nested <> [] then
yield formatTree nested ] ]
ListBlock(kind, items, ctx.CurrentRange)
@@ -778,7 +785,7 @@ let rec parseParagraphs (ctx:ParsingContext) (lines:(string * MarkdownRange) lis
yield InlineBlock(all, ctx.CurrentRange)
yield! parseParagraphs ctx lines
| TakeParagraphLines(Lines.TrimParagraphLines lines, Lines.TrimBlankStart rest) ->
- yield Paragraph (parseSpans (lines |> List.map fst |> String.concat ctx.Newline, lines |> List.map snd |> MarkdownRange.MergeRanges) ctx, ctx.CurrentRange)
+ yield Paragraph (parseSpans (lines |> List.map fst |> String.concat ctx.Newline, lines |> List.map snd |> MarkdownRange.mergeRanges) ctx, ctx.CurrentRange)
yield! parseParagraphs ctx rest
| Lines.TrimBlankStart [] -> ()
diff --git a/src/FSharp.MetadataFormat/Main.fs b/src/FSharp.MetadataFormat/Main.fs
index ce1d74f99..74a7e7403 100755
--- a/src/FSharp.MetadataFormat/Main.fs
+++ b/src/FSharp.MetadataFormat/Main.fs
@@ -546,7 +546,7 @@ module Reader =
Seq.iter (fun (x : XNode) ->
if x.NodeType = XmlNodeType.Text then
let text = (x :?> XText).Value
- match findCommand (text, MarkdownRange.Zero) with
+ match findCommand (text, MarkdownRange.zero) with
| Some (k,v) -> cmds.Add(k,v)
| None -> full.Append(text) |> ignore
elif x.NodeType = XmlNodeType.Element then
@@ -713,7 +713,7 @@ module Reader =
| null ->
dict[], (Comment.Create ("", el.Value, []))
| sum ->
- let lines = removeSpaces sum.Value |> Seq.map (fun s -> (s, MarkdownRange.Zero))
+ let lines = removeSpaces sum.Value |> Seq.map (fun s -> (s, MarkdownRange.zero))
let cmds = new System.Collections.Generic.Dictionary<_, _>()
if ctx.MarkdownComments then
From 9087ca204ae6bb0e619d2cef9bd02056b2bfc5de Mon Sep 17 00:00:00 2001
From: Tomas Petricek
Date: Mon, 1 Aug 2016 15:33:38 +0100
Subject: [PATCH 008/108] Beta release
---
src/Common/AssemblyInfo.cs | 8 ++++----
src/Common/AssemblyInfo.fs | 8 ++++----
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/src/Common/AssemblyInfo.cs b/src/Common/AssemblyInfo.cs
index fc4249517..119fb60d0 100644
--- a/src/Common/AssemblyInfo.cs
+++ b/src/Common/AssemblyInfo.cs
@@ -4,12 +4,12 @@
[assembly: AssemblyTitleAttribute("FSharp.Formatting")]
[assembly: AssemblyProductAttribute("FSharp.Formatting")]
[assembly: AssemblyDescriptionAttribute("A package of libraries for building great F# documentation, samples and blogs")]
-[assembly: AssemblyVersionAttribute("2.14.3")]
-[assembly: AssemblyFileVersionAttribute("2.14.3")]
-[assembly: AssemblyInformationalVersionAttribute("2.14.3")]
+[assembly: AssemblyVersionAttribute("3.0.0")]
+[assembly: AssemblyFileVersionAttribute("3.0.0")]
+[assembly: AssemblyInformationalVersionAttribute("3.0.0-beta01")]
[assembly: AssemblyCopyrightAttribute("Apache 2.0 License")]
namespace System {
internal static class AssemblyVersionInformation {
- internal const string Version = "2.14.3";
+ internal const string Version = "3.0.0";
}
}
diff --git a/src/Common/AssemblyInfo.fs b/src/Common/AssemblyInfo.fs
index b6bc18d01..d0f098350 100644
--- a/src/Common/AssemblyInfo.fs
+++ b/src/Common/AssemblyInfo.fs
@@ -4,11 +4,11 @@ open System.Reflection
[]
[]
[]
-[]
-[]
-[]
+[]
+[]
+[]
[]
do ()
module internal AssemblyVersionInformation =
- let [] Version = "2.14.3"
+ let [] Version = "3.0.0"
From 3b18ef83f93ca79cabccb87bdc5730bac1970f67 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Krzysztof=20Cie=C5=9Blak?=
Date: Tue, 4 Oct 2016 16:31:50 +0200
Subject: [PATCH 009/108] Remove Razor reference from FSharp.Literate
---
paket.lock | 4 +-
.../FSharp.CodeFormat.fsproj | 6 +--
.../FSharp.Formatting.CommandTool.fsproj | 10 ++---
.../FSharp.Formatting.Common.fsproj | 4 +-
src/FSharp.Literate/FSharp.Literate.fsproj | 40 ++-----------------
src/FSharp.Literate/paket.references | 2 -
.../FSharp.MetadataFormat.fsproj | 10 ++---
.../FSharp.Literate.Tests.fsproj | 6 +--
.../FSharp.Markdown.Tests.fsproj | 10 ++---
.../FSharp.MetadataFormat.Tests.fsproj | 10 ++---
.../files/FsLib/FsLib1.fsproj | 10 ++---
.../files/FsLib/FsLib2.fsproj | 10 ++---
.../files/TestLib/TestLib1.fsproj | 10 ++---
.../files/TestLib/TestLib2.fsproj | 10 ++---
14 files changed, 52 insertions(+), 90 deletions(-)
diff --git a/paket.lock b/paket.lock
index 04f628c2f..ce4088f8e 100644
--- a/paket.lock
+++ b/paket.lock
@@ -1,7 +1,6 @@
REDIRECTS: ON
NUGET
remote: http://www.nuget.org/api/v2
- specs:
CommandLineParser (1.9.71)
FAKE (4.22.8)
FSharp.Compiler.Service (2.0.0.6)
@@ -21,5 +20,4 @@ NUGET
Zlib.Portable (1.11) - framework: portable-net40+sl50+wp80+win80
GITHUB
remote: matthid/Yaaf.FSharp.Scripting
- specs:
- src/source/Yaaf.FSharp.Scripting/YaafFSharpScripting.fs (48789eeb63382a6934966472e270e87880cb49ed)
+ src/source/Yaaf.FSharp.Scripting/YaafFSharpScripting.fs (48789eeb63382a6934966472e270e87880cb49ed)
\ No newline at end of file
diff --git a/src/FSharp.CodeFormat/FSharp.CodeFormat.fsproj b/src/FSharp.CodeFormat/FSharp.CodeFormat.fsproj
index 8686e8d61..4681c815f 100644
--- a/src/FSharp.CodeFormat/FSharp.CodeFormat.fsproj
+++ b/src/FSharp.CodeFormat/FSharp.CodeFormat.fsproj
@@ -106,7 +106,7 @@
-->
-
+ ..\..\packages\FSharp.Compiler.Service\lib\net40\FSharp.Compiler.Service.dll
@@ -115,7 +115,7 @@
-
+ ..\..\packages\FSharp.Compiler.Service\lib\net45\FSharp.Compiler.Service.dll
@@ -126,7 +126,7 @@
-
+ ..\..\packages\FSharpVSPowerTools.Core\lib\net45\FSharpVSPowerTools.Core.dll
diff --git a/src/FSharp.Formatting.CommandTool/FSharp.Formatting.CommandTool.fsproj b/src/FSharp.Formatting.CommandTool/FSharp.Formatting.CommandTool.fsproj
index 9267d2d07..316ffe1e1 100644
--- a/src/FSharp.Formatting.CommandTool/FSharp.Formatting.CommandTool.fsproj
+++ b/src/FSharp.Formatting.CommandTool/FSharp.Formatting.CommandTool.fsproj
@@ -142,7 +142,7 @@
-
+ ..\..\packages\CommandLineParser\lib\net40\CommandLine.dll
@@ -151,7 +151,7 @@
-
+ ..\..\packages\CommandLineParser\lib\net45\CommandLine.dll
@@ -162,7 +162,7 @@
-
+ ..\..\packages\Microsoft.AspNet.Razor\lib\net45\System.Web.Razor.dll
@@ -173,7 +173,7 @@
-
+ ..\..\packages\RazorEngine\lib\net40\RazorEngine.dll
@@ -182,7 +182,7 @@
-
+ ..\..\packages\RazorEngine\lib\net45\RazorEngine.dll
diff --git a/src/FSharp.Formatting.Common/FSharp.Formatting.Common.fsproj b/src/FSharp.Formatting.Common/FSharp.Formatting.Common.fsproj
index 33e7125c9..466b0ee31 100644
--- a/src/FSharp.Formatting.Common/FSharp.Formatting.Common.fsproj
+++ b/src/FSharp.Formatting.Common/FSharp.Formatting.Common.fsproj
@@ -83,7 +83,7 @@
-
+ ..\..\packages\FSharp.Compiler.Service\lib\net40\FSharp.Compiler.Service.dll
@@ -92,7 +92,7 @@
-
+ ..\..\packages\FSharp.Compiler.Service\lib\net45\FSharp.Compiler.Service.dll
diff --git a/src/FSharp.Literate/FSharp.Literate.fsproj b/src/FSharp.Literate/FSharp.Literate.fsproj
index 6f7df1c52..60ed222fd 100644
--- a/src/FSharp.Literate/FSharp.Literate.fsproj
+++ b/src/FSharp.Literate/FSharp.Literate.fsproj
@@ -63,9 +63,6 @@
Common\StringParsing.fs
-
- Common\Razor.fs
-
@@ -107,7 +104,7 @@
True
-
-
+ ..\..\packages\FSharp.Compiler.Service\lib\net40\FSharp.Compiler.Service.dll
@@ -125,7 +122,7 @@
-
+ ..\..\packages\FSharp.Compiler.Service\lib\net45\FSharp.Compiler.Service.dll
@@ -135,35 +132,4 @@
-
-
-
-
- ..\..\packages\Microsoft.AspNet.Razor\lib\net45\System.Web.Razor.dll
- True
- True
-
-
-
-
-
-
-
-
- ..\..\packages\RazorEngine\lib\net40\RazorEngine.dll
- True
- True
-
-
-
-
-
-
- ..\..\packages\RazorEngine\lib\net45\RazorEngine.dll
- True
- True
-
-
-
-
\ No newline at end of file
diff --git a/src/FSharp.Literate/paket.references b/src/FSharp.Literate/paket.references
index 1570c9dec..e0dfff83f 100644
--- a/src/FSharp.Literate/paket.references
+++ b/src/FSharp.Literate/paket.references
@@ -1,3 +1 @@
FSharp.Compiler.Service
-Microsoft.AspNet.Razor
-RazorEngine
diff --git a/src/FSharp.MetadataFormat/FSharp.MetadataFormat.fsproj b/src/FSharp.MetadataFormat/FSharp.MetadataFormat.fsproj
index 790605fd9..e097a7a59 100644
--- a/src/FSharp.MetadataFormat/FSharp.MetadataFormat.fsproj
+++ b/src/FSharp.MetadataFormat/FSharp.MetadataFormat.fsproj
@@ -119,7 +119,7 @@
-
+ ..\..\packages\FSharp.Compiler.Service\lib\net40\FSharp.Compiler.Service.dll
@@ -128,7 +128,7 @@
-
+ ..\..\packages\FSharp.Compiler.Service\lib\net45\FSharp.Compiler.Service.dll
@@ -139,7 +139,7 @@
-
+ ..\..\packages\Microsoft.AspNet.Razor\lib\net45\System.Web.Razor.dll
@@ -150,7 +150,7 @@
-
+ ..\..\packages\RazorEngine\lib\net40\RazorEngine.dll
@@ -159,7 +159,7 @@
-
+ ..\..\packages\RazorEngine\lib\net45\RazorEngine.dll
diff --git a/tests/FSharp.Literate.Tests/FSharp.Literate.Tests.fsproj b/tests/FSharp.Literate.Tests/FSharp.Literate.Tests.fsproj
index e96be3a09..70055fec4 100644
--- a/tests/FSharp.Literate.Tests/FSharp.Literate.Tests.fsproj
+++ b/tests/FSharp.Literate.Tests/FSharp.Literate.Tests.fsproj
@@ -135,7 +135,7 @@
-
+ ..\..\packages\Microsoft.AspNet.Razor\lib\net45\System.Web.Razor.dll
@@ -153,7 +153,7 @@
-
+ ..\..\packages\RazorEngine\lib\net40\RazorEngine.dll
@@ -162,7 +162,7 @@
-
+ ..\..\packages\RazorEngine\lib\net45\RazorEngine.dll
diff --git a/tests/FSharp.Markdown.Tests/FSharp.Markdown.Tests.fsproj b/tests/FSharp.Markdown.Tests/FSharp.Markdown.Tests.fsproj
index 01ed64dc6..06e3a3ad8 100644
--- a/tests/FSharp.Markdown.Tests/FSharp.Markdown.Tests.fsproj
+++ b/tests/FSharp.Markdown.Tests/FSharp.Markdown.Tests.fsproj
@@ -107,19 +107,19 @@
-
+
+
+ True
+ ..\..\packages\FSharp.Data\lib\net40\FSharp.Data.dllTrueTrue
-
- True
-
-
+ ..\..\packages\FSharp.Data\lib\portable-net40+sl5+wp8+win8\FSharp.Data.dll
diff --git a/tests/FSharp.MetadataFormat.Tests/FSharp.MetadataFormat.Tests.fsproj b/tests/FSharp.MetadataFormat.Tests/FSharp.MetadataFormat.Tests.fsproj
index 12069c1a4..bc9251eb4 100644
--- a/tests/FSharp.MetadataFormat.Tests/FSharp.MetadataFormat.Tests.fsproj
+++ b/tests/FSharp.MetadataFormat.Tests/FSharp.MetadataFormat.Tests.fsproj
@@ -105,7 +105,7 @@
-
+ ..\..\packages\FSharp.Compiler.Service\lib\net40\FSharp.Compiler.Service.dll
@@ -114,7 +114,7 @@
-
+ ..\..\packages\FSharp.Compiler.Service\lib\net45\FSharp.Compiler.Service.dll
@@ -125,7 +125,7 @@
-
+ ..\..\packages\Microsoft.AspNet.Razor\lib\net45\System.Web.Razor.dll
@@ -143,7 +143,7 @@
-
+ ..\..\packages\RazorEngine\lib\net40\RazorEngine.dll
@@ -152,7 +152,7 @@
-
+ ..\..\packages\RazorEngine\lib\net45\RazorEngine.dll
diff --git a/tests/FSharp.MetadataFormat.Tests/files/FsLib/FsLib1.fsproj b/tests/FSharp.MetadataFormat.Tests/files/FsLib/FsLib1.fsproj
index 2b261984d..14ed6d95b 100644
--- a/tests/FSharp.MetadataFormat.Tests/files/FsLib/FsLib1.fsproj
+++ b/tests/FSharp.MetadataFormat.Tests/files/FsLib/FsLib1.fsproj
@@ -72,7 +72,7 @@
-->
-
+ ..\..\..\..\packages\FSharp.Compiler.Service\lib\net40\FSharp.Compiler.Service.dll
@@ -81,7 +81,7 @@
-
+ ..\..\..\..\packages\FSharp.Compiler.Service\lib\net45\FSharp.Compiler.Service.dll
@@ -92,7 +92,7 @@
-
+ ..\..\..\..\packages\Microsoft.AspNet.Razor\lib\net45\System.Web.Razor.dll
@@ -103,7 +103,7 @@
-
+ ..\..\..\..\packages\RazorEngine\lib\net40\RazorEngine.dll
@@ -112,7 +112,7 @@
-
+ ..\..\..\..\packages\RazorEngine\lib\net45\RazorEngine.dll
diff --git a/tests/FSharp.MetadataFormat.Tests/files/FsLib/FsLib2.fsproj b/tests/FSharp.MetadataFormat.Tests/files/FsLib/FsLib2.fsproj
index a4fd49d9f..7d4412e2e 100644
--- a/tests/FSharp.MetadataFormat.Tests/files/FsLib/FsLib2.fsproj
+++ b/tests/FSharp.MetadataFormat.Tests/files/FsLib/FsLib2.fsproj
@@ -74,7 +74,7 @@
-
+ ..\..\..\..\packages\FSharp.Compiler.Service\lib\net40\FSharp.Compiler.Service.dll
@@ -83,7 +83,7 @@
-
+ ..\..\..\..\packages\FSharp.Compiler.Service\lib\net45\FSharp.Compiler.Service.dll
@@ -94,7 +94,7 @@
-
+ ..\..\..\..\packages\Microsoft.AspNet.Razor\lib\net45\System.Web.Razor.dll
@@ -105,7 +105,7 @@
-
+ ..\..\..\..\packages\RazorEngine\lib\net40\RazorEngine.dll
@@ -114,7 +114,7 @@
-
+ ..\..\..\..\packages\RazorEngine\lib\net45\RazorEngine.dll
diff --git a/tests/FSharp.MetadataFormat.Tests/files/TestLib/TestLib1.fsproj b/tests/FSharp.MetadataFormat.Tests/files/TestLib/TestLib1.fsproj
index 06aa031e8..655dfc1bf 100644
--- a/tests/FSharp.MetadataFormat.Tests/files/TestLib/TestLib1.fsproj
+++ b/tests/FSharp.MetadataFormat.Tests/files/TestLib/TestLib1.fsproj
@@ -73,7 +73,7 @@
-->
-
+ ..\..\..\..\packages\FSharp.Compiler.Service\lib\net40\FSharp.Compiler.Service.dll
@@ -82,7 +82,7 @@
-
+ ..\..\..\..\packages\FSharp.Compiler.Service\lib\net45\FSharp.Compiler.Service.dll
@@ -93,7 +93,7 @@
-
+ ..\..\..\..\packages\Microsoft.AspNet.Razor\lib\net45\System.Web.Razor.dll
@@ -104,7 +104,7 @@
-
+ ..\..\..\..\packages\RazorEngine\lib\net40\RazorEngine.dll
@@ -113,7 +113,7 @@
-
+ ..\..\..\..\packages\RazorEngine\lib\net45\RazorEngine.dll
diff --git a/tests/FSharp.MetadataFormat.Tests/files/TestLib/TestLib2.fsproj b/tests/FSharp.MetadataFormat.Tests/files/TestLib/TestLib2.fsproj
index 15610c01a..d119aa3f5 100644
--- a/tests/FSharp.MetadataFormat.Tests/files/TestLib/TestLib2.fsproj
+++ b/tests/FSharp.MetadataFormat.Tests/files/TestLib/TestLib2.fsproj
@@ -69,7 +69,7 @@
-->
-
+ ..\..\..\..\packages\FSharp.Compiler.Service\lib\net40\FSharp.Compiler.Service.dll
@@ -78,7 +78,7 @@
-
+ ..\..\..\..\packages\FSharp.Compiler.Service\lib\net45\FSharp.Compiler.Service.dll
@@ -89,7 +89,7 @@
-
+ ..\..\..\..\packages\Microsoft.AspNet.Razor\lib\net45\System.Web.Razor.dll
@@ -100,7 +100,7 @@
-
+ ..\..\..\..\packages\RazorEngine\lib\net40\RazorEngine.dll
@@ -109,7 +109,7 @@
-
+ ..\..\..\..\packages\RazorEngine\lib\net45\RazorEngine.dll
From a9e1f1137fe0b214d0b0e1448ef7ee0e13540809 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Krzysztof=20Cie=C5=9Blak?=
Date: Tue, 4 Oct 2016 16:35:02 +0200
Subject: [PATCH 010/108] Use plugable generator function
---
src/FSharp.Literate/Contexts.fs | 15 ++--
src/FSharp.Literate/Formatting.fs | 67 +++++------------
src/FSharp.Literate/Main.fs | 118 ++++++++++++++++++------------
3 files changed, 101 insertions(+), 99 deletions(-)
diff --git a/src/FSharp.Literate/Contexts.fs b/src/FSharp.Literate/Contexts.fs
index 733abc674..aea975aaf 100644
--- a/src/FSharp.Literate/Contexts.fs
+++ b/src/FSharp.Literate/Contexts.fs
@@ -2,9 +2,9 @@
open FSharp.CodeFormat
-/// Specifies a context that is passed to functions
+/// Specifies a context that is passed to functions
/// that need to use the F# compiler
-type CompilerContext =
+type CompilerContext =
{ // An instance of the F# code formatting agent
FormatAgent : CodeFormatAgent
// F# interactive evaluator
@@ -18,8 +18,11 @@ type CompilerContext =
[]
type OutputKind = Html | Latex
+/// Defines type of function responsible for generating output
+type Generator = (string list option) -> string -> list -> string option -> string -> seq -> unit
+
/// Specifies a context that is passed to functions that generate the output
-type ProcessingContext =
+type ProcessingContext =
{ // Path to the template file
TemplateFile : string option
// Short prefix code added to all HTML 'id' elements
@@ -34,5 +37,7 @@ type ProcessingContext =
GenerateHeaderAnchors : bool
// The output format
OutputKind : OutputKind
- // Where to look for Razor templates, when using Razor
- LayoutRoots : seq }
+ // Where to look for templates
+ LayoutRoots : seq
+ // Function generating output
+ Generator : Generator }
diff --git a/src/FSharp.Literate/Formatting.fs b/src/FSharp.Literate/Formatting.fs
index 93bbad5a3..0fc552df9 100644
--- a/src/FSharp.Literate/Formatting.fs
+++ b/src/FSharp.Literate/Formatting.fs
@@ -15,31 +15,31 @@ open FSharp.Markdown
module Formatting =
/// Format document with the specified output kind
- let format doc generateAnchors outputKind =
+ let format doc generateAnchors outputKind =
match outputKind with
| OutputKind.Latex -> Markdown.WriteLatex(doc)
- | OutputKind.Html ->
+ | OutputKind.Html ->
let sb = new System.Text.StringBuilder()
use wr = new StringWriter(sb)
Html.formatMarkdown wr generateAnchors System.Environment.NewLine true doc.DefinedLinks doc.Paragraphs
sb.ToString()
/// Try find first-level heading in the paragraph collection
- let findHeadings paragraphs generateAnchors (outputKind:OutputKind) =
- paragraphs |> Seq.tryPick (function
- | Heading(1, text, r) ->
+ let findHeadings paragraphs generateAnchors (outputKind:OutputKind) =
+ paragraphs |> Seq.tryPick (function
+ | Heading(1, text, r) ->
let doc = MarkdownDocument([Span(text, r)], dict [])
Some(format doc generateAnchors outputKind)
| _ -> None)
- /// Given literate document, get a new MarkdownDocument that represents the
+ /// Given literate document, get a new MarkdownDocument that represents the
/// entire source code of the specified document (with possible `fsx` formatting)
let getSourceDocument (doc:LiterateDocument) =
match doc.Source with
| LiterateSource.Markdown text ->
doc.With(paragraphs = [CodeBlock (text, "", "", None)])
| LiterateSource.Script snippets ->
- let paragraphs =
+ let paragraphs =
[ for Snippet(name, lines) in snippets do
if snippets.Length > 1 then
yield Heading(3, [Literal(name, None)], None)
@@ -53,64 +53,33 @@ module Formatting =
/// [omit]
module Templating =
- /// Replace {parameter} in the input string with
- /// values defined in the specified list
- let private replaceParameters (contentTag:string) (parameters:seq) input =
- match input with
- | None ->
- // If there is no template, return just document + tooltips
- let lookup = parameters |> dict
- lookup.[contentTag] + "\n\n" + lookup.["tooltips"]
- | Some input ->
- // First replace keys with some uglier keys and then replace them with values
- // (in case one of the keys appears in some other value)
- let id = System.Guid.NewGuid().ToString("d")
- let input = parameters |> Seq.fold (fun (html:string) (key, value) ->
- html.Replace("{" + key + "}", "{" + key + id + "}")) input
- let result = parameters |> Seq.fold (fun (html:string) (key, value) ->
- html.Replace("{" + key + id + "}", value)) input
- result
-
- /// Depending on the template file, use either Razor engine
- /// or simple Html engine with {replacements} to format the document
- let private generateFile references contentTag parameters templateOpt output layoutRoots =
- match templateOpt with
- | Some (file:string) when file.EndsWith("cshtml", true, CultureInfo.InvariantCulture) ->
- let razor = RazorRender(layoutRoots |> Seq.toList, [], file, ?references = references)
- let props = [ "Properties", dict parameters ]
- let generated = razor.ProcessFile(props)
- File.WriteAllText(output, generated)
- | _ ->
- let templateOpt = templateOpt |> Option.map File.ReadAllText
- File.WriteAllText(output, replaceParameters contentTag parameters templateOpt)
-
// ------------------------------------------------------------------------------------
// Formate literate document
// ------------------------------------------------------------------------------------
- let processFile references (doc:LiterateDocument) output ctx =
+ let processFile references (doc:LiterateDocument) output ctx =
// If we want to include the source code of the script, then process
// the entire source and generate replacement {source} => ...some html...
let sourceReplacements =
- if ctx.IncludeSource then
- let doc =
+ if ctx.IncludeSource then
+ let doc =
Formatting.getSourceDocument doc
- |> Transformations.replaceLiterateParagraphs ctx
+ |> Transformations.replaceLiterateParagraphs ctx
let content = Formatting.format doc.MarkdownDocument ctx.GenerateHeaderAnchors ctx.OutputKind
[ "source", content ]
else []
// Get page title (either heading or file name)
- let pageTitle =
+ let pageTitle =
let name = Path.GetFileNameWithoutExtension(output)
defaultArg (Formatting.findHeadings doc.Paragraphs ctx.GenerateHeaderAnchors ctx.OutputKind) name
// To avoid clashes in templating use {contents} for Latex and older {document} for HTML
- let contentTag =
- match ctx.OutputKind with
- | OutputKind.Html -> "document"
- | OutputKind.Latex -> "contents"
+ let contentTag =
+ match ctx.OutputKind with
+ | OutputKind.Html -> "document"
+ | OutputKind.Latex -> "contents"
// Replace all special elements with ordinary Html/Latex Markdown
let doc = Transformations.replaceLiterateParagraphs ctx doc
@@ -118,10 +87,10 @@ module Templating =
let tipsHtml = doc.FormattedTips
// Construct new Markdown document and write it
- let parameters =
+ let parameters =
ctx.Replacements @ sourceReplacements @
[ "page-title", pageTitle
"page-source", doc.SourceFile
contentTag, formattedDocument
"tooltips", tipsHtml ]
- generateFile references contentTag parameters ctx.TemplateFile output ctx.LayoutRoots
+ ctx.Generator references contentTag parameters ctx.TemplateFile output ctx.LayoutRoots
diff --git a/src/FSharp.Literate/Main.fs b/src/FSharp.Literate/Main.fs
index 37a7314ac..136e7daa1 100644
--- a/src/FSharp.Literate/Main.fs
+++ b/src/FSharp.Literate/Main.fs
@@ -14,43 +14,71 @@ open FSharp.CodeFormat
/// The `ProcessMarkdown` and `ProcessScriptFile` methods process a single Markdown document
/// and F# script, respectively. The `ProcessDirectory` method handles an entire directory tree
/// (looking for `*.fsx` and `*.md` files).
-type Literate private () =
+type Literate private () =
+
+ /// Replace {parameter} in the input string with
+ /// values defined in the specified list
+ static let replaceParameters (contentTag:string) (parameters:seq) input =
+ match input with
+ | None ->
+ // If there is no template, return just document + tooltips
+ let lookup = parameters |> dict
+ lookup.[contentTag] + "\n\n" + lookup.["tooltips"]
+ | Some input ->
+ // First replace keys with some uglier keys and then replace them with values
+ // (in case one of the keys appears in some other value)
+ let id = System.Guid.NewGuid().ToString("d")
+ let input = parameters |> Seq.fold (fun (html:string) (key, value) ->
+ html.Replace("{" + key + "}", "{" + key + id + "}")) input
+ let result = parameters |> Seq.fold (fun (html:string) (key, value) ->
+ html.Replace("{" + key + id + "}", value)) input
+ result
+
+
+ /// Depending on the template file, use either Razor engine
+ /// or simple Html engine with {replacements} to format the document
+ static let generatePlainFile references contentTag parameters templateOpt output layoutRoots =
+ let templateOpt = templateOpt |> Option.map File.ReadAllText
+ File.WriteAllText(output, replaceParameters contentTag parameters templateOpt)
+
/// Build default options context for formatting literate document
- static let formattingContext templateFile format prefix lineNumbers includeSource generateAnchors replacements layoutRoots =
- { TemplateFile = templateFile
+ static let formattingContext templateFile format prefix lineNumbers includeSource generateAnchors replacements layoutRoots generator=
+ { TemplateFile = templateFile
Replacements = defaultArg replacements []
GenerateLineNumbers = defaultArg lineNumbers true
IncludeSource = defaultArg includeSource false
Prefix = defaultArg prefix "fs"
OutputKind = defaultArg format OutputKind.Html
GenerateHeaderAnchors = defaultArg generateAnchors false
- LayoutRoots = defaultArg layoutRoots [] }
-
+ LayoutRoots = defaultArg layoutRoots []
+ Generator = defaultArg generator generatePlainFile
+ }
+
/// Build default options context for parsing literate scripts/documents
- static let parsingContext formatAgent evaluator compilerOptions definedSymbols =
+ static let parsingContext formatAgent evaluator compilerOptions definedSymbols =
let agent =
match formatAgent with
| Some agent -> agent
| _ -> CodeFormat.CreateAgent()
{ FormatAgent = agent
CompilerOptions = compilerOptions
- Evaluator = evaluator
+ Evaluator = evaluator
DefinedSymbols = Option.map (String.concat ",") definedSymbols }
-
+
/// Get default output file name, given various information
static let defaultOutput output input kind =
- match output, defaultArg kind OutputKind.Html with
+ match output, defaultArg kind OutputKind.Html with
| Some out, _ -> out
| _, OutputKind.Latex -> Path.ChangeExtension(input, "tex")
| _, OutputKind.Html -> Path.ChangeExtension(input, "html")
-
+
/// Apply the specified transformations to a document
static let transform references doc =
- let doc =
+ let doc =
if references <> Some true then doc
else Transformations.generateReferences doc
- doc
+ doc
static let customize customizeDocument ctx doc =
match customizeDocument with
@@ -60,9 +88,9 @@ type Literate private () =
// ------------------------------------------------------------------------------------
// Parsing functions
// ------------------------------------------------------------------------------------
-
+
/// Parse F# Script file
- static member ParseScriptFile
+ static member ParseScriptFile
( path, ?formatAgent, ?compilerOptions, ?definedSymbols, ?references, ?fsiEvaluator ) =
let ctx = parsingContext formatAgent fsiEvaluator compilerOptions definedSymbols
ParseScript.parseScriptFile path (File.ReadAllText path) ctx
@@ -71,7 +99,7 @@ type Literate private () =
|> Transformations.evaluateCodeSnippets ctx
/// Parse F# Script file
- static member ParseScriptString
+ static member ParseScriptString
( content, ?path, ?formatAgent, ?compilerOptions, ?definedSymbols, ?references, ?fsiEvaluator ) =
let ctx = parsingContext formatAgent fsiEvaluator compilerOptions definedSymbols
ParseScript.parseScriptFile (defaultArg path "C:\\Document.fsx") content ctx
@@ -83,7 +111,7 @@ type Literate private () =
static member ParseMarkdownFile
( path, ?formatAgent, ?compilerOptions, ?definedSymbols, ?references, ?fsiEvaluator ) =
let ctx = parsingContext formatAgent fsiEvaluator compilerOptions definedSymbols
- ParseMarkdown.parseMarkdown path (File.ReadAllText path)
+ ParseMarkdown.parseMarkdown path (File.ReadAllText path)
|> transform references
|> Transformations.formatCodeSnippets path ctx
|> Transformations.evaluateCodeSnippets ctx
@@ -102,7 +130,7 @@ type Literate private () =
// ------------------------------------------------------------------------------------
static member WriteHtml(doc:LiterateDocument, ?prefix, ?lineNumbers, ?generateAnchors) =
- let ctx = formattingContext None (Some OutputKind.Html) prefix lineNumbers None generateAnchors None None
+ let ctx = formattingContext None (Some OutputKind.Html) prefix lineNumbers None generateAnchors None None None
let doc = Transformations.replaceLiterateParagraphs ctx doc
let doc = MarkdownDocument(doc.Paragraphs @ [InlineBlock(doc.FormattedTips, None)], doc.DefinedLinks)
let sb = new System.Text.StringBuilder()
@@ -111,18 +139,18 @@ type Literate private () =
sb.ToString()
static member WriteHtml(doc:LiterateDocument, writer:TextWriter, ?prefix, ?lineNumbers, ?generateAnchors) =
- let ctx = formattingContext None (Some OutputKind.Html) prefix lineNumbers None generateAnchors None None
+ let ctx = formattingContext None (Some OutputKind.Html) prefix lineNumbers None generateAnchors None None None
let doc = Transformations.replaceLiterateParagraphs ctx doc
let doc = MarkdownDocument(doc.Paragraphs @ [InlineBlock(doc.FormattedTips, None)], doc.DefinedLinks)
Html.formatMarkdown writer ctx.GenerateHeaderAnchors Environment.NewLine true doc.DefinedLinks doc.Paragraphs
static member WriteLatex(doc:LiterateDocument, ?prefix, ?lineNumbers, ?generateAnchors) =
- let ctx = formattingContext None (Some OutputKind.Latex) prefix lineNumbers None generateAnchors None None
+ let ctx = formattingContext None (Some OutputKind.Latex) prefix lineNumbers None generateAnchors None None None
let doc = Transformations.replaceLiterateParagraphs ctx doc
Markdown.WriteLatex(MarkdownDocument(doc.Paragraphs, doc.DefinedLinks))
static member WriteLatex(doc:LiterateDocument, writer:TextWriter, ?prefix, ?lineNumbers, ?generateAnchors) =
- let ctx = formattingContext None (Some OutputKind.Latex) prefix lineNumbers None generateAnchors None None
+ let ctx = formattingContext None (Some OutputKind.Latex) prefix lineNumbers None generateAnchors None None None
let doc = Transformations.replaceLiterateParagraphs ctx doc
Markdown.WriteLatex(MarkdownDocument(doc.Paragraphs, doc.DefinedLinks), writer)
@@ -131,7 +159,7 @@ type Literate private () =
// ------------------------------------------------------------------------------------
static member FormatLiterateNodes(doc:LiterateDocument, ?format, ?prefix, ?lineNumbers, ?generateAnchors) =
- let ctx = formattingContext None format prefix lineNumbers None generateAnchors None None
+ let ctx = formattingContext None format prefix lineNumbers None generateAnchors None None None
Transformations.replaceLiterateParagraphs ctx doc
// ------------------------------------------------------------------------------------
@@ -141,65 +169,65 @@ type Literate private () =
/// Process the given literate document
static member ProcessDocument
( doc, output, ?templateFile, ?format, ?prefix, ?lineNumbers, ?includeSource, ?generateAnchors,
- ?replacements, ?layoutRoots, ?assemblyReferences) =
- let ctx = formattingContext templateFile format prefix lineNumbers includeSource generateAnchors replacements layoutRoots
+ ?replacements, ?layoutRoots, ?assemblyReferences, ?generator) =
+ let ctx = formattingContext templateFile format prefix lineNumbers includeSource generateAnchors replacements layoutRoots generator
Templating.processFile assemblyReferences doc output ctx
/// Process Markdown document
static member ProcessMarkdown
- ( input, ?templateFile, ?output, ?format, ?formatAgent, ?prefix, ?compilerOptions,
+ ( input, ?templateFile, ?output, ?format, ?formatAgent, ?prefix, ?compilerOptions,
?lineNumbers, ?references, ?replacements, ?includeSource, ?layoutRoots, ?generateAnchors,
- ?assemblyReferences, ?customizeDocument ) =
- let doc =
+ ?assemblyReferences, ?customizeDocument, ?generator ) =
+ let doc =
Literate.ParseMarkdownFile
- ( input, ?formatAgent=formatAgent, ?compilerOptions=compilerOptions,
+ ( input, ?formatAgent=formatAgent, ?compilerOptions=compilerOptions,
?references = references )
- let ctx = formattingContext templateFile format prefix lineNumbers includeSource generateAnchors replacements layoutRoots
+ let ctx = formattingContext templateFile format prefix lineNumbers includeSource generateAnchors replacements layoutRoots generator
let doc = customize customizeDocument ctx doc
Templating.processFile assemblyReferences doc (defaultOutput output input format) ctx
/// Process F# Script file
static member ProcessScriptFile
- ( input, ?templateFile, ?output, ?format, ?formatAgent, ?prefix, ?compilerOptions,
+ ( input, ?templateFile, ?output, ?format, ?formatAgent, ?prefix, ?compilerOptions,
?lineNumbers, ?references, ?fsiEvaluator, ?replacements, ?includeSource, ?layoutRoots,
- ?generateAnchors, ?assemblyReferences, ?customizeDocument ) =
- let doc =
+ ?generateAnchors, ?assemblyReferences, ?customizeDocument, ?generator ) =
+ let doc =
Literate.ParseScriptFile
- ( input, ?formatAgent=formatAgent, ?compilerOptions=compilerOptions,
+ ( input, ?formatAgent=formatAgent, ?compilerOptions=compilerOptions,
?references = references, ?fsiEvaluator = fsiEvaluator )
- let ctx = formattingContext templateFile format prefix lineNumbers includeSource generateAnchors replacements layoutRoots
+ let ctx = formattingContext templateFile format prefix lineNumbers includeSource generateAnchors replacements layoutRoots generator
let doc = customize customizeDocument ctx doc
Templating.processFile assemblyReferences doc (defaultOutput output input format) ctx
/// Process directory containing a mix of Markdown documents and F# Script files
static member ProcessDirectory
- ( inputDirectory, ?templateFile, ?outputDirectory, ?format, ?formatAgent, ?prefix, ?compilerOptions,
+ ( inputDirectory, ?templateFile, ?outputDirectory, ?format, ?formatAgent, ?prefix, ?compilerOptions,
?lineNumbers, ?references, ?fsiEvaluator, ?replacements, ?includeSource, ?layoutRoots, ?generateAnchors,
?assemblyReferences, ?processRecursive, ?customizeDocument ) =
let processRecursive = defaultArg processRecursive true
// Call one or the other process function with all the arguments
- let processScriptFile file output =
+ let processScriptFile file output =
Literate.ProcessScriptFile
- ( file, ?templateFile = templateFile, output = output, ?format = format,
- ?formatAgent = formatAgent, ?prefix = prefix, ?compilerOptions = compilerOptions,
- ?lineNumbers = lineNumbers, ?references = references, ?fsiEvaluator = fsiEvaluator, ?replacements = replacements,
+ ( file, ?templateFile = templateFile, output = output, ?format = format,
+ ?formatAgent = formatAgent, ?prefix = prefix, ?compilerOptions = compilerOptions,
+ ?lineNumbers = lineNumbers, ?references = references, ?fsiEvaluator = fsiEvaluator, ?replacements = replacements,
?includeSource = includeSource, ?layoutRoots = layoutRoots, ?generateAnchors = generateAnchors,
?assemblyReferences = assemblyReferences, ?customizeDocument = customizeDocument )
- let processMarkdown file output =
+ let processMarkdown file output =
Literate.ProcessMarkdown
- ( file, ?templateFile = templateFile, output = output, ?format = format,
- ?formatAgent = formatAgent, ?prefix = prefix, ?compilerOptions = compilerOptions,
- ?lineNumbers = lineNumbers, ?references = references, ?replacements = replacements,
+ ( file, ?templateFile = templateFile, output = output, ?format = format,
+ ?formatAgent = formatAgent, ?prefix = prefix, ?compilerOptions = compilerOptions,
+ ?lineNumbers = lineNumbers, ?references = references, ?replacements = replacements,
?includeSource = includeSource, ?layoutRoots = layoutRoots, ?generateAnchors = generateAnchors,
?assemblyReferences = assemblyReferences, ?customizeDocument = customizeDocument )
-
+
/// Recursively process all files in the directory tree
- let rec processDirectory indir outdir =
+ let rec processDirectory indir outdir =
// Create output directory if it does not exist
if Directory.Exists(outdir) |> not then
- try Directory.CreateDirectory(outdir) |> ignore
+ try Directory.CreateDirectory(outdir) |> ignore
with _ -> failwithf "Cannot create directory '%s'" outdir
let fsx = [ for f in Directory.GetFiles(indir, "*.fsx") -> processScriptFile, f ]
From 18356751edcb386c71dd7f697ca7702b61f168c8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Krzysztof=20Cie=C5=9Blak?=
Date: Tue, 4 Oct 2016 21:30:43 +0200
Subject: [PATCH 011/108] Add generator to ProcessDirectory
---
src/FSharp.Literate/Main.fs | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/FSharp.Literate/Main.fs b/src/FSharp.Literate/Main.fs
index 136e7daa1..cf4f39e8f 100644
--- a/src/FSharp.Literate/Main.fs
+++ b/src/FSharp.Literate/Main.fs
@@ -205,7 +205,7 @@ type Literate private () =
static member ProcessDirectory
( inputDirectory, ?templateFile, ?outputDirectory, ?format, ?formatAgent, ?prefix, ?compilerOptions,
?lineNumbers, ?references, ?fsiEvaluator, ?replacements, ?includeSource, ?layoutRoots, ?generateAnchors,
- ?assemblyReferences, ?processRecursive, ?customizeDocument ) =
+ ?assemblyReferences, ?processRecursive, ?customizeDocument, ?generator ) =
let processRecursive = defaultArg processRecursive true
// Call one or the other process function with all the arguments
let processScriptFile file output =
@@ -214,14 +214,14 @@ type Literate private () =
?formatAgent = formatAgent, ?prefix = prefix, ?compilerOptions = compilerOptions,
?lineNumbers = lineNumbers, ?references = references, ?fsiEvaluator = fsiEvaluator, ?replacements = replacements,
?includeSource = includeSource, ?layoutRoots = layoutRoots, ?generateAnchors = generateAnchors,
- ?assemblyReferences = assemblyReferences, ?customizeDocument = customizeDocument )
+ ?assemblyReferences = assemblyReferences, ?customizeDocument = customizeDocument, ?generator = generator )
let processMarkdown file output =
Literate.ProcessMarkdown
( file, ?templateFile = templateFile, output = output, ?format = format,
?formatAgent = formatAgent, ?prefix = prefix, ?compilerOptions = compilerOptions,
?lineNumbers = lineNumbers, ?references = references, ?replacements = replacements,
?includeSource = includeSource, ?layoutRoots = layoutRoots, ?generateAnchors = generateAnchors,
- ?assemblyReferences = assemblyReferences, ?customizeDocument = customizeDocument )
+ ?assemblyReferences = assemblyReferences, ?customizeDocument = customizeDocument, ?generator = generator )
/// Recursively process all files in the directory tree
let rec processDirectory indir outdir =
From 02dbe756713376c900e212b21077a59a66c6f7b0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Krzysztof=20Cie=C5=9Blak?=
Date: Tue, 4 Oct 2016 22:23:59 +0200
Subject: [PATCH 012/108] Use record type
---
src/FSharp.Literate/Contexts.fs | 16 +++++++++++++---
src/FSharp.Literate/Formatting.fs | 11 ++++++++++-
src/FSharp.Literate/Main.fs | 6 +++---
3 files changed, 26 insertions(+), 7 deletions(-)
diff --git a/src/FSharp.Literate/Contexts.fs b/src/FSharp.Literate/Contexts.fs
index aea975aaf..7f816c483 100644
--- a/src/FSharp.Literate/Contexts.fs
+++ b/src/FSharp.Literate/Contexts.fs
@@ -18,8 +18,18 @@ type CompilerContext =
[]
type OutputKind = Html | Latex
-/// Defines type of function responsible for generating output
-type Generator = (string list option) -> string -> list -> string option -> string -> seq -> unit
+
+/// Defines input type for output generator
+type GeneratorInput =
+ {
+ References : string list option
+ ContentTag : string
+ Parameters : (string * string) list
+ TemplateFile : string option
+ OutputFile : string
+ LayoutRoots : string seq
+ }
+
/// Specifies a context that is passed to functions that generate the output
type ProcessingContext =
@@ -40,4 +50,4 @@ type ProcessingContext =
// Where to look for templates
LayoutRoots : seq
// Function generating output
- Generator : Generator }
+ Generator : GeneratorInput -> unit }
diff --git a/src/FSharp.Literate/Formatting.fs b/src/FSharp.Literate/Formatting.fs
index 0fc552df9..2ae27f472 100644
--- a/src/FSharp.Literate/Formatting.fs
+++ b/src/FSharp.Literate/Formatting.fs
@@ -93,4 +93,13 @@ module Templating =
"page-source", doc.SourceFile
contentTag, formattedDocument
"tooltips", tipsHtml ]
- ctx.Generator references contentTag parameters ctx.TemplateFile output ctx.LayoutRoots
+ let gi = {
+ References = references
+ ContentTag = contentTag
+ Parameters = parameters
+ TemplateFile = ctx.TemplateFile
+ OutputFile = output
+ LayoutRoots = ctx.LayoutRoots
+ }
+
+ ctx.Generator gi
diff --git a/src/FSharp.Literate/Main.fs b/src/FSharp.Literate/Main.fs
index cf4f39e8f..3dea542fd 100644
--- a/src/FSharp.Literate/Main.fs
+++ b/src/FSharp.Literate/Main.fs
@@ -37,9 +37,9 @@ type Literate private () =
/// Depending on the template file, use either Razor engine
/// or simple Html engine with {replacements} to format the document
- static let generatePlainFile references contentTag parameters templateOpt output layoutRoots =
- let templateOpt = templateOpt |> Option.map File.ReadAllText
- File.WriteAllText(output, replaceParameters contentTag parameters templateOpt)
+ static let generatePlainFile (gi : GeneratorInput) =
+ let templateOpt = gi.TemplateFile |> Option.map File.ReadAllText
+ File.WriteAllText(gi.OutputFile, replaceParameters gi.ContentTag gi.Parameters templateOpt)
/// Build default options context for formatting literate document
From 2fd147c893bb9f21fa1201630025851d3c44985d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Krzysztof=20Cie=C5=9Blak?=
Date: Tue, 4 Oct 2016 23:19:21 +0200
Subject: [PATCH 013/108] Remove Razor dependency from FSharp.MetadataFormat
---
.../FSharp.MetadataFormat.fsproj | 36 +-
src/FSharp.MetadataFormat/Main.fs | 483 +++++++++---------
src/FSharp.MetadataFormat/paket.references | 4 +-
3 files changed, 236 insertions(+), 287 deletions(-)
diff --git a/src/FSharp.MetadataFormat/FSharp.MetadataFormat.fsproj b/src/FSharp.MetadataFormat/FSharp.MetadataFormat.fsproj
index e097a7a59..61826e835 100644
--- a/src/FSharp.MetadataFormat/FSharp.MetadataFormat.fsproj
+++ b/src/FSharp.MetadataFormat/FSharp.MetadataFormat.fsproj
@@ -61,7 +61,7 @@
-
-
+
\ No newline at end of file
diff --git a/src/FSharp.MetadataFormat/FSharp.MetadataFormat.fsproj b/src/FSharp.MetadataFormat/FSharp.MetadataFormat.fsproj
index 61826e835..a03e494cf 100644
--- a/src/FSharp.MetadataFormat/FSharp.MetadataFormat.fsproj
+++ b/src/FSharp.MetadataFormat/FSharp.MetadataFormat.fsproj
@@ -15,7 +15,7 @@
..\..\true
- 4.3.0.0
+ 4.4.0.0true
@@ -38,6 +38,7 @@
..\..\bin\FSharp.MetadataFormat.xml
+ 12.011
@@ -49,18 +50,28 @@
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets
-
+
- $(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.1\Framework\v4.0\Microsoft.FSharp.Targets
+ $(MSBuildProgramFiles32)\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets
-
+
- $(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets
+ $(MSBuildProgramFiles32)\Microsoft SDKs\F#\3.1\Framework\v4.0\Microsoft.FSharp.Targets
+
+
+ $(MSBuildProgramFiles32)\Microsoft SDKs\F#\4.0\Framework\v4.0\Microsoft.FSharp.Targets
+
+
+
+
+ $(MSBuildProgramFiles32)\Microsoft SDKs\F#\4.1\Framework\v4.0\Microsoft.FSharp.Targets
+
+
-
+
-
- FsUnit.fs
- Always
@@ -85,12 +88,6 @@
-
- ..\..\bin\FSharp.CodeFormat.dll
-
-
- False
-
@@ -102,11 +99,159 @@
True
-
-
- ..\..\packages\NUnit\lib\nunit.framework.dll
- True
- True
-
-
+
+
+
+
+ ..\..\packages\FSharp.Core\lib\net20\FSharp.Core.dll
+ True
+ True
+
+
+
+
+
+
+ ..\..\packages\FSharp.Core\lib\net40\FSharp.Core.dll
+ True
+ True
+
+
+
+
+
+
+ ..\..\packages\FSharp.Core\lib\portable-net45+monoandroid10+monotouch10+xamarinios10\FSharp.Core.dll
+ True
+ True
+
+
+
+
+
+
+ ..\..\packages\FSharp.Core\lib\portable-net45+netcore45\FSharp.Core.dll
+ True
+ True
+
+
+
+
+
+
+ ..\..\packages\FSharp.Core\lib\portable-net45+netcore45+wp8\FSharp.Core.dll
+ True
+ True
+
+
+
+
+
+
+ ..\..\packages\FSharp.Core\lib\portable-net45+netcore45+wpa81+wp8\FSharp.Core.dll
+ True
+ True
+
+
+
+
+
+
+ ..\..\packages\FSharp.Core\lib\portable-net45+sl5+netcore45\FSharp.Core.dll
+ True
+ True
+
+
+
+
+
+
+
+
+ ..\..\packages\test\FsUnit\lib\net45\FsUnit.NUnit.dll
+ True
+ True
+
+
+
+
+
+
+
+
+ ..\..\packages\test\NUnit\lib\MonoAndroid\nunit.framework.dll
+ True
+ True
+
+
+
+
+
+
+ ..\..\packages\test\NUnit\lib\net20\NUnit.System.Linq.dll
+ True
+ True
+
+
+ ..\..\packages\test\NUnit\lib\net20\nunit.framework.dll
+ True
+ True
+
+
+
+
+
+
+ ..\..\packages\test\NUnit\lib\net35\nunit.framework.dll
+ True
+ True
+
+
+
+
+
+
+ ..\..\packages\test\NUnit\lib\net40\nunit.framework.dll
+ True
+ True
+
+
+
+
+
+
+ ..\..\packages\test\NUnit\lib\net45\nunit.framework.dll
+ True
+ True
+
+
+
+
+
+
+ ..\..\packages\test\NUnit\lib\netstandard1.6\nunit.framework.dll
+ True
+ True
+
+
+
+
+
+
+ ..\..\packages\test\NUnit\lib\portable-net45+win8+wp8+wpa81\nunit.framework.dll
+ True
+ True
+
+
+
+
+
+
+ ..\..\packages\test\NUnit\lib\Xamarin.iOS10\nunit.framework.dll
+ True
+ True
+
+
+
+
\ No newline at end of file
diff --git a/tests/FSharp.CodeFormat.Tests/Tests.fs b/tests/FSharp.CodeFormat.Tests/Tests.fs
index 369c14e8d..476320801 100644
--- a/tests/FSharp.CodeFormat.Tests/Tests.fs
+++ b/tests/FSharp.CodeFormat.Tests/Tests.fs
@@ -1,7 +1,7 @@
#if INTERACTIVE
#r "../../bin/FSharp.CodeFormat.dll"
-#r "../../packages/NUnit/lib/nunit.framework.dll"
-#load "../Common/FsUnit.fs"
+#r "../../packages/test/NUnit/lib/net45/nunit.framework.dll"
+#r "../../packages/test/FsUnit/lib/net45/FsUnit.NUnit.dll"
#else
module FSharp.CodeFormat.Tests
#endif
@@ -9,6 +9,7 @@ module FSharp.CodeFormat.Tests
open FsUnit
open NUnit.Framework
open FSharp.CodeFormat
+open FsUnitTyped
// --------------------------------------------------------------------------------------
// Initialization - find F# compiler dll, setup formatting agent
diff --git a/tests/FSharp.CodeFormat.Tests/paket.references b/tests/FSharp.CodeFormat.Tests/paket.references
index 24a08ca93..bc0023968 100644
--- a/tests/FSharp.CodeFormat.Tests/paket.references
+++ b/tests/FSharp.CodeFormat.Tests/paket.references
@@ -1,2 +1,6 @@
+FSharp.Core
+group Test
+
NUnit
-NUnit.Runners
+NUnit.Console
+FsUnit
\ No newline at end of file
diff --git a/tests/FSharp.Literate.Tests/App.config b/tests/FSharp.Literate.Tests/App.config
index eaba40a10..0bb6ee95a 100644
--- a/tests/FSharp.Literate.Tests/App.config
+++ b/tests/FSharp.Literate.Tests/App.config
@@ -18,10 +18,6 @@
-
-
-
-
@@ -31,8 +27,14 @@
+ True
-
+
+
+
+ True
+
+
\ No newline at end of file
diff --git a/tests/FSharp.Literate.Tests/EvalTests.fs b/tests/FSharp.Literate.Tests/EvalTests.fs
index c294d2193..51115d87d 100644
--- a/tests/FSharp.Literate.Tests/EvalTests.fs
+++ b/tests/FSharp.Literate.Tests/EvalTests.fs
@@ -3,8 +3,8 @@
#r "FSharp.Literate.dll"
#r "FSharp.CodeFormat.dll"
#r "FSharp.Markdown.dll"
-#r "../../packages/NUnit/lib/nunit.framework.dll"
-#load "../Common/FsUnit.fs"
+#r "../../packages/test/NUnit/lib/net45/nunit.framework.dll"
+#r "../../packages/test/FsUnit/lib/net45/FsUnit.NUnit.dll"
#load "../Common/MarkdownUnit.fs"
#load "Setup.fs"
#else
@@ -12,6 +12,7 @@ module FSharp.Literate.Tests.Eval
#endif
open FsUnit
+open FsUnitTyped
open System.IO
open FSharp.Markdown
open FSharp.Literate
@@ -46,7 +47,7 @@ printf ">>%d<<" 12343
(*** include-output: test ***)
"""
- let doc = Literate.ParseScriptString(content, "." @@ "A.fsx", getFormatAgent(), fsiEvaluator = getFsiEvaluator())
+ let doc = Literate.ParseScriptString(content, "." > "A.fsx", getFormatAgent(), fsiEvaluator = getFsiEvaluator())
doc.Errors |> Seq.length |> shouldEqual 0
// Contains formatted code and markdown
@@ -70,7 +71,7 @@ let ``Can evaluate hidden code snippets`` () =
printfn "42"
(*** include-output: test ***)
"""
- let doc = Literate.ParseScriptString(content, "." @@ "A.fsx", getFormatAgent(), fsiEvaluator = getFsiEvaluator())
+ let doc = Literate.ParseScriptString(content, "." > "A.fsx", getFormatAgent(), fsiEvaluator = getFsiEvaluator())
let html = Literate.WriteHtml(doc)
html.Contains("42") |> shouldEqual true
html.Contains(">printfn<") |> shouldEqual false
@@ -90,7 +91,7 @@ let test = [1;2;3]
Some [ ListBlock(MarkdownListKind.Ordered, items, None) ]
else None)
- let doc = Literate.ParseScriptString(content, "." @@ "A.fsx", getFormatAgent(), fsiEvaluator = fsiEvaluator)
+ let doc = Literate.ParseScriptString(content, "." > "A.fsx", getFormatAgent(), fsiEvaluator = fsiEvaluator)
doc.Paragraphs
|> shouldMatchPar (function
| ListBlock(Ordered, items, None) ->
@@ -115,7 +116,7 @@ test 2
printfn "hi"
(*** include-output:t ***)
"""
- let doc = Literate.ParseScriptString(content, "." @@ "A.fsx", getFormatAgent(), fsiEvaluator = getFsiEvaluator())
+ let doc = Literate.ParseScriptString(content, "." > "A.fsx", getFormatAgent(), fsiEvaluator = getFsiEvaluator())
let html = Literate.WriteHtml(doc)
html.Split([| "
" |], System.StringSplitOptions.None).Length
|> shouldEqual 5
@@ -128,11 +129,11 @@ let ``Can disable evaluation on an entire script file`` () =
printfn "%d" (40 + 2)
(*** include-output:t ***)
"""
- let doc1 = Literate.ParseScriptString(content, "." @@ "A.fsx", getFormatAgent(), fsiEvaluator = getFsiEvaluator())
+ let doc1 = Literate.ParseScriptString(content, "." > "A.fsx", getFormatAgent(), fsiEvaluator = getFsiEvaluator())
let html1 = Literate.WriteHtml(doc1)
html1.Contains("42") |> shouldEqual true
- let doc2 = Literate.ParseScriptString("(*** do-not-eval-file ***)\n" + content, "." @@ "A.fsx", getFormatAgent(), fsiEvaluator = getFsiEvaluator())
+ let doc2 = Literate.ParseScriptString("(*** do-not-eval-file ***)\n" + content, "." > "A.fsx", getFormatAgent(), fsiEvaluator = getFsiEvaluator())
let html2 = Literate.WriteHtml(doc2)
html2.Contains("42") |> shouldEqual false
@@ -156,7 +157,7 @@ printfn "%d" FsLab.Demo.test
(*** include-output:t ***)""".Replace("[PATH]", path)
let fsie = getFsiEvaluator()
fsie.EvaluationFailed.Add(printfn "%A")
- let doc1 = Literate.ParseScriptString(content, "." @@ "A.fsx", getFormatAgent(), fsiEvaluator = fsie)
+ let doc1 = Literate.ParseScriptString(content, "." > "A.fsx", getFormatAgent(), fsiEvaluator = fsie)
let html1 = Literate.WriteHtml(doc1)
html1.Contains("42") |> shouldEqual true
File.Delete(path)
@@ -183,7 +184,7 @@ module Demo =
FsLab.Demo.test
(*** include-it:t2 ***)""".Replace("[PATH]", path)
let fsie = FSharp.Literate.FsiEvaluator(fsiObj = FsiEvaluatorConfig.CreateNoOpFsiObject())
- let doc1 = Literate.ParseScriptString(content, "." @@ "A.fsx", getFormatAgent(), fsiEvaluator = fsie)
+ let doc1 = Literate.ParseScriptString(content, "." > "A.fsx", getFormatAgent(), fsiEvaluator = fsie)
let html1 = Literate.WriteHtml(doc1)
html1.Contains("Not executed") |> shouldEqual true
html1.Contains("Executed") |> shouldEqual false
diff --git a/tests/FSharp.Literate.Tests/FSharp.Literate.Tests.fsproj b/tests/FSharp.Literate.Tests/FSharp.Literate.Tests.fsproj
index 318e2749d..62ec62b09 100644
--- a/tests/FSharp.Literate.Tests/FSharp.Literate.Tests.fsproj
+++ b/tests/FSharp.Literate.Tests/FSharp.Literate.Tests.fsproj
@@ -44,6 +44,7 @@
bin\Release\FSharp.Literate.Tests.xml
+ 12.011
@@ -52,32 +53,34 @@
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets
-
+
- $(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\4.0\Framework\v4.0\Microsoft.FSharp.Targets
+ $(MSBuildProgramFiles32)\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets
-
+
- $(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.1\Framework\v4.0\Microsoft.FSharp.Targets
+ $(MSBuildProgramFiles32)\Microsoft SDKs\F#\3.1\Framework\v4.0\Microsoft.FSharp.Targets
-
+
- $(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets
+ $(MSBuildProgramFiles32)\Microsoft SDKs\F#\4.0\Framework\v4.0\Microsoft.FSharp.Targets
+
+
+ $(MSBuildProgramFiles32)\Microsoft SDKs\F#\4.1\Framework\v4.0\Microsoft.FSharp.Targets
+
+
-
+
-
- Common\FsUnit.fs
-
Common\MarkdownUnit.fs
@@ -90,15 +93,6 @@
-
- ..\..\bin\CSharpFormat.dll
-
-
- ..\..\bin\FSharp.CodeFormat.dll
-
-
- False
-
@@ -113,6 +107,11 @@
-->
+
+ CSharpFormat
+ {9ab3650b-cc24-4404-a175-a573da928475}
+ True
+ FSharp.CodeFormat{341ebf32-d470-4c55-99e9-55f14f7ffbb1}
@@ -123,6 +122,11 @@
{91bad90e-bf3b-4646-a1a7-1568f8f25075}True
+
+ FSharp.Formatting.Razor
+ {c6b3c274-71a8-4239-ba9a-1af7b2f7c736}
+ True
+ FSharp.Literate{65e6d541-0486-4383-b619-5cfc5d2ba2f0}
@@ -133,11 +137,72 @@
{c44c1c05-599a-40dd-9590-465eab8960c5}True
-
- FSharp.Formatting.Razor.fsproj
- {c6b3c274-71a8-4239-ba9a-1af7b2f7c736}
-
+
+
+
+
+ ..\..\packages\FSharp.Core\lib\net20\FSharp.Core.dll
+ True
+ True
+
+
+
+
+
+
+ ..\..\packages\FSharp.Core\lib\net40\FSharp.Core.dll
+ True
+ True
+
+
+
+
+
+
+ ..\..\packages\FSharp.Core\lib\portable-net45+monoandroid10+monotouch10+xamarinios10\FSharp.Core.dll
+ True
+ True
+
+
+
+
+
+
+ ..\..\packages\FSharp.Core\lib\portable-net45+netcore45\FSharp.Core.dll
+ True
+ True
+
+
+
+
+
+
+ ..\..\packages\FSharp.Core\lib\portable-net45+netcore45+wp8\FSharp.Core.dll
+ True
+ True
+
+
+
+
+
+
+ ..\..\packages\FSharp.Core\lib\portable-net45+netcore45+wpa81+wp8\FSharp.Core.dll
+ True
+ True
+
+
+
+
+
+
+ ..\..\packages\FSharp.Core\lib\portable-net45+sl5+netcore45\FSharp.Core.dll
+ True
+ True
+
+
+
+
@@ -149,18 +214,65 @@
-
-
- ..\..\packages\NUnit\lib\nunit.framework.dll
- True
- True
-
-
-
+
- ..\..\packages\RazorEngine\lib\net40\RazorEngine.dll
+ ..\..\packages\RazorEngine\lib\net45\RazorEngine.dll
+ True
+ True
+
+
+
+
+
+
+
+
+ ..\..\packages\test\FsUnit\lib\net45\FsUnit.NUnit.dll
+ True
+ True
+
+
+
+
+
+
+
+
+ ..\..\packages\test\NUnit\lib\MonoAndroid\nunit.framework.dll
+ True
+ True
+
+
+
+
+
+
+ ..\..\packages\test\NUnit\lib\net20\NUnit.System.Linq.dll
+ True
+ True
+
+
+ ..\..\packages\test\NUnit\lib\net20\nunit.framework.dll
+ True
+ True
+
+
+
+
+
+
+ ..\..\packages\test\NUnit\lib\net35\nunit.framework.dll
+ True
+ True
+
+
+
+
+
+
+ ..\..\packages\test\NUnit\lib\net40\nunit.framework.dllTrueTrue
@@ -168,8 +280,35 @@
-
- ..\..\packages\RazorEngine\lib\net45\RazorEngine.dll
+
+ ..\..\packages\test\NUnit\lib\net45\nunit.framework.dll
+ True
+ True
+
+
+
+
+
+
+ ..\..\packages\test\NUnit\lib\netstandard1.6\nunit.framework.dll
+ True
+ True
+
+
+
+
+
+
+ ..\..\packages\test\NUnit\lib\portable-net45+win8+wp8+wpa81\nunit.framework.dll
+ True
+ True
+
+
+
+
+
+
+ ..\..\packages\test\NUnit\lib\Xamarin.iOS10\nunit.framework.dllTrueTrue
diff --git a/tests/FSharp.Literate.Tests/Setup.fs b/tests/FSharp.Literate.Tests/Setup.fs
index 35e0dc717..23f333613 100644
--- a/tests/FSharp.Literate.Tests/Setup.fs
+++ b/tests/FSharp.Literate.Tests/Setup.fs
@@ -8,7 +8,7 @@ open System.Reflection
// Setup - find the compiler assembly etc.
// --------------------------------------------------------------------------------------
-let (@@) a b = Path.Combine(a, b)
+let (>) a b = Path.Combine(a, b)
type TempFile() =
let file = Path.GetTempFileName()
diff --git a/tests/FSharp.Literate.Tests/Tests.fs b/tests/FSharp.Literate.Tests/Tests.fs
index 7e567ecab..859089b3c 100644
--- a/tests/FSharp.Literate.Tests/Tests.fs
+++ b/tests/FSharp.Literate.Tests/Tests.fs
@@ -4,8 +4,8 @@
#r "FSharp.CodeFormat.dll"
#r "FSharp.Markdown.dll"
#r "CSharpFormat.dll"
-#r "../../packages/NUnit/lib/nunit.framework.dll"
-#load "../Common/FsUnit.fs"
+#r "../../packages/test/NUnit/lib/net45/nunit.framework.dll"
+#r "../../packages/test/FsUnit/lib/net45/FsUnit.NUnit.dll"
#load "../Common/MarkdownUnit.fs"
#load "Setup.fs"
#else
@@ -19,6 +19,7 @@ open FSharp.Markdown.Unit
open NUnit.Framework
open FSharp.Literate.Tests.Setup
open FSharp.Formatting.Razor
+open FsUnitTyped
module Logging = FSharp.Formatting.Common.Log
@@ -60,7 +61,7 @@ a
[lang=csharp,file=Tests.fs,key=test]
-b""", __SOURCE_DIRECTORY__ @@ "Test.fsx")
+b""", __SOURCE_DIRECTORY__ > "Test.fsx")
//[/test]
doc.Paragraphs |> shouldMatchPar (function Paragraph([Literal("a", Some({ StartLine = 2 }))], Some({ StartLine = 2 })) -> true | _ -> false)
doc.Paragraphs |> shouldMatchPar (function Paragraph([Literal("b", Some({ StartLine = 6 }))], Some({ StartLine = 6 })) -> true | _ -> false)
@@ -78,7 +79,7 @@ let ``Can parse and format literate F# script`` () =
let content = """
(** **hello** *)
let test = 42"""
- let doc = Literate.ParseScriptString(content, "C" @@ "A.fsx", getFormatAgent())
+ let doc = Literate.ParseScriptString(content, "C" > "A.fsx", getFormatAgent())
doc.Errors |> Seq.length |> shouldEqual 0
doc.Paragraphs |> shouldMatchPar (function
| Matching.LiterateParagraph(FormattedCode(_)) -> true | _ -> false)
@@ -91,7 +92,7 @@ let ``Can parse heading on the same line as opnening comment (#147)`` () =
(** ## Heading
content *)
let test = 42"""
- let doc = Literate.ParseScriptString(content, "C" @@ "A.fsx", getFormatAgent())
+ let doc = Literate.ParseScriptString(content, "C" > "A.fsx", getFormatAgent())
doc.Paragraphs |> shouldMatchPar (function
| Heading(2, [Literal("Heading", Some({ StartLine = 1 }))], Some({ StartLine = 1 })) -> true | _ -> false)
@@ -144,7 +145,7 @@ some [link][ref] to
[ref]: http://there "Author: Article"
*)"""
- let doc = Literate.ParseScriptString(content, "C" @@ "A.fsx", getFormatAgent(), references=true)
+ let doc = Literate.ParseScriptString(content, "C" > "A.fsx", getFormatAgent(), references=true)
doc.Paragraphs |> shouldMatchPar (function ListBlock(_, _, _) -> true | _ -> false)
doc.Paragraphs |> shouldMatchSpan (function Literal("Article", None) -> true | _ -> false)
doc.Paragraphs |> shouldMatchSpan (function Literal(" - Author", None) -> true | _ -> false)
@@ -163,7 +164,7 @@ let ``Can report errors in F# code snippets (in Markdown document)`` () =
let content = """
(** **hello** *)
let test = 4 + 1.0"""
- let doc = Literate.ParseScriptString(content, "C" @@ "A.fsx", getFormatAgent())
+ let doc = Literate.ParseScriptString(content, "C" > "A.fsx", getFormatAgent())
doc.Errors |> Seq.length |> should be (greaterThan 0)
// --------------------------------------------------------------------------------------
@@ -291,7 +292,7 @@ let ``Path to network share should not be recognized as comments in Paket code b
cache //hive/dependencies"""
let doc = Literate.ParseMarkdownString(content, formatAgent=getFormatAgent())
let html = Literate.WriteHtml(doc)
- html |> should notContain "//hive/dependencies"
+ html |> shouldNotContainText "//hive/dependencies"
[]
let ``Correctly handles Paket coloring`` () =
@@ -351,8 +352,8 @@ let ``Correctly handles Paket coloring`` () =
html |> should contain "strategy"
html |> should contain "version_in_path"
- html |> should notContain "https"
- html |> should notContain ".git"
+ html |> shouldNotContainText "https"
+ html |> shouldNotContainText ".git"
html |> should contain "~>"
html |> should contain ">="
@@ -366,7 +367,7 @@ let ``Correctly handles Paket coloring`` () =
html |> should contain "// NuGet packages"
html |> should contain "// nuget.org"
- html |> should notContain "//hive/dependencies"
+ html |> shouldNotContainText "//hive/dependencies"
html |> should contain @"https://nuget.org/api/v2"
html |> should contain @"http://www.fssnip.net/1n"
@@ -385,7 +386,7 @@ let a2 = 2"""
html |> should contain "
Hello
"
html |> should contain "1:"
html |> should contain "2:"
- html |> should notContain "3:"
+ html |> shouldNotContainText "3:"
[]
let ``Generates line numbers for non-F# code snippets`` () =
@@ -401,7 +402,7 @@ var a2 = 2;
html |> should contain "
Hello
"
html |> should contain "1:"
html |> should contain "2:"
- html |> should notContain "3:"
+ html |> shouldNotContainText "3:"
[]
let ``HTML for line numbers generated for F# and non-F# is the same``() =
@@ -451,12 +452,12 @@ let ``Parsing simple script and markdown produces the same result`` () =
// Test processing simple files using simple templates
// --------------------------------------------------------------------------------------
-let templateHtml = __SOURCE_DIRECTORY__ @@ "files/template.html"
-let templateCsHtml = __SOURCE_DIRECTORY__ @@ "files/template.cshtml"
+let templateHtml = __SOURCE_DIRECTORY__ > "files/template.html"
+let templateCsHtml = __SOURCE_DIRECTORY__ > "files/template.cshtml"
[]
let ``Code and HTML is formatted with a tooltip in Markdown file using HTML template``() =
- let simpleMd = __SOURCE_DIRECTORY__ @@ "files/simple.md"
+ let simpleMd = __SOURCE_DIRECTORY__ > "files/simple.md"
use temp = new TempFile()
RazorLiterate.ProcessMarkdown(simpleMd, templateHtml, temp.File)
temp.Content |> should contain ""
@@ -464,7 +465,7 @@ let ``Code and HTML is formatted with a tooltip in Markdown file using HTML temp
[]
let ``Code and HTML is formatted with a tooltip in F# Script file using HTML template``() =
- let simpleFsx = __SOURCE_DIRECTORY__ @@ "files/simple.fsx"
+ let simpleFsx = __SOURCE_DIRECTORY__ > "files/simple.fsx"
use temp = new TempFile()
RazorLiterate.ProcessScriptFile(simpleFsx, templateHtml, temp.File)
temp.Content |> should contain ""
@@ -472,11 +473,11 @@ let ``Code and HTML is formatted with a tooltip in F# Script file using HTML tem
[]
let ``Code and HTML is formatted with a tooltip in F# Script file using Razor template``() =
- let simpleFsx = __SOURCE_DIRECTORY__ @@ "files/simple.fsx"
+ let simpleFsx = __SOURCE_DIRECTORY__ > "files/simple.fsx"
use temp = new TempFile()
RazorLiterate.ProcessScriptFile
( simpleFsx, templateCsHtml, temp.File,
- layoutRoots = [__SOURCE_DIRECTORY__ @@ "files"] )
+ layoutRoots = [__SOURCE_DIRECTORY__ > "files"] )
temp.Content |> should contain ""
temp.Content |> should contain "val hello : string"
temp.Content |> should contain "Heading"
@@ -493,25 +494,25 @@ let info =
"project-nuget", "http://nuget.com/packages/FSharp.ProjectScaffold"
"root", "http://tpetricek.github.io/FSharp.FSharp.ProjectScaffold" ]
-let docPageTemplate = __SOURCE_DIRECTORY__ @@ "../../misc/templates/docpage.cshtml"
+let docPageTemplate = __SOURCE_DIRECTORY__ > "../../misc/templates/docpage.cshtml"
[]
let ``Can process fsx file using the template included in NuGet package``() =
- let simpleFsx = __SOURCE_DIRECTORY__ @@ "files/simple.fsx"
+ let simpleFsx = __SOURCE_DIRECTORY__ > "files/simple.fsx"
use temp = new TempFile()
RazorLiterate.ProcessScriptFile
( simpleFsx, docPageTemplate, temp.File,
- layoutRoots = [__SOURCE_DIRECTORY__ @@ "../../misc/templates"], replacements = info)
+ layoutRoots = [__SOURCE_DIRECTORY__ > "../../misc/templates"], replacements = info)
temp.Content |> should contain "val hello : string"
temp.Content |> should contain "Heading"
[]
let ``Can process md file using the template included in NuGet package``() =
- let simpleMd = __SOURCE_DIRECTORY__ @@ "files/simple.md"
+ let simpleMd = __SOURCE_DIRECTORY__ > "files/simple.md"
use temp = new TempFile()
RazorLiterate.ProcessMarkdown
( simpleMd, docPageTemplate, temp.File,
- layoutRoots = [__SOURCE_DIRECTORY__ @@ "../../misc/templates"], replacements = info)
+ layoutRoots = [__SOURCE_DIRECTORY__ > "../../misc/templates"], replacements = info)
temp.Content |> should contain "val hello : string"
temp.Content |> should contain "Heading"
@@ -522,7 +523,7 @@ let ``Gives nice error when parsing unclosed comment`` () =
(** **hello**
let test = 42"""
try
- Literate.ParseScriptString(content, "C" @@ "A.fsx", getFormatAgent()) |> ignore
+ Literate.ParseScriptString(content, "C" > "A.fsx", getFormatAgent()) |> ignore
failwith ""
with
| e when e.Message.Contains("comment was not closed") -> ()
@@ -566,12 +567,12 @@ hello
*)
let test = 42
"""
- let doc = Literate.ParseScriptString(content, "." @@ "A.fsx", getFormatAgent())
+ let doc = Literate.ParseScriptString(content, "." > "A.fsx", getFormatAgent())
let doc2 = Literate.FormatLiterateNodes(doc,format=OutputKind.Html)
let html = Literate.WriteHtml(doc2.With(formattedTips=""))
let tips = doc2.FormattedTips
tips |> should contain "test : int"
- html |> should notContain "test : int"
+ html |> shouldNotContainText "test : int"
html |> should contain "hello"
diff --git a/tests/FSharp.Literate.Tests/paket.references b/tests/FSharp.Literate.Tests/paket.references
index 99552bb38..582963fe6 100644
--- a/tests/FSharp.Literate.Tests/paket.references
+++ b/tests/FSharp.Literate.Tests/paket.references
@@ -1,3 +1,7 @@
+FSharp.Core
Microsoft.AspNet.Razor
+RazorEngine
+
+group Test
+FsUnit
NUnit
-RazorEngine
\ No newline at end of file
diff --git a/tests/FSharp.Markdown.Tests/App.config b/tests/FSharp.Markdown.Tests/App.config
index 016441f87..782c7196a 100644
--- a/tests/FSharp.Markdown.Tests/App.config
+++ b/tests/FSharp.Markdown.Tests/App.config
@@ -4,35 +4,37 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+
+
+
+
+ True
+
+
+
+
\ No newline at end of file
diff --git a/tests/FSharp.Markdown.Tests/CommonMarkSpecTest.fs b/tests/FSharp.Markdown.Tests/CommonMarkSpecTest.fs
index 0895020bf..6a59a8985 100644
--- a/tests/FSharp.Markdown.Tests/CommonMarkSpecTest.fs
+++ b/tests/FSharp.Markdown.Tests/CommonMarkSpecTest.fs
@@ -2,8 +2,8 @@
open System.IO
open System.Diagnostics
-let (++) a b = Path.Combine(a, b)
-let testdir = __SOURCE_DIRECTORY__ ++ Path.Combine("..", "..", "tests")
+let (>) a b = Path.Combine(a, b)
+let testdir = __SOURCE_DIRECTORY__ > Path.Combine("..", "..", "tests")
open FSharp.Data
type CommonMarkSpecJson = JsonProvider<"../../tests/commonmark_spec.json">
@@ -46,14 +46,14 @@ let ``manual markdown test: show a blockquote with a code block`` () =
let markdown = """Blockquotes can contain other Markdown elements, including headers, lists,
and code blocks:
- > ## This is a header.
- >
- > 1. This is the first list item.
- > 2. This is the second list item.
- >
- > Here's some example code:
- >
- > return shell_exec("echo $input | $markdown_script");
+ > ## This is a header.
+ >
+ > 1. This is the first list item.
+ > 2. This is the second list item.
+ >
+ > Here's some example code:
+ >
+ > return shell_exec("echo $input | $markdown_script");
Any decent text editor should make email-style quoting easy."""
let html = """