@@ -1203,3 +1203,233 @@ Notice that the first two backslashes appear verbatim in the output, since they
1203
1203
precede a quote character.
1204
1204
However, the next backslash character escapes the backslash that follows it, and the
1205
1205
last backslash escapes a quote, since these backslashes appear before a quote.
1206
+
1207
+ ## [ Styling] (@id man-styling)
1208
+
1209
+ When working with strings, formatting and styling often appear as a secondary
1210
+ concern.
1211
+
1212
+ !!! note
1213
+ For instance, when printing to a terminal you might want to sprinkle [ ANSI
1214
+ escape
1215
+ sequences] ( https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters )
1216
+ in the output, when outputting HTML styling constructs (` <span style="..."> ` ,
1217
+ etc.) serve a similar purpose, and so on. It is possible to simply insert the
1218
+ raw styling constructs into the string next to the content itself, but it
1219
+ quickly becomes apparent that this is not well suited for anything but the most
1220
+ basic use-cases. Not all terminals support the same ANSI codes, the styling
1221
+ constructs need to be painstakingly removed when calculating the width of
1222
+ already-styled content, and that's before you even get into handling
1223
+ multiple output formats.
1224
+
1225
+ Instead of leaving this headache to be widely experienced downstream, it is
1226
+ tackled head-on by the introduction of a special string type
1227
+ ([ ` StyledString ` ] ( @ref ) ). This string type wraps any other string type and
1228
+ allows for formating information to be applied to regions (e.g. characters 1
1229
+ through to 7 are bold and red).
1230
+
1231
+ Regions of a string are styled by applying [ ` Face ` ] ( @ref ) s to them —a
1232
+ structure that holds styling information— (think "typeface"). As a
1233
+ convenience, it is possible to name a face in the global faces dictionary
1234
+ instead of giving the [ ` Face ` ] ( @ref ) directly.
1235
+
1236
+ Along with these capabilities, we also provide a convenient way for constructing
1237
+ [ ` StyledString ` ] ( @ref ) s, detailed in [ Styled String Literals] (@ref man-styled-string-literals).
1238
+
1239
+ ``` jldoctest
1240
+ julia> S"{yellow:hello} {blue:there}"
1241
+ "hello there" # prints with colour in the REPL
1242
+ ```
1243
+
1244
+ ### [ Styled Strings] (@id man-styled-strings)
1245
+
1246
+ [ ` StyledString ` ] ( @ref ) s wrap another string and overlay a list of tagged
1247
+ regions. All generic string operations are applied to the underlying string.
1248
+ When possible though, styling information is maintained (e.g. when
1249
+ [ ` split ` ] ( @ref ) ting a [ ` StyledString ` ] ( @ref ) ).
1250
+
1251
+ To concatenate printable values and styled strings together (maintaining styling
1252
+ information), the [ ` styledstring ` ] ( @ref ) function can be used (as a counterpart
1253
+ to [ ` string ` ] ( @ref ) ).
1254
+
1255
+ ``` jldoctest
1256
+ julia> str = StyledString("hello there",
1257
+ [(1:5, :face => :yellow), (7:11, :face => :blue)])
1258
+ "hello there"
1259
+
1260
+ julia> collect(Base.eachstyle(str))
1261
+ 3-element Vector{Tuple{SubString{String}, Vector{Pair{Symbol, Any}}}}:
1262
+ ("hello", [:face => :yellow])
1263
+ (" ", [])
1264
+ ("there", [:face => :blue])
1265
+
1266
+ julia> length(str)
1267
+ 11
1268
+
1269
+ julia> lpad(str, 14)
1270
+ " hello there"
1271
+
1272
+ julia> typeof(lpad(str, 7))
1273
+ StyledString{String}
1274
+
1275
+ julia> str2 = StyledString(" julia", [(2:6, :face => :magenta)])
1276
+
1277
+ julia> styledstring(str, str2)
1278
+ "hello there julia"
1279
+
1280
+ julia> str * str2 == styledstring(str, str2) # *-concatination still works
1281
+ true
1282
+
1283
+ julia> collect(Base.eachstyle(str * str2))
1284
+ 5-element Vector{Tuple{SubString{String}, Vector{Pair{Symbol, Any}}}}:
1285
+ ("hello", [:face => :yellow])
1286
+ (" ", [])
1287
+ ("there", [:face => :blue])
1288
+ (" ", [])
1289
+ ("julia", [:face => :magenta])
1290
+ ```
1291
+
1292
+ #### Advanced uses
1293
+
1294
+ While styling is the focus here, the system is actually more general. It allows
1295
+ for arbitrary annotations to be added to regions of the underlying string. Each
1296
+ annotation is in the form of a ` tag::Symbol => value::Any ` tagged value. You can
1297
+ tag any information you want, such as source location the string was extracted
1298
+ from, or an alternative form of some text, but the most obvious use case is to
1299
+ hold styling information (which use a ` :face ` tag).
1300
+
1301
+ ### [ Faces] (@id man-faces)
1302
+
1303
+ #### The ` Face ` type
1304
+
1305
+ A [ ` Face ` ] ( @ref ) specifies details of a typeface that text can be set in. It
1306
+ covers a set of basic attributes that generalise well across different formats,
1307
+ namely:
1308
+
1309
+ - ` height `
1310
+ - ` weight `
1311
+ - ` slant `
1312
+ - ` foreground `
1313
+ - ` background `
1314
+ - ` underline `
1315
+ - ` strikethrough `
1316
+ - ` inverse `
1317
+ - ` inherit `
1318
+
1319
+ For details on the particular forms these attributes take, see the
1320
+ [ ` Face ` ] ( @ref ) docstring, but of particular interest is ` inherit ` as it allows
1321
+ you to _ inherit_ attributes from other [ ` Face ` ] ( @ref ) s.
1322
+
1323
+ #### The global ` FACES ` dictionary
1324
+
1325
+ To make referring to particular styles more convenient, there is a global
1326
+ ` Dict{Symbol, Face} ` that allows for [ ` Face ` ] ( @ref ) s to be referred to simply by
1327
+ name. Packages can add faces to this dictionary via the [ ` Base.addface! ` ] ( @ref )
1328
+ function, and the loaded faces can be easily [ customised] (@ref man-face-toml).
1329
+
1330
+ !!! warning
1331
+ Any package registering new faces should ensure that they are prefixed
1332
+ by the package name, i.e. follow the format ` mypackage_myface ` .
1333
+ This is important for predictability, and to prevent name clashes.
1334
+
1335
+ There is one set of exemptions to the package-prefix rule, the set of basic
1336
+ faces that are part of the default value of the faces dictionary.
1337
+
1338
+ ##### [ Basic faces] (@id man-basic-faces)
1339
+
1340
+ Basic faces are intended represent a general idea, that is widely applicable.
1341
+
1342
+ For setting some text with a certain attribute, we have the ` bold ` , ` italic ` ,
1343
+ ` underline ` , ` strikethrough ` , and ` inverse ` faces.
1344
+
1345
+ There are also named faces for the 16 terminal colours: ` black ` , ` red ` , ` green ` ,
1346
+ ` yellow ` , ` blue ` , ` magenta ` , ` cyan ` , ` white ` , ` bright_black ` /` grey ` /` gray ` ,
1347
+ ` bright_red ` , ` bright_green ` , ` bright_blue ` , ` bright_magenta ` , ` bright_cyan ` ,
1348
+ and ` bright_white ` .
1349
+
1350
+ For shadowed text (i.e. dim but there) there is the ` shadow ` face. To indicate a
1351
+ selected region, there is the ` region ` face. Similarly for emphasis and
1352
+ highlighting the ` emphasis ` and ` highlight ` faces are defined. There is also
1353
+ ` code ` for code-like text.
1354
+
1355
+ For visually indicating the severity of messages the ` error ` , ` warning ` ,
1356
+ ` success ` , ` info ` , ` note ` , and ` tip ` faces are defined.
1357
+
1358
+ #### [ Customisation of faces (` Faces.toml ` )] (@id man-face-toml)
1359
+
1360
+ It is good for the name faces in the global face dictionary to be customizable.
1361
+ Theming and aesthetics are nice, and it is important for accessibility reasons
1362
+ too. A TOML file can be parsed into a list of [ ` Face ` ] ( @ref ) specifications that
1363
+ are merged with the pre-existing entry in the face dictionary.
1364
+
1365
+ A [ ` Face ` ] ( @ref ) is represented in TOML like so:
1366
+
1367
+ ``` toml
1368
+ [facename ]
1369
+ attribute = " value"
1370
+ ...
1371
+
1372
+ [package .facename ]
1373
+ attribute = " value"
1374
+ ```
1375
+
1376
+ For example, if the ` shadow ` face is too hard to read it can be made brighter
1377
+ like so:
1378
+
1379
+ ``` toml
1380
+ [shadow ]
1381
+ foreground = " white"
1382
+ ```
1383
+
1384
+ #### Applying faces to a ` StyledString `
1385
+
1386
+ By convention, the ` :face ` attributes of a [ ` StyledString ` ] ( @ref ) hold
1387
+ information on the [ ` Face ` ] ( @ref ) s that currently apply. This can be given in
1388
+ multiple forms, as a single ` Symbol ` naming a [ ` Face ` ] ( @ref ) s in the global face
1389
+ dictionary, a [ ` Face ` ] ( @ref ) itself, or a vector of either.
1390
+
1391
+ The ` show(::IO, ::MIME"text/plain", ::StyledString) ` and `show(::IO,
1392
+ ::MIME"text/html", ::StyledString)` methods both look at the ` : face ` attributes
1393
+ and merge them all together when determining the overall styling.
1394
+
1395
+ We can supply ` :face ` attributes to a ` StyledString ` during construction, add
1396
+ them to the properties list afterwards, or use the convenient [ Styled String
1397
+ literals] (@ref man-styled-string-literals).
1398
+
1399
+ ``` jldoctest
1400
+ julia> str1 = StyledString("blue text", [(1:9, :face => Face(foreground=:blue))])
1401
+ "blue text"
1402
+
1403
+ julia> str2 = StyledString("blue text", :face => Face(foreground=:blue))
1404
+ "blue text"
1405
+
1406
+ julia> str1 == str2
1407
+ true
1408
+
1409
+ julia> sprint(show, MIME("text/plain"), str1, context = :color => true)
1410
+ "\"\e[34mblue text\e[39m\""
1411
+
1412
+ julia> sprint(show, MIME("text/html"), str1, context = :color => true)
1413
+ "<pre><span style=\"color: #000080;\">blue text</span></pre>"
1414
+ ```
1415
+
1416
+ ## [ Styled String Literals] (@id man-styled-string-literals)
1417
+
1418
+ To ease construction of [ ` StyledString ` ] ( @ref ) s with [ ` Face ` ] ( @ref ) s applied,
1419
+ the [ ` S"..." ` ] (@ref @S_str) styled string literal allows for the content and
1420
+ attributes to be easily expressed together via a custom grammar.
1421
+
1422
+ Within a [ ` S"..." ` ] (@ref @S_str) literal, curly parenthesis are considered
1423
+ special characters and must be escaped in normal usage (` \{ ` , ` \} ` ). This allows
1424
+ them to be used to express annotations with (nestable) ` {annotations...:text} `
1425
+ constructs.
1426
+
1427
+ The ` annotations... ` component is a comma-separated list of three types of annotations.
1428
+ - Face names
1429
+ - Inline ` Face ` expressions ` (key=val,...) `
1430
+ - ` key=value ` pairs
1431
+
1432
+ Interpolation is possible everywhere except for inline face keys.
1433
+
1434
+ For more information on the grammar, see the extended help of the
1435
+ [ ` S"..." ` ] (@ref @S_str) docstring.
0 commit comments