Nothing
## Copyright (C) Brodie Gaslam
##
## This file is part of "fansi - ANSI Control Sequence Aware String Functions"
##
## This program is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 2 or 3 of the License.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## Go to <https://www.r-project.org/Licenses> for copies of the licenses.
library(fansi)
unitizer_sect("Simple", {
str01 <- sprintf("hello %sworld%s how", red, inv);
substr_ctl(str01, 1, 7)
substr_ctl(str01, 7, 11)
substr_ctl(str01, 8, 10)
substr_ctl(str01, 8, 14)
str02 <- sprintf(
"%shello world %sit's a %scrazy world%s out there %sisn't it%s%s right?",
grn.bg, red, end, rgb.und, inv, end, rgb.256
)
# enable truecolor as not enabled by default
term.cap <- c('bright', '256', 'truecolor')
substr_ctl(str02, 1, 7)
substr_ctl(str02, 10, 20)
substr_ctl(str02, 15, 40, term.cap=term.cap)
substr_ctl(str02, 35, 60, term.cap=term.cap)
str03 <-sprintf("hello %sworld", rgb.und)
substr_ctl(str03, 1, 12, term.cap=term.cap)
str04 <- sprintf("hello%s%s world%s%s yowza", red, inv, grn.bg, rgb.und)
substr_ctl(str04, 5, 7, term.cap=term.cap)
substr_ctl(str04, 5, 13, term.cap=term.cap)
})
unitizer_sect("Multi-line", {
str.m.0 <- paste0(
"\033[44m",
c("hello world", rep("goodbye \033[45mmoon", 2), "yowza bombastic"),
"\033[m"
)
substr_ctl(str.m.0, (1:4) * 2, (3:8) * 2)
})
unitizer_sect("tabs", {
substr2_ctl("yo\tworld", 1, 8, tabs.as.spaces=TRUE)
})
unitizer_sect("Corner cases", {
substr_ctl("hello", 0, -1)
substr_ctl("hello", 0, 0)
substr_ctl(rep("hello", 2), c(1, 0), c(1, 1))
substr_ctl(character(), 1, 1)
substr_ctl(list("hello", list("goodbye", "there")), 1, 2)
substr_ctl(structure(list(list("goodbye", "there")), class="foo"), 1, 2)
str.0 <- "\033[31mred\033[m"
str.1 <- "\033[31mred\033[42m"
str.2 <- c(str.0, str.1)
substr_ctl(str.2, 0, 0)
substr_ctl(str.2, 1, 1)
substr_ctl(str.2, 3, 3)
substr_ctl(str.2, 4, 4)
substr_ctl(str.2, 3, 4)
substr_ctl(str.2, 3, 5)
substr_ctl(str.2, 3, 4, terminate=FALSE)
substr_ctl(str.2, 3, 5, terminate=FALSE)
substr_ctl(str.2, -1, 2)
substr_ctl(str.2, -2, -1)
substr_ctl(str.2, 4, 1)
substr_ctl(str.2, 4, 1, terminate=FALSE)
substr_ctl(str.2, 4, 1, carry="\033[44m")
substr_ctl(str.2, 4, 1, carry="\033[44m", terminate=FALSE)
substr_ctl("hello", 5, 5)
substr_ctl("hello", 6, 6)
substr_ctl("hello", 7, 6)
substr_ctl("hello", 6, 7)
substr_ctl("hello", 7, 5)
substr_ctl("hello", 0, 6)
substr_ctl("hello", 0, 5)
substr_ctl("hello", 1, 6)
substr_ctl("hello", "1", 1)
substr_ctl("hello", 1, "1")
substr_ctl("hello", "a", "b")
substr_ctl("hello", 1, NA_integer_)
substr_ctl("hello", NA_integer_, 1)
# Nested
substr_ctl(rep("\033[31mhello\033[m", 3), c(3,2,1), c(3,4,5))
# Preserve attributes
str.3 <- structure("fu\033[42mba\033[0mr", class="foo", at="bar")
substr_ctl(str.3, 2, 3)
# Turn off sgr
substr_ctl(str.2, 2, 6, ctl=c('all', 'sgr'))
substr_ctl(str.2, 8, 10, ctl=c('all', 'sgr'))
# Make sure things stay in order
substr2_ctl(rep("o\033[31m ", 2), 1:2, 1:2)
# bad sequence at beginning or end
substr_ctl("hello\033[41b", 1, 5)
substr_ctl("hello\033[41b", 1, 6)
substr_ctl("\033[1p\033[31mA", 1, 1)
substr_ctl("\033[1p\033[31mA", 0, 1)
substr_ctl("\033[1p\033[31mA", -1, 1)
# Good/bad sequence at beginning
substr_ctl("\033[31m\033[1pA", 1, 1)
substr_ctl("\033[31m\033[1pA", 0, 1)
substr_ctl("\033[31m\033[1pA", -1, 1)
# Good good (test re-emission)
substr_ctl("\033[41m\033[1mA", 1, 1)
substr_ctl("\033[41m\033[1mA", 0, 1)
substr_ctl("\033[41m\033[1mA", -1, 1)
# Re-issue when state change out of substring
str.4 <- c("A\033[45mB", "A")
substr_ctl(str.4, 1, 1, carry=TRUE, terminate=FALSE)
# Incomplete sequences
substr_ctl("a\033[42", 1, 1)
substr_ctl("a\033[42", 1, 2)
substr_ctl("a\033[42", 1, 2, terminate=FALSE)
substr_ctl("a\033]8;;END", 1, 1)
# Incomplete, but we know it's a URL, so we remove it even if past end
substr_ctl("a\033]8;;END", 1, 2)
# But leave it if not terminating
substr_ctl("a\033]8;;END", 1, 2, terminate=FALSE)
substr_ctl("a\033];;END", 1, 1)
substr_ctl("a\033];;END", 1, 2)
substr_ctl("a\033[38;5mb", 1, 2, term.cap="all")
substr_ctl("a\033[38;2mb", 1, 2, term.cap="all")
substr_ctl("a\033[38;2;255mb", 1, 2, term.cap="all")
substr_ctl("a\033[38;2;255;255mb", 1, 2, term.cap="all")
# Select leading controls
substr_ctl("\033[45pA", 1, 1, warn=FALSE)
substr_ctl("\033[45pA", 0, 1, warn=FALSE)
# NA handling
substr_ctl(c("AB", NA, "CD"), 1, 2)
substr_ctl(c("AB", NA, "CD"), 1, 2, carry=TRUE)
substr_ctl(c("AB", "CD"), c(NA, 1), 2)
substr_ctl(c("AB", "CD"), c(NA, 1), 2, carry=TRUE)
# Old vs new term.cap behavior (almost certainly captured already, but adding
# specific tests).
substr_ctl("\033[38;5;4mA", 1, 1, term.cap="bright")
substr_ctl("\033[38;5;4mA", 1, 1, term.cap=c("bright", "old"))
substr_ctl("\033[38;5;4mA", 1, 1, term.cap=c("all", "256"))
substr_ctl("\033[38;5;4mA", 1, 1, term.cap=c("all", "256", "old"))
substr_ctl("\033[38;5;4mA", 1, 1, term.cap=c("256"))
substr_ctl("\033[38;5;4mA", 1, 1, term.cap=c("256", "old"))
substr_ctl("\033[38;2;1;1;1mA", 1, 1, term.cap="bright")
substr_ctl("\033[38;2;1;1;1mA", 1, 1, term.cap=c("bright", "old"))
substr_ctl("\033[38;2;1;1;1mA", 1, 1, term.cap=c("all", "truecolor"))
substr_ctl("\033[38;2;1;1;1mA", 1, 1, term.cap=c("all", "truecolor", "old"))
substr_ctl("\033[38;2;1;1;1mA", 1, 1, term.cap=c("truecolor"))
substr_ctl("\033[38;2;1;1;1mA", 1, 1, term.cap=c("truecolor", "old"))
substr_ctl("\033[107mA", 1, 1, term.cap="256")
substr_ctl("\033[107mA", 1, 1, term.cap=c("256", "old"))
substr_ctl("\033[107mA", 1, 1, term.cap=c("all", "bright"))
substr_ctl("\033[107mA", 1, 1, term.cap=c("all", "bright", "old"))
substr_ctl("\033[107mA", 1, 1, term.cap=c("bright"))
substr_ctl("\033[107mA", 1, 1, term.cap=c("bright", "old"))
# Detect changes in last truecolor byte
str.5 <- c("\033[48;2;100;100;100mAB", "\033[48;2;100;100;100mCD")
substr_ctl(str.5, 2, 2, terminate=FALSE, carry=TRUE, term.cap="all")
str.5a <- c("\033[48;2;100;100;100mAB", "\033[48;2;100;100;101mCD")
substr_ctl(str.5a, 2, 2, terminate=FALSE, carry=TRUE, term.cap="all")
})
unitizer_sect("Obscure escapes", {
# illegal 38/48
tryCatch(
substr_ctl("\033[38;6;31mworld\033[m", 2, 3),
warning=conditionMessage
)
suppressWarnings(substr_ctl("\033[38;6;31mworld\033[m", 2, 3))
# illegal colors leave prior color unchanged
tryCatch(
substr_ctl("\033[31mhello\033[38;5;256m world\033[m", 7, 8),
warning=conditionMessage
)
suppressWarnings(substr_ctl("\033[31mhello\033[38;5;256m world\033[m", 7, 8))
# fraktur and double underline and prop spacing, and other odd ones
substr_ctl("\033[20mworld\033[m", 2, 3)
substr_ctl("\033[21mworld\033[m", 2, 3)
substr_ctl(rep("\033[26mhello \033[50mworld\033[m", 2), c(2, 8), c(3, 10))
substr_ctl(rep("\033[61mwor\033[65mld\033[m", 2), c(2, 4), c(3, 5))
# unknown tokens
tryCatch(
substr_ctl("\033[56mworld\033[m", 2, 3),
warning=conditionMessage
)
suppressWarnings(substr_ctl("\033[56mworld\033[m", 2, 3))
tryCatch(
substr_ctl("\033[66mworld\033[m", 2, 3),
warning=conditionMessage
)
tryCatch(
substr_ctl("\033[200mworld\033[m", 2, 3),
warning=conditionMessage
)
# bright colors
substr_ctl(rep("\033[91mwor\033[101mld\033[m", 2), c(2, 4), c(3, 5))
})
unitizer_sect('bad args', {
# bad args
hello2.0 <- "\033[42m\thello world\033[m foobar"
substr2_ctl(hello2.0, 1, 2, warn=NULL)
substr2_ctl(hello2.0, 1, 2, tabs.as.spaces=1)
substr2_ctl(hello2.0, 1, 2, tabs.as.spaces=NA)
substr2_ctl(hello2.0, 1, 2, tab.stops=-(1:3))
substr2_ctl(hello2.0, 1, 2, tab.stops=0)
substr2_ctl(hello2.0, 1, 2, round='bananas')
substr2_ctl(hello2.0, 1, 2, term.cap=0)
substr2_ctl(hello2.0, 1, 2, term.cap='bananas')
substr2_ctl(hello2.0, 1, 2, type='bananas')
substr2_ctl(hello2.0, 1, 2, ctl='bananas')
substr2_ctl(hello2.0, 1, 2, ctl=0)
})
unitizer_sect('`ctl` related issues', {
# Make sure SGR end properly detected
substr_sgr("\033[31;42mhello world", 2, 4)
# Repeated SGR
substr_sgr("\033[31m\033[42mhello world", 2, 4)
# Intermediate byte (this is not an SGR!); tryCatch due to inconsistency
# on whether call is included in condition message
tryCatch(
substr_sgr("\033[31;42!mhello world", 2, 4),
warning=function(x) conditionMessage(x)
)
# non-SGR CSI mixed with SGR when not parsing non-SGR CSI
substr_sgr("\033[55;38l\033[31mhello world", 2, 4, warn=FALSE)
substr_sgr("\033[31m\033[55;38lhello world", 2, 4, warn=FALSE)
substr_sgr("hello \033[31m\033[55;38lworld", 7, 9, warn=FALSE)
# Mix of escapes
substr_ctl("\033[55;38l\033[31mhello world", 2, 4, warn=FALSE)
substr_ctl("\033[31m\033[55;38lhello world", 2, 4, warn=FALSE)
substr_ctl("hello \033[31m\033[55;38lworld", 7, 9, warn=FALSE)
substr_ctl("hello\033[55;38l \033[31mworld", 4, 7, warn=FALSE)
# C0 / nl
substr_sgr("ab\n\tcd\n", 3, 6, warn=FALSE)
substr_sgr("ab\n\033[31m\tcd\n", 3, 6, warn=FALSE)
substr_ctl("ab\n\033[31m\tcd\n", 3, 6, warn=FALSE, ctl=c('all', 'nl'))
substr_ctl("ab\n\033[31m\tcd\n", 3, 6, warn=FALSE, ctl=c('all', 'nl', 'c0'))
# Index reporting
substr_sgr(c("\a", "b", "c"), 1, 1)
substr_sgr(c("a", "\b", "c"), 1, 1)
substr_sgr(c("a", "b", "\ac"), 1, 1)
})
unitizer_sect("Rep Funs - Equivalence", {
txt0 <- "ABCD"
## Basic equivalence
identical(`substr_ctl<-`(txt0, 2, 2, value="#"), `substr<-`(txt0, 2, 2, "#"))
identical(`substr_ctl<-`(txt0, 2, 2, value="#?"), `substr<-`(txt0, 2, 2, "#?"))
identical(`substr_ctl<-`(txt0, 2, 3, value="#?-"), `substr<-`(txt0, 2, 3, "#?-"))
identical(`substr_ctl<-`(txt0, 0, 0, value="#"), `substr<-`(txt0, 0, 0, "#"))
identical(`substr_ctl<-`(txt0, 2, 1, value="#"), `substr<-`(txt0, 2, 1, "#"))
identical(`substr_ctl<-`(txt0, 10, 12, value="#"), `substr<-`(txt0, 10, 12, "#"))
identical(`substr_ctl<-`(txt0, 2, 3, value="#"), `substr<-`(txt0, 2, 3, "#"))
identical(`substr_ctl<-`(txt0, 1, 5, value="#"), `substr<-`(txt0, 1, 5, "#"))
identical(`substr_ctl<-`(txt0, 0, 5, value="#"), `substr<-`(txt0, 0, 5, "#"))
## Bug in R means we can't use identical
`substr_ctl<-`(txt0, 0, -1, value="#")
## Recycling
rep1 <- c("_", "_.")
rep2 <- c("_", "_.", "...")
identical(`substr_ctl<-`(txt0, 2, 3, value=rep1), `substr<-`(txt0, 2, 3, rep1))
identical(`substr_ctl<-`(txt0, 2, 3, value=rep2), `substr<-`(txt0, 2, 3, rep2))
txt1 <- c("AB", "CDE")
identical(`substr_ctl<-`(txt1, 2, 3, value='_'), `substr<-`(txt1, 2, 3, '_'))
identical(`substr_ctl<-`(txt1, 2, 3, value=rep1), `substr<-`(txt1, 2, 3, rep1))
identical(`substr_ctl<-`(txt1, 2, 3, value=rep2), `substr<-`(txt1, 2, 3, rep2))
txt2 <- c("AB", "CDE", "EFGH")
identical(`substr_ctl<-`(txt2, 2, 3, value='_'), `substr<-`(txt2, 2, 3, '_'))
identical(`substr_ctl<-`(txt2, 2, 3, value=rep1), `substr<-`(txt2, 2, 3, rep1))
identical(`substr_ctl<-`(txt2, 2, 3, value=rep2), `substr<-`(txt2, 2, 3, rep2))
txt3a <- txt3b <- c("ABC", "ABC")
substr(txt3a[2], 2, 2) <- "_"
substr_ctl(txt3b[2], 2, 2) <- "_"
identical(txt3a, txt3b)
## NA handling
identical(
`substr_ctl<-`(txt0, 2, 3, value=NA_character_),
`substr<-`(txt0, 2, 3, NA_character_)
)
txt.na <- NA_character_
identical(`substr_ctl<-`(txt.na, 1, 2, value="AB"),`substr<-`(txt.na, 1, 2, "AB"))
})
unitizer_sect("Rep Funs - SGR", {
txt1 <- "\033[33mABCD"
txt2 <- "\033[33mA\033[44mBCD"
txt3 <- "\033[33mA\033[44mBC\033[1mD"
`substr_ctl<-`(txt1, 2, 2, value="#")
`substr_ctl<-`(txt1, 2, 3, value="#?-")
`substr_ctl<-`(txt1, 2, 3, value="#\033[32m?-")
`substr_ctl<-`(txt1, 2, 3, value="#\033[32m?-\033[0m")
`substr_ctl<-`(txt1, 2, 3, value="#\033[0m?-")
`substr_ctl<-`(txt2, 2, 3, value="#\033[32m?-")
`substr_ctl<-`(txt2, 2, 3, value="#\033[32m?-\033[0m")
`substr_ctl<-`(txt2, 2, 3, value="#\033[0m?-")
`substr_ctl<-`(txt3, 2, 3, value="#\033[32m?-")
`substr_ctl<-`(txt3, 2, 3, value="#\033[32m?-\033[0m")
`substr_ctl<-`(txt3, 2, 3, value="#\033[0m?-")
## Terminate
`substr_ctl<-`(txt2, 2, 2, terminate=FALSE, value="#")
`substr_ctl<-`(txt2, 2, 3, terminate=FALSE, value="#\033[32m?-")
`substr_ctl<-`(txt2, 2, 3, terminate=FALSE, value="#\033[32m?-\033[0m")
`substr_ctl<-`(txt2, 2, 3, terminate=FALSE, value="#\033[0m?-")
`substr_ctl<-`(txt1, 2, 3, terminate=FALSE, value="#\033[0m?\033[45m-")
`substr_ctl<-`(txt1, 2, 3, terminate=FALSE, value="#\033[0m\033[45m?-")
txt4 <- c(txt2, txt0, "\033[39mABCD")
## Different lengths
`substr_ctl<-`(txt4, 2, 3, value="#")
`substr_ctl<-`(txt4, 2, 3, value=c("#", "?"))
`substr_ctl<-`(txt4, 2, 3, value=c("#", "?", "$"))
## Lengths + Carry; note sequences in middle of `value` boundary are treated
## differently than on the ends.
`substr_ctl<-`(txt4, 2, 2, carry=TRUE, value="#")
`substr_ctl<-`(txt4, 2, 3, carry=TRUE, value="#\033[32m?-")
`substr_ctl<-`(txt4, 2, 3, carry=TRUE, value="#\033[42m?-\033[0m")
`substr_ctl<-`(txt4, 2, 3, carry=TRUE, value="#\033[0m?-")
## Weirdness here because the 39 in `value` causes re-issue of 45. This is
## correct; a consequence of the mess of termintate=FALSE in replace mode.
rep4 <- c("\033[32m_\033[45m", ".-", "\033[39m__")
`substr_ctl<-`(txt4, 2, 3, carry=TRUE, value=rep4)
## Lengths + Terminate + Carry
`substr_ctl<-`(txt4, 2, 2, terminate=FALSE, carry=TRUE, value="#")
`substr_ctl<-`(txt4, 2, 3, terminate=FALSE, carry=TRUE, value="#\033[32m?-")
`substr_ctl<-`(txt4, 2, 3, terminate=FALSE, carry=TRUE, value="#\033[35m?-\033[0m")
`substr_ctl<-`(txt4, 2, 3, terminate=FALSE, carry=TRUE, value="#\033[0m?-")
`substr_ctl<-`(txt4, 2, 3, terminate=FALSE, carry=TRUE, value=rep4)
## Reference for bridge against end of prior `value` substring
txt5 <- c("ABD", "DFG")
`substr_ctl<-`(txt5, 2, 2, value=".\033[45m", carry=TRUE, terminate=FALSE)
## Tabs
txt6 <- "A123456789B"
`substr2_ctl<-`(txt6, 2, 9, value="\t", tabs.as.spaces=TRUE)
`substr2_ctl<-`(txt6, 2, 3, value="\t", tabs.as.spaces=TRUE)
`substr2_ctl<-`(txt6, 2, 10, value="\t", tabs.as.spaces=TRUE)
## Encodings
txt7a <- "\u0160os"
txt7b <- "sos"
txt7c <- "so\u0160"
val.scar <- "\u0161"
Encoding(`substr_ctl<-`(txt7a, 1, 1, value=val.scar))
Encoding(`substr_ctl<-`(txt7a, 1, 1, value="s"))
Encoding(`substr_ctl<-`(txt7a, 2, 2, value=val.scar))
Encoding(`substr_ctl<-`(txt7a, 2, 2, value="s"))
Encoding(`substr_ctl<-`(txt7b, 2, 2, value=val.scar))
Encoding(`substr_ctl<-`(txt7b, 2, 2, value="s"))
Encoding(`substr_ctl<-`(txt7c, 3, 3, value=val.scar))
Encoding(`substr_ctl<-`(txt7c, 3, 3, value="s"))
})
unitizer_sect("Rep Funs - Corner Cases", {
## Include trail when selecting past end of `value`
`substr_ctl<-`(txt2, 1, 3, terminate=FALSE, value="#\033[32m?\033[0m")
## Only portions of string that are replaced are modified; leading and
## trailing controls remain, possibly causing redundant sequences when the
## lead and trail sequences are zero width, particularly with terminate=T.
txt8 <- "\033[32mAB\033[45m"
`substr_ctl<-`(txt8, 1, 2, value="12")
`substr_ctl<-`(txt8, 1, 2, value="12", terminate=FALSE)
`substr_ctl<-`(txt8, 1, 3, value="12")
`substr_ctl<-`(txt8, 1, 3, value="1")
`substr_ctl<-`(txt8, 1, 3, value="")
`substr_ctl<-`(txt8, 1, 3, value="123")
`substr_ctl<-`(txt8, 0, 2, value="12")
`substr_ctl<-`(txt8, 0, 3, value="12")
## Zero width gets inserted
`substr_ctl<-`(txt8, 1, 3, value="\033[1m", terminate=FALSE)
## Errors
tce(`substr_ctl<-`(txt8, 1, 3, value="A", carry="\033[41m"))
lat <- "fa\xe7ile"
Encoding(lat) <- "latin1"
tce(`substr_ctl<-`(lat, 1, 3, value="ABC"))
## NA handling
txt.na2 <- c("AB", NA, "BC")
`substr_ctl<-`(txt.na2, 1, 1, value="#")
txt.nona <- c("AB", "BC", "CD")
`substr_ctl<-`(txt.nona, 1, 1, value=c("#", NA), carry=TRUE)
})
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.