diff options
author | Vincent Ambo <mail@tazj.in> | 2022-08-10T15·51+0300 |
---|---|---|
committer | tazjin <tazjin@tvl.su> | 2022-08-24T21·23+0000 |
commit | 4c9aad17add413a387bf927438de8831c00065c5 (patch) | |
tree | 5004546f6a9b5f0723e48647570ba5c716dfe991 /tvix/eval/src/value | |
parent | a2b4b4a48521d1751fa9c88cec980f0b4b59427d (diff) |
fix(tvix/value): add escaping logic for Nix strings r/4459
Nix strings displayed to users must be escaped the same way as they are in C++ Nix. This adds the scaffolding for escapes, but is most likely not yet complete. Change-Id: Icfdcb2ac98d292c567ba894a92b6529a53e0cc17 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6124 Tested-by: BuildkiteCI Reviewed-by: grfn <grfn@gws.fyi>
Diffstat (limited to '')
-rw-r--r-- | tvix/eval/src/value/string.rs | 56 |
1 files changed, 46 insertions, 10 deletions
diff --git a/tvix/eval/src/value/string.rs b/tvix/eval/src/value/string.rs index 1937a35870d3..0b665a0a5ec6 100644 --- a/tvix/eval/src/value/string.rs +++ b/tvix/eval/src/value/string.rs @@ -1,4 +1,4 @@ -use std::fmt::Display; +use std::{borrow::Cow, fmt::Display}; /// This module implements Nix language strings and their different /// backing implementations. @@ -9,15 +9,6 @@ pub enum NixString { Heap(String), } -impl Display for NixString { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - NixString::Static(s) => f.write_str(s), - NixString::Heap(s) => f.write_str(s), - } - } -} - impl PartialEq for NixString { fn eq(&self, other: &Self) -> bool { self.as_str() == other.as_str() @@ -53,3 +44,48 @@ impl NixString { } } } + +fn nix_escape_char(ch: char) -> Option<&'static str> { + match ch { + '\\' => Some("\\"), + '"' => Some("\\"), + '\n' => Some("\\n"), + _ => None, + } +} + +// Escape a Nix string for display, as the user-visible representation +// is always an escaped string (except for traces). +// +// Note that this does not add the outer pair of surrounding quotes. +fn escape_string(input: &str) -> Cow<str> { + for (i, c) in input.chars().enumerate() { + if let Some(esc) = nix_escape_char(c) { + let mut escaped = String::with_capacity(input.len()); + escaped.push_str(&input[..i]); + escaped.push_str(esc); + + for c in input[i + 1..].chars() { + match nix_escape_char(c) { + Some(esc) => escaped.push_str(esc), + None => escaped.push(c), + } + } + + return Cow::Owned(escaped); + } + } + + Cow::Borrowed(input) +} + +impl Display for NixString { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str("\"")?; + match self { + NixString::Static(s) => f.write_str(&escape_string(s))?, + NixString::Heap(s) => f.write_str(&escape_string(s))?, + }; + f.write_str("\"") + } +} |