Line | Exclusive | Inclusive | Code |
---|---|---|---|
1 | # This file is a part of Julia. License is MIT: https://julialang.org/license | ||
2 | |||
3 | ## core text I/O ## | ||
4 | |||
5 | """ | ||
6 | print([io::IO], xs...) | ||
7 | |||
8 | Write to `io` (or to the default output stream [`stdout`](@ref) | ||
9 | if `io` is not given) a canonical (un-decorated) text representation | ||
10 | of values `xs` if there is one, otherwise call [`show`](@ref). | ||
11 | The representation used by `print` includes minimal formatting and tries to | ||
12 | avoid Julia-specific details. | ||
13 | |||
14 | Printing `nothing` is not allowed and throws an error. | ||
15 | |||
16 | # Examples | ||
17 | ```jldoctest | ||
18 | julia> print("Hello World!") | ||
19 | Hello World! | ||
20 | julia> io = IOBuffer(); | ||
21 | |||
22 | julia> print(io, "Hello", ' ', :World!) | ||
23 | |||
24 | julia> String(take!(io)) | ||
25 | "Hello World!" | ||
26 | ``` | ||
27 | """ | ||
28 |
15 (35.71%) samples spent in print
function print(io::IO, x)
1 (100.00%) (ex.), 15 (100.00%) (incl.) when called from print_to_string line 122 |
||
29 | lock(io) | ||
30 | 1 (2.38%) | 1 (2.38%) | try |
31 | 14 (33.33%) |
14 (100.00%)
samples spent calling
show
show(io, x)
|
|
32 | finally | ||
33 | unlock(io) | ||
34 | end | ||
35 | return nothing | ||
36 | end | ||
37 | |||
38 | function print(io::IO, xs...) | ||
39 | lock(io) | ||
40 | try | ||
41 | for x in xs | ||
42 | print(io, x) | ||
43 | end | ||
44 | finally | ||
45 | unlock(io) | ||
46 | end | ||
47 | return nothing | ||
48 | end | ||
49 | |||
50 | """ | ||
51 | println([io::IO], xs...) | ||
52 | |||
53 | Print (using [`print`](@ref)) `xs` followed by a newline. | ||
54 | If `io` is not supplied, prints to [`stdout`](@ref). | ||
55 | |||
56 | # Examples | ||
57 | ```jldoctest | ||
58 | julia> println("Hello, world") | ||
59 | Hello, world | ||
60 | |||
61 | julia> io = IOBuffer(); | ||
62 | |||
63 | julia> println(io, "Hello, world") | ||
64 | |||
65 | julia> String(take!(io)) | ||
66 | "Hello, world\\n" | ||
67 | ``` | ||
68 | """ | ||
69 | println(io::IO, xs...) = print(io, xs..., '\n') | ||
70 | |||
71 | ## conversion of general objects to strings ## | ||
72 | |||
73 | """ | ||
74 | sprint(f::Function, args...; context=nothing, sizehint=0) | ||
75 | |||
76 | Call the given function with an I/O stream and the supplied extra arguments. | ||
77 | Everything written to this I/O stream is returned as a string. | ||
78 | `context` can be either an [`IOContext`](@ref) whose properties will be used, | ||
79 | or a `Pair` specifying a property and its value. `sizehint` suggests the capacity | ||
80 | of the buffer (in bytes). | ||
81 | |||
82 | The optional keyword argument `context` can be set to `:key=>value` pair | ||
83 | or an `IO` or [`IOContext`](@ref) object whose attributes are used for the I/O | ||
84 | stream passed to `f`. The optional `sizehint` is a suggested size (in bytes) | ||
85 | to allocate for the buffer used to write the string. | ||
86 | |||
87 | # Examples | ||
88 | ```jldoctest | ||
89 | julia> sprint(show, 66.66666; context=:compact => true) | ||
90 | "66.6667" | ||
91 | |||
92 | julia> sprint(showerror, BoundsError([1], 100)) | ||
93 | "BoundsError: attempt to access 1-element Array{Int64,1} at index [100]" | ||
94 | ``` | ||
95 | """ | ||
96 | function sprint(f::Function, args...; context=nothing, sizehint::Integer=0) | ||
97 | s = IOBuffer(sizehint=sizehint) | ||
98 | if context !== nothing | ||
99 | f(IOContext(s, context), args...) | ||
100 | else | ||
101 | f(s, args...) | ||
102 | end | ||
103 | String(resize!(s.data, s.size)) | ||
104 | end | ||
105 | |||
106 |
1 (2.38%) samples spent in tostr_sizehint
tostr_sizehint(x) = 8
0 (ex.), 1 (100.00%) (incl.) when called from print_to_string line 117 |
||
107 | 1 (2.38%) |
1 (100.00%)
samples spent calling
lastindex
tostr_sizehint(x::AbstractString) = lastindex(x)
|
|
108 | tostr_sizehint(x::Float64) = 20 | ||
109 | tostr_sizehint(x::Float32) = 12 | ||
110 | |||
111 |
37 (88.10%) samples spent in print_to_string
function print_to_string(xs...)
5 (100.00%) (ex.), 37 (100.00%) (incl.) when called from string line 155 |
||
112 | if isempty(xs) | ||
113 | return "" | ||
114 | end | ||
115 | siz = 0 | ||
116 | for x in xs | ||
117 | 3 (7.14%) | 5 (11.90%) | siz += tostr_sizehint(x) |
118 | end | ||
119 | # specialized for performance reasons | ||
120 | 12 (28.57%) |
12 (100.00%)
samples spent calling
Type
s = IOBuffer(sizehint=siz)
|
|
121 | for x in xs | ||
122 | 2 (4.76%) | 18 (42.86%) | print(s, x) |
123 | end | ||
124 | 2 (4.76%) | String(resize!(s.data, s.size)) | |
125 | end | ||
126 | |||
127 | function string_with_env(env, xs...) | ||
128 | if isempty(xs) | ||
129 | return "" | ||
130 | end | ||
131 | siz = 0 | ||
132 | for x in xs | ||
133 | siz += tostr_sizehint(x) | ||
134 | end | ||
135 | # specialized for performance reasons | ||
136 | s = IOBuffer(sizehint=siz) | ||
137 | env_io = IOContext(s, env) | ||
138 | for x in xs | ||
139 | print(env_io, x) | ||
140 | end | ||
141 | String(resize!(s.data, s.size)) | ||
142 | end | ||
143 | |||
144 | """ | ||
145 | string(xs...) | ||
146 | |||
147 | Create a string from any values, except `nothing`, using the [`print`](@ref) function. | ||
148 | |||
149 | # Examples | ||
150 | ```jldoctest | ||
151 | julia> string("a", 1, true) | ||
152 | "a1true" | ||
153 | ``` | ||
154 | """ | ||
155 | 37 (88.10%) |
37 (100.00%)
samples spent calling
print_to_string
string(xs...) = print_to_string(xs...)
|
|
156 | |||
157 | # note: print uses an encoding determined by `io` (defaults to UTF-8), whereas | ||
158 | # write uses an encoding determined by `s` (UTF-8 for `String`) | ||
159 | print(io::IO, s::AbstractString) = for c in s; print(io, c); end | ||
160 | write(io::IO, s::AbstractString) = (len = 0; for c in s; len += write(io, c); end; len) | ||
161 | show(io::IO, s::AbstractString) = print_quoted(io, s) | ||
162 | |||
163 | # optimized methods to avoid iterating over chars | ||
164 | write(io::IO, s::Union{String,SubString{String}}) = | ||
165 |
1 (2.38%) samples spent in print
GC.@preserve s unsafe_write(io, pointer(s), reinterpret(UInt, sizeof(s)))
0 (ex.), 1 (100.00%) (incl.) when called from print_to_string line 122 |
||
166 | 2 (4.76%) | print(io::IO, s::Union{String,SubString{String}}) = (write(io, s); nothing) | |
167 | |||
168 | ## printing literal quoted string data ## | ||
169 | |||
170 | # this is the inverse of print_unescaped_chars(io, s, "\\\") | ||
171 | |||
172 | function print_quoted_literal(io, s::AbstractString) | ||
173 | print(io, '"') | ||
174 | for c = s; c == '"' ? print(io, "\\\"") : print(io, c); end | ||
175 | print(io, '"') | ||
176 | end | ||
177 | |||
178 | """ | ||
179 | repr(x; context=nothing) | ||
180 | |||
181 | Create a string from any value using the [`show`](@ref) function. | ||
182 | |||
183 | The optional keyword argument `context` can be set to an `IO` or [`IOContext`](@ref) | ||
184 | object whose attributes are used for the I/O stream passed to `show`. | ||
185 | |||
186 | Note that `repr(x)` is usually similar to how the value of `x` would | ||
187 | be entered in Julia. See also [`repr(MIME("text/plain"), x)`](@ref) to instead | ||
188 | return a "pretty-printed" version of `x` designed more for human consumption, | ||
189 | equivalent to the REPL display of `x`. | ||
190 | |||
191 | # Examples | ||
192 | ```jldoctest | ||
193 | julia> repr(1) | ||
194 | "1" | ||
195 | |||
196 | julia> repr(zeros(3)) | ||
197 | "[0.0, 0.0, 0.0]" | ||
198 | |||
199 | julia> repr(big(1/3)) | ||
200 | "3.33333333333333314829616256247390992939472198486328125e-01" | ||
201 | |||
202 | julia> repr(big(1/3), context=:compact => true) | ||
203 | "3.33333e-01" | ||
204 | |||
205 | ``` | ||
206 | """ | ||
207 | repr(x; context=nothing) = sprint(show, x; context=context) | ||
208 | |||
209 | # IOBuffer views of a (byte)string: | ||
210 | |||
211 | """ | ||
212 | IOBuffer(string::String) | ||
213 | |||
214 | Create a read-only `IOBuffer` on the data underlying the given string. | ||
215 | |||
216 | # Examples | ||
217 | ```jldoctest | ||
218 | julia> io = IOBuffer("Haho"); | ||
219 | |||
220 | julia> String(take!(io)) | ||
221 | "Haho" | ||
222 | |||
223 | julia> String(take!(io)) | ||
224 | "Haho" | ||
225 | ``` | ||
226 | """ | ||
227 | IOBuffer(str::String) = IOBuffer(unsafe_wrap(Vector{UInt8}, str)) | ||
228 | IOBuffer(s::SubString{String}) = IOBuffer(view(unsafe_wrap(Vector{UInt8}, s.string), s.offset + 1 : s.offset + sizeof(s))) | ||
229 | |||
230 | # join is implemented using IO | ||
231 | |||
232 | """ | ||
233 | join([io::IO,] strings, delim, [last]) | ||
234 | |||
235 | Join an array of `strings` into a single string, inserting the given delimiter between | ||
236 | adjacent strings. If `last` is given, it will be used instead of `delim` between the last | ||
237 | two strings. If `io` is given, the result is written to `io` rather than returned as | ||
238 | as a `String`. | ||
239 | |||
240 | # Examples | ||
241 | ```jldoctest | ||
242 | julia> join(["apples", "bananas", "pineapples"], ", ", " and ") | ||
243 | "apples, bananas and pineapples" | ||
244 | ``` | ||
245 | |||
246 | `strings` can be any iterable over elements `x` which are convertible to strings | ||
247 | via `print(io::IOBuffer, x)`. `strings` will be printed to `io`. | ||
248 | """ | ||
249 | function join(io::IO, strings, delim, last) | ||
250 | first = true | ||
251 | local prev | ||
252 | for str in strings | ||
253 | if @isdefined prev | ||
254 | first ? (first = false) : print(io, delim) | ||
255 | print(io, prev) | ||
256 | end | ||
257 | prev = str | ||
258 | end | ||
259 | if @isdefined prev | ||
260 | first || print(io, last) | ||
261 | print(io, prev) | ||
262 | end | ||
263 | nothing | ||
264 | end | ||
265 | function join(io::IO, strings, delim="") | ||
266 | # Specialization of the above code when delim==last, | ||
267 | # which lets us emit (compile) less code | ||
268 | first = true | ||
269 | for str in strings | ||
270 | first ? (first = false) : print(io, delim) | ||
271 | print(io, str) | ||
272 | end | ||
273 | end | ||
274 | |||
275 | join(strings) = sprint(join, strings) | ||
276 | join(strings, delim) = sprint(join, strings, delim) | ||
277 | join(strings, delim, last) = sprint(join, strings, delim, last) | ||
278 | |||
279 | ## string escaping & unescaping ## | ||
280 | |||
281 | need_full_hex(c::Union{Nothing, AbstractChar}) = c !== nothing && isxdigit(c) | ||
282 | escape_nul(c::Union{Nothing, AbstractChar}) = | ||
283 | (c !== nothing && '0' <= c <= '7') ? "\\x00" : "\\0" | ||
284 | |||
285 | """ | ||
286 | escape_string(str::AbstractString[, esc])::AbstractString | ||
287 | escape_string(io, str::AbstractString[, esc::])::Nothing | ||
288 | |||
289 | General escaping of traditional C and Unicode escape sequences. The first form returns the | ||
290 | escaped string, the second prints the result to `io`. | ||
291 | |||
292 | Backslashes (`\\`) are escaped with a double-backslash (`"\\\\"`). Non-printable | ||
293 | characters are escaped either with their standard C escape codes, `"\\0"` for NUL (if | ||
294 | unambiguous), unicode code point (`"\\u"` prefix) or hex (`"\\x"` prefix). | ||
295 | |||
296 | The optional `esc` argument specifies any additional characters that should also be | ||
297 | escaped by a prepending backslash (`\"` is also escaped by default in the first form). | ||
298 | |||
299 | # Examples | ||
300 | ```jldoctest | ||
301 | julia> escape_string("aaa\\nbbb") | ||
302 | "aaa\\\\nbbb" | ||
303 | |||
304 | julia> escape_string("\\xfe\\xff") # invalid utf-8 | ||
305 | "\\\\xfe\\\\xff" | ||
306 | |||
307 | julia> escape_string(string('\\u2135','\\0')) # unambiguous | ||
308 | "ℵ\\\\0" | ||
309 | |||
310 | julia> escape_string(string('\\u2135','\\0','0')) # \\0 would be ambiguous | ||
311 | "ℵ\\\\x000" | ||
312 | ``` | ||
313 | |||
314 | ## See also | ||
315 | [`unescape_string`](@ref) for the reverse operation. | ||
316 | """ | ||
317 | function escape_string(io::IO, s::AbstractString, esc="") | ||
318 | a = Iterators.Stateful(s) | ||
319 | for c in a | ||
320 | if c in esc | ||
321 | print(io, '\\', c) | ||
322 | elseif isascii(c) | ||
323 | c == '\0' ? print(io, escape_nul(peek(a))) : | ||
324 | c == '\e' ? print(io, "\\e") : | ||
325 | c == '\\' ? print(io, "\\\\") : | ||
326 | '\a' <= c <= '\r' ? print(io, '\\', "abtnvfr"[Int(c)-6]) : | ||
327 | isprint(c) ? print(io, c) : | ||
328 | print(io, "\\x", string(UInt32(c), base = 16, pad = 2)) | ||
329 | elseif !isoverlong(c) && !ismalformed(c) | ||
330 | isprint(c) ? print(io, c) : | ||
331 | c <= '\x7f' ? print(io, "\\x", string(UInt32(c), base = 16, pad = 2)) : | ||
332 | c <= '\uffff' ? print(io, "\\u", string(UInt32(c), base = 16, pad = need_full_hex(peek(a)) ? 4 : 2)) : | ||
333 | print(io, "\\U", string(UInt32(c), base = 16, pad = need_full_hex(peek(a)) ? 8 : 4)) | ||
334 | else # malformed or overlong | ||
335 | u = bswap(reinterpret(UInt32, c)) | ||
336 | while true | ||
337 | print(io, "\\x", string(u % UInt8, base = 16, pad = 2)) | ||
338 | (u >>= 8) == 0 && break | ||
339 | end | ||
340 | end | ||
341 | end | ||
342 | end | ||
343 | |||
344 | escape_string(s::AbstractString, esc=('\"',)) = sprint(escape_string, s, esc, sizehint=lastindex(s)) | ||
345 | |||
346 | function print_quoted(io, s::AbstractString) | ||
347 | print(io, '"') | ||
348 | escape_string(io, s, ('\"','$')) #"# work around syntax highlighting problem | ||
349 | print(io, '"') | ||
350 | end | ||
351 | |||
352 | # general unescaping of traditional C and Unicode escape sequences | ||
353 | |||
354 | # TODO: handle unescaping invalid UTF-8 sequences | ||
355 | """ | ||
356 | unescape_string(str::AbstractString)::AbstractString | ||
357 | unescape_string(io, str::AbstractString)::Nothing | ||
358 | |||
359 | General unescaping of traditional C and Unicode escape sequences. The first form returns | ||
360 | the escaped string, the second prints the result to `io`. | ||
361 | |||
362 | The following escape sequences are recognised: | ||
363 | - Escaped backslash (`\\\\`) | ||
364 | - Escaped double-quote (`\\\"`) | ||
365 | - Standard C escape sequences (`\\a`, `\\b`, `\\t`, `\\n`, `\\v`, `\\f`, `\\r`, `\\e`) | ||
366 | - Unicode code points (`\\u` or `\\U` prefixes with 1-4 trailing hex digits) | ||
367 | - Hex bytes (`\\x` with 1-2 trailing hex digits) | ||
368 | - Octal bytes (`\\` with 1-3 trailing octal digits) | ||
369 | |||
370 | # Examples | ||
371 | ```jldoctest | ||
372 | julia> unescape_string("aaa\\\\nbbb") # C escape sequence | ||
373 | "aaa\\nbbb" | ||
374 | |||
375 | julia> unescape_string("\\\\u03c0") # unicode | ||
376 | "π" | ||
377 | |||
378 | julia> unescape_string("\\\\101") # octal | ||
379 | "A" | ||
380 | ``` | ||
381 | |||
382 | ## See also | ||
383 | [`escape_string`](@ref). | ||
384 | """ | ||
385 | function unescape_string(io, s::AbstractString) | ||
386 | a = Iterators.Stateful(s) | ||
387 | for c in a | ||
388 | if !isempty(a) && c == '\\' | ||
389 | c = popfirst!(a) | ||
390 | if c == 'x' || c == 'u' || c == 'U' | ||
391 | n = k = 0 | ||
392 | m = c == 'x' ? 2 : | ||
393 | c == 'u' ? 4 : 8 | ||
394 | while (k += 1) <= m && !isempty(a) | ||
395 | nc = peek(a) | ||
396 | n = '0' <= nc <= '9' ? n<<4 + (nc-'0') : | ||
397 | 'a' <= nc <= 'f' ? n<<4 + (nc-'a'+10) : | ||
398 | 'A' <= nc <= 'F' ? n<<4 + (nc-'A'+10) : break | ||
399 | popfirst!(a) | ||
400 | end | ||
401 | if k == 1 || n > 0x10ffff | ||
402 | u = m == 4 ? 'u' : 'U' | ||
403 | throw(ArgumentError("invalid $(m == 2 ? "hex (\\x)" : | ||
404 | "unicode (\\$u)") escape sequence")) | ||
405 | end | ||
406 | if m == 2 # \x escape sequence | ||
407 | write(io, UInt8(n)) | ||
408 | else | ||
409 | print(io, Char(n)) | ||
410 | end | ||
411 | elseif '0' <= c <= '7' | ||
412 | k = 1 | ||
413 | n = c-'0' | ||
414 | while (k += 1) <= 3 && !isempty(a) | ||
415 | c = peek(a) | ||
416 | n = ('0' <= c <= '7') ? n<<3 + c-'0' : break | ||
417 | popfirst!(a) | ||
418 | end | ||
419 | if n > 255 | ||
420 | throw(ArgumentError("octal escape sequence out of range")) | ||
421 | end | ||
422 | write(io, UInt8(n)) | ||
423 | else | ||
424 | print(io, c == 'a' ? '\a' : | ||
425 | c == 'b' ? '\b' : | ||
426 | c == 't' ? '\t' : | ||
427 | c == 'n' ? '\n' : | ||
428 | c == 'v' ? '\v' : | ||
429 | c == 'f' ? '\f' : | ||
430 | c == 'r' ? '\r' : | ||
431 | c == 'e' ? '\e' : | ||
432 | (c == '\\' || c == '"') ? c : | ||
433 | throw(ArgumentError("invalid escape sequence \\$c"))) | ||
434 | end | ||
435 | else | ||
436 | print(io, c) | ||
437 | end | ||
438 | end | ||
439 | end | ||
440 | unescape_string(s::AbstractString) = sprint(unescape_string, s, sizehint=lastindex(s)) | ||
441 | |||
442 | |||
443 | macro b_str(s) | ||
444 | v = codeunits(unescape_string(s)) | ||
445 | QuoteNode(v) | ||
446 | end | ||
447 | |||
448 | """ | ||
449 | @raw_str -> String | ||
450 | |||
451 | Create a raw string without interpolation and unescaping. | ||
452 | The exception is that quotation marks still must be escaped. Backslashes | ||
453 | escape both quotation marks and other backslashes, but only when a sequence | ||
454 | of backslashes precedes a quote character. Thus, 2n backslashes followed by | ||
455 | a quote encodes n backslashes and the end of the literal while 2n+1 backslashes | ||
456 | followed by a quote encodes n backslashes followed by a quote character. | ||
457 | |||
458 | # Examples | ||
459 | ```jldoctest | ||
460 | julia> println(raw"\\ \$x") | ||
461 | \\ \$x | ||
462 | |||
463 | julia> println(raw"\\"") | ||
464 | " | ||
465 | |||
466 | julia> println(raw"\\\\\\"") | ||
467 | \\" | ||
468 | |||
469 | julia> println(raw"\\\\x \\\\\\"") | ||
470 | \\\\x \\" | ||
471 | ``` | ||
472 | """ | ||
473 | macro raw_str(s); s; end | ||
474 | |||
475 | ## multiline strings ## | ||
476 | |||
477 | """ | ||
478 | indentation(str::AbstractString; tabwidth=8) -> (Int, Bool) | ||
479 | |||
480 | Calculate the width of leading white space. Return the width and a flag to indicate | ||
481 | if the string is empty. | ||
482 | |||
483 | # Examples | ||
484 | ```jldoctest | ||
485 | julia> Base.indentation("") | ||
486 | (0, true) | ||
487 | |||
488 | julia> Base.indentation(" a") | ||
489 | (2, false) | ||
490 | |||
491 | julia> Base.indentation("\\ta"; tabwidth=3) | ||
492 | (3, false) | ||
493 | ``` | ||
494 | """ | ||
495 | function indentation(str::AbstractString; tabwidth=8) | ||
496 | count = 0 | ||
497 | for ch in str | ||
498 | if ch == ' ' | ||
499 | count += 1 | ||
500 | elseif ch == '\t' | ||
501 | count = div(count + tabwidth, tabwidth) * tabwidth | ||
502 | else | ||
503 | return count, false | ||
504 | end | ||
505 | end | ||
506 | count, true | ||
507 | end | ||
508 | |||
509 | """ | ||
510 | unindent(str::AbstractString, indent::Int; tabwidth=8) | ||
511 | |||
512 | Remove leading indentation from string. | ||
513 | |||
514 | # Examples | ||
515 | ```jldoctest | ||
516 | julia> Base.unindent(" a\\n b", 2) | ||
517 | " a\\n b" | ||
518 | |||
519 | julia> Base.unindent("\\ta\\n\\tb", 2, tabwidth=8) | ||
520 | " a\\n b" | ||
521 | ``` | ||
522 | """ | ||
523 | function unindent(str::AbstractString, indent::Int; tabwidth=8) | ||
524 | indent == 0 && return str | ||
525 | # Note: this loses the type of the original string | ||
526 | buf = IOBuffer(sizehint=sizeof(str)) | ||
527 | cutting = true | ||
528 | col = 0 # current column (0 based) | ||
529 | for ch in str | ||
530 | if cutting | ||
531 | if ch == ' ' | ||
532 | col += 1 | ||
533 | elseif ch == '\t' | ||
534 | col = div(col + tabwidth, tabwidth) * tabwidth | ||
535 | elseif ch == '\n' | ||
536 | # Now we need to output enough indentation | ||
537 | for i = 1:col-indent | ||
538 | print(buf, ' ') | ||
539 | end | ||
540 | col = 0 | ||
541 | print(buf, '\n') | ||
542 | else | ||
543 | cutting = false | ||
544 | # Now we need to output enough indentation to get to | ||
545 | # correct place | ||
546 | for i = 1:col-indent | ||
547 | print(buf, ' ') | ||
548 | end | ||
549 | col += 1 | ||
550 | print(buf, ch) | ||
551 | end | ||
552 | elseif ch == '\t' # Handle internal tabs | ||
553 | upd = div(col + tabwidth, tabwidth) * tabwidth | ||
554 | # output the number of spaces that would have been seen | ||
555 | # with original indentation | ||
556 | for i = 1:(upd-col) | ||
557 | print(buf, ' ') | ||
558 | end | ||
559 | col = upd | ||
560 | elseif ch == '\n' | ||
561 | cutting = true | ||
562 | col = 0 | ||
563 | print(buf, '\n') | ||
564 | else | ||
565 | col += 1 | ||
566 | print(buf, ch) | ||
567 | end | ||
568 | end | ||
569 | # If we were still "cutting" when we hit the end of the string, | ||
570 | # we need to output the right number of spaces for the indentation | ||
571 | if cutting | ||
572 | for i = 1:col-indent | ||
573 | print(buf, ' ') | ||
574 | end | ||
575 | end | ||
576 | String(take!(buf)) | ||
577 | end | ||
578 | |||
579 | function String(chars::AbstractVector{<:AbstractChar}) | ||
580 | sprint(sizehint=length(chars)) do io | ||
581 | for c in chars | ||
582 | print(io, c) | ||
583 | end | ||
584 | end | ||
585 | end |