-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
RFC add markdown Table #9878
RFC add markdown Table #9878
Changes from all commits
9d60cf0
b4b8324
c752ffd
fc60fb8
d36e51e
575cf67
cca79f6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
type Table | ||
rows::Vector{Vector{Any}} | ||
align | ||
end | ||
|
||
function github_table(stream::IO, md::MD, config::Config) | ||
withstream(stream) do | ||
rows = Any[] | ||
n = 0 | ||
align = :r # default is to align right | ||
while !eof(stream) | ||
n += 1 | ||
pos = position(stream) | ||
skipwhitespace(stream) | ||
line = readline(stream) |> chomp | ||
|
||
if n == 1 | ||
pipe_border = line[1] == '|' | ||
if !('|' in line) | ||
return false | ||
end | ||
end | ||
|
||
row = map(strip, split(line, "|")) | ||
if pipe_border | ||
if row[1] == row[end] == "" | ||
row = row[2:end-1] | ||
else | ||
return false | ||
end | ||
end | ||
|
||
if n == 2 && all(['-' in r && issubset(Set(r), Set(" -:")) | ||
for r in row]) | ||
# handle possible --- line | ||
align = Symbol[] | ||
for r in row | ||
if r[1] == ':' | ||
if r[end] == ':' | ||
push!(align, :c) | ||
else | ||
push!(align, :l) | ||
end | ||
else | ||
if r[end] == ':' | ||
push!(align, :r) | ||
else | ||
# default is align right | ||
push!(align, :r) | ||
end | ||
end | ||
end | ||
|
||
elseif n == 1 || length(rows[1]) == length(row) | ||
push!(rows, map(x -> parseinline(x, config), row)) | ||
elseif length(row) > 1 | ||
seek(stream, pos) | ||
break | ||
else | ||
return false | ||
end | ||
end | ||
if length(rows) < 2 | ||
return false | ||
end | ||
push!(md, Table(rows, align)) | ||
return true | ||
end | ||
end | ||
|
||
function html(io::IO, md::Table) | ||
withtag(io, :table) do | ||
for (i, row) in enumerate(md.rows) | ||
withtag(io, :tr) do | ||
for c in md.rows[i] | ||
t = (i == 1) ? :th : :td | ||
withtag(io, t) do | ||
htmlinline(io, c) | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end | ||
|
||
function plain(io::IO, md::Table) | ||
plain_cells = map(row -> map(plaininline, row), md.rows) | ||
plain_lengths = map(row -> int(map(length, row)), plain_cells) | ||
col_widths = reduce(max, plain_lengths) | ||
|
||
for i in 1:length(md.rows) | ||
for (j, text) in enumerate(plain_cells[i]) | ||
(j != 1) && print(io, " | ") | ||
print(io, " " ^ (col_widths[j] - plain_lengths[i][j])) | ||
print(io, text) | ||
end | ||
println(io) | ||
|
||
if i == 1 | ||
for (j, w) in enumerate(col_widths) | ||
if j != 1 | ||
print(io, " | ") | ||
end | ||
a = typeof(md.align) == Symbol ? md.align : md.align[j] | ||
print(io, _dash(w, a)) | ||
end | ||
println(io) | ||
end | ||
end | ||
end | ||
|
||
function _dash(width, align) | ||
if align == :l | ||
return ":" * "-" ^ max(3, width - 1) | ||
elseif align == :r | ||
return "-" ^ max(3, width - 1) * ":" | ||
elseif align == :c | ||
return ":" * "-" ^ max(3, width - 2) * ":" | ||
else | ||
throw(ArgumentError("Unrecognized alignment $align")) | ||
end | ||
end | ||
|
||
|
||
function writemime(io::IO, ::MIME"text/latex", md::Table) | ||
wrapblock(io, "tabular") do | ||
if typeof(md.align) == Symbol | ||
align = string(md.align) ^ length(md.rows[1]) | ||
else | ||
align = md.align | ||
end | ||
println(io, "{$(join(align, " | "))}") | ||
for (i, row) in enumerate(md.rows) | ||
for (j, cell) in enumerate(row) | ||
if j != 1 | ||
print(io, " & ") | ||
end | ||
latex_inline(io, cell) | ||
end | ||
println(io, " \\\\") | ||
if i == 1 | ||
println("\\hline") | ||
end | ||
end | ||
end | ||
end | ||
|
||
function term(io::IO, md::Table, columns) | ||
plain_lengths = map(row -> int(map(x -> ansi_length(terminline(x)), row)), | ||
md.rows) | ||
col_widths = reduce(max, plain_lengths) | ||
|
||
col_widths = max(col_widths, 3) | ||
for (i, row) in enumerate(md.rows) | ||
for (j, h) in enumerate(row) | ||
(j != 1) && print(io, " ") | ||
a = typeof(md.align) == Symbol ? md.align : md.align[j] | ||
print_align(io, h, plain_lengths[i][j], col_widths[j], a) | ||
end | ||
println(io) | ||
|
||
if i == 1 | ||
for (j, w) in enumerate(col_widths) | ||
(j != 1) && print(io, " ") | ||
print(io, "-" ^ w) | ||
end | ||
println(io) | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -51,19 +51,19 @@ function plaininline(io::IO, md...) | |
end | ||
|
||
plaininline(io::IO, md::Vector) = !isempty(md) && plaininline(io, md...) | ||
|
||
plaininline(io::IO, md::Image) = print(io, "![$(md.alt)]($(md.url))") | ||
|
||
plaininline(io::IO, s::String) = print(io, s) | ||
|
||
plaininline(io::IO, md::Bold) = plaininline(io, "**", md.text, "**") | ||
|
||
plaininline(io::IO, md::Italic) = plaininline(io, "*", md.text, "*") | ||
|
||
plaininline(io::IO, md::Image) = print(io, "![", plaininline(md.alt), "](", | ||
md.url, ")") | ||
plaininline(io::IO, md::Link) = print(io, "[", plaininline(md.text), "](", | ||
md.url, ")") | ||
plaininline(io::IO, md::Bold) = print(io, "**", plaininline(md.text), "**") | ||
plaininline(io::IO, md::Italic) = print(io, "*", plaininline(md.text), "*") | ||
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. Good to see the extra methods here but there are a lot of unnecessary stylistic changes – would be great to see the diff being as simple as possible |
||
plaininline(io::IO, md::Code) = print(io, "`", md.code, "`") | ||
|
||
plaininline(io::IO, s::String) = print(io, s) | ||
plaininline(io::IO, x) = writemime(io, MIME"text/plain"(), x) | ||
|
||
plaininline(s::String) = s | ||
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. This method should be unnecessary, it's covered by the one below 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. This just saves copying a string. 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. Strings are stored in generated markdown trees as |
||
plaininline(x) = sprint(plaininline, x) | ||
|
||
# writemime | ||
|
||
Base.writemime(io::IO, ::MIME"text/plain", md::MD) = plain(io, md) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
using Base.Markdown | ||
import Base.Markdown: MD, Paragraph, Italic, Bold, plain, term, html | ||
import Base.Markdown: MD, Paragraph, Italic, Bold, plain, term, html, Table, Code | ||
import Base: writemime | ||
|
||
# Basics | ||
|
@@ -39,3 +39,17 @@ writemime(io::IO, m::MIME"text/plain", r::Reference) = | |
print(io, "$(r.ref) (see Julia docs)") | ||
|
||
@test md"Behaves like $(ref(fft))" == md"Behaves like fft (see Julia docs)" | ||
|
||
# GH tables | ||
@test md"""a|b | ||
1|2""" == MD(Table(Any[Any[Any["a"],Any["b"]];Any[Any["1"],Any["2"]]], :r)) | ||
|
||
table = md"""| a | b | c | | ||
| :- | -: | - | | ||
| d`gh`hg | hgh**jhj**ge | f |""" | ||
@test table == MD(Table(Any[Any[Any["a"],Any["b"],Any["c"]], | ||
Any[Any["d",Markdown.Code("","gh"),"hg"], | ||
Any["hgh",Markdown.Bold(Any["jhj"]),"ge"], | ||
Any["f"]]], | ||
[:l, :r, :r])) | ||
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. It would be nice to make the tests as human-readable as possible, e.g. you can write this as MD(Table(Any[["a","b","c"],
Any[["d",Code("gh"),"hg"],
["hgh",Bold("jhj"),"ge"],
"f"]],
[:l, :r, :r])) (This actually doesn't work at the moment, which I think is due to a problem with |
||
|
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.
There's a strong practice in Markdown.jl of not handling the stream position explicitly. I guess it's not essential, but it would still be nice to see row parsing factored out to address that
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.
It may be easier to refactor some of this after merging