1## Copyright (C) 2021  Brodie Gaslam
2##
3## This file is part of "fansi - ANSI Control Sequence Aware String Functions"
4##
5## This program is free software: you can redistribute it and/or modify
6## it under the terms of the GNU General Public License as published by
7## the Free Software Foundation, either version 2 of the License, or
8## (at your option) any later version.
9##
10## This program is distributed in the hope that it will be useful,
11## but WITHOUT ANY WARRANTY; without even the implied warranty of
12## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13## GNU General Public License for more details.
14##
15## Go to <https://www.r-project.org/Licenses/GPL-2> for a copy of the license.
16
17#' Strip ANSI Control Sequences
18#'
19#' Removes _Control Sequences_ from strings.  By default it will
20#' strip all known _Control Sequences_, including ANSI CSI
21#' sequences, two character sequences starting with ESC, and all C0 control
22#' characters, including newlines.  You can fine tune this behavior with the
23#' `ctl` parameter.  `strip_sgr` only strips ANSI CSI SGR sequences.
24#'
25#' The `ctl` value contains the names of **non-overlapping** subsets of the
26#' known _Control Sequences_ (e.g. "csi" does not contain "sgr", and "c0" does
27#' not contain newlines).  The one exception is "all" which means strip every
28#' known sequence.  If you combine "all" with any other option then everything
29#' **but** that option will be stripped.
30#'
31#' @note Non-ASCII strings are converted to and returned in UTF-8 encoding.
32#' @seealso [fansi] for details on how _Control Sequences_ are
33#'   interpreted, particularly if you are getting unexpected results.
34#' @inheritParams substr_ctl
35#' @inheritSection substr_ctl _ctl vs. _sgr
36#' @export
37#' @param ctl character, any combination of the following values (see details):
38#'   * "nl": strip newlines.
39#'   * "c0": strip all other "C0" control characters (i.e. x01-x1f, x7F),
40#'     except for newlines and the actual ESC character.
41#'   * "sgr": strip ANSI CSI SGR sequences.
42#'   * "csi": strip all non-SGR csi sequences.
43#'   * "esc": strip all other escape sequences.
44#'   * "all": all of the above, except when used in combination with any of the
45#'     above, in which case it means "all but" (see details).
46#' @param strip character, deprecated in favor of `ctl`.
47#' @return character vector of same length as x with ANSI escape sequences
48#'   stripped
49#' @examples
50#' string <- "hello\033k\033[45p world\n\033[31mgoodbye\a moon"
51#' strip_ctl(string)
52#' strip_ctl(string, c("nl", "c0", "sgr", "csi", "esc")) # equivalently
53#' strip_ctl(string, "sgr")
54#' strip_ctl(string, c("c0", "esc"))
55#'
56#' ## everything but C0 controls, we need to specify "nl"
57#' ## in addition to "c0" since "nl" is not part of "c0"
58#' ## as far as the `strip` argument is concerned
59#' strip_ctl(string, c("all", "nl", "c0"))
60#'
61#' ## convenience function, same as `strip_ctl(ctl='sgr')`
62#' strip_sgr(string)
63
64strip_ctl <- function(x, ctl='all', warn=getOption('fansi.warn'), strip) {
65  if(!missing(strip)) {
66    message("Parameter `strip` has been deprecated; use `ctl` instead.")
67    ctl <- strip
68  }
69  if(!is.character(x)) x <- as.character(x)
70
71  if(!is.logical(warn)) warn <- as.logical(warn)
72  if(length(warn) != 1L || is.na(warn))
73    stop("Argument `warn` must be TRUE or FALSE.")
74
75  if(!is.character(ctl))
76    stop("Argument `ctl` must be character.")
77  if(length(ctl)) {
78    # duplicate values in `ctl` are okay, so save a call to `unique` here
79    if(anyNA(ctl.int <- match(ctl, VALID.CTL)))
80      stop(
81        "Argument `ctl` may contain only values in `",
82        deparse(VALID.CTL), "`"
83      )
84    .Call(FANSI_strip_csi, enc2utf8(x), ctl.int, warn)
85  } else x
86}
87#' @export
88#' @rdname strip_ctl
89
90strip_sgr <- function(x, warn=getOption('fansi.warn')) {
91  if(!is.character(x)) x <- as.character(x)
92  if(!is.logical(warn)) warn <- as.logical(warn)
93  if(length(warn) != 1L || is.na(warn))
94    stop("Argument `warn` must be TRUE or FALSE.")
95
96  ctl.int <- match("sgr", VALID.CTL)
97  if(anyNA(ctl.int))
98    stop("Internal Error: invalid ctl type; contact maintainer.") # nocov
99
100  .Call(FANSI_strip_csi, enc2utf8(x), ctl.int, warn)
101}
102
103## Process String by Removing Unwanted Characters
104##
105## This is to simulate what `strwrap` does, exposed for testing purposes.
106
107process <- function(x) .Call(FANSI_process, enc2utf8(x))
108
109