diff --git a/Project.toml b/Project.toml index 23735177d..aa41bf700 100644 --- a/Project.toml +++ b/Project.toml @@ -5,6 +5,7 @@ version = "0.2.0" [deps] Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" +DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab" DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" JuDocTemplates = "6793090a-55ae-11e9-0511-73b91164f4ea" LiveServer = "16fef848-5104-11e9-1b77-fb7a48bbb589" diff --git a/docs/src/man/syntax.md b/docs/src/man/syntax.md index 0fb3a4fde..9c77f7ec8 100644 --- a/docs/src/man/syntax.md +++ b/docs/src/man/syntax.md @@ -33,6 +33,7 @@ Most of what is presented here is also shown in that example. * [Inserting a figure](#Inserting-a-figure-1) * [Linking a file](#Linking-a-file-1) * [Inserting markdown](#Inserting-markdown-1) + * [Inserting a table](#Inserting-a-table-1) * [Page variables](#Page-variables-1) * [Local page variables](#Local-page-variables-1) * [Default variables](#Default-variables-1) @@ -681,6 +682,55 @@ This is the index then some **markdown** in a side file. **Note**: if you don't specify a file extension, `.md` is appended to the specified path. +### Inserting a table + +You can insert tables directly from CSV files with the `\tableinput{header}{path}` command. +If you generate the file on-the-fly, you should follow this example: +`````judoc +```julia:./tableinput/gen +testcsv = "h1,h2,h3 +152,some string, 1.5f0 +0,another string,2.87" +write("assets/pages/tableinput/testcsv.csv", testcsv) +``` +````` +Then you can insert the table with: +`````judoc +\tableinput{}{./tableinput/testcsv.csv} +````` +Which will result in: + +| h1 | h2 | h3 | +| --- | -------------- | ----- | +| 152 | some string | 1.5f0 | +| 0 | another string | 2.87 | +In this case given no header was specified in the call, a header was generated from the first line in the CSV (here: h1, h2, h3). + +If you're file doesn't have a header, you can specify it in the call: +`````judoc +```julia:./tableinput/gen +testcsv = "152,some string, 1.5f0 +0,another string,2.87" +write("assets/pages/tableinput/testcsv2.csv", testcsv) + +\tableinput{custom h1,custom h2,custom h3}{./tableinput/testcsv2.csv} +````` + +| custom h1 | custom h2 | custom h3 | +| --------- | -------------- | --------- | +| 152 | some string | 1.5f0 | +| 0 | another string | 2.87 | + +With the above in mind, you can also include existing CSV files. + +!!! note + + The look of the table will be defined by your CSS stylesheet. + +There's a couple of rules that you have to keep in mind when using the `\tableinput{}{}` command: +* Columns must be separated with comma (`,`). +* If a header is specified, its length must match the number of columns of the file. + ## Page variables Page variables are a way to interact with the HTML templating. diff --git a/src/JuDoc.jl b/src/JuDoc.jl index 813584557..2ed4e0061 100644 --- a/src/JuDoc.jl +++ b/src/JuDoc.jl @@ -4,6 +4,7 @@ using JuDocTemplates using Markdown using Dates # see jd_vars +using DelimitedFiles: readdlm import LiveServer diff --git a/src/converter/lx_simple.jl b/src/converter/lx_simple.jl index 7727eeaab..838bb1346 100644 --- a/src/converter/lx_simple.jl +++ b/src/converter/lx_simple.jl @@ -68,6 +68,72 @@ function resolve_lx_figalt(lxc::LxCom)::String end +""" +$SIGNATURES + +Internal function to resolve a `\\tableinput{header}{rpath}` (finds a csv and includes it with header). +""" +function resolve_lx_tableinput(lxc::LxCom)::String + rpath = strip(content(lxc.braces[2])) + header = strip(content(lxc.braces[1])) + path = resolve_assets_rpath(rpath; canonical=false) + fdir, fext = splitext(path) + # copy-paste from resolve_lx_figalt() + # A. a path with extension --> use that + # there can be a relative path set but the user may mean + # that it's in the subfolder /output/ (if generated by code) so should look + # both in the relpath and if not found and if /output/ not already the last subdir + syspath = joinpath(PATHS[:folder], split(path, '/')...) + if isfile(syspath) + return csv2html(syspath, header) + end + # now try in the output dir just in case (provided we weren't already looking there) + p1, p2 = splitdir(fdir) + if splitdir(p1)[2] != "output" + candpath = joinpath(p1, "output", p2 * fext) + syspath = joinpath(PATHS[:folder], split(candpath, '/')...) + isfile(syspath) && return csv2html(syspath, header) + end + return html_err("table matching '$path' not found") +end + + +""" +$SIGNATURES + +Internal function to process an array of strings to markdown table (in one single string). +If header is empty, the first row of the file will be used for header. +""" +function csv2html(path, header)::String + csvcontent = readdlm(path, ',', String, header=false) + nrows, ncols = size(csvcontent) + io = IOBuffer() + # writing the header + if ! isempty(header) + # header provided + newheader = split(header, ",") + hs = size(newheader,1) + hs != ncols && return html_err("header size ($hs) and number of columns ($ncols) do not match") + write(io, prod("| " * h * " " for h in newheader)) + rowrange = 1:nrows + else + # header from csv file + write(io, prod("| " * csvcontent[1, i] * " " for i in 1:ncols)) + rowrange = 2:nrows + end + # writing end of header & header separator + write(io, "|\n|", repeat( " ----- |", ncols), "\n") + # writing content + for i in rowrange + for j in 1:ncols + write(io, "| ", csvcontent[i,j], " ") + end + write(io, "|\n") + end + return md2html(String(take!(io))) +end + + """ $SIGNATURES @@ -94,6 +160,7 @@ const LXCOM_SIMPLE = Dict{String, Function}( "\\output" => resolve_lx_output, # include plain output generated by code "\\figalt" => resolve_lx_figalt, # include a figure (may or may not have been generated) "\\file" => resolve_lx_file, # include a file + "\\tableinput" => resolve_lx_tableinput, # include table from a csv file ) diff --git a/src/jd_vars.jl b/src/jd_vars.jl index 512b21211..ab32c2240 100644 --- a/src/jd_vars.jl +++ b/src/jd_vars.jl @@ -116,6 +116,7 @@ the site. See [`resolve_lxcom`](@ref). GLOBAL_LXDEFS["\\figalt"] = LxDef("\\figalt", 2, EMPTY_SS) GLOBAL_LXDEFS["\\fig"] = LxDef("\\fig", 1, subs("\\figalt{}{#1}")) GLOBAL_LXDEFS["\\file"] = LxDef("\\file", 2, subs("[#1]()")) + GLOBAL_LXDEFS["\\tableinput"] = LxDef("\\tableinput", 2, EMPTY_SS) # text formatting GLOBAL_LXDEFS["\\underline"] = LxDef("\\underline", 1, subs("~~~!#1~~~")) diff --git a/test/converter/lx_simple.jl b/test/converter/lx_simple.jl index 388db4aaf..2e4a6b35e 100644 --- a/test/converter/lx_simple.jl +++ b/test/converter/lx_simple.jl @@ -49,3 +49,79 @@ end
View $(J.html_err("file matching '/assets/blih.pdf' not found")) here.
""") end + +@testset "table: source with header" begin + testcsv = "h1,h2,h3\nstring1, 1.567, 0\n,,\n l i n e ,.158,99999999" + write(joinpath(J.PATHS[:assets], "testcsv.csv"), testcsv) + # no header specified + h = raw""" + A table: + \tableinput{}{/assets/testcsv.csv} + Done. + """ |> seval + shouldbe = """A table:
h1 | h2 | h3 |
---|---|---|
string1 | 1.567 | 0 |
l i n e | .158 | 99999999 |
A table:
A | B | C |
---|---|---|
h1 | h2 | h3 |
string1 | 1.567 | 0 |
l i n e | .158 | 99999999 |
A table:
// header size (2) and number of columns (3) do not match //
+ Done.""" + @test isapproxstr(h, shouldbe) +end + +@testset "table: source without header" begin + testcsv = "string1, 1.567, 0\n,,\n l i n e ,.158,99999999" + write(joinpath(J.PATHS[:assets], "testcsv.csv"), testcsv) + # no header specified + h = raw""" + A table: + \tableinput{}{/assets/testcsv.csv} + Done. + """ |> seval + shouldbe = """A table:
string1 | 1.567 | 0 |
---|---|---|
l i n e | .158 | 99999999 |
A table:
A | B | C |
---|---|---|
string1 | 1.567 | 0 |
l i n e | .158 | 99999999 |
A table:
// header size (2) and number of columns (3) do not match //
+ Done.""" + @test isapproxstr(h, shouldbe) +end