diff --git a/lib/export/html.ml b/lib/export/html.ml index 91ac493..e0da332 100644 --- a/lib/export/html.ml +++ b/lib/export/html.ml @@ -101,6 +101,7 @@ and inline config t = | Plain s | Spaces s -> [ Xml.data s ] + | Escaped s -> [ Xml.data ("\\" ^ s) ] | Superscript l -> [ Xml.block "sup" (map_inline config l) ] | Subscript l -> [ Xml.block "sub" (map_inline config l) ] | Emphasis (kind, data) -> diff --git a/lib/export/markdown.ml b/lib/export/markdown.ml index c43e50e..afad14c 100644 --- a/lib/export/markdown.ml +++ b/lib/export/markdown.ml @@ -103,6 +103,12 @@ let rec inline state config (t : Inline.t) : t list = map_raw_text [ String.ltrim s ] ) else map_raw_text [ s ] + | Escaped s -> + if state.last_newline then ( + state.last_newline <- false; + map_raw_text [ "\\"; s ] + ) else + map_raw_text [ "\\"; s ] | Link l -> inline_link l | Nested_link l -> inline_nested_link l | Target s -> map_raw_text [ "<<"; s; ">>" ] diff --git a/lib/mldoc_parser.ml b/lib/mldoc_parser.ml index 81d25d7..7ddca28 100644 --- a/lib/mldoc_parser.ml +++ b/lib/mldoc_parser.ml @@ -47,12 +47,7 @@ let parsers config = let parse config input = match parse_string ~consume:All (parsers config) input with - | Ok result -> - let ast = Paragraph.concat_paragraph_lines config result in - if Conf.is_markdown config then - List.map (fun (t, pos) -> (Type_op.md_unescaped t, pos)) ast - else - ast + | Ok result -> Paragraph.concat_paragraph_lines config result | Error err -> failwith err let load_file f = diff --git a/lib/syntax/inline.ml b/lib/syntax/inline.ml index 800944c..36819b9 100644 --- a/lib/syntax/inline.ml +++ b/lib/syntax/inline.ml @@ -121,6 +121,7 @@ and t = | Email of Email_address.t | Inline_Hiccup of string | Inline_Html of string + | Escaped of string [@@deriving yojson] and t_with_pos = t * pos_meta option @@ -208,6 +209,13 @@ let in_plain_delims config c = let whitespaces = ws >>| fun spaces -> Plain spaces +let md_escaped_char set_last_char = + char '\\' >>= fun _ -> + satisfy is_md_escape_char >>| fun c -> + let s = String.make 1 c in + set_last_char s; + Escaped s + let plain ?state config = let set_last_char s = Option.( @@ -223,10 +231,7 @@ let plain ?state config = <|> ( ws >>| fun s -> set_last_char s; Plain s ) - <|> ( char '\\' *> satisfy is_md_escape_char >>| fun c -> - let s = String.make 1 c in - set_last_char s; - Plain ("\\" ^ s) ) + <|> md_escaped_char set_last_char <|> ( any_char >>= fun c -> if in_plain_delims config c then ( let s = String.make 1 c in @@ -487,7 +492,7 @@ let entity = try let entity = Entity.find s in Entity entity - with Not_found -> Plain s + with Not_found -> Plain ("\\" ^ s) (* FIXME: nested emphasis not working *) (* foo_bar, foo_{bar}, foo^bar, foo^{bar} *) @@ -919,6 +924,7 @@ let nested_link_or_link config = let nested_emphasis ?state config = let rec aux_nested_emphasis = function | Plain s -> Plain s + | Escaped s -> Escaped s | Emphasis (`Italic, [ Emphasis (`Bold, _) ]) as e -> e | Emphasis (typ, l) -> let parser = diff --git a/lib/syntax/type_op.ml b/lib/syntax/type_op.ml index ce4c442..e037b7f 100644 --- a/lib/syntax/type_op.ml +++ b/lib/syntax/type_op.ml @@ -52,116 +52,3 @@ let rec type_move_forawrd t forward_pos = | Footnote_Definition (s, l) -> Footnote_Definition (s, inline_list_move_forward l forward_pos) | _ -> t - -let unescaped_md_string s = - let open Bytes in - let b = of_string s in - let n = ref 0 in - let i = ref 0 in - let lenb = length b in - while !i < lenb do - n := - !n - + - match get b !i with - | '\\' when !i + 1 < lenb && Parsers.is_md_escape_char (get b (!i + 1)) -> - i := !i + 2; - 1 - | _ -> - incr i; - 1 - done; - if !n = length b then - s - else - let b' = create !n in - n := 0; - let i = ref 0 in - let len_1 = length b - 1 in - while !i <= len_1 do - (match get b !i with - | '\\' when !i < len_1 -> - let c = get b (!i + 1) in - if Parsers.is_md_escape_char c then - set b' !n c - else ( - set b' !n '\\'; - incr n; - set b' !n c - ); - incr i - | c -> set b' !n c); - incr n; - incr i - done; - to_string b' - -let map_escaped_string t f = - let rec inline_aux (t : Inline.t) = - match t with - | Inline.Emphasis (em_type, tl) -> - Inline.Emphasis (em_type, List.map inline_aux tl) - | Inline.Tag tl -> Inline.Tag (List.map inline_aux tl) - | Inline.Plain s -> Inline.Plain (f s) - | Inline.Link link -> - let label = List.map inline_aux link.label in - let url = - match link.url with - | Inline.File s -> Inline.File (f s) - | Inline.Search s -> Inline.Search (f s) - | Inline.Page_ref s -> Inline.Page_ref (f s) - | Inline.Complex complex -> - Inline.Complex { complex with link = f complex.link } - | Inline.Block_ref _ -> link.url - | Inline.Embed_data _ -> link.url - in - Inline.Link { link with label; url } - | Inline.Subscript tl -> Inline.Subscript (List.map inline_aux tl) - | Inline.Superscript tl -> Inline.Superscript (List.map inline_aux tl) - | Inline.Footnote_Reference fr -> - Inline.Footnote_Reference - { fr with definition = Option.map (List.map inline_aux) fr.definition } - | _ -> t - in - let rec block_list_aux list_item = - let content' = List.map block_aux list_item.content in - let items = List.map block_list_aux list_item.items in - let name = - List.map (fun (t', pos) -> (inline_aux t', pos)) list_item.name - in - { list_item with content = content'; items; name } - and block_aux (t : Type.t) = - match t with - | Paragraph l -> - Paragraph (List.map (fun (t', pos) -> (inline_aux t', pos)) l) - | Heading heading -> - let title' = - List.map (fun (t', pos) -> (inline_aux t', pos)) heading.title - in - Heading { heading with title = title' } - | List l -> List (List.map block_list_aux l) - | Quote tl -> Quote (List.map block_aux tl) - | Custom (name, opts, data, s) -> - let data' = List.map block_aux data in - Custom (name, opts, data', s) - | Footnote_Definition (name, content) -> - let content' = List.map (fun (t', pos) -> (inline_aux t', pos)) content in - Footnote_Definition (name, content') - | Table table -> - let header = Option.map (List.map (List.map inline_aux)) table.header in - let groups = - List.map (List.map (List.map (List.map inline_aux))) table.groups - in - Table { table with header; groups } - | _ -> t - in - block_aux t - -(** unescape string in Type.Plain: - e.g. \* -> * - see also Parsers.md_escape_chars - text in code fence should preserve '\' *) -let md_unescaped t = map_escaped_string t unescaped_md_string - -(** TODO *) -let md_escaped _t = failwith "not impl yet" diff --git a/test/test_export_markdown.ml b/test/test_export_markdown.ml index d52f0ca..86451a6 100644 --- a/test/test_export_markdown.ml +++ b/test/test_export_markdown.ml @@ -119,8 +119,8 @@ let export_md = \t\t [[line6]]\n\ \t\t\t-\n\ \t\t\t ```\n\ - \t\t\t dwdw\n\ - \t\t\t jdiejdie\n\ + \t\t\t \t dwdw\n\ + \t\t\t \t jdiejdie\n\ \t\t\t ```" ) ; ( "(5)" , `Quick @@ -173,6 +173,14 @@ let export_md = , `Quick , check_aux "- {{cloze (content1,content2)}}" "- (content1,content2)" ) + ; ("escaped", `Quick, check_aux "- a\\`b" "- a\\`b") + ; ( "escaped" + , `Quick + , check_aux "- a\\^b \\*non-italic*" "- a\\^b \\*non-italic*" ) + ; ( "escaped" + , `Quick + , check_aux "- example postgres cmd: \\dt" + "- example postgres cmd: \\dt" ) ] ) ] diff --git a/test/test_markdown.ml b/test/test_markdown.ml index a067f2f..94ec4e7 100644 --- a/test/test_markdown.ml +++ b/test/test_markdown.ml @@ -696,13 +696,22 @@ let inline = [ ( "emphasis(1)" , `Quick , check_aux "*a\\*b*" - (paragraph [ Inline.Emphasis (`Italic, [ Inline.Plain "a*b" ]) ]) - ) + (paragraph + [ Inline.Emphasis + (`Italic, [ I.Plain "a"; I.Escaped "*"; I.Plain "b" ]) + ]) ) ; ( "emphasis(2)" , `Quick , check_aux "*a\\\\\\*b*" (paragraph - [ Inline.Emphasis (`Italic, [ Inline.Plain "a\\*b" ]) ]) ) + [ Inline.Emphasis + ( `Italic + , [ I.Plain "a" + ; I.Escaped "\\" + ; I.Escaped "*" + ; I.Plain "b" + ] ) + ]) ) ; ( "code" , `Quick , check_aux "`a\\``" @@ -710,14 +719,16 @@ let inline = ; ( "nested emphasis" , `Quick , check_aux "_a*b\\*_" - (paragraph [ Inline.Emphasis (`Italic, [ Inline.Plain "a*b*" ]) ]) - ) + (paragraph + [ Inline.Emphasis + (`Italic, [ Inline.Plain "a*b"; I.Escaped "*" ]) + ]) ) ; ( "link (1)" , `Quick , check_aux "[[\\]]]" (paragraph [ Inline.Link - { url = Inline.Page_ref "]" + { url = Inline.Page_ref "\\]" ; label = [ Inline.Plain "" ] ; full_text = "[[\\]]]" ; metadata = "" @@ -730,7 +741,7 @@ let inline = (paragraph [ Inline.Link { url = Inline.Search "xxx" - ; label = [ Inline.Plain "label](x)" ] + ; label = [ Inline.Plain "label\\](x)" ] ; full_text = "[label\\](x)](xxx)" ; metadata = "" ; title = None @@ -741,7 +752,7 @@ let inline = , check_aux "[label](ur\\)l)" (paragraph [ Inline.Link - { url = Inline.Search "ur)l" + { url = Inline.Search "ur\\)l" ; label = [ Inline.Plain "label" ] ; full_text = "[label](ur\\)l)" ; metadata = ""