fix incorrect folder name for julia-0.6.x
Former-commit-id: ef2c7401e0876f22d2f7762d182cfbcd5a7d9c70
This commit is contained in:
11
julia-0.6.3/share/julia/base/markdown/Common/Common.jl
Normal file
11
julia-0.6.3/share/julia/base/markdown/Common/Common.jl
Normal file
@@ -0,0 +1,11 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
include("block.jl")
|
||||
include("inline.jl")
|
||||
|
||||
@flavor common [list, indentcode, blockquote, admonition, footnote, hashheader, horizontalrule,
|
||||
paragraph,
|
||||
|
||||
linebreak, escapes, inline_code,
|
||||
asterisk_bold, asterisk_italic, image, footnote_link, link, autolink]
|
||||
|
||||
356
julia-0.6.3/share/julia/base/markdown/Common/block.jl
Normal file
356
julia-0.6.3/share/julia/base/markdown/Common/block.jl
Normal file
@@ -0,0 +1,356 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
# ––––––––––
|
||||
# Paragraphs
|
||||
# ––––––––––
|
||||
|
||||
mutable struct Paragraph
|
||||
content
|
||||
end
|
||||
|
||||
Paragraph() = Paragraph([])
|
||||
|
||||
function paragraph(stream::IO, md::MD)
|
||||
buffer = IOBuffer()
|
||||
p = Paragraph()
|
||||
push!(md, p)
|
||||
skipwhitespace(stream)
|
||||
prev_char = '\n'
|
||||
while !eof(stream)
|
||||
char = read(stream, Char)
|
||||
if char == '\n' || char == '\r'
|
||||
char == '\r' && !eof(stream) && Char(peek(stream)) == '\n' && read(stream, Char)
|
||||
if prev_char == '\\'
|
||||
write(buffer, '\n')
|
||||
elseif blankline(stream) || parse(stream, md, breaking = true)
|
||||
break
|
||||
else
|
||||
write(buffer, ' ')
|
||||
end
|
||||
else
|
||||
write(buffer, char)
|
||||
end
|
||||
prev_char = char
|
||||
end
|
||||
p.content = parseinline(seek(buffer, 0), md)
|
||||
return true
|
||||
end
|
||||
|
||||
# –––––––
|
||||
# Headers
|
||||
# –––––––
|
||||
|
||||
mutable struct Header{level}
|
||||
text
|
||||
end
|
||||
|
||||
Header(s, level::Int) = Header{level}(s)
|
||||
Header(s) = Header(s, 1)
|
||||
|
||||
@breaking true ->
|
||||
function hashheader(stream::IO, md::MD)
|
||||
withstream(stream) do
|
||||
eatindent(stream) || return false
|
||||
level = 0
|
||||
while startswith(stream, '#') level += 1 end
|
||||
level < 1 || level > 6 && return false
|
||||
|
||||
c = ' '
|
||||
# Allow empty headers, but require a space
|
||||
!eof(stream) && (c = read(stream, Char); !(c in " \n")) &&
|
||||
return false
|
||||
|
||||
if c != '\n' # Empty header
|
||||
h = strip(readline(stream))
|
||||
h = match(r"(.*?)( +#+)?$", h).captures[1]
|
||||
buffer = IOBuffer()
|
||||
print(buffer, h)
|
||||
push!(md.content, Header(parseinline(seek(buffer, 0), md), level))
|
||||
else
|
||||
push!(md.content, Header("", level))
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function setextheader(stream::IO, md::MD)
|
||||
withstream(stream) do
|
||||
eatindent(stream) || return false
|
||||
header = strip(readline(stream))
|
||||
isempty(header) && return false
|
||||
|
||||
eatindent(stream) || return false
|
||||
underline = strip(readline(stream))
|
||||
length(underline) < 3 && return false
|
||||
u = underline[1]
|
||||
u in "-=" || return false
|
||||
all(c -> c == u, underline) || return false
|
||||
level = (u == '=') ? 1 : 2
|
||||
|
||||
push!(md.content, Header(parseinline(header, md), level))
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
# ––––
|
||||
# Code
|
||||
# ––––
|
||||
|
||||
mutable struct Code
|
||||
language::String
|
||||
code::String
|
||||
end
|
||||
|
||||
Code(code) = Code("", code)
|
||||
|
||||
function indentcode(stream::IO, block::MD)
|
||||
withstream(stream) do
|
||||
buffer = IOBuffer()
|
||||
while !eof(stream)
|
||||
if startswith(stream, " ") || startswith(stream, "\t")
|
||||
write(buffer, readline(stream, chomp=false))
|
||||
elseif blankline(stream)
|
||||
write(buffer, '\n')
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
code = String(take!(buffer))
|
||||
!isempty(code) && (push!(block, Code(rstrip(code))); return true)
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
# --------
|
||||
# Footnote
|
||||
# --------
|
||||
|
||||
mutable struct Footnote
|
||||
id::String
|
||||
text
|
||||
end
|
||||
|
||||
function footnote(stream::IO, block::MD)
|
||||
withstream(stream) do
|
||||
regex = r"^\[\^(\w+)\]:"
|
||||
str = startswith(stream, regex)
|
||||
if isempty(str)
|
||||
return false
|
||||
else
|
||||
ref = match(regex, str).captures[1]
|
||||
buffer = IOBuffer()
|
||||
write(buffer, readline(stream, chomp=false))
|
||||
while !eof(stream)
|
||||
if startswith(stream, " ")
|
||||
write(buffer, readline(stream, chomp=false))
|
||||
elseif blankline(stream)
|
||||
write(buffer, '\n')
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
content = parse(seekstart(buffer)).content
|
||||
push!(block, Footnote(ref, content))
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# ––––––
|
||||
# Quotes
|
||||
# ––––––
|
||||
|
||||
mutable struct BlockQuote
|
||||
content
|
||||
end
|
||||
|
||||
BlockQuote() = BlockQuote([])
|
||||
|
||||
# TODO: Laziness
|
||||
@breaking true ->
|
||||
function blockquote(stream::IO, block::MD)
|
||||
withstream(stream) do
|
||||
buffer = IOBuffer()
|
||||
empty = true
|
||||
while eatindent(stream) && startswith(stream, '>')
|
||||
startswith(stream, " ")
|
||||
write(buffer, readline(stream, chomp=false))
|
||||
empty = false
|
||||
end
|
||||
empty && return false
|
||||
|
||||
md = String(take!(buffer))
|
||||
push!(block, BlockQuote(parse(md, flavor = config(block)).content))
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
# -----------
|
||||
# Admonitions
|
||||
# -----------
|
||||
|
||||
mutable struct Admonition
|
||||
category::String
|
||||
title::String
|
||||
content::Vector
|
||||
end
|
||||
|
||||
@breaking true ->
|
||||
function admonition(stream::IO, block::MD)
|
||||
withstream(stream) do
|
||||
# Admonition syntax:
|
||||
#
|
||||
# !!! category "optional explicit title within double quotes"
|
||||
# Any number of other indented markdown elements.
|
||||
#
|
||||
# This is the second paragraph.
|
||||
#
|
||||
startswith(stream, "!!! ") || return false
|
||||
# Extract the category of admonition and its title:
|
||||
category, title =
|
||||
let untitled = r"^([a-z]+)$", # !!! <CATEGORY_NAME>
|
||||
titled = r"^([a-z]+) \"(.*)\"$", # !!! <CATEGORY_NAME> "<TITLE>"
|
||||
line = strip(readline(stream))
|
||||
if ismatch(untitled, line)
|
||||
m = match(untitled, line)
|
||||
# When no title is provided we use CATEGORY_NAME, capitalising it.
|
||||
m.captures[1], ucfirst(m.captures[1])
|
||||
elseif ismatch(titled, line)
|
||||
m = match(titled, line)
|
||||
# To have a blank TITLE provide an explicit empty string as TITLE.
|
||||
m.captures[1], m.captures[2]
|
||||
else
|
||||
# Admonition header is invalid so we give up parsing here and move
|
||||
# on to the next parser.
|
||||
return false
|
||||
end
|
||||
end
|
||||
# Consume the following indented (4 spaces) block.
|
||||
buffer = IOBuffer()
|
||||
while !eof(stream)
|
||||
if startswith(stream, " ")
|
||||
write(buffer, readline(stream, chomp=false))
|
||||
elseif blankline(stream)
|
||||
write(buffer, '\n')
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
# Parse the nested block as markdown and create a new Admonition block.
|
||||
nested = parse(String(take!(buffer)), flavor = config(block))
|
||||
push!(block, Admonition(category, title, nested.content))
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
# –––––
|
||||
# Lists
|
||||
# –––––
|
||||
|
||||
mutable struct List
|
||||
items::Vector{Any}
|
||||
ordered::Int # `-1` is unordered, `>= 0` is ordered.
|
||||
|
||||
List(x::AbstractVector, b::Integer) = new(x, b)
|
||||
List(x::AbstractVector) = new(x, -1)
|
||||
List(b::Integer) = new(Any[], b)
|
||||
end
|
||||
|
||||
List(xs...) = List(vcat(xs...))
|
||||
|
||||
isordered(list::List) = list.ordered >= 0
|
||||
|
||||
const BULLETS = r"^ {0,3}(\*|\+|-)( |$)"
|
||||
const NUM_OR_BULLETS = r"^ {0,3}(\*|\+|-|\d+(\.|\)))( |$)"
|
||||
|
||||
@breaking true ->
|
||||
function list(stream::IO, block::MD)
|
||||
withstream(stream) do
|
||||
bullet = startswith(stream, NUM_OR_BULLETS; eat = false)
|
||||
indent = isempty(bullet) ? (return false) : length(bullet)
|
||||
# Calculate the starting number and regex to use for bullet matching.
|
||||
initial, regex =
|
||||
if ismatch(BULLETS, bullet)
|
||||
# An unordered list. Use `-1` to flag the list as unordered.
|
||||
-1, BULLETS
|
||||
elseif ismatch(r"^ {0,3}\d+(\.|\))( |$)", bullet)
|
||||
# An ordered list. Either with `1. ` or `1) ` style numbering.
|
||||
r = contains(bullet, ".") ? r"^ {0,3}(\d+)\.( |$)" : r"^ {0,3}(\d+)\)( |$)"
|
||||
Base.parse(Int, match(r, bullet).captures[1]), r
|
||||
else
|
||||
# Failed to match any bullets. This branch shouldn't actually be needed
|
||||
# since the `NUM_OR_BULLETS` regex should cover this, but we include it
|
||||
# simply for thoroughness.
|
||||
return false
|
||||
end
|
||||
|
||||
# Initialise the empty list object: either ordered or unordered.
|
||||
list = List(initial)
|
||||
|
||||
buffer = IOBuffer() # For capturing nested text for recursive parsing.
|
||||
newline = false # For checking if we have two consecutive newlines: end of list.
|
||||
count = 0 # Count of list items. Used to check if we need to push remaining
|
||||
# content in `buffer` after leaving the `while` loop.
|
||||
while !eof(stream)
|
||||
if startswith(stream, "\n")
|
||||
if newline
|
||||
# Double newline ends the current list.
|
||||
pushitem!(list, buffer)
|
||||
break
|
||||
else
|
||||
newline = true
|
||||
println(buffer)
|
||||
end
|
||||
else
|
||||
newline = false
|
||||
if startswith(stream, " "^indent)
|
||||
# Indented text that is part of the current list item.
|
||||
print(buffer, readline(stream, chomp=false))
|
||||
else
|
||||
matched = startswith(stream, regex)
|
||||
if isempty(matched)
|
||||
# Unindented text meaning we have left the current list.
|
||||
pushitem!(list, buffer)
|
||||
break
|
||||
else
|
||||
# Start of a new list item.
|
||||
count += 1
|
||||
count > 1 && pushitem!(list, buffer)
|
||||
print(buffer, readline(stream, chomp=false))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
count == length(list.items) || pushitem!(list, buffer)
|
||||
push!(block, list)
|
||||
return true
|
||||
end
|
||||
end
|
||||
pushitem!(list, buffer) = push!(list.items, parse(String(take!(buffer))).content)
|
||||
|
||||
# ––––––––––––––
|
||||
# HorizontalRule
|
||||
# ––––––––––––––
|
||||
|
||||
mutable struct HorizontalRule
|
||||
end
|
||||
|
||||
function horizontalrule(stream::IO, block::MD)
|
||||
withstream(stream) do
|
||||
n, rule = 0, ' '
|
||||
while !eof(stream)
|
||||
char = read(stream, Char)
|
||||
char == '\n' && break
|
||||
isspace(char) && continue
|
||||
if n==0 || char==rule
|
||||
rule = char
|
||||
n += 1
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
is_hr = (n ≥ 3 && rule in "*-")
|
||||
is_hr && push!(block, HorizontalRule())
|
||||
return is_hr
|
||||
end
|
||||
end
|
||||
175
julia-0.6.3/share/julia/base/markdown/Common/inline.jl
Normal file
175
julia-0.6.3/share/julia/base/markdown/Common/inline.jl
Normal file
@@ -0,0 +1,175 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
# ––––––––
|
||||
# Emphasis
|
||||
# ––––––––
|
||||
|
||||
mutable struct Italic
|
||||
text
|
||||
end
|
||||
|
||||
@trigger '*' ->
|
||||
function asterisk_italic(stream::IO, md::MD)
|
||||
result = parse_inline_wrapper(stream, "*")
|
||||
return result === nothing ? nothing : Italic(parseinline(result, md))
|
||||
end
|
||||
|
||||
mutable struct Bold
|
||||
text
|
||||
end
|
||||
|
||||
@trigger '*' ->
|
||||
function asterisk_bold(stream::IO, md::MD)
|
||||
result = parse_inline_wrapper(stream, "**")
|
||||
return result === nothing ? nothing : Bold(parseinline(result, md))
|
||||
end
|
||||
|
||||
# ––––
|
||||
# Code
|
||||
# ––––
|
||||
|
||||
@trigger '`' ->
|
||||
function inline_code(stream::IO, md::MD)
|
||||
withstream(stream) do
|
||||
ticks = startswith(stream, r"^(`+)")
|
||||
result = readuntil(stream, ticks)
|
||||
if result === nothing
|
||||
nothing
|
||||
else
|
||||
result = strip(result)
|
||||
# An odd number of backticks wrapping the text will produce a `Code` node, while
|
||||
# an even number will result in a `LaTeX` node. This allows for arbitary
|
||||
# backtick combinations to be embedded inside the resulting node, i.e.
|
||||
#
|
||||
# `a`, ``a``, `` `a` ``, ``` ``a`` ```, ``` `a` ```, etc.
|
||||
# ^ ^ ^ ^ ^
|
||||
# C L L C C with C=Code and L=LaTeX.
|
||||
#
|
||||
isodd(length(ticks)) ? Code(result) : LaTeX(result)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# ––––––––––––––
|
||||
# Images & Links
|
||||
# ––––––––––––––
|
||||
|
||||
mutable struct Image
|
||||
url::String
|
||||
alt::String
|
||||
end
|
||||
|
||||
@trigger '!' ->
|
||||
function image(stream::IO, md::MD)
|
||||
withstream(stream) do
|
||||
startswith(stream, "![") || return
|
||||
alt = readuntil(stream, ']', match = '[')
|
||||
alt ≡ nothing && return
|
||||
skipwhitespace(stream)
|
||||
startswith(stream, '(') || return
|
||||
url = readuntil(stream, ')', match = '(')
|
||||
url ≡ nothing && return
|
||||
return Image(url, alt)
|
||||
end
|
||||
end
|
||||
|
||||
mutable struct Link
|
||||
text
|
||||
url::String
|
||||
end
|
||||
|
||||
@trigger '[' ->
|
||||
function link(stream::IO, md::MD)
|
||||
withstream(stream) do
|
||||
startswith(stream, '[') || return
|
||||
text = readuntil(stream, ']', match = '[')
|
||||
text ≡ nothing && return
|
||||
skipwhitespace(stream)
|
||||
startswith(stream, '(') || return
|
||||
url = readuntil(stream, ')', match = '(')
|
||||
url ≡ nothing && return
|
||||
return Link(parseinline(text, md), url)
|
||||
end
|
||||
end
|
||||
|
||||
@trigger '[' ->
|
||||
function footnote_link(stream::IO, md::MD)
|
||||
withstream(stream) do
|
||||
regex = r"^\[\^(\w+)\]"
|
||||
str = startswith(stream, regex)
|
||||
if isempty(str)
|
||||
return
|
||||
else
|
||||
ref = match(regex, str).captures[1]
|
||||
return Footnote(ref, nothing)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@trigger '<' ->
|
||||
function autolink(stream::IO, md::MD)
|
||||
withstream(stream) do
|
||||
startswith(stream, '<') || return
|
||||
url = readuntil(stream, '>')
|
||||
url ≡ nothing && return
|
||||
_is_link(url) && return Link(url, url)
|
||||
_is_mailto(url) && return Link(url, url)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
# This list is taken from the commonmark spec
|
||||
# http://spec.commonmark.org/0.19/#absolute-uri
|
||||
const _allowable_schemes = Set(split("coap doi javascript aaa aaas about acap cap cid crid data dav dict dns file ftp geo go gopher h323 http https iax icap im imap info ipp iris iris.beep iris.xpc iris.xpcs iris.lwz ldap mailto mid msrp msrps mtqp mupdate news nfs ni nih nntp opaquelocktoken pop pres rtsp service session shttp sieve sip sips sms snmp,soap.beep soap.beeps tag tel telnet tftp thismessage tn3270 tip tv urn vemmi ws wss xcon xcon-userid xmlrpc.beep xmlrpc.beeps xmpp z39.50r z39.50s
|
||||
adiumxtra afp afs aim apt,attachment aw beshare bitcoin bolo callto chrome,chrome-extension com-eventbrite-attendee content cvs,dlna-playsingle dlna-playcontainer dtn dvb ed2k facetime feed finger fish gg git gizmoproject gtalk hcp icon ipn irc irc6 ircs itms jar jms keyparc lastfm ldaps magnet maps market,message mms ms-help msnim mumble mvn notes oid palm paparazzi platform proxy psyc query res resource rmi rsync rtmp secondlife sftp sgn skype smb soldat spotify ssh steam svn teamspeak
|
||||
things udp unreal ut2004 ventrilo view-source webcal wtai wyciwyg xfire xri ymsgr"))
|
||||
|
||||
function _is_link(s::AbstractString)
|
||||
'<' in s && return false
|
||||
|
||||
m = match(r"^(.*)://(\S+?)(:\S*)?$", s)
|
||||
m ≡ nothing && return false
|
||||
scheme = lowercase(m.captures[1])
|
||||
return scheme in _allowable_schemes
|
||||
end
|
||||
|
||||
# non-normative regex from the HTML5 spec
|
||||
const _email_regex = r"^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$"
|
||||
|
||||
function _is_mailto(s::AbstractString)
|
||||
length(s) < 6 && return false
|
||||
# slicing strings is a bit risky, but this equality check is safe
|
||||
lowercase(s[1:6]) == "mailto:" || return false
|
||||
return ismatch(_email_regex, s[6:end])
|
||||
end
|
||||
|
||||
# –––––––––––
|
||||
# Punctuation
|
||||
# –––––––––––
|
||||
|
||||
mutable struct LineBreak end
|
||||
|
||||
@trigger '\\' ->
|
||||
function linebreak(stream::IO, md::MD)
|
||||
if startswith(stream, "\\\n")
|
||||
return LineBreak()
|
||||
end
|
||||
end
|
||||
|
||||
@trigger '-' ->
|
||||
function en_dash(stream::IO, md::MD)
|
||||
if startswith(stream, "--")
|
||||
return "–"
|
||||
end
|
||||
end
|
||||
|
||||
const escape_chars = "\\`*_#+-.!{}[]()\$"
|
||||
|
||||
@trigger '\\' ->
|
||||
function escapes(stream::IO, md::MD)
|
||||
withstream(stream) do
|
||||
if startswith(stream, "\\") && !eof(stream) && (c = read(stream, Char)) in escape_chars
|
||||
return string(c)
|
||||
end
|
||||
end
|
||||
end
|
||||
66
julia-0.6.3/share/julia/base/markdown/GitHub/GitHub.jl
Normal file
66
julia-0.6.3/share/julia/base/markdown/GitHub/GitHub.jl
Normal file
@@ -0,0 +1,66 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
include("table.jl")
|
||||
|
||||
@breaking true ->
|
||||
function fencedcode(stream::IO, block::MD)
|
||||
withstream(stream) do
|
||||
startswith(stream, "~~~", padding = true) || startswith(stream, "```", padding = true) || return false
|
||||
skip(stream, -1)
|
||||
ch = read(stream, Char)
|
||||
trailing = strip(readline(stream))
|
||||
flavor = lstrip(trailing, ch)
|
||||
n = 3 + length(trailing) - length(flavor)
|
||||
|
||||
# inline code block
|
||||
ch in flavor && return false
|
||||
|
||||
buffer = IOBuffer()
|
||||
while !eof(stream)
|
||||
line_start = position(stream)
|
||||
if startswith(stream, string(ch) ^ n)
|
||||
if !startswith(stream, string(ch))
|
||||
if flavor == "math"
|
||||
push!(block, LaTeX(String(take!(buffer)) |> chomp))
|
||||
else
|
||||
push!(block, Code(flavor, String(take!(buffer)) |> chomp))
|
||||
end
|
||||
return true
|
||||
else
|
||||
seek(stream, line_start)
|
||||
end
|
||||
end
|
||||
write(buffer, readline(stream, chomp=false))
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function github_paragraph(stream::IO, md::MD)
|
||||
skipwhitespace(stream)
|
||||
buffer = IOBuffer()
|
||||
p = Paragraph()
|
||||
push!(md, p)
|
||||
while !eof(stream)
|
||||
char = read(stream, Char)
|
||||
if char == '\n'
|
||||
eof(stream) && break
|
||||
if blankline(stream) || parse(stream, md, breaking = true)
|
||||
break
|
||||
else
|
||||
write(buffer, '\n')
|
||||
end
|
||||
else
|
||||
write(buffer, char)
|
||||
end
|
||||
end
|
||||
p.content = parseinline(seek(buffer, 0), md)
|
||||
return true
|
||||
end
|
||||
|
||||
@flavor github [list, indentcode, blockquote, admonition, footnote, fencedcode, hashheader,
|
||||
github_table, github_paragraph,
|
||||
|
||||
linebreak, escapes, en_dash, inline_code, asterisk_bold,
|
||||
asterisk_italic, image, footnote_link, link, autolink]
|
||||
|
||||
168
julia-0.6.3/share/julia/base/markdown/GitHub/table.jl
Normal file
168
julia-0.6.3/share/julia/base/markdown/GitHub/table.jl
Normal file
@@ -0,0 +1,168 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
mutable struct Table
|
||||
rows::Vector{Vector{Any}}
|
||||
align::Vector{Symbol}
|
||||
end
|
||||
|
||||
function parserow(stream::IO)
|
||||
withstream(stream) do
|
||||
line = readline(stream)
|
||||
row = split(line, r"(?<!\\)\|")
|
||||
length(row) == 1 && return
|
||||
isempty(row[1]) && shift!(row)
|
||||
map!(x -> strip(replace(x, "\\|", "|")), row, row)
|
||||
isempty(row[end]) && pop!(row)
|
||||
return row
|
||||
end
|
||||
end
|
||||
|
||||
function rowlength!(row, len)
|
||||
while length(row) < len push!(row, "") end
|
||||
while length(row) > len pop!(row) end
|
||||
return row
|
||||
end
|
||||
|
||||
const default_align = :r
|
||||
|
||||
function parsealign(row)
|
||||
align = Symbol[]
|
||||
for s in row
|
||||
(length(s) ≥ 3 && s ⊆ Set("-:")) || return
|
||||
push!(align,
|
||||
s[1] == ':' ? (s[end] == ':' ? :c : :l) :
|
||||
s[end] == ':' ? :r :
|
||||
default_align)
|
||||
end
|
||||
return align
|
||||
end
|
||||
|
||||
function github_table(stream::IO, md::MD)
|
||||
withstream(stream) do
|
||||
skipblank(stream)
|
||||
rows = []
|
||||
cols = 0
|
||||
align = nothing
|
||||
while (row = parserow(stream)) !== nothing
|
||||
if length(rows) == 0
|
||||
isempty(row[1]) && return false
|
||||
cols = length(row)
|
||||
end
|
||||
if align === nothing && length(rows) == 1 # Must have a --- row
|
||||
align = parsealign(row)
|
||||
(align === nothing || length(align) != cols) && return false
|
||||
else
|
||||
push!(rows, map(x -> parseinline(x, md), rowlength!(row, cols)))
|
||||
end
|
||||
end
|
||||
length(rows) <= 1 && return false
|
||||
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]
|
||||
withtag(io, i == 1 ? :th : :td) do
|
||||
htmlinline(io, c)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
mapmap(f, xss) = map(xs->map(f, xs), xss)
|
||||
|
||||
colwidths(rows; len = length, min = 0) =
|
||||
reduce((x,y) -> max.(x,y), [min; convert(Vector{Vector{Int}}, mapmap(len, rows))])
|
||||
|
||||
padding(width, twidth, a) =
|
||||
a == :l ? (0, twidth - width) :
|
||||
a == :r ? (twidth - width, 0) :
|
||||
a == :c ? (floor(Int, (twidth-width)/2), ceil(Int, (twidth-width)/2)) :
|
||||
error("Invalid alignment $a")
|
||||
|
||||
function padcells!(rows, align; len = length, min = 0)
|
||||
widths = colwidths(rows, len = len, min = min)
|
||||
for i = 1:length(rows), j = indices(rows[1],1)
|
||||
cell = rows[i][j]
|
||||
lpad, rpad = padding(len(cell), widths[j], align[j])
|
||||
rows[i][j] = " "^lpad * cell * " "^rpad
|
||||
end
|
||||
return rows
|
||||
end
|
||||
|
||||
_dash(width, align) =
|
||||
align == :l ? ":" * "-"^width * " " :
|
||||
align == :r ? " " * "-"^width * ":" :
|
||||
align == :c ? ":" * "-"^width * ":" :
|
||||
throw(ArgumentError("Invalid alignment $align"))
|
||||
|
||||
function plain(io::IO, md::Table)
|
||||
cells = mapmap(md.rows) do each
|
||||
replace(plaininline(each), "|", "\\|")
|
||||
end
|
||||
padcells!(cells, md.align, len = length, min = 3)
|
||||
for i = indices(cells,1)
|
||||
print(io, "| ")
|
||||
join(io, cells[i], " | ")
|
||||
println(io, " |")
|
||||
if i == 1
|
||||
print(io, "|")
|
||||
join(io, [_dash(length(cells[i][j]), md.align[j]) for j = indices(cells[1],1)], "|")
|
||||
println(io, "|")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function rst(io::IO, md::Table)
|
||||
cells = mapmap(rstinline, md.rows)
|
||||
padcells!(cells, md.align, len = length, min = 3)
|
||||
single = ["-"^length(c) for c in cells[1]]
|
||||
double = ["="^length(c) for c in cells[1]]
|
||||
function print_row(row, row_sep, col_sep)
|
||||
print(io, col_sep, row_sep)
|
||||
join(io, row, string(row_sep, col_sep, row_sep))
|
||||
println(io, row_sep, col_sep)
|
||||
end
|
||||
print_row(single, '-', '+')
|
||||
for i = 1:length(cells)
|
||||
print_row(cells[i], ' ', '|')
|
||||
i ≡ 1 ? print_row(double, '=', '+') :
|
||||
print_row(single, '-', '+')
|
||||
end
|
||||
end
|
||||
|
||||
function term(io::IO, md::Table, columns)
|
||||
cells = mapmap(terminline, md.rows)
|
||||
padcells!(cells, md.align, len = ansi_length)
|
||||
for i = 1:length(cells)
|
||||
join(io, cells[i], " ")
|
||||
println(io)
|
||||
if i == 1
|
||||
join(io, ["–"^ansi_length(cells[i][j]) for j = 1:length(cells[1])], " ")
|
||||
println(io)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function latex(io::IO, md::Table)
|
||||
wrapblock(io, "tabular") do
|
||||
align = md.align
|
||||
println(io, "{$(join(align, " | "))}")
|
||||
for (i, row) in enumerate(md.rows)
|
||||
for (j, cell) in enumerate(row)
|
||||
j != 1 && print(io, " & ")
|
||||
latexinline(io, cell)
|
||||
end
|
||||
println(io, " \\\\")
|
||||
if i == 1
|
||||
println("\\hline")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
35
julia-0.6.3/share/julia/base/markdown/IPython/IPython.jl
Normal file
35
julia-0.6.3/share/julia/base/markdown/IPython/IPython.jl
Normal file
@@ -0,0 +1,35 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
mutable struct LaTeX
|
||||
formula::String
|
||||
end
|
||||
|
||||
@trigger '$' ->
|
||||
function tex(stream::IO, md::MD)
|
||||
result = parse_inline_wrapper(stream, "\$", rep = true)
|
||||
return result === nothing ? nothing : LaTeX(result)
|
||||
end
|
||||
|
||||
function blocktex(stream::IO, md::MD)
|
||||
withstream(stream) do
|
||||
ex = tex(stream, md)
|
||||
if ex ≡ nothing
|
||||
return false
|
||||
else
|
||||
push!(md, ex)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
show(io::IO, tex::LaTeX) =
|
||||
print(io, '$', tex.formula, '$')
|
||||
|
||||
latex(io::IO, tex::LaTeX) =
|
||||
println(io, "\$\$", tex.formula, "\$\$")
|
||||
|
||||
latexinline(io::IO, tex::LaTeX) =
|
||||
print(io, '$', tex.formula, '$')
|
||||
|
||||
term(io::IO, tex::LaTeX, cols) = println_with_format(:magenta, io, tex.formula)
|
||||
terminline(io::IO, tex::LaTeX) = print_with_format(:magenta, io, tex.formula)
|
||||
15
julia-0.6.3/share/julia/base/markdown/Julia/Julia.jl
Normal file
15
julia-0.6.3/share/julia/base/markdown/Julia/Julia.jl
Normal file
@@ -0,0 +1,15 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
# This file contains markdown extensions designed to make documenting
|
||||
# Julia easy peasy.
|
||||
#
|
||||
# We start by borrowing GitHub's `fencedcode` extension – more to follow.
|
||||
|
||||
include("interp.jl")
|
||||
|
||||
@flavor julia [blocktex, blockinterp, hashheader, list, indentcode, fencedcode,
|
||||
blockquote, admonition, footnote, github_table, horizontalrule, setextheader, paragraph,
|
||||
|
||||
linebreak, escapes, tex, interp, en_dash, inline_code,
|
||||
asterisk_bold, asterisk_italic, image, footnote_link, link, autolink]
|
||||
|
||||
48
julia-0.6.3/share/julia/base/markdown/Julia/interp.jl
Normal file
48
julia-0.6.3/share/julia/base/markdown/Julia/interp.jl
Normal file
@@ -0,0 +1,48 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
function Base.parse(stream::IO; greedy::Bool = true, raise::Bool = true)
|
||||
pos = position(stream)
|
||||
ex, Δ = Base.parse(readstring(stream), 1, greedy = greedy, raise = raise)
|
||||
seek(stream, pos + Δ - 1)
|
||||
return ex
|
||||
end
|
||||
|
||||
function interpinner(stream::IO, greedy = false)
|
||||
startswith(stream, '$') || return
|
||||
(eof(stream) || Char(peek(stream)) in whitespace) && return
|
||||
try
|
||||
return Base.parse(stream::IOBuffer, greedy = greedy)
|
||||
catch e
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
@trigger '$' ->
|
||||
function interp(stream::IO, md::MD)
|
||||
withstream(stream) do
|
||||
ex = interpinner(stream)
|
||||
return ex
|
||||
end
|
||||
end
|
||||
|
||||
function blockinterp(stream::IO, md::MD)
|
||||
withstream(stream) do
|
||||
ex = interpinner(stream)
|
||||
if ex ≡ nothing
|
||||
return false
|
||||
else
|
||||
push!(md, ex)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
toexpr(x) = x
|
||||
|
||||
toexpr(xs::Vector{Any}) = Expr(:call, GlobalRef(Base,:vector_any), map(toexpr, xs)...)
|
||||
|
||||
for T in Any[MD, Paragraph, Header, Link, Bold, Italic]
|
||||
@eval function toexpr(md::$T)
|
||||
Expr(:call, typeof(md), $(map(x->:(toexpr(md.$x)), fieldnames(Base.unwrap_unionall(T)))...))
|
||||
end
|
||||
end
|
||||
67
julia-0.6.3/share/julia/base/markdown/Markdown.jl
Normal file
67
julia-0.6.3/share/julia/base/markdown/Markdown.jl
Normal file
@@ -0,0 +1,67 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
module Markdown
|
||||
|
||||
import Base: show, ==
|
||||
import Core: @doc_str
|
||||
|
||||
include(joinpath("parse", "config.jl"))
|
||||
include(joinpath("parse", "util.jl"))
|
||||
include(joinpath("parse", "parse.jl"))
|
||||
|
||||
include(joinpath("Common", "Common.jl"))
|
||||
include(joinpath("GitHub", "GitHub.jl"))
|
||||
include(joinpath("IPython", "IPython.jl"))
|
||||
include(joinpath("Julia", "Julia.jl"))
|
||||
|
||||
include(joinpath("render", "plain.jl"))
|
||||
include(joinpath("render", "html.jl"))
|
||||
include(joinpath("render", "latex.jl"))
|
||||
include(joinpath("render", "rst.jl"))
|
||||
|
||||
include(joinpath("render", "terminal", "render.jl"))
|
||||
|
||||
export readme, license, @md_str, @doc_str
|
||||
|
||||
parse(markdown::AbstractString; flavor = julia) = parse(IOBuffer(markdown), flavor = flavor)
|
||||
parse_file(file::AbstractString; flavor = julia) = parse(readstring(file), flavor = flavor)
|
||||
|
||||
readme(pkg::AbstractString; flavor = github) = parse_file(Pkg.dir(pkg, "README.md"), flavor = flavor)
|
||||
readme(pkg::Module; flavor = github) = readme(string(pkg), flavor = flavor)
|
||||
|
||||
license(pkg::AbstractString; flavor = github) = parse_file(Pkg.dir(pkg, "LICENSE.md"), flavor = flavor)
|
||||
license(pkg::Module; flavor = github) = license(string(pkg), flavor = flavor)
|
||||
|
||||
function mdexpr(s, flavor = :julia)
|
||||
md = parse(s, flavor = Symbol(flavor))
|
||||
esc(toexpr(md))
|
||||
end
|
||||
|
||||
function docexpr(s, flavor = :julia)
|
||||
quote
|
||||
let md = $(mdexpr(s, flavor))
|
||||
md.meta[:path] = @__FILE__
|
||||
md.meta[:module] = current_module()
|
||||
md
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
macro md_str(s, t...)
|
||||
mdexpr(s, t...)
|
||||
end
|
||||
|
||||
doc_str(md, file, mod) = (md.meta[:path] = file; md.meta[:module] = mod; md)
|
||||
doc_str(md::AbstractString, file, mod) = doc_str(parse(md), file, mod)
|
||||
|
||||
macro doc_str(s::AbstractString, t...)
|
||||
:($(doc_str)($(mdexpr(s, t...)), $(Base).@__FILE__, $(current_module)()))
|
||||
end
|
||||
|
||||
function Base.display(d::Base.REPL.REPLDisplay, md::Vector{MD})
|
||||
for md in md
|
||||
display(d, md)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
82
julia-0.6.3/share/julia/base/markdown/parse/config.jl
Normal file
82
julia-0.6.3/share/julia/base/markdown/parse/config.jl
Normal file
@@ -0,0 +1,82 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
const InnerConfig = Dict{Char, Vector{Function}}
|
||||
|
||||
mutable struct Config
|
||||
breaking::Vector{Function}
|
||||
regular::Vector{Function}
|
||||
inner::InnerConfig
|
||||
end
|
||||
|
||||
Config() = Config(Function[], Function[], InnerConfig())
|
||||
|
||||
const META = Dict{Function, Dict{Symbol, Any}}()
|
||||
|
||||
getset(coll, key, default) = coll[key] = get(coll, key, default)
|
||||
|
||||
meta(f) = getset(META, f, Dict{Symbol, Any}())
|
||||
|
||||
breaking!(f) = meta(f)[:breaking] = true
|
||||
breaking(f) = get(meta(f), :breaking, false)
|
||||
|
||||
triggers!(f, ts) = meta(f)[:triggers] = Set{Char}(ts)
|
||||
triggers(f) = get(meta(f), :triggers, Set{Char}())
|
||||
|
||||
# Macros
|
||||
|
||||
isexpr(x::Expr, ts...) = x.head in ts
|
||||
isexpr(x::T, ts...) where {T} = T in ts
|
||||
|
||||
macro breaking(ex)
|
||||
isexpr(ex, :->) || error("invalid @breaking form, use ->")
|
||||
b, def = ex.args
|
||||
if b
|
||||
quote
|
||||
f = $(esc(def))
|
||||
breaking!(f)
|
||||
f
|
||||
end
|
||||
else
|
||||
esc(def)
|
||||
end
|
||||
end
|
||||
|
||||
macro trigger(ex)
|
||||
isexpr(ex, :->) || error("invalid @triggers form, use ->")
|
||||
ts, def = ex.args
|
||||
quote
|
||||
f = $(esc(def))
|
||||
triggers!(f, $ts)
|
||||
f
|
||||
end
|
||||
end
|
||||
|
||||
# Construction
|
||||
|
||||
function config(parsers::Function...)
|
||||
c = Config()
|
||||
for parser in parsers
|
||||
ts = triggers(parser)
|
||||
if breaking(parser)
|
||||
push!(c.breaking, parser)
|
||||
elseif !isempty(ts)
|
||||
for t in ts
|
||||
push!(getset(c.inner, t, Function[]), parser)
|
||||
end
|
||||
else
|
||||
push!(c.regular, parser)
|
||||
end
|
||||
end
|
||||
return c
|
||||
end
|
||||
|
||||
# Flavour definitions
|
||||
|
||||
const flavors = Dict{Symbol, Config}()
|
||||
|
||||
macro flavor(name, features)
|
||||
quote
|
||||
const $(esc(name)) = config($(map(esc,features.args)...))
|
||||
flavors[$(Expr(:quote, name))] = $(esc(name))
|
||||
end
|
||||
end
|
||||
96
julia-0.6.3/share/julia/base/markdown/parse/parse.jl
Normal file
96
julia-0.6.3/share/julia/base/markdown/parse/parse.jl
Normal file
@@ -0,0 +1,96 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
mutable struct MD
|
||||
content::Vector{Any}
|
||||
meta::Dict{Any, Any}
|
||||
|
||||
MD(content::AbstractVector, meta::Dict = Dict()) =
|
||||
new(content, meta)
|
||||
end
|
||||
|
||||
MD(xs...) = MD(vcat(xs...))
|
||||
|
||||
function MD(cfg::Config, xs...)
|
||||
md = MD(xs...)
|
||||
md.meta[:config] = cfg
|
||||
return md
|
||||
end
|
||||
|
||||
config(md::MD) = md.meta[:config]::Config
|
||||
|
||||
# Forward some array methods
|
||||
|
||||
Base.push!(md::MD, x) = push!(md.content, x)
|
||||
Base.getindex(md::MD, args...) = md.content[args...]
|
||||
Base.setindex!(md::MD, args...) = setindex!(md.content, args...)
|
||||
Base.endof(md::MD) = endof(md.content)
|
||||
Base.length(md::MD) = length(md.content)
|
||||
Base.isempty(md::MD) = isempty(md.content)
|
||||
|
||||
==(a::MD, b::MD) = (html(a) == html(b))
|
||||
|
||||
# Parser functions:
|
||||
# md – should be modified appropriately
|
||||
# return – basically, true if parse was successful
|
||||
# false uses the next parser in the queue, true
|
||||
# goes back to the beginning
|
||||
#
|
||||
# Inner parsers:
|
||||
# return – element to use or nothing
|
||||
|
||||
# Inner parsing
|
||||
|
||||
function parseinline(stream::IO, md::MD, parsers::Vector{Function})
|
||||
for parser in parsers
|
||||
inner = parser(stream, md)
|
||||
inner ≡ nothing || return inner
|
||||
end
|
||||
end
|
||||
|
||||
function parseinline(stream::IO, md::MD, config::Config)
|
||||
content = []
|
||||
buffer = IOBuffer()
|
||||
while !eof(stream)
|
||||
# FIXME: this is broken if we're looking for non-ASCII
|
||||
# characters because peek only returns a single byte.
|
||||
char = Char(peek(stream))
|
||||
if haskey(config.inner, char) &&
|
||||
(inner = parseinline(stream, md, config.inner[char])) !== nothing
|
||||
c = String(take!(buffer))
|
||||
!isempty(c) && push!(content, c)
|
||||
buffer = IOBuffer()
|
||||
push!(content, inner)
|
||||
else
|
||||
write(buffer, read(stream, Char))
|
||||
end
|
||||
end
|
||||
c = String(take!(buffer))
|
||||
!isempty(c) && push!(content, c)
|
||||
return content
|
||||
end
|
||||
|
||||
parseinline(s::AbstractString, md::MD, c::Config) =
|
||||
parseinline(IOBuffer(s), md, c)
|
||||
|
||||
parseinline(s, md::MD) = parseinline(s, md, config(md))
|
||||
|
||||
# Block parsing
|
||||
|
||||
function parse(stream::IO, block::MD, config::Config; breaking = false)
|
||||
skipblank(stream)
|
||||
eof(stream) && return false
|
||||
for parser in (breaking ? config.breaking : [config.breaking; config.regular])
|
||||
parser(stream, block) && return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
parse(stream::IO, block::MD; breaking = false) =
|
||||
parse(stream, block, config(block), breaking = breaking)
|
||||
|
||||
function parse(stream::IO; flavor = julia)
|
||||
isa(flavor, Symbol) && (flavor = flavors[flavor])
|
||||
markdown = MD(flavor)
|
||||
while parse(stream, markdown, flavor) end
|
||||
return markdown
|
||||
end
|
||||
206
julia-0.6.3/share/julia/base/markdown/parse/util.jl
Normal file
206
julia-0.6.3/share/julia/base/markdown/parse/util.jl
Normal file
@@ -0,0 +1,206 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
import Base: peek
|
||||
|
||||
macro dotimes(n, body)
|
||||
quote
|
||||
for i = 1:$(esc(n))
|
||||
$(esc(body))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
const whitespace = " \t\r"
|
||||
|
||||
"""
|
||||
Skip any leading whitespace. Returns io.
|
||||
"""
|
||||
function skipwhitespace(io::IO; newlines = true)
|
||||
while !eof(io) && (Char(peek(io)) in whitespace || (newlines && peek(io) == UInt8('\n')))
|
||||
read(io, Char)
|
||||
end
|
||||
return io
|
||||
end
|
||||
|
||||
"""
|
||||
Skip any leading blank lines. Returns the number skipped.
|
||||
"""
|
||||
function skipblank(io::IO)
|
||||
start = position(io)
|
||||
i = 0
|
||||
while !eof(io)
|
||||
c = read(io, Char)
|
||||
c == '\n' && (start = position(io); i+=1; continue)
|
||||
c == '\r' && (start = position(io); i+=1; continue)
|
||||
c in whitespace || break
|
||||
end
|
||||
seek(io, start)
|
||||
return i
|
||||
end
|
||||
|
||||
"""
|
||||
Returns true if the line contains only (and, unless allowempty,
|
||||
at least one of) the characters given.
|
||||
"""
|
||||
function linecontains(io::IO, chars; allow_whitespace = true,
|
||||
eat = true,
|
||||
allowempty = false)
|
||||
start = position(io)
|
||||
l = readline(io)
|
||||
length(l) == 0 && return allowempty
|
||||
|
||||
result = allowempty
|
||||
for c in l
|
||||
c in whitespace && (allow_whitespace ? continue : (result = false; break))
|
||||
c in chars && (result = true; continue)
|
||||
result = false; break
|
||||
end
|
||||
!(result && eat) && seek(io, start)
|
||||
return result
|
||||
end
|
||||
|
||||
blankline(io::IO; eat = true) =
|
||||
linecontains(io, "",
|
||||
allow_whitespace = true,
|
||||
allowempty = true,
|
||||
eat = eat)
|
||||
|
||||
"""
|
||||
Test if the stream starts with the given string.
|
||||
`eat` specifies whether to advance on success (true by default).
|
||||
`padding` specifies whether leading whitespace should be ignored.
|
||||
"""
|
||||
function startswith(stream::IO, s::AbstractString; eat = true, padding = false, newlines = true)
|
||||
start = position(stream)
|
||||
padding && skipwhitespace(stream, newlines = newlines)
|
||||
result = true
|
||||
for char in s
|
||||
!eof(stream) && read(stream, Char) == char ||
|
||||
(result = false; break)
|
||||
end
|
||||
!(result && eat) && seek(stream, start)
|
||||
return result
|
||||
end
|
||||
|
||||
function startswith(stream::IO, c::Char; eat = true)
|
||||
if !eof(stream) && peek(stream) == UInt8(c)
|
||||
eat && read(stream, Char)
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function startswith(stream::IO, ss::Vector{<:AbstractString}; kws...)
|
||||
any(s->startswith(stream, s; kws...), ss)
|
||||
end
|
||||
|
||||
function startswith(stream::IO, r::Regex; eat = true, padding = false)
|
||||
@assert Base.startswith(r.pattern, "^")
|
||||
start = position(stream)
|
||||
padding && skipwhitespace(stream)
|
||||
line = readline(stream)
|
||||
seek(stream, start)
|
||||
m = match(r, line)
|
||||
m === nothing && return ""
|
||||
eat && @dotimes length(m.match) read(stream, Char)
|
||||
return m.match
|
||||
end
|
||||
|
||||
"""
|
||||
Executes the block of code, and if the return value is `nothing`,
|
||||
returns the stream to its initial position.
|
||||
"""
|
||||
function withstream(f, stream)
|
||||
pos = position(stream)
|
||||
result = f()
|
||||
(result ≡ nothing || result ≡ false) && seek(stream, pos)
|
||||
return result
|
||||
end
|
||||
|
||||
"""
|
||||
Consume the standard allowed markdown indent of
|
||||
three spaces. Returns false if there are more than
|
||||
three present.
|
||||
"""
|
||||
function eatindent(io::IO, n = 3)
|
||||
withstream(io) do
|
||||
m = 0
|
||||
while startswith(io, ' ') m += 1 end
|
||||
return m <= n
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
Read the stream until startswith(stream, delim)
|
||||
The delimiter is consumed but not included.
|
||||
Returns nothing and resets the stream if delim is
|
||||
not found.
|
||||
"""
|
||||
function readuntil(stream::IO, delimiter; newlines = false, match = nothing)
|
||||
withstream(stream) do
|
||||
buffer = IOBuffer()
|
||||
count = 0
|
||||
while !eof(stream)
|
||||
if startswith(stream, delimiter)
|
||||
if count == 0
|
||||
return String(take!(buffer))
|
||||
else
|
||||
count -= 1
|
||||
write(buffer, delimiter)
|
||||
continue
|
||||
end
|
||||
end
|
||||
char = read(stream, Char)
|
||||
char == match && (count += 1)
|
||||
!newlines && char == '\n' && break
|
||||
write(buffer, char)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: refactor this. If we're going to assume
|
||||
# the delimiter is a single character + a minimum
|
||||
# repeat we may as well just pass that into the
|
||||
# function.
|
||||
|
||||
"""
|
||||
Parse a symmetrical delimiter which wraps words.
|
||||
i.e. `*word word*` but not `*word * word`.
|
||||
`repeat` specifies whether the delimiter can be repeated.
|
||||
Escaped delimiters are not yet supported.
|
||||
"""
|
||||
function parse_inline_wrapper(stream::IO, delimiter::AbstractString; rep = false)
|
||||
delimiter, nmin = string(delimiter[1]), length(delimiter)
|
||||
withstream(stream) do
|
||||
if position(stream) >= 1
|
||||
# check the previous byte isn't a delimiter
|
||||
skip(stream, -1)
|
||||
(read(stream, Char) in delimiter) && return nothing
|
||||
end
|
||||
n = nmin
|
||||
startswith(stream, delimiter^n) || return nothing
|
||||
while startswith(stream, delimiter); n += 1; end
|
||||
!rep && n > nmin && return nothing
|
||||
!eof(stream) && Char(peek(stream)) in whitespace && return nothing
|
||||
|
||||
buffer = IOBuffer()
|
||||
while !eof(stream)
|
||||
char = read(stream, Char)
|
||||
write(buffer, char)
|
||||
if !(char in whitespace || char == '\n' || char in delimiter) && startswith(stream, delimiter^n)
|
||||
trailing = 0
|
||||
while startswith(stream, delimiter); trailing += 1; end
|
||||
trailing == 0 && return String(take!(buffer))
|
||||
write(buffer, delimiter ^ (n + trailing))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function showrest(io::IO)
|
||||
start = position(io)
|
||||
show(readstring(io))
|
||||
println()
|
||||
seek(io, start)
|
||||
end
|
||||
191
julia-0.6.3/share/julia/base/markdown/render/html.jl
Normal file
191
julia-0.6.3/share/julia/base/markdown/render/html.jl
Normal file
@@ -0,0 +1,191 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
include("rich.jl")
|
||||
|
||||
# Utils
|
||||
|
||||
function withtag(f, io::IO, tag, attrs...)
|
||||
print(io, "<$tag")
|
||||
for (attr, value) in attrs
|
||||
print(io, " ")
|
||||
htmlesc(io, attr)
|
||||
print(io, "=\"")
|
||||
htmlesc(io, value)
|
||||
print(io, "\"")
|
||||
end
|
||||
f === nothing && return print(io, " />")
|
||||
|
||||
print(io, ">")
|
||||
f()
|
||||
print(io, "</$tag>")
|
||||
end
|
||||
|
||||
tag(io::IO, tag, attrs...) = withtag(nothing, io, tag, attrs...)
|
||||
|
||||
const _htmlescape_chars = Dict('<'=>"<", '>'=>">",
|
||||
'"'=>""", '&'=>"&",
|
||||
# ' '=>" ",
|
||||
)
|
||||
for ch in "'`!\$\%()=+{}[]"
|
||||
_htmlescape_chars[ch] = "&#$(Int(ch));"
|
||||
end
|
||||
|
||||
function htmlesc(io::IO, s::AbstractString)
|
||||
# s1 = replace(s, r"&(?!(\w+|\#\d+);)", "&")
|
||||
for ch in s
|
||||
print(io, get(_htmlescape_chars, ch, ch))
|
||||
end
|
||||
end
|
||||
function htmlesc(io::IO, s::Symbol)
|
||||
htmlesc(io, string(s))
|
||||
end
|
||||
function htmlesc(io::IO, xs::Union{AbstractString,Symbol}...)
|
||||
for s in xs
|
||||
htmlesc(io, s)
|
||||
end
|
||||
end
|
||||
function htmlesc(s::Union{AbstractString,Symbol})
|
||||
sprint(htmlesc, s)
|
||||
end
|
||||
|
||||
# Block elements
|
||||
|
||||
function html(io::IO, content::Vector)
|
||||
for md in content
|
||||
html(io, md)
|
||||
println(io)
|
||||
end
|
||||
end
|
||||
|
||||
html(io::IO, md::MD) = html(io, md.content)
|
||||
|
||||
function html{l}(io::IO, header::Header{l})
|
||||
withtag(io, "h$l") do
|
||||
htmlinline(io, header.text)
|
||||
end
|
||||
end
|
||||
|
||||
function html(io::IO, code::Code)
|
||||
withtag(io, :pre) do
|
||||
maybe_lang = !isempty(code.language) ? Any[:class=>"language-$(code.language)"] : []
|
||||
withtag(io, :code, maybe_lang...) do
|
||||
htmlesc(io, code.code)
|
||||
# TODO should print newline if this is longer than one line ?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function html(io::IO, md::Paragraph)
|
||||
withtag(io, :p) do
|
||||
htmlinline(io, md.content)
|
||||
end
|
||||
end
|
||||
|
||||
function html(io::IO, md::BlockQuote)
|
||||
withtag(io, :blockquote) do
|
||||
println(io)
|
||||
html(io, md.content)
|
||||
end
|
||||
end
|
||||
|
||||
function html(io::IO, f::Footnote)
|
||||
withtag(io, :div, :class => "footnote", :id => "footnote-$(f.id)") do
|
||||
withtag(io, :p, :class => "footnote-title") do
|
||||
print(io, f.id)
|
||||
end
|
||||
html(io, f.text)
|
||||
end
|
||||
end
|
||||
|
||||
function html(io::IO, md::Admonition)
|
||||
withtag(io, :div, :class => "admonition $(md.category)") do
|
||||
withtag(io, :p, :class => "admonition-title") do
|
||||
print(io, md.title)
|
||||
end
|
||||
html(io, md.content)
|
||||
end
|
||||
end
|
||||
|
||||
function html(io::IO, md::List)
|
||||
maybe_attr = md.ordered > 1 ? Any[:start => string(md.ordered)] : []
|
||||
withtag(io, isordered(md) ? :ol : :ul, maybe_attr...) do
|
||||
for item in md.items
|
||||
println(io)
|
||||
withtag(io, :li) do
|
||||
html(io, item)
|
||||
end
|
||||
end
|
||||
println(io)
|
||||
end
|
||||
end
|
||||
|
||||
function html(io::IO, md::HorizontalRule)
|
||||
tag(io, :hr)
|
||||
end
|
||||
|
||||
html(io::IO, x) = tohtml(io, x)
|
||||
|
||||
# Inline elements
|
||||
|
||||
function htmlinline(io::IO, content::Vector)
|
||||
for x in content
|
||||
htmlinline(io, x)
|
||||
end
|
||||
end
|
||||
|
||||
function htmlinline(io::IO, code::Code)
|
||||
withtag(io, :code) do
|
||||
htmlesc(io, code.code)
|
||||
end
|
||||
end
|
||||
|
||||
function htmlinline(io::IO, md::Union{Symbol,AbstractString})
|
||||
htmlesc(io, md)
|
||||
end
|
||||
|
||||
function htmlinline(io::IO, md::Bold)
|
||||
withtag(io, :strong) do
|
||||
htmlinline(io, md.text)
|
||||
end
|
||||
end
|
||||
|
||||
function htmlinline(io::IO, md::Italic)
|
||||
withtag(io, :em) do
|
||||
htmlinline(io, md.text)
|
||||
end
|
||||
end
|
||||
|
||||
function htmlinline(io::IO, md::Image)
|
||||
tag(io, :img, :src=>md.url, :alt=>md.alt)
|
||||
end
|
||||
|
||||
|
||||
function htmlinline(io::IO, f::Footnote)
|
||||
withtag(io, :a, :href => "#footnote-$(f.id)", :class => "footnote") do
|
||||
print(io, "[", f.id, "]")
|
||||
end
|
||||
end
|
||||
|
||||
function htmlinline(io::IO, link::Link)
|
||||
withtag(io, :a, :href=>link.url) do
|
||||
htmlinline(io, link.text)
|
||||
end
|
||||
end
|
||||
|
||||
function htmlinline(io::IO, br::LineBreak)
|
||||
tag(io, :br)
|
||||
end
|
||||
|
||||
htmlinline(io::IO, x) = tohtml(io, x)
|
||||
|
||||
# API
|
||||
|
||||
export html
|
||||
|
||||
html(md) = sprint(html, md)
|
||||
|
||||
function show(io::IO, ::MIME"text/html", md::MD)
|
||||
withtag(io, :div, :class=>"markdown") do
|
||||
html(io, md)
|
||||
end
|
||||
end
|
||||
172
julia-0.6.3/share/julia/base/markdown/render/latex.jl
Normal file
172
julia-0.6.3/share/julia/base/markdown/render/latex.jl
Normal file
@@ -0,0 +1,172 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
export latex
|
||||
|
||||
function wrapblock(f, io, env)
|
||||
println(io, "\\begin{", env, "}")
|
||||
f()
|
||||
println(io, "\\end{", env, "}")
|
||||
end
|
||||
|
||||
function wrapinline(f, io, cmd)
|
||||
print(io, "\\", cmd, "{")
|
||||
f()
|
||||
print(io, "}")
|
||||
end
|
||||
|
||||
# Block elements
|
||||
|
||||
latex(io::IO, md::MD) = latex(io, md.content)
|
||||
|
||||
function latex(io::IO, content::Vector)
|
||||
for c in content
|
||||
latex(io, c)
|
||||
end
|
||||
end
|
||||
|
||||
function latex{l}(io::IO, header::Header{l})
|
||||
tag = l < 4 ? "sub"^(l-1) * "section" : "sub"^(l-4) * "paragraph"
|
||||
wrapinline(io, tag) do
|
||||
latexinline(io, header.text)
|
||||
end
|
||||
println(io)
|
||||
end
|
||||
|
||||
function latex(io::IO, code::Code)
|
||||
wrapblock(io, "verbatim") do
|
||||
# TODO latex escape
|
||||
println(io, code.code)
|
||||
end
|
||||
end
|
||||
|
||||
function latexinline(io::IO, code::Code)
|
||||
wrapinline(io, "texttt") do
|
||||
print(io, latexesc(code.code))
|
||||
end
|
||||
end
|
||||
|
||||
function latex(io::IO, md::Paragraph)
|
||||
for md in md.content
|
||||
latexinline(io, md)
|
||||
end
|
||||
println(io)
|
||||
println(io)
|
||||
end
|
||||
|
||||
function latex(io::IO, md::BlockQuote)
|
||||
wrapblock(io, "quote") do
|
||||
latex(io, md.content)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function latex(io::IO, f::Footnote)
|
||||
print(io, "\\footnotetext[", f.id, "]{")
|
||||
latex(io, f.text)
|
||||
println(io, "}")
|
||||
end
|
||||
|
||||
function latex(io::IO, md::Admonition)
|
||||
wrapblock(io, "quote") do
|
||||
wrapinline(io, "textbf") do
|
||||
print(io, md.category)
|
||||
end
|
||||
println(io, "\n\n", md.title, "\n")
|
||||
latex(io, md.content)
|
||||
end
|
||||
end
|
||||
|
||||
function latex(io::IO, md::List)
|
||||
# `\begin{itemize}` is used here for both ordered and unordered lists since providing
|
||||
# custom starting numbers for enumerated lists is simpler to do by manually assigning
|
||||
# each number to `\item` ourselves rather than using `\setcounter{enumi}{<start>}`.
|
||||
#
|
||||
# For an ordered list starting at 5 the following will be generated:
|
||||
#
|
||||
# \begin{itemize}
|
||||
# \item[5. ] ...
|
||||
# \item[6. ] ...
|
||||
# ...
|
||||
# \end{itemize}
|
||||
#
|
||||
pad = ndigits(md.ordered + length(md.items)) + 2
|
||||
fmt = n -> (isordered(md) ? "[$(rpad("$(n + md.ordered - 1).", pad))]" : "")
|
||||
wrapblock(io, "itemize") do
|
||||
for (n, item) in enumerate(md.items)
|
||||
print(io, "\\item$(fmt(n)) ")
|
||||
latex(io, item)
|
||||
n < length(md.items) && println(io)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function show(io::IO, ::MIME"text/latex", md::HorizontalRule)
|
||||
println(io, "\\rule{\\textwidth}{1pt}")
|
||||
end
|
||||
|
||||
# Inline elements
|
||||
|
||||
function latexinline(io::IO, md::Vector)
|
||||
for c in md
|
||||
latexinline(io, c)
|
||||
end
|
||||
end
|
||||
|
||||
function latexinline(io::IO, md::AbstractString)
|
||||
latexesc(io, md)
|
||||
end
|
||||
|
||||
function latexinline(io::IO, md::Bold)
|
||||
wrapinline(io, "textbf") do
|
||||
latexinline(io, md.text)
|
||||
end
|
||||
end
|
||||
|
||||
function latexinline(io::IO, md::Italic)
|
||||
wrapinline(io, "emph") do
|
||||
latexinline(io, md.text)
|
||||
end
|
||||
end
|
||||
|
||||
function latexinline(io::IO, md::Image)
|
||||
wrapblock(io, "figure") do
|
||||
println(io, "\\centering")
|
||||
wrapinline(io, "includegraphics") do
|
||||
print(io, md.url)
|
||||
end
|
||||
println(io)
|
||||
wrapinline(io, "caption") do
|
||||
latexinline(io, md.alt)
|
||||
end
|
||||
println(io)
|
||||
end
|
||||
end
|
||||
|
||||
latexinline(io::IO, f::Footnote) = print(io, "\\footnotemark[", f.id, "]")
|
||||
|
||||
function latexinline(io::IO, md::Link)
|
||||
wrapinline(io, "href") do
|
||||
print(io, md.url)
|
||||
end
|
||||
print(io, "{")
|
||||
latexinline(io, md.text)
|
||||
print(io, "}")
|
||||
end
|
||||
|
||||
const _latexescape_chars = Dict{Char, AbstractString}(
|
||||
'~'=>"{\\sim}", '^'=>"\\^{}", '\\'=>"{\\textbackslash}")
|
||||
for ch in "&%\$#_{}"
|
||||
_latexescape_chars[ch] = "\\$ch"
|
||||
end
|
||||
|
||||
function latexesc(io, s::AbstractString)
|
||||
for ch in s
|
||||
print(io, get(_latexescape_chars, ch, ch))
|
||||
end
|
||||
end
|
||||
|
||||
latex(md) = sprint(latex, md)
|
||||
latexinline(md) = sprint(latexinline, md)
|
||||
latexesc(s) = sprint(latexesc, s)
|
||||
|
||||
show(io::IO, ::MIME"text/latex", md::MD) = latex(io, md)
|
||||
140
julia-0.6.3/share/julia/base/markdown/render/plain.jl
Normal file
140
julia-0.6.3/share/julia/base/markdown/render/plain.jl
Normal file
@@ -0,0 +1,140 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
plain(x) = sprint(plain, x)
|
||||
|
||||
function plain(io::IO, content::Vector)
|
||||
isempty(content) && return
|
||||
for md in content[1:end-1]
|
||||
plain(io, md)
|
||||
println(io)
|
||||
end
|
||||
plain(io, content[end])
|
||||
end
|
||||
|
||||
plain(io::IO, md::MD) = plain(io, md.content)
|
||||
|
||||
function plain(io::IO, header::Header{l}) where l
|
||||
print(io, "#"^l*" ")
|
||||
plaininline(io, header.text)
|
||||
println(io)
|
||||
end
|
||||
|
||||
function plain(io::IO, code::Code)
|
||||
# If the code includes a fenced block this will break parsing,
|
||||
# so it must be enclosed by a longer ````-sequence.
|
||||
n = mapreduce(length, max, 2, matchall(r"^`+"m, code.code)) + 1
|
||||
println(io, "`" ^ n, code.language)
|
||||
println(io, code.code)
|
||||
println(io, "`" ^ n)
|
||||
end
|
||||
|
||||
function plain(io::IO, p::Paragraph)
|
||||
plaininline(io, p.content)
|
||||
println(io)
|
||||
end
|
||||
|
||||
function plain(io::IO, list::List)
|
||||
for (i, item) in enumerate(list.items)
|
||||
print(io, isordered(list) ? "$(i + list.ordered - 1). " : " * ")
|
||||
lines = split(rstrip(sprint(plain, item)), "\n")
|
||||
for (n, line) in enumerate(lines)
|
||||
print(io, (n == 1 || isempty(line)) ? "" : " ", line)
|
||||
n < length(lines) && println(io)
|
||||
end
|
||||
println(io)
|
||||
end
|
||||
end
|
||||
|
||||
function plain(io::IO, q::BlockQuote)
|
||||
s = sprint(plain, q.content)
|
||||
for line in split(rstrip(s), "\n")
|
||||
println(io, isempty(line) ? ">" : "> ", line)
|
||||
end
|
||||
println(io)
|
||||
end
|
||||
|
||||
function plain(io::IO, f::Footnote)
|
||||
print(io, "[^", f.id, "]:")
|
||||
s = sprint(plain, f.text)
|
||||
lines = split(rstrip(s), "\n")
|
||||
# Single line footnotes are printed on the same line as their label
|
||||
# rather than taking up an additional line.
|
||||
if length(lines) == 1
|
||||
println(io, " ", lines[1])
|
||||
else
|
||||
println(io)
|
||||
for line in lines
|
||||
println(io, isempty(line) ? "" : " ", line)
|
||||
end
|
||||
println(io)
|
||||
end
|
||||
end
|
||||
|
||||
function plain(io::IO, md::Admonition)
|
||||
s = sprint(plain, md.content)
|
||||
title = md.title == ucfirst(md.category) ? "" : " \"$(md.title)\""
|
||||
println(io, "!!! ", md.category, title)
|
||||
for line in split(rstrip(s), "\n")
|
||||
println(io, isempty(line) ? "" : " ", line)
|
||||
end
|
||||
println(io)
|
||||
end
|
||||
|
||||
function plain(io::IO, md::HorizontalRule)
|
||||
println(io, "-" ^ 3)
|
||||
end
|
||||
|
||||
function plain(io::IO, l::LaTeX)
|
||||
println(io, '$', '$')
|
||||
println(io, l.formula)
|
||||
println(io, '$', '$')
|
||||
end
|
||||
|
||||
function plain(io::IO, md)
|
||||
show(io, MIME"text/plain"(), md)
|
||||
println(io)
|
||||
end
|
||||
|
||||
# Inline elements
|
||||
|
||||
plaininline(x) = sprint(plaininline, x)
|
||||
|
||||
function plaininline(io::IO, md...)
|
||||
for el in md
|
||||
plaininline(io, el)
|
||||
end
|
||||
end
|
||||
|
||||
plaininline(io::IO, md::Vector) = !isempty(md) && plaininline(io, md...)
|
||||
|
||||
plaininline(io::IO, f::Footnote) = print(io, "[^", f.id, "]")
|
||||
|
||||
plaininline(io::IO, link::Link) = plaininline(io, "[", link.text, "](", link.url, ")")
|
||||
|
||||
plaininline(io::IO, md::Image) = plaininline(io, "")
|
||||
|
||||
plaininline(io::IO, s::AbstractString) = print(io, s)
|
||||
|
||||
plaininline(io::IO, md::Bold) = plaininline(io, "**", md.text, "**")
|
||||
|
||||
plaininline(io::IO, md::Italic) = plaininline(io, "*", md.text, "*")
|
||||
|
||||
function plaininline(io::IO, md::Code)
|
||||
if contains(md.code, "`")
|
||||
n = maximum(length(m) for m in matchall(r"(`+)", md.code))
|
||||
s = "`"^((iseven(n) ? 1 : 2) + n)
|
||||
print(io, s, Base.startswith(md.code, "`") ? " " : "")
|
||||
print(io, md.code, endswith(md.code, "`") ? " " : "", s)
|
||||
else
|
||||
print(io, "`", md.code, "`")
|
||||
end
|
||||
end
|
||||
|
||||
plaininline(io::IO, br::LineBreak) = println(io)
|
||||
|
||||
plaininline(io::IO, x) = show(io, MIME"text/plain"(), x)
|
||||
|
||||
# show
|
||||
|
||||
Base.show(io::IO, md::MD) = plain(io, md)
|
||||
Base.show(io::IO, ::MIME"text/markdown", md::MD) = plain(io, md)
|
||||
30
julia-0.6.3/share/julia/base/markdown/render/rich.jl
Normal file
30
julia-0.6.3/share/julia/base/markdown/render/rich.jl
Normal file
@@ -0,0 +1,30 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
function tohtml(io::IO, m::MIME"text/html", x)
|
||||
show(io, m, x)
|
||||
end
|
||||
|
||||
function tohtml(io::IO, m::MIME"text/plain", x)
|
||||
htmlesc(io, sprint(show, m, x))
|
||||
end
|
||||
|
||||
function tohtml(io::IO, m::MIME"image/png", img)
|
||||
print(io, """<img src="data:image/png;base64,""")
|
||||
print(io, stringmime(m, img))
|
||||
print(io, "\" />")
|
||||
end
|
||||
|
||||
function tohtml(io::IO, m::MIME"image/svg+xml", img)
|
||||
show(io, m, img)
|
||||
end
|
||||
|
||||
# Display infrastructure
|
||||
|
||||
function bestmime(val)
|
||||
for mime in ("text/html", "image/svg+xml", "image/png", "text/plain")
|
||||
mimewritable(mime, val) && return MIME(Symbol(mime))
|
||||
end
|
||||
error("Cannot render $val to Markdown.")
|
||||
end
|
||||
|
||||
tohtml(io::IO, x) = tohtml(io, bestmime(x), x)
|
||||
145
julia-0.6.3/share/julia/base/markdown/render/rst.jl
Normal file
145
julia-0.6.3/share/julia/base/markdown/render/rst.jl
Normal file
@@ -0,0 +1,145 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
rst(x) = sprint(rst, x)
|
||||
|
||||
function rst(io::IO, content::Vector)
|
||||
isempty(content) && return
|
||||
for md in content[1:end-1]
|
||||
rst(io, md)
|
||||
println(io)
|
||||
end
|
||||
rst(io, content[end])
|
||||
end
|
||||
|
||||
rst(io::IO, md::MD) = rst(io, md.content)
|
||||
|
||||
function rst{l}(io::IO, header::Header{l})
|
||||
s = rstinline(header.text)
|
||||
println(io, s)
|
||||
println(io, string("*=-~:.^"[l])^length(s))
|
||||
println(io)
|
||||
end
|
||||
|
||||
function rst(io::IO, code::Code)
|
||||
if code.language == "jldoctest"
|
||||
println(io, ".. doctest::\n")
|
||||
elseif code.language != "rst"
|
||||
println(io, ".. code-block:: julia\n")
|
||||
end
|
||||
for l in lines(code.code)
|
||||
println(io, " ", l)
|
||||
end
|
||||
end
|
||||
|
||||
function rst(io::IO, p::Paragraph)
|
||||
rstinline(io, p.content)
|
||||
println(io)
|
||||
end
|
||||
|
||||
function rst(io::IO, list::List)
|
||||
for (i, item) in enumerate(list.items)
|
||||
bullet = isordered(list) ? "$(i + list.ordered - 1). " : "* "
|
||||
print(io, bullet)
|
||||
lines = split(rstrip(sprint(rst, item)), '\n')
|
||||
for (n, line) in enumerate(lines)
|
||||
print(io, (n == 1 || isempty(line)) ? "" : " "^length(bullet), line)
|
||||
n < length(lines) && println(io)
|
||||
end
|
||||
println(io)
|
||||
end
|
||||
end
|
||||
|
||||
function rst(io::IO, q::BlockQuote)
|
||||
s = sprint(rst, q.content)
|
||||
for line in split(rstrip(s), "\n")
|
||||
println(io, " ", line)
|
||||
end
|
||||
println(io)
|
||||
end
|
||||
|
||||
function rst(io::IO, f::Footnote)
|
||||
print(io, ".. [", f.id, "]")
|
||||
s = sprint(rst, f.text)
|
||||
lines = split(rstrip(s), "\n")
|
||||
# Single line footnotes are printed on the same line as their label
|
||||
# rather than taking up an additional line.
|
||||
if length(lines) == 1
|
||||
println(io, " ", lines[1])
|
||||
else
|
||||
println(io)
|
||||
for line in lines
|
||||
println(io, isempty(line) ? "" : " ", rstrip(line))
|
||||
end
|
||||
println(io)
|
||||
end
|
||||
end
|
||||
|
||||
function rst(io::IO, md::Admonition)
|
||||
s = sprint(rst, md.content)
|
||||
title = md.title == ucfirst(md.category) ? "" : md.title
|
||||
println(io, ".. ", md.category, "::", isempty(title) ? "" : " $title")
|
||||
for line in split(rstrip(s), "\n")
|
||||
println(io, isempty(line) ? "" : " ", line)
|
||||
end
|
||||
println(io)
|
||||
end
|
||||
|
||||
function rst(io::IO, md::HorizontalRule)
|
||||
println(io, "–" ^ 5)
|
||||
end
|
||||
|
||||
function rst(io::IO, l::LaTeX)
|
||||
println(io, ".. math::\n")
|
||||
for l in lines(l.formula)
|
||||
println(io, " ", l)
|
||||
end
|
||||
end
|
||||
|
||||
rst(io::IO, md) = show(io, "text/rst", md)
|
||||
|
||||
# Inline elements
|
||||
|
||||
rstinline(x) = sprint(rstinline, x)
|
||||
|
||||
function rstinline(io::IO, md...)
|
||||
wasCode = false
|
||||
for el in md
|
||||
wasCode && isa(el, AbstractString) && !Base.startswith(el, " ") && print(io, "\\ ")
|
||||
wasCode = (isa(el, Code) || isa(el, LaTeX) || isa(el, Link)) && (wasCode = true)
|
||||
rstinline(io, el)
|
||||
end
|
||||
end
|
||||
|
||||
rstinline(io::IO, md::Vector) = !isempty(md) && rstinline(io, md...)
|
||||
|
||||
# rstinline(io::IO, md::Image) = rstinline(io, ".. image:: ", md.url)
|
||||
|
||||
function rstinline(io::IO, md::Link)
|
||||
if ismatch(r":(func|obj|ref|exc|class|const|data):`\.*", md.url)
|
||||
rstinline(io, md.url)
|
||||
else
|
||||
rstinline(io, "`", md.text, " <", md.url, ">`_")
|
||||
end
|
||||
end
|
||||
|
||||
rstinline(io::IO, f::Footnote) = print(io, "[", f.id, "]_")
|
||||
|
||||
rstescape(s) = replace(s, "\\", "\\\\")
|
||||
|
||||
rstinline(io::IO, s::AbstractString) = print(io, rstescape(s))
|
||||
|
||||
rstinline(io::IO, md::Bold) = rstinline(io, "**", md.text, "**")
|
||||
|
||||
rstinline(io::IO, md::Italic) = rstinline(io, "*", md.text, "*")
|
||||
|
||||
rstinline(io::IO, md::Code) = print(io, "``", md.code, "``")
|
||||
|
||||
rstinline(io::IO, br::LineBreak) = println(io)
|
||||
|
||||
rstinline(io::IO, l::LaTeX) = print(io, ":math:`", l.formula, "`")
|
||||
|
||||
rstinline(io::IO, x) = show(io, MIME"text/rst"(), x)
|
||||
|
||||
# show
|
||||
|
||||
Base.show(io::IO, ::MIME"text/rst", md::MD) = rst(io, md)
|
||||
@@ -0,0 +1,107 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
# Styles
|
||||
|
||||
const text_formats = Dict(
|
||||
:black => ("\e[30m", "\e[39m"),
|
||||
:red => ("\e[31m", "\e[39m"),
|
||||
:green => ("\e[32m", "\e[39m"),
|
||||
:yellow => ("\e[33m", "\e[39m"),
|
||||
:blue => ("\e[34m", "\e[39m"),
|
||||
:magenta => ("\e[35m", "\e[39m"),
|
||||
:cyan => ("\e[36m", "\e[39m"),
|
||||
:white => ("\e[37m", "\e[39m"),
|
||||
:reset => ("\e[0m", "\e[0m"),
|
||||
:bold => ("\e[1m", "\e[22m"),
|
||||
:underline => ("\e[4m", "\e[24m"),
|
||||
:blink => ("\e[5m", "\e[25m"),
|
||||
:negative => ("\e[7m", "\e[27m"))
|
||||
|
||||
function with_output_format(f::Function, formats::Vector{Symbol}, io::IO, args...)
|
||||
Base.have_color && for format in formats
|
||||
haskey(text_formats, format) &&
|
||||
print(io, text_formats[format][1])
|
||||
end
|
||||
try f(io, args...)
|
||||
finally
|
||||
Base.have_color && for format in formats
|
||||
haskey(text_formats, format) &&
|
||||
print(io, text_formats[format][2])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
with_output_format(f::Function, format::Symbol, args...) =
|
||||
with_output_format(f, [format], args...)
|
||||
|
||||
with_output_format(format, f::Function, args...) =
|
||||
with_output_format(f, format, args...)
|
||||
|
||||
function print_with_format(format, io::IO, x)
|
||||
with_output_format(format, io) do io
|
||||
print(io, x)
|
||||
end
|
||||
end
|
||||
|
||||
function println_with_format(format, io::IO, x)
|
||||
print_with_format(format, io, x)
|
||||
println(io)
|
||||
end
|
||||
|
||||
# Wrapping
|
||||
|
||||
function ansi_length(s)
|
||||
replace(s, r"\e\[[0-9]+m", "") |> length
|
||||
end
|
||||
|
||||
words(s) = split(s, " ")
|
||||
lines(s) = split(s, "\n")
|
||||
|
||||
# This could really be more efficient
|
||||
function wrapped_lines(s::AbstractString; width = 80, i = 0)
|
||||
if ismatch(r"\n", s)
|
||||
return vcat(map(s->wrapped_lines(s, width = width, i = i), split(s, "\n"))...)
|
||||
end
|
||||
ws = words(s)
|
||||
lines = AbstractString[ws[1]]
|
||||
i += ws[1] |> ansi_length
|
||||
for word in ws[2:end]
|
||||
word_length = ansi_length(word)
|
||||
if i + word_length + 1 > width
|
||||
i = word_length
|
||||
push!(lines, word)
|
||||
else
|
||||
i += word_length + 1
|
||||
lines[end] *= " " * word
|
||||
end
|
||||
end
|
||||
return lines
|
||||
end
|
||||
|
||||
wrapped_lines(f::Function, args...; width = 80, i = 0) =
|
||||
wrapped_lines(sprint(f, args...), width = width, i = 0)
|
||||
|
||||
function print_wrapped(io::IO, s...; width = 80, pre = "", i = 0)
|
||||
lines = wrapped_lines(s..., width = width, i = i)
|
||||
println(io, lines[1])
|
||||
for line in lines[2:end]
|
||||
println(io, pre, line)
|
||||
end
|
||||
length(lines), length(pre) + ansi_length(lines[end])
|
||||
end
|
||||
|
||||
print_wrapped(f::Function, io::IO, args...; kws...) = print_wrapped(io, f, args...; kws...)
|
||||
|
||||
function print_centred(io::IO, s...; columns = 80, width = columns)
|
||||
lines = wrapped_lines(s..., width = width)
|
||||
for line in lines
|
||||
print(io, " "^(div(columns-ansi_length(line), 2)))
|
||||
println(io, line)
|
||||
end
|
||||
length(lines), length(pre) + length(lines[end])
|
||||
end
|
||||
|
||||
function centred(s, columns)
|
||||
pad = div(columns - ansi_length(s), 2)
|
||||
" "^pad * s
|
||||
end
|
||||
148
julia-0.6.3/share/julia/base/markdown/render/terminal/render.jl
Normal file
148
julia-0.6.3/share/julia/base/markdown/render/terminal/render.jl
Normal file
@@ -0,0 +1,148 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
include("formatting.jl")
|
||||
|
||||
const margin = 2
|
||||
cols(io) = displaysize(io)[2]
|
||||
|
||||
function term(io::IO, content::Vector, cols)
|
||||
isempty(content) && return
|
||||
for md in content[1:end-1]
|
||||
term(io, md, cols)
|
||||
println(io)
|
||||
end
|
||||
term(io, content[end], cols)
|
||||
end
|
||||
|
||||
term(io::IO, md::MD, columns = cols(io)) = term(io, md.content, columns)
|
||||
|
||||
function term(io::IO, md::Paragraph, columns)
|
||||
print(io, " "^margin)
|
||||
print_wrapped(io, width = columns-2margin, pre = " "^margin) do io
|
||||
terminline(io, md.content)
|
||||
end
|
||||
end
|
||||
|
||||
function term(io::IO, md::BlockQuote, columns)
|
||||
s = sprint(term, md.content, columns - 10)
|
||||
for line in split(rstrip(s), "\n")
|
||||
println(io, " "^margin, "|", line)
|
||||
end
|
||||
end
|
||||
|
||||
function term(io::IO, md::Admonition, columns)
|
||||
print(io, " "^margin, "| ")
|
||||
with_output_format(:bold, print, io, isempty(md.title) ? md.category : md.title)
|
||||
println(io, "\n", " "^margin, "|")
|
||||
s = sprint(term, md.content, columns - 10)
|
||||
for line in split(rstrip(s), "\n")
|
||||
println(io, " "^margin, "|", line)
|
||||
end
|
||||
end
|
||||
|
||||
function term(io::IO, f::Footnote, columns)
|
||||
print(io, " "^margin, "| ")
|
||||
with_output_format(:bold, print, io, "[^$(f.id)]")
|
||||
println(io, "\n", " "^margin, "|")
|
||||
s = sprint(term, f.text, columns - 10)
|
||||
for line in split(rstrip(s), "\n")
|
||||
println(io, " "^margin, "|", line)
|
||||
end
|
||||
end
|
||||
|
||||
function term(io::IO, md::List, columns)
|
||||
for (i, point) in enumerate(md.items)
|
||||
print(io, " "^2margin, isordered(md) ? "$(i + md.ordered - 1). " : "• ")
|
||||
print_wrapped(io, width = columns-(4margin+2), pre = " "^(2margin+2),
|
||||
i = 2margin+2) do io
|
||||
term(io, point, columns - 10)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function _term_header(io::IO, md, char, columns)
|
||||
text = terminline(md.text)
|
||||
with_output_format(:bold, io) do io
|
||||
print(io, " "^(2margin), " ")
|
||||
line_no, lastline_width = print_wrapped(io, text,
|
||||
width=columns - 4margin; pre=" ")
|
||||
line_width = min(1 + lastline_width, columns)
|
||||
if line_no > 1
|
||||
line_width = max(line_width, div(columns, 3))
|
||||
end
|
||||
char != ' ' && println(io, " "^(2margin), string(char) ^ line_width)
|
||||
end
|
||||
end
|
||||
|
||||
const _header_underlines = collect("≡=–-⋅ ")
|
||||
# TODO settle on another option with unicode e.g. "≡=≃–∼⋅" ?
|
||||
|
||||
function term{l}(io::IO, md::Header{l}, columns)
|
||||
underline = _header_underlines[l]
|
||||
_term_header(io, md, underline, columns)
|
||||
end
|
||||
|
||||
function term(io::IO, md::Code, columns)
|
||||
with_output_format(:cyan, io) do io
|
||||
for line in lines(md.code)
|
||||
print(io, " "^margin)
|
||||
println(io, line)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function term(io::IO, br::LineBreak, columns)
|
||||
println(io)
|
||||
end
|
||||
|
||||
function term(io::IO, br::HorizontalRule, columns)
|
||||
println(io, " " ^ margin, "-" ^ (columns - 2margin))
|
||||
end
|
||||
|
||||
term(io::IO, x, _) = show(io, MIME"text/plain"(), x)
|
||||
|
||||
# Inline Content
|
||||
|
||||
terminline(md) = sprint(terminline, md)
|
||||
|
||||
function terminline(io::IO, content::Vector)
|
||||
for md in content
|
||||
terminline(io, md)
|
||||
end
|
||||
end
|
||||
|
||||
function terminline(io::IO, md::AbstractString)
|
||||
print(io, replace(md, r"[\s\t\n]+", " "))
|
||||
end
|
||||
|
||||
function terminline(io::IO, md::Bold)
|
||||
with_output_format(:bold, terminline, io, md.text)
|
||||
end
|
||||
|
||||
function terminline(io::IO, md::Italic)
|
||||
with_output_format(:underline, terminline, io, md.text)
|
||||
end
|
||||
|
||||
function terminline(io::IO, md::LineBreak)
|
||||
println(io)
|
||||
end
|
||||
|
||||
function terminline(io::IO, md::Image)
|
||||
terminline(io, "(Image: $(md.alt))")
|
||||
end
|
||||
|
||||
terminline(io::IO, f::Footnote) = with_output_format(:bold, terminline, io, "[^$(f.id)]")
|
||||
|
||||
function terminline(io::IO, md::Link)
|
||||
terminline(io, md.text)
|
||||
end
|
||||
|
||||
function terminline(io::IO, code::Code)
|
||||
print_with_format(:cyan, io, code.code)
|
||||
end
|
||||
|
||||
terminline(io::IO, x) = show(io, MIME"text/plain"(), x)
|
||||
|
||||
# Show in terminal
|
||||
|
||||
Base.display(d::Base.REPL.REPLDisplay, md::MD) = term(Base.REPL.outstream(d.repl), md)
|
||||
Reference in New Issue
Block a user