-
Notifications
You must be signed in to change notification settings - Fork 46
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for GitHub-Flavoured Markdown tables #292
Merged
shonfeder
merged 11 commits into
ocaml-community:master
from
bobatkey:topic/support-tables
Nov 20, 2022
Merged
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
d160cdd
Support for GitHub-Flavoured Markdown tables
bobatkey fb795d5
Improve parsing for GFM-style tables
bobatkey 433824d
Specialised HTML output for tables
bobatkey d3b171a
Tests for the GFM-style tables support
bobatkey 8ccb1e8
Apply ocamlformat
bobatkey c6a298a
Add comments for table parts
shonfeder 10a4bd0
Use labeled arg for pipe_prefix argument
shonfeder 77e7910
Rename take_n to take_prefix
shonfeder 16700ca
Add missing word
shonfeder 543418e
Add changelog entry and thank you
shonfeder 168f3e3
Fix formatting
shonfeder File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,8 @@ module Pre = struct | |
| Rindented_code of string list | ||
| Rhtml of Parser.html_kind * string list | ||
| Rdef_list of string * string list | ||
| Rtable_header of StrSlice.t list * string | ||
| Rtable of (string * cell_alignment) list * string list list | ||
| Rempty | ||
|
||
and t = | ||
|
@@ -74,13 +76,57 @@ module Pre = struct | |
let rec loop = function "" :: l -> loop l | _ as l -> l in | ||
Code_block ([], "", concat (loop l)) :: blocks | ||
| Rhtml (_, l) -> Html_block ([], concat l) :: blocks | ||
| Rtable_header (_header, line) -> | ||
(* FIXME: this will only ever get called on the very last | ||
line. Should it do the link definitions? *) | ||
close link_defs { blocks; next = Rparagraph [ line ] } | ||
| Rtable (header, rows) -> Table ([], header, List.rev rows) :: blocks | ||
| Rempty -> blocks | ||
|
||
and finish link_defs state = List.rev (close link_defs state) | ||
|
||
let empty = { blocks = []; next = Rempty } | ||
let classify_line s = Parser.parse s | ||
|
||
let classify_delimiter s = | ||
let left, s = | ||
match StrSlice.head s with | ||
| Some ':' -> (true, StrSlice.drop 1 s) | ||
| _ -> (false, s) | ||
in | ||
let right, s = | ||
match StrSlice.last s with | ||
| Some ':' -> (true, StrSlice.drop_last s) | ||
| _ -> (false, s) | ||
in | ||
if StrSlice.exists (fun c -> c <> '-') s then None | ||
else | ||
match (left, right) with | ||
| true, true -> Some Centre | ||
| true, false -> Some Left | ||
| false, true -> Some Right | ||
| false, false -> Some Default | ||
|
||
let match_table_headers headers delimiters = | ||
let rec loop processed = function | ||
| [], [] -> Some (List.rev processed) | ||
| header :: headers, line :: delimiters -> ( | ||
match classify_delimiter line with | ||
| None -> None | ||
| Some alignment -> | ||
loop | ||
((StrSlice.to_string header, alignment) :: processed) | ||
(headers, delimiters)) | ||
| [], _ :: _ | _ :: _, [] -> None | ||
in | ||
loop [] (headers, delimiters) | ||
|
||
let rec match_row_length l1 l2 = | ||
match (l1, l2) with | ||
| [], _ -> [] | ||
| l1, [] -> List.init (List.length l1) (fun _ -> "") | ||
| _ :: l1, x :: l2 -> StrSlice.to_string x :: match_row_length l1 l2 | ||
|
||
let rec process link_defs { blocks; next } s = | ||
let process = process link_defs in | ||
let close = close link_defs in | ||
|
@@ -103,8 +149,10 @@ module Pre = struct | |
{ blocks | ||
; next = Rlist (kind, Tight, false, indent, [], process empty s) | ||
} | ||
| Rempty, (Lsetext_heading _ | Lparagraph | Ldef_list _) -> | ||
| Rempty, (Lsetext_heading _ | Lparagraph | Ldef_list _ | Ltable_line []) -> | ||
{ blocks; next = Rparagraph [ StrSlice.to_string s ] } | ||
| Rempty, Ltable_line items -> | ||
{ blocks; next = Rtable_header (items, StrSlice.to_string s) } | ||
| Rparagraph [ h ], Ldef_list def -> | ||
{ blocks; next = Rdef_list (h, [ def ]) } | ||
| Rdef_list (term, defs), Ldef_list def -> | ||
|
@@ -152,6 +200,36 @@ module Pre = struct | |
} | ||
| Rdef_list _, _ -> | ||
process { blocks = close { blocks; next }; next = Rempty } s | ||
| Rtable_header (headers, line), Ltable_line items -> ( | ||
match match_table_headers headers items with | ||
| Some headers -> | ||
(* Makes sure that there are the same number of delimiters | ||
as headers. See | ||
https://github.github.com/gfm/#example-203 *) | ||
Comment on lines
+206
to
+208
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks very much for the helpful comments and references! |
||
{ blocks; next = Rtable (headers, []) } | ||
| None -> | ||
(* Reinterpret the previous line as the start of a | ||
paragraph. *) | ||
process { blocks; next = Rparagraph [ line ] } s) | ||
| Rtable_header (_, line), _ -> | ||
(* If we only have a potential header, and the current line | ||
doesn't look like a table delimiter, then reinterpret the | ||
previous line as the start of a paragraph. *) | ||
process { blocks; next = Rparagraph [ line ] } s | ||
| Rtable (header, rows), Ltable_line row -> | ||
(* Make sure the number of items in the row is consistent with | ||
the headers and the rest of the rows. See | ||
https://github.github.com/gfm/#example-204 *) | ||
let row = match_row_length header row in | ||
{ blocks; next = Rtable (header, row :: rows) } | ||
| Rtable (header, rows), (Lparagraph | Lsetext_heading _) -> | ||
(* Treat a contiguous line after a table as a row, even if it | ||
doesn't contain any '|' | ||
characters. https://github.github.com/gfm/#example-202 *) | ||
let row = match_row_length header [ s ] in | ||
{ blocks; next = Rtable (header, row :: rows) } | ||
| Rtable _, _ -> | ||
process { blocks = close { blocks; next }; next = Rempty } s | ||
| Rindented_code lines, Lindented_code s -> | ||
{ blocks; next = Rindented_code (StrSlice.to_string s :: lines) } | ||
| Rindented_code lines, Lempty -> | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,13 +15,23 @@ and inline = function | |
| Text (_, s) -> Atom s | ||
| Emph (_, il) -> List [ Atom "emph"; inline il ] | ||
| Strong (_, il) -> List [ Atom "strong"; inline il ] | ||
| Code _ -> Atom "code" | ||
| Code _ -> Atom "code" (* FIXME: this seems broken? *) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Noted in #293. Thanks! |
||
| Hard_break _ -> Atom "hard-break" | ||
| Soft_break _ -> Atom "soft-break" | ||
| Link (_, def) -> List [ Atom "url"; link def ] | ||
| Html (_, s) -> List [ Atom "html"; Atom s ] | ||
| Image _ -> Atom "img" | ||
|
||
let table_header (header, alignment) = | ||
List | ||
[ inline header | ||
; (match alignment with | ||
| Default -> Atom "default" | ||
| Left -> Atom "left" | ||
| Centre -> Atom "centre" | ||
| Right -> Atom "right") | ||
] | ||
|
||
let rec block = function | ||
| Paragraph (_, x) -> List [ Atom "paragraph"; inline x ] | ||
| List (_, _, _, bls) -> | ||
|
@@ -44,6 +54,12 @@ let rec block = function | |
List [ inline elt.term; List (List.map inline elt.defs) ]) | ||
l) | ||
] | ||
| Table (_, headers, rows) -> | ||
List | ||
[ Atom "table" | ||
; List (List.map table_header headers) | ||
; List (List.map (fun row -> List (List.map inline row)) rows) | ||
] | ||
|
||
let create ast = List (List.map block ast) | ||
|
||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if it's worth making the last two fields an inline record to identify for readers the header from the rows... not sure if that's worth it, but at least a comment to explain would be helpful.