Various line editor fixes and optimizations

This commit is contained in:
2026-02-25 15:43:08 -05:00
parent 415c9b4a53
commit 28ce008234
18 changed files with 359 additions and 152 deletions

View File

@@ -1,6 +1,7 @@
use std::collections::HashSet;
use crate::expand::{perform_param_expansion, DUB_QUOTE, VAR_SUB};
use crate::expand::perform_param_expansion;
use crate::prompt::readline::markers;
use crate::state::VarFlags;
use super::*;
@@ -296,7 +297,7 @@ fn dquote_escape_dollar() {
// "\$foo" should strip backslash, produce literal $foo (no expansion)
let result = unescape_str(r#""\$foo""#);
assert!(
!result.contains(VAR_SUB),
!result.contains(markers::VAR_SUB),
"Escaped $ should not become VAR_SUB"
);
assert!(result.contains('$'), "Literal $ should be preserved");
@@ -307,7 +308,7 @@ fn dquote_escape_dollar() {
fn dquote_escape_backslash() {
// "\\" in double quotes should produce a single backslash
let result = unescape_str(r#""\\""#);
let inner: String = result.chars().filter(|&c| c != DUB_QUOTE).collect();
let inner: String = result.chars().filter(|&c| c != markers::DUB_QUOTE).collect();
assert_eq!(
inner, "\\",
"Double backslash should produce single backslash"
@@ -318,7 +319,7 @@ fn dquote_escape_backslash() {
fn dquote_escape_quote() {
// "\"" should produce a literal double quote
let result = unescape_str(r#""\"""#);
let inner: String = result.chars().filter(|&c| c != DUB_QUOTE).collect();
let inner: String = result.chars().filter(|&c| c != markers::DUB_QUOTE).collect();
assert!(
inner.contains('"'),
"Escaped quote should produce literal quote"
@@ -329,7 +330,7 @@ fn dquote_escape_quote() {
fn dquote_escape_backtick() {
// "\`" should strip backslash, produce literal backtick
let result = unescape_str(r#""\`""#);
let inner: String = result.chars().filter(|&c| c != DUB_QUOTE).collect();
let inner: String = result.chars().filter(|&c| c != markers::DUB_QUOTE).collect();
assert_eq!(
inner, "`",
"Escaped backtick should produce literal backtick"
@@ -340,7 +341,7 @@ fn dquote_escape_backtick() {
fn dquote_escape_nonspecial_preserves_backslash() {
// "\a" inside double quotes should preserve the backslash (a is not special)
let result = unescape_str(r#""\a""#);
let inner: String = result.chars().filter(|&c| c != DUB_QUOTE).collect();
let inner: String = result.chars().filter(|&c| c != markers::DUB_QUOTE).collect();
assert_eq!(
inner, "\\a",
"Backslash before non-special char should be preserved"
@@ -352,7 +353,7 @@ fn dquote_unescaped_dollar_expands() {
// "$foo" inside double quotes should produce VAR_SUB (expansion marker)
let result = unescape_str(r#""$foo""#);
assert!(
result.contains(VAR_SUB),
result.contains(markers::VAR_SUB),
"Unescaped $ should become VAR_SUB"
);
}
@@ -361,10 +362,10 @@ fn dquote_unescaped_dollar_expands() {
fn dquote_mixed_escapes() {
// "hello \$world \\end" should have literal $, single backslash
let result = unescape_str(r#""hello \$world \\end""#);
assert!(!result.contains(VAR_SUB), "Escaped $ should not expand");
assert!(!result.contains(markers::VAR_SUB), "Escaped $ should not expand");
assert!(result.contains('$'), "Literal $ should be in output");
// Should have exactly one backslash (from \\)
let inner: String = result.chars().filter(|&c| c != DUB_QUOTE).collect();
let inner: String = result.chars().filter(|&c| c != markers::DUB_QUOTE).collect();
let backslash_count = inner.chars().filter(|&c| c == '\\').count();
assert_eq!(backslash_count, 1, "\\\\ should produce one backslash");
}