mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-05-21 03:21:16 -03:00
io: accept intoCharIter in more functions
This makes them more general than the previous versions which expected `&wstr`. It comes at the cost of additional eager calls to `chars()`. To implement `appendln` without having to call `append` twice, implement `IntoCharIter` for chained iterators whose elements are both the kind of iterator specified by `IntoCharIter`. Because `IntoCharIter` is not implemented for owned types to avoid allocations, some call sites which used to pass `WString` need to be updated to pass references instead, which constitutes the bulk of the changes in this commit. Part of #12396
This commit is contained in:
committed by
Johannes Altmanninger
parent
934def3b75
commit
414dba994f
@@ -240,6 +240,15 @@ fn extend_wstring(&self, out: &mut WString) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: DoubleEndedIterator<Item = char> + Clone, B: DoubleEndedIterator<Item = char> + Clone>
|
||||
IntoCharIter for std::iter::Chain<A, B>
|
||||
{
|
||||
type Iter = std::iter::Chain<A, B>;
|
||||
fn chars(self) -> Self::Iter {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Return true if `prefix` is a prefix of `contents`.
|
||||
fn iter_prefixes_iter<Prefix, Contents>(prefix: Prefix, mut contents: Contents) -> bool
|
||||
where
|
||||
|
||||
@@ -428,7 +428,7 @@ fn abbr_add(opts: &Options, streams: &mut IoStreams) -> BuiltinResult {
|
||||
}
|
||||
});
|
||||
if !opts.commands.is_empty() && position == Position::Command {
|
||||
streams.err.appendln(wgettext_fmt!(
|
||||
streams.err.appendln(&wgettext_fmt!(
|
||||
"%s: --command cannot be combined with --position=command",
|
||||
CMD,
|
||||
));
|
||||
|
||||
@@ -401,7 +401,7 @@ fn list_modes(&mut self, streams: &mut IoStreams) {
|
||||
modes.dedup();
|
||||
|
||||
for mode in modes {
|
||||
streams.out.appendln(mode);
|
||||
streams.out.appendln(&mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,7 +232,7 @@ fn write_part(
|
||||
}
|
||||
|
||||
for arg in args {
|
||||
streams.out.appendln(arg.completion);
|
||||
streams.out.appendln(&arg.completion);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ pub fn contains(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) ->
|
||||
for (i, arg) in args[optind..].iter().enumerate().skip(1) {
|
||||
if needle == arg {
|
||||
if opts.print_index {
|
||||
streams.out.appendln(i.to_wstring());
|
||||
streams.out.appendln(&i.to_wstring());
|
||||
}
|
||||
return Ok(SUCCESS);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ pub fn count(_parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> B
|
||||
.filter(|input_value| input_value.want_newline)
|
||||
.count();
|
||||
|
||||
streams.out.appendln(numargs.to_wstring());
|
||||
streams.out.appendln(&numargs.to_wstring());
|
||||
|
||||
if numargs == 0 {
|
||||
return Err(STATUS_CMD_ERROR);
|
||||
|
||||
@@ -1007,7 +1007,7 @@ enum OutputType {
|
||||
return Ok(SUCCESS);
|
||||
}
|
||||
'v' => {
|
||||
streams.out.appendln(wgettext_fmt!(
|
||||
streams.out.appendln(&wgettext_fmt!(
|
||||
"%s, version %s",
|
||||
get_program_name(),
|
||||
crate::BUILD_VERSION
|
||||
@@ -1051,7 +1051,7 @@ enum OutputType {
|
||||
while i < args.len() || (args.is_empty() && i == 0) {
|
||||
if args.is_empty() && i == 0 {
|
||||
if output_type == OutputType::File {
|
||||
streams.err.appendln(wgettext_fmt!(
|
||||
streams.err.appendln(&wgettext_fmt!(
|
||||
"Expected file path to read/write for -w:\n\n $ %s -w foo.fish",
|
||||
get_program_name()
|
||||
));
|
||||
@@ -1087,7 +1087,7 @@ enum OutputType {
|
||||
output_location = arg;
|
||||
}
|
||||
Err(err) => {
|
||||
streams.err.appendln(wgettext_fmt!(
|
||||
streams.err.appendln(&wgettext_fmt!(
|
||||
"Opening \"%s\" failed: %s",
|
||||
arg,
|
||||
err.to_string()
|
||||
@@ -1168,7 +1168,7 @@ enum OutputType {
|
||||
let _ = file.write_all(&wcs2bytes(&output_wtext));
|
||||
}
|
||||
Err(err) => {
|
||||
streams.err.appendln(wgettext_fmt!(
|
||||
streams.err.appendln(&wgettext_fmt!(
|
||||
"Opening \"%s\" failed: %s",
|
||||
output_location,
|
||||
err.to_string()
|
||||
@@ -1314,12 +1314,12 @@ fn prettify(streams: &mut IoStreams, src: &wstr, do_indent: bool) -> WString {
|
||||
};
|
||||
let ast = ast::parse(src, flags, None);
|
||||
let ast_dump = ast.dump(src);
|
||||
streams.err.appendln(ast_dump);
|
||||
streams.err.appendln(&ast_dump);
|
||||
|
||||
// Output metrics too.
|
||||
let mut metrics = AstSizeMetrics::default();
|
||||
metrics.visit(ast.top());
|
||||
streams.err.appendln(format!("{}", metrics));
|
||||
streams.err.appendln(&format!("{}", metrics));
|
||||
}
|
||||
let ast = ast::parse(src, parse_flags(), None);
|
||||
let mut printer = PrettyPrinter::new(src, &ast, do_indent);
|
||||
|
||||
@@ -160,7 +160,7 @@ fn setup_and_process_keys(
|
||||
.err
|
||||
.appendln("To terminate this program type \"exit\" or \"quit\" in this window,");
|
||||
let modes = shell_modes();
|
||||
streams.err.appendln(wgettext_fmt!(
|
||||
streams.err.appendln(&wgettext_fmt!(
|
||||
"or press ctrl-%c or ctrl-%c twice in a row.",
|
||||
char::from(modes.c_cc[VINTR] + 0x60),
|
||||
char::from(modes.c_cc[VEOF] + 0x60)
|
||||
@@ -201,7 +201,7 @@ fn parse_flags(
|
||||
return ControlFlow::Break(Ok(SUCCESS));
|
||||
}
|
||||
'v' => {
|
||||
streams.out.appendln(wgettext_fmt!(
|
||||
streams.out.appendln(&wgettext_fmt!(
|
||||
"%s, version %s",
|
||||
get_program_name(),
|
||||
crate::BUILD_VERSION
|
||||
@@ -235,7 +235,7 @@ fn parse_flags(
|
||||
if argc != 0 {
|
||||
streams
|
||||
.err
|
||||
.appendln(wgettext_fmt!("Expected no arguments, got %d", argc));
|
||||
.appendln(&wgettext_fmt!("Expected no arguments, got %d", argc));
|
||||
return ControlFlow::Break(Err(STATUS_CMD_ERROR));
|
||||
}
|
||||
|
||||
|
||||
@@ -208,7 +208,7 @@ pub fn functions(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) -
|
||||
} else {
|
||||
L!("n/a").to_owned()
|
||||
};
|
||||
streams.out.appendln(def_file);
|
||||
streams.out.appendln(&def_file);
|
||||
|
||||
if opts.verbose {
|
||||
let copy_place = match props.as_ref() {
|
||||
@@ -223,20 +223,20 @@ pub fn functions(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) -
|
||||
Some(p) if !p.is_autoload.load() => L!("not-autoloaded").to_owned(),
|
||||
_ => L!("n/a").to_owned(),
|
||||
};
|
||||
streams.out.appendln(copy_place);
|
||||
streams.out.appendln(©_place);
|
||||
let line = if let Some(p) = props.as_ref() {
|
||||
p.definition_lineno()
|
||||
} else {
|
||||
0
|
||||
};
|
||||
streams.out.appendln(line.to_wstring());
|
||||
streams.out.appendln(&line.to_wstring());
|
||||
|
||||
let shadow = match props.as_ref() {
|
||||
Some(p) if p.shadow_scope => L!("scope-shadowing").to_owned(),
|
||||
Some(p) if !p.shadow_scope => L!("no-scope-shadowing").to_owned(),
|
||||
_ => L!("n/a").to_owned(),
|
||||
};
|
||||
streams.out.appendln(shadow);
|
||||
streams.out.appendln(&shadow);
|
||||
|
||||
let desc = match props.as_ref() {
|
||||
Some(p) => {
|
||||
@@ -254,7 +254,7 @@ pub fn functions(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) -
|
||||
}
|
||||
_ => L!("n/a").to_owned(),
|
||||
};
|
||||
streams.out.appendln(desc);
|
||||
streams.out.appendln(&desc);
|
||||
}
|
||||
// Historical - this never failed?
|
||||
return Ok(SUCCESS);
|
||||
@@ -297,7 +297,7 @@ pub fn functions(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) -
|
||||
.append(&reformat_for_screen(&buff, &termsize_last()));
|
||||
} else {
|
||||
for name in names {
|
||||
streams.out.appendln(name);
|
||||
streams.out.appendln(&name);
|
||||
}
|
||||
}
|
||||
return Ok(SUCCESS);
|
||||
|
||||
@@ -63,6 +63,6 @@ pub fn pwd(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> Buil
|
||||
if pwd.is_empty() {
|
||||
return Err(STATUS_CMD_ERROR);
|
||||
}
|
||||
streams.out.appendln(pwd);
|
||||
streams.out.appendln(&pwd);
|
||||
Ok(SUCCESS)
|
||||
}
|
||||
|
||||
@@ -162,6 +162,6 @@ fn parse_ull(streams: &mut IoStreams, cmd: &wstr, num: &wstr) -> Result<u64, wut
|
||||
// Safe because end was a valid i64 and the result here is in the range start..=end.
|
||||
let result: i64 = start.checked_add_unsigned(rand * step).unwrap();
|
||||
|
||||
streams.out.appendln(result.to_wstring());
|
||||
streams.out.appendln(&result.to_wstring());
|
||||
Ok(SUCCESS)
|
||||
}
|
||||
|
||||
@@ -186,7 +186,7 @@ fn parse(
|
||||
// implicit drop(w); here
|
||||
if args[optind - 1].starts_with("-o") {
|
||||
// TODO: translate this
|
||||
streams.err.appendln(sprintf!(
|
||||
streams.err.appendln(&sprintf!(
|
||||
"Fish does not have shell options. See `help %s`.",
|
||||
help_section!("fish_for_bash_users")
|
||||
));
|
||||
|
||||
@@ -562,7 +562,7 @@ pub fn status(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) -> B
|
||||
return Err(STATUS_INVALID_ARGS);
|
||||
}
|
||||
if args[0] != "scroll-content-up" {
|
||||
streams.err.appendln(wgettext_fmt!(
|
||||
streams.err.appendln(&wgettext_fmt!(
|
||||
"%s %s: unrecognized feature '%s'",
|
||||
cmd,
|
||||
c.to_wstr(),
|
||||
@@ -602,18 +602,18 @@ pub fn status(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) -> B
|
||||
};
|
||||
streams.out.appendln(buildsystem);
|
||||
streams.out.append(L!("Version: "));
|
||||
streams.out.appendln(version);
|
||||
streams.out.appendln(&version);
|
||||
if target == host {
|
||||
streams.out.append(L!("Target (and host): "));
|
||||
streams.out.appendln(target);
|
||||
streams.out.appendln(&target);
|
||||
} else {
|
||||
streams.out.append(L!("Target: "));
|
||||
streams.out.appendln(target);
|
||||
streams.out.appendln(&target);
|
||||
streams.out.append(L!("Host: "));
|
||||
streams.out.appendln(host);
|
||||
streams.out.appendln(&host);
|
||||
}
|
||||
streams.out.append(L!("Profile: "));
|
||||
streams.out.appendln(profile);
|
||||
streams.out.appendln(&profile);
|
||||
streams.out.append(L!("Features: "));
|
||||
let features: &[&str] = &[
|
||||
#[cfg(feature = "embed-manpages")]
|
||||
@@ -623,7 +623,7 @@ pub fn status(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) -> B
|
||||
#[cfg(target_feature = "crt-static")]
|
||||
"crt-static",
|
||||
];
|
||||
streams.out.appendln(str2wcstring(features.join(" ")));
|
||||
streams.out.appendln(&str2wcstring(features.join(" ")));
|
||||
streams.out.appendln("");
|
||||
return Ok(SUCCESS);
|
||||
}
|
||||
@@ -643,7 +643,7 @@ pub fn status(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) -> B
|
||||
Some(f) => f,
|
||||
None => wgettext!("Not a function").to_owned(),
|
||||
};
|
||||
streams.out.appendln(f);
|
||||
streams.out.appendln(&f);
|
||||
}
|
||||
STATUS_LINE_NUMBER => {
|
||||
// TBD is how to interpret the level argument when fetching the line number.
|
||||
@@ -651,7 +651,7 @@ pub fn status(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) -> B
|
||||
// streams.out.append_format(L"%d\n", parser.get_lineno(opts.level));
|
||||
streams
|
||||
.out
|
||||
.appendln(parser.get_lineno_for_display().to_wstring());
|
||||
.appendln(&parser.get_lineno_for_display().to_wstring());
|
||||
}
|
||||
STATUS_IS_INTERACTIVE => {
|
||||
if is_interactive_session() {
|
||||
@@ -745,7 +745,7 @@ pub fn status(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) -> B
|
||||
}
|
||||
LookUpInPath => Cow::Borrowed(get_program_name()),
|
||||
};
|
||||
streams.out.appendln(result);
|
||||
streams.out.appendln(&result);
|
||||
}
|
||||
STATUS_TERMINAL => {
|
||||
let xtversion = xtversion().unwrap_or_default();
|
||||
|
||||
@@ -52,7 +52,7 @@ fn handle(
|
||||
nnonempty += 1;
|
||||
}
|
||||
if !self.quiet {
|
||||
streams.out.appendln(max.to_wstring());
|
||||
streams.out.appendln(&max.to_wstring());
|
||||
} else if nnonempty > 0 {
|
||||
return Ok(());
|
||||
}
|
||||
@@ -63,7 +63,7 @@ fn handle(
|
||||
nnonempty += 1;
|
||||
}
|
||||
if !self.quiet {
|
||||
streams.out.appendln(n.to_wstring());
|
||||
streams.out.appendln(&n.to_wstring());
|
||||
} else if nnonempty > 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ fn handle(
|
||||
// echo whatever
|
||||
// end
|
||||
for InputValue { arg, .. } in iter {
|
||||
streams.out.appendln(arg);
|
||||
streams.out.appendln(&arg);
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
@@ -182,7 +182,7 @@ fn handle(
|
||||
res
|
||||
}
|
||||
};
|
||||
streams.out.appendln(output);
|
||||
streams.out.appendln(&output);
|
||||
continue;
|
||||
} else {
|
||||
/* shorten the right side */
|
||||
@@ -221,7 +221,7 @@ fn handle(
|
||||
}
|
||||
|
||||
if pos == line.len() {
|
||||
streams.out.appendln(line);
|
||||
streams.out.appendln(&line);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -1020,7 +1020,7 @@ pub fn test(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> Bui
|
||||
|
||||
if feature_test(FeatureFlag::TestRequireArg) {
|
||||
if argc == 0 {
|
||||
streams.err.appendln(wgettext_fmt!(
|
||||
streams.err.appendln(&wgettext_fmt!(
|
||||
"%s: Expected at least one argument",
|
||||
program_name
|
||||
));
|
||||
@@ -1035,7 +1035,7 @@ pub fn test(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> Bui
|
||||
}
|
||||
} else if argc == 0 {
|
||||
if should_flog!(deprecated_test) {
|
||||
streams.err.appendln(wgettext_fmt!(
|
||||
streams.err.appendln(&wgettext_fmt!(
|
||||
"%s: called with no arguments. This will be an error in future.",
|
||||
program_name
|
||||
));
|
||||
@@ -1044,7 +1044,7 @@ pub fn test(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> Bui
|
||||
return Err(STATUS_INVALID_ARGS); // Per 1003.1, exit false.
|
||||
} else if argc == 1 {
|
||||
if should_flog!(deprecated_test) && args[0] != "-z" {
|
||||
streams.err.appendln(wgettext_fmt!(
|
||||
streams.err.appendln(&wgettext_fmt!(
|
||||
"%s: called with one argument. This will return false in future.",
|
||||
program_name
|
||||
));
|
||||
|
||||
21
src/io.rs
21
src/io.rs
@@ -690,12 +690,18 @@ pub fn append(&mut self, s: impl IntoCharIter) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
/// Append the given characters and a trailing newline.
|
||||
pub fn appendln(&mut self, s: impl IntoCharIter) -> bool {
|
||||
// Try calling "append" less - it might write() to an fd
|
||||
self.append(s.chars().chain(std::iter::once('\n')))
|
||||
}
|
||||
|
||||
/// An optional override point. This is for explicit separation.
|
||||
/// \param want_newline this is true if the output item should be ended with a newline. This
|
||||
/// is only relevant if we are printing the output to a stream,
|
||||
pub fn append_with_separation(
|
||||
&mut self,
|
||||
s: &wstr,
|
||||
s: impl IntoCharIter,
|
||||
typ: SeparationType,
|
||||
want_newline: bool,
|
||||
) -> bool {
|
||||
@@ -703,10 +709,7 @@ pub fn append_with_separation(
|
||||
OutputStream::Buffered(stream) => stream.append_with_separation(s, typ, want_newline),
|
||||
OutputStream::Fd(_) | OutputStream::Null | OutputStream::String(_) => {
|
||||
if typ == SeparationType::explicitly && want_newline {
|
||||
// Try calling "append" less - it might write() to an fd
|
||||
let mut buf = s.to_owned();
|
||||
buf.push('\n');
|
||||
self.append(&buf)
|
||||
self.appendln(s)
|
||||
} else {
|
||||
self.append(s)
|
||||
}
|
||||
@@ -714,12 +717,6 @@ pub fn append_with_separation(
|
||||
}
|
||||
}
|
||||
|
||||
/// Append a &wstr or WString with a newline
|
||||
pub fn appendln(&mut self, s: impl Into<WString>) -> bool {
|
||||
let s = s.into() + L!("\n");
|
||||
self.append(&s)
|
||||
}
|
||||
|
||||
pub fn append_char(&mut self, c: char) -> bool {
|
||||
self.append(wstr::from_char_slice(&[c]))
|
||||
}
|
||||
@@ -840,7 +837,7 @@ fn append(&mut self, s: impl IntoCharIter) -> bool {
|
||||
}
|
||||
fn append_with_separation(
|
||||
&mut self,
|
||||
s: &wstr,
|
||||
s: impl IntoCharIter,
|
||||
typ: SeparationType,
|
||||
_want_newline: bool,
|
||||
) -> bool {
|
||||
|
||||
Reference in New Issue
Block a user