• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JuliaLang / julia / 1391

29 Dec 2025 07:41PM UTC coverage: 76.638% (+0.02%) from 76.621%
1391

push

buildkite

web-flow
🤖 Bump StyledStrings stdlib 9bb8ffd → a033d46 (#60503)

Co-authored-by: KristofferC <1282691+KristofferC@users.noreply.github.com>

62409 of 81433 relevant lines covered (76.64%)

22974996.93 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

72.51
/stdlib/Markdown/src/render/terminal/render.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
include("formatting.jl")
4

5
cols(io) = displaysize(io)[2]
102✔
6

7
function term(io::IO, content::Vector, cols)
138✔
8
    isempty(content) && return
138✔
9
    for md in content[1:end-1]
135✔
10
        term(io, md, cols)
33✔
11
        print(io, '\n', '\n')
33✔
12
    end
33✔
13
    term(io, content[end], cols)
135✔
14
end
15

16
function term(io::IO, md::MD, columns = cols(io))
27✔
17
    md = insert_hlines(md)
231✔
18
    return term(io, md.content, columns)
129✔
19
end
20

21
function term(io::IO, md::Paragraph, columns)
117✔
22
    lines = wraplines(annotprint(terminline, md.content), columns-2margin)
117✔
23
    for (i, line) in enumerate(lines)
234✔
24
        print(io, ' '^margin, line)
219✔
25
        i < length(lines) && println(io)
219✔
26
    end
219✔
27
end
28

29
function term(io::IO, md::BlockQuote, columns)
3✔
30
    content = annotprint(term, md.content, columns - 10)
3✔
31
    lines = wraplines(rstrip(content), columns - 10)
3✔
32
    for (i, line) in enumerate(lines)
6✔
33
        print(io, ' '^margin, '│', line)
3✔
34
        i < length(lines) && println(io)
3✔
35
    end
3✔
36
end
37

38
function term(io::IO, md::Admonition, columns)
3✔
39
    accent = if md.category == "danger"
3✔
40
        :error
×
41
    elseif md.category in ("warning", "info", "note", "tip")
6✔
42
        Symbol(md.category)
3✔
43
    elseif md.category == "compat"
×
44
        :bright_cyan
×
45
    elseif md.category == "todo"
×
46
        :magenta
×
47
    else
48
        :default
6✔
49
    end
50
    title = if isempty(md.title) md.category else md.title end
6✔
51
    print(io, ' '^margin, styled"{$accent,markdown_admonition:│ $title}",
6✔
52
          '\n', ' '^margin, styled"{$accent,markdown_admonition:│}", '\n')
53
    content = annotprint(term, md.content, columns - 10)
3✔
54
    lines = split(rstrip(content), '\n')
3✔
55
    for (i, line) in enumerate(lines)
6✔
56
        print(io, ' '^margin, styled"{$accent,markdown_admonition:│}", line)
18✔
57
        i < length(lines) && println(io)
9✔
58
    end
9✔
59
end
60

61
function term(io::IO, f::Footnote, columns)
×
62
    print(io, ' '^margin, "│ ")
×
63
    print(io, styled"{markdown_footnote:[^$(f.id)]}")
×
64
    println(io, '\n', ' '^margin, '│')
×
65
    content = annotprint(term, f.text, columns - 10)
×
66
    lines = split(rstrip(content), '\n')
×
67
    for (i, line) in enumerate(lines)
×
68
        print(io, ' '^margin, '│', line)
×
69
        i < length(lines) && println(io)
×
70
    end
×
71
end
72

73
const _list_bullets = ("•  ", "–  ", "▪  ")
74

75
function term(io::IO, md::List, columns, depth::Int = 1)
54✔
76
    dterm(io, md, columns, _depth)      = term(io, md, columns)
105✔
77
    dterm(io, md::List, columns, depth) = term(io, md, columns, depth)
×
78
    for (i, point) in enumerate(md.items)
27✔
79
        bullet = if isordered(md)
51✔
80
            string(lpad(i + md.ordered - 1, ndigits(length(md.items))), ". ")
42✔
81
        elseif depth == 1
9✔
82
            first(_list_bullets)
9✔
83
        else
84
            _list_bullets[2 + mod(depth, length(_list_bullets) - 1)]
60✔
85
        end
86
        print(io, ' '^ifelse(depth == 1, 2margin, 2*(depth-1)), styled"{markdown_list:$bullet}")
102✔
87
        buf = AnnotatedIOBuffer()
51✔
88
        if point isa Vector && !isempty(point)
51✔
89
            for (i, elt) in enumerate(point[1:end-1])
48✔
90
                dterm(buf, elt, columns - 10, depth + 1)
×
91
                println(buf)
×
92
                (!(point[i+1] isa List) || point[i+1].loose) && println(buf)
×
93
            end
×
94
            dterm(buf, point[end], columns - 10, depth + 1)
96✔
95
        else
96
            dterm(buf, point, columns - 10, depth + 1)
3✔
97
        end
98
        content = read(seekstart(buf), AnnotatedString)
102✔
99
        lines = split(rstrip(content), '\n')
51✔
100
        common_indent = minimum(
51✔
101
            (sum((1 for _ in Iterators.takewhile(isspace, line)), init=0)
102
             for line in Iterators.filter(!isempty, lines)),
103
            init=if isempty(lines) 0 else length(first(lines)) end)
51✔
104
        for (l, line) in enumerate(lines)
102✔
105
            l > 1 && print(io, ' '^ifelse(depth == 1, 2margin + 3, 3))
87✔
106
            !isempty(line) && print(io, line[common_indent+1:end])
87✔
107
            l < length(lines) && println(io)
87✔
108
        end
123✔
109
        i < length(md.items) && print(io, '\n'^(1 + md.loose))
51✔
110
    end
51✔
111
end
112

113
const _header_underlines = collect("≡=–-⋅ ")
114
# TODO settle on another option with unicode e.g. "≡=≃–∼⋅" ?
115

116
function term(io::AnnotIO, md::Header{l}, columns) where l
21✔
117
    face = Symbol("markdown_h$l")
21✔
118
    underline = _header_underlines[l]
21✔
119
    pre = ' '^margin
21✔
120
    line_width = with_output_annotations(io, :face => face) do io
21✔
121
        headline = annotprint(terminline, md.text)
21✔
122
        lines = wraplines(headline, columns - 4margin)
21✔
123
        for (i, line) in enumerate(lines)
39✔
124
            print(io, pre, line)
18✔
125
            i < length(lines) && println(io)
18✔
126
        end
18✔
127
        if length(lines) == 1
21✔
128
            return min(textwidth(lines[end]), columns)
18✔
129
        elseif length(lines) > 1
3✔
130
            return max(textwidth(lines[end]), div(columns, 3)+length(pre))
×
131
        else
132
            return 0
3✔
133
        end
134
    end
135
    header_width = max(0, line_width)
21✔
136
    if underline != ' ' && header_width > 0
21✔
137
        print(io, '\n', ' '^(margin))
18✔
138
        with_output_annotations(io -> print(io, underline^header_width), io, :face => face)
36✔
139
    end
140
end
141

142
function term(io::IO, md::Code, columns)
12✔
143
    code = if md.language == "julia"
12✔
144
        highlight(md.code)
6✔
145
    elseif md.language == "julia-repl" || Base.startswith(md.language, "jldoctest")
12✔
146
        hl = AnnotatedString(md.code)
×
147
        for (; match) in eachmatch(r"(?:^|\n)julia>", hl)
×
148
            StyledStrings.face!(match, :markdown_julia_prompt)
×
149
            afterprompt = match.offset + ncodeunits(match) + 1
×
150
            _, exprend = Meta.parse(md.code, afterprompt, raise = false)
×
151
            highlight!(hl[afterprompt:prevind(md.code, exprend)])
×
152
            if (nextspace = findnext(' ', md.code, exprend)) |> !isnothing
×
153
                nextword = hl[exprend:prevind(hl, nextspace)]
×
154
                if nextword == "ERROR:"
×
155
                    StyledStrings.face!(nextword, :error)
×
156
                end
157
            end
158
        end
×
159
        hl
×
160
    elseif md.language == "styled"
6✔
161
        styled(md.code)
×
162
    else
163
        styled"{markdown_code:$(md.code)}"
24✔
164
    end
165
    lines = split(code, '\n')
12✔
166
    for (i, line) in enumerate(lines)
24✔
167
        print(io, ' '^margin, line)
12✔
168
        i < length(lines) && println(io)
12✔
169
    end
12✔
170
end
171

172
function term(io::IO, tex::LaTeX, columns)
3✔
173
    print(io, ' '^margin, styled"{markdown_latex:$(tex.formula)}")
3✔
174
end
175

176
term(io::IO, br::LineBreak, columns) = nothing # line breaks already printed between subsequent elements
×
177

178
function term(io::IO, br::HorizontalRule, columns)
×
179
    print(io, ' '^margin, styled"{markdown_hrule:$('─'^(columns - 2margin))}")
×
180
end
181

182
function term(io::IO, md::MarkdownElement, columns)
21✔
183
    a = IOContext(AnnotatedIOBuffer(), io)
21✔
184
    term(a, md, columns)
21✔
185
    print(io, read(seekstart(a.io), AnnotatedString))
21✔
186
end
187

188
term(io::IO, x, _) = show(io, MIME"text/plain"(), x)
3✔
189

190
# Inline Content
191

192
terminline(io::IO, content...) = terminline(io, collect(content))
×
193

194
function terminline(io::IO, content::Vector)
228✔
195
    for md in content
228✔
196
        terminline(io, md)
354✔
197
    end
354✔
198
end
199

200
function terminline(io::IO, md::AbstractString)
231✔
201
    print(io, replace(md, r"[\s\t\n]+" => ' '))
234✔
202
end
203

204
function terminline(io::AnnotIO, md::Bold)
6✔
205
    with_output_annotations(io -> terminline(io, md.text), io, :face => :bold)
12✔
206
end
207

208
function terminline(io::AnnotIO, md::Italic)
15✔
209
    with_output_annotations(io -> terminline(io, md.text), io, :face => :italic)
30✔
210
end
211

212
function terminline(io::IO, md::LineBreak)
6✔
213
    println(io)
6✔
214
end
215

216
function terminline(io::IO, md::Image)
3✔
217
    terminline(io, "(Image: $(md.alt))")
3✔
218
end
219

220
function terminline(io::IO, f::Footnote)
×
221
    print(io, styled"{markdown_footnote:[^$(f.id)]}")
×
222
end
223

224
function terminline(io::AnnotIO, md::Link)
39✔
225
    annots = if occursin(r"^(https?|file)://", md.url)
39✔
226
        (:face => :markdown_link, :link => md.url)
3✔
227
    else
228
        (:face => :markdown_link,)
75✔
229
    end
230
    with_output_annotations(io -> terminline(io, md.text), io, annots...)
78✔
231
end
232

233
function terminline(io::IO, code::Code)
51✔
234
    body = if code.language == "styled"
51✔
235
        styled(code.code)
×
236
    else
237
        code.code
102✔
238
    end
239
    print(io, styled"{markdown_inlinecode:$body}")
51✔
240
end
241

242
function terminline(io::IO, tex::LaTeX)
×
243
    print(io, styled"{markdown_latex:$(tex.formula)}")
×
244
end
245

246
function terminline(io::IO, md::MarkdownElement)
×
247
    a = IOContext(AnnotatedIOBuffer(), io)
×
248
    terminline(a, md)
×
249
    print(io, read(seekstart(a.io), AnnotatedString))
×
250
end
251

252
terminline(io::IO, x) = show(io, MIME"text/plain"(), x)
3✔
253

254
# Show in terminal
255
Base.show(io::IO, ::MIME"text/plain", md::MD) = (term(io, md); nothing)
63✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc