Move escapeString to its own file

Change-Id: Ie5c954ec73c46c9d3c679ef99a83a29cc7a08352
This commit is contained in:
Rebecca Turner 2024-03-28 16:26:42 -07:00
parent 34a49fad2c
commit 9f274c75db
Signed by: rbt
SSH key fingerprint: SHA256:SiNaEWabvotTldoNb5jIKqjJ3RnpS4aRXA4KLAdW5vs
10 changed files with 142 additions and 74 deletions

View file

@ -4,6 +4,7 @@
#include "symbol-table.hh" #include "symbol-table.hh"
#include "util.hh" #include "util.hh"
#include "print.hh" #include "print.hh"
#include "escape-string.hh"
#include <cstdlib> #include <cstdlib>
@ -36,7 +37,7 @@ void ExprFloat::show(const SymbolTable & symbols, std::ostream & str) const
void ExprString::show(const SymbolTable & symbols, std::ostream & str) const void ExprString::show(const SymbolTable & symbols, std::ostream & str) const
{ {
printLiteralString(str, s); escapeString(str, s);
} }
void ExprPath::show(const SymbolTable & symbols, std::ostream & str) const void ExprPath::show(const SymbolTable & symbols, std::ostream & str) const

View file

@ -2,6 +2,7 @@
#include "print.hh" #include "print.hh"
#include "eval.hh" #include "eval.hh"
#include "signals.hh" #include "signals.hh"
#include "escape-string.hh"
namespace nix { namespace nix {
@ -27,7 +28,7 @@ void printAmbiguous(
printLiteralBool(str, v.boolean); printLiteralBool(str, v.boolean);
break; break;
case nString: case nString:
printLiteralString(str, v.string.s); escapeString(str, v.string.s);
break; break;
case nPath: case nPath:
str << v.path().to_string(); // !!! escaping? str << v.path().to_string(); // !!! escaping?

View file

@ -2,6 +2,7 @@
#include <span> #include <span>
#include <unordered_set> #include <unordered_set>
#include "escape-string.hh"
#include "print.hh" #include "print.hh"
#include "ansicolor.hh" #include "ansicolor.hh"
#include "store-api.hh" #include "store-api.hh"
@ -11,57 +12,6 @@
namespace nix { namespace nix {
void printElided(
std::ostream & output,
unsigned int value,
const std::string_view single,
const std::string_view plural,
bool ansiColors)
{
if (ansiColors)
output << ANSI_FAINT;
output << "«";
pluralize(output, value, single, plural);
output << " elided»";
if (ansiColors)
output << ANSI_NORMAL;
}
std::ostream &
printLiteralString(std::ostream & str, const std::string_view string, size_t maxLength, bool ansiColors)
{
size_t charsPrinted = 0;
if (ansiColors)
str << ANSI_MAGENTA;
str << "\"";
for (auto i = string.begin(); i != string.end(); ++i) {
if (charsPrinted >= maxLength) {
str << "\" ";
printElided(str, string.length() - charsPrinted, "byte", "bytes", ansiColors);
return str;
}
if (*i == '\"' || *i == '\\') str << "\\" << *i;
else if (*i == '\n') str << "\\n";
else if (*i == '\r') str << "\\r";
else if (*i == '\t') str << "\\t";
else if (*i == '$' && *(i+1) == '{') str << "\\" << *i;
else str << *i;
charsPrinted++;
}
str << "\"";
if (ansiColors)
str << ANSI_NORMAL;
return str;
}
std::ostream &
printLiteralString(std::ostream & str, const std::string_view string)
{
return printLiteralString(str, string, std::numeric_limits<size_t>::max(), false);
}
std::ostream & std::ostream &
printLiteralBool(std::ostream & str, bool boolean) printLiteralBool(std::ostream & str, bool boolean)
{ {
@ -93,7 +43,7 @@ printIdentifier(std::ostream & str, std::string_view s) {
else { else {
char c = s[0]; char c = s[0];
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_')) { if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_')) {
printLiteralString(str, s); escapeString(str, s);
return str; return str;
} }
for (auto c : s) for (auto c : s)
@ -101,7 +51,7 @@ printIdentifier(std::ostream & str, std::string_view s) {
(c >= 'A' && c <= 'Z') || (c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9') || (c >= '0' && c <= '9') ||
c == '_' || c == '\'' || c == '-')) { c == '_' || c == '\'' || c == '-')) {
printLiteralString(str, s); escapeString(str, s);
return str; return str;
} }
str << s; str << s;
@ -129,7 +79,7 @@ printAttributeName(std::ostream & str, std::string_view name) {
if (isVarName(name)) if (isVarName(name))
str << name; str << name;
else else
printLiteralString(str, name); escapeString(str, name);
return str; return str;
} }
@ -248,7 +198,13 @@ private:
void printString(Value & v) void printString(Value & v)
{ {
printLiteralString(output, v.string.s, options.maxStringLength, options.ansiColors); // NB: Non-printing characters won't be escaped.
escapeString(
output,
v.string.s,
options.maxStringLength,
options.ansiColors
);
} }
void printPath(Value & v) void printPath(Value & v)

View file

@ -11,28 +11,13 @@
#include "fmt.hh" #include "fmt.hh"
#include "print-options.hh" #include "print-options.hh"
#include "print-elided.hh"
namespace nix { namespace nix {
class EvalState; class EvalState;
struct Value; struct Value;
/**
* Print a string as a Nix string literal.
*
* Quotes and fairly minimal escaping are added.
*
* @param o The output stream to print to
* @param s The logical string
*/
std::ostream & printLiteralString(std::ostream & o, std::string_view s);
inline std::ostream & printLiteralString(std::ostream & o, const char * s) {
return printLiteralString(o, std::string_view(s));
}
inline std::ostream & printLiteralString(std::ostream & o, const std::string & s) {
return printLiteralString(o, std::string_view(s));
}
/** Print `true` or `false`. */ /** Print `true` or `false`. */
std::ostream & printLiteralBool(std::ostream & o, bool b); std::ostream & printLiteralBool(std::ostream & o, bool b);

View file

@ -0,0 +1,40 @@
#include <iomanip>
#include <ostream>
#include <sstream>
#include "ansicolor.hh"
#include "escape-char.hh"
#include "english.hh"
#include "escape-string.hh"
#include "print-elided.hh"
namespace nix {
std::ostream &
escapeString(std::ostream & str, const std::string_view string, size_t maxLength, bool ansiColors)
{
size_t charsPrinted = 0;
if (ansiColors)
str << ANSI_MAGENTA;
str << "\"";
for (auto i = string.begin(); i != string.end(); ++i) {
if (charsPrinted >= maxLength) {
str << "\" ";
printElided(str, string.length() - charsPrinted, "byte", "bytes", ansiColors);
return str;
}
if (*i == '\"' || *i == '\\') str << "\\" << *i;
else if (*i == '\n') str << "\\n";
else if (*i == '\r') str << "\\r";
else if (*i == '\t') str << "\\t";
else if (*i == '$' && *(i+1) == '{') str << "\\" << *i;
else str << *i;
charsPrinted++;
}
str << "\"";
if (ansiColors)
str << ANSI_NORMAL;
return str;
}
}; // namespace nix

View file

@ -0,0 +1,34 @@
#pragma once
#include <limits>
#include <ostream>
namespace nix {
/**
* Escape a string for output.
*
* With default optional parameters, the output string will round-trip through
* the Nix evaluator (i.e. you can copy/paste this function's output into the
* REPL and have it evaluate as the string that got passed in).
*
* With non-default optional parameters, the output string will be
* human-readable.
*/
std::ostream & escapeString(
std::ostream & output,
const std::string_view string,
size_t maxLength = std::numeric_limits<size_t>::max(),
bool ansiColors = false
);
/**
* Escape a string for output, writing the escaped result to a new string.
*/
inline std::ostream & escapeString(std::ostream & output, const char * string)
{
return escapeString(output, std::string_view(string));
}
} // namespace nix

View file

@ -9,6 +9,7 @@ libutil_sources = files(
'english.cc', 'english.cc',
'error.cc', 'error.cc',
'escape-char.cc', 'escape-char.cc',
'escape-string.cc',
'exit.cc', 'exit.cc',
'experimental-features.cc', 'experimental-features.cc',
'filesystem.cc', 'filesystem.cc',
@ -19,6 +20,7 @@ libutil_sources = files(
'logging.cc', 'logging.cc',
'namespaces.cc', 'namespaces.cc',
'position.cc', 'position.cc',
'print-elided.cc',
'references.cc', 'references.cc',
'serialise.cc', 'serialise.cc',
'shlex.cc', 'shlex.cc',
@ -52,6 +54,7 @@ libutil_headers = files(
'english.hh', 'english.hh',
'error.hh', 'error.hh',
'escape-char.hh', 'escape-char.hh',
'escape-string.hh',
'exit.hh', 'exit.hh',
'experimental-features.hh', 'experimental-features.hh',
'experimental-features-json.hh', 'experimental-features-json.hh',
@ -70,6 +73,7 @@ libutil_headers = files(
'namespaces.hh', 'namespaces.hh',
'pool.hh', 'pool.hh',
'position.hh', 'position.hh',
'print-elided.hh',
'ref.hh', 'ref.hh',
'references.hh', 'references.hh',
'regex-combinators.hh', 'regex-combinators.hh',

View file

@ -0,0 +1,23 @@
#include "print-elided.hh"
#include "ansicolor.hh"
#include "english.hh"
namespace nix {
void printElided(
std::ostream & output,
unsigned int value,
const std::string_view single,
const std::string_view plural,
bool ansiColors)
{
if (ansiColors)
output << ANSI_FAINT;
output << "«";
pluralize(output, value, single, plural);
output << " elided»";
if (ansiColors)
output << ANSI_NORMAL;
}
}

View file

@ -0,0 +1,23 @@
#pragma once
#include <ostream>
namespace nix {
/**
* Print an `«... elided»` placeholder.
*
* Arguments are forwarded to `pluralize`.
*
* If `ansiColors` is set, the output will be wrapped in `ANSI_FAINT`.
*/
void printElided(
std::ostream & output,
unsigned int value,
const std::string_view single,
const std::string_view plural,
bool ansiColors
);
}

View file

@ -1,4 +1,5 @@
#include "cli-literate-parser.hh" #include "cli-literate-parser.hh"
#include "escape-string.hh"
#include "libexpr/print.hh" #include "libexpr/print.hh"
#include "escape-char.hh" #include "escape-char.hh"
#include "types.hh" #include "types.hh"
@ -41,7 +42,7 @@ auto CLILiterateParser::Node::print() const -> std::string
s << "Output "; s << "Output ";
break; break;
} }
printLiteralString(s, this->text); escapeString(s, this->text);
return s.str(); return s.str();
} }