mirror of
https://github.com/fish-shell/fish-shell.git
synced 2024-11-25 09:39:52 +08:00
Remove widestring-suffix uses
This removes both the `#[widestrs]` annotation as well as all `"foo"L` suffixes, and does a `cargo fmt` run on the result
This commit is contained in:
parent
ca972f6e0f
commit
09cd7c7ad9
102
src/ast.rs
102
src/ast.rs
|
@ -2224,47 +2224,46 @@ impl BlockStatementHeaderVariant {
|
|||
}
|
||||
|
||||
/// \return a string literal name for an ast type.
|
||||
#[widestrs]
|
||||
pub fn ast_type_to_string(t: Type) -> &'static wstr {
|
||||
match t {
|
||||
Type::token_base => "token_base"L,
|
||||
Type::keyword_base => "keyword_base"L,
|
||||
Type::redirection => "redirection"L,
|
||||
Type::variable_assignment => "variable_assignment"L,
|
||||
Type::variable_assignment_list => "variable_assignment_list"L,
|
||||
Type::argument_or_redirection => "argument_or_redirection"L,
|
||||
Type::argument_or_redirection_list => "argument_or_redirection_list"L,
|
||||
Type::statement => "statement"L,
|
||||
Type::job_pipeline => "job_pipeline"L,
|
||||
Type::job_conjunction => "job_conjunction"L,
|
||||
Type::for_header => "for_header"L,
|
||||
Type::while_header => "while_header"L,
|
||||
Type::function_header => "function_header"L,
|
||||
Type::begin_header => "begin_header"L,
|
||||
Type::block_statement => "block_statement"L,
|
||||
Type::if_clause => "if_clause"L,
|
||||
Type::elseif_clause => "elseif_clause"L,
|
||||
Type::elseif_clause_list => "elseif_clause_list"L,
|
||||
Type::else_clause => "else_clause"L,
|
||||
Type::if_statement => "if_statement"L,
|
||||
Type::case_item => "case_item"L,
|
||||
Type::switch_statement => "switch_statement"L,
|
||||
Type::decorated_statement => "decorated_statement"L,
|
||||
Type::not_statement => "not_statement"L,
|
||||
Type::job_continuation => "job_continuation"L,
|
||||
Type::job_continuation_list => "job_continuation_list"L,
|
||||
Type::job_conjunction_continuation => "job_conjunction_continuation"L,
|
||||
Type::andor_job => "andor_job"L,
|
||||
Type::andor_job_list => "andor_job_list"L,
|
||||
Type::freestanding_argument_list => "freestanding_argument_list"L,
|
||||
Type::token_conjunction => "token_conjunction"L,
|
||||
Type::job_conjunction_continuation_list => "job_conjunction_continuation_list"L,
|
||||
Type::maybe_newlines => "maybe_newlines"L,
|
||||
Type::token_pipe => "token_pipe"L,
|
||||
Type::case_item_list => "case_item_list"L,
|
||||
Type::argument => "argument"L,
|
||||
Type::argument_list => "argument_list"L,
|
||||
Type::job_list => "job_list"L,
|
||||
Type::token_base => L!("token_base"),
|
||||
Type::keyword_base => L!("keyword_base"),
|
||||
Type::redirection => L!("redirection"),
|
||||
Type::variable_assignment => L!("variable_assignment"),
|
||||
Type::variable_assignment_list => L!("variable_assignment_list"),
|
||||
Type::argument_or_redirection => L!("argument_or_redirection"),
|
||||
Type::argument_or_redirection_list => L!("argument_or_redirection_list"),
|
||||
Type::statement => L!("statement"),
|
||||
Type::job_pipeline => L!("job_pipeline"),
|
||||
Type::job_conjunction => L!("job_conjunction"),
|
||||
Type::for_header => L!("for_header"),
|
||||
Type::while_header => L!("while_header"),
|
||||
Type::function_header => L!("function_header"),
|
||||
Type::begin_header => L!("begin_header"),
|
||||
Type::block_statement => L!("block_statement"),
|
||||
Type::if_clause => L!("if_clause"),
|
||||
Type::elseif_clause => L!("elseif_clause"),
|
||||
Type::elseif_clause_list => L!("elseif_clause_list"),
|
||||
Type::else_clause => L!("else_clause"),
|
||||
Type::if_statement => L!("if_statement"),
|
||||
Type::case_item => L!("case_item"),
|
||||
Type::switch_statement => L!("switch_statement"),
|
||||
Type::decorated_statement => L!("decorated_statement"),
|
||||
Type::not_statement => L!("not_statement"),
|
||||
Type::job_continuation => L!("job_continuation"),
|
||||
Type::job_continuation_list => L!("job_continuation_list"),
|
||||
Type::job_conjunction_continuation => L!("job_conjunction_continuation"),
|
||||
Type::andor_job => L!("andor_job"),
|
||||
Type::andor_job_list => L!("andor_job_list"),
|
||||
Type::freestanding_argument_list => L!("freestanding_argument_list"),
|
||||
Type::token_conjunction => L!("token_conjunction"),
|
||||
Type::job_conjunction_continuation_list => L!("job_conjunction_continuation_list"),
|
||||
Type::maybe_newlines => L!("maybe_newlines"),
|
||||
Type::token_pipe => L!("token_pipe"),
|
||||
Type::case_item_list => L!("case_item_list"),
|
||||
Type::argument => L!("argument"),
|
||||
Type::argument_list => L!("argument_list"),
|
||||
Type::job_list => L!("job_list"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2794,7 +2793,6 @@ impl<'s> NodeVisitorMut for Populator<'s> {
|
|||
self.depth += 1
|
||||
}
|
||||
|
||||
#[widestrs]
|
||||
fn did_visit_fields_of<'a>(&'a mut self, node: &'a dyn NodeMut, flow: VisitResult) {
|
||||
self.depth -= 1;
|
||||
|
||||
|
@ -2817,27 +2815,27 @@ impl<'s> NodeVisitorMut for Populator<'s> {
|
|||
}
|
||||
Type::for_header => {
|
||||
let n = cursor.as_for_header().unwrap();
|
||||
break Some((n.kw_for.range.unwrap(), "for loop"L));
|
||||
break Some((n.kw_for.range.unwrap(), L!("for loop")));
|
||||
}
|
||||
Type::while_header => {
|
||||
let n = cursor.as_while_header().unwrap();
|
||||
break Some((n.kw_while.range.unwrap(), "while loop"L));
|
||||
break Some((n.kw_while.range.unwrap(), L!("while loop")));
|
||||
}
|
||||
Type::function_header => {
|
||||
let n = cursor.as_function_header().unwrap();
|
||||
break Some((n.kw_function.range.unwrap(), "function definition"L));
|
||||
break Some((n.kw_function.range.unwrap(), L!("function definition")));
|
||||
}
|
||||
Type::begin_header => {
|
||||
let n = cursor.as_begin_header().unwrap();
|
||||
break Some((n.kw_begin.range.unwrap(), "begin"L));
|
||||
break Some((n.kw_begin.range.unwrap(), L!("begin")));
|
||||
}
|
||||
Type::if_statement => {
|
||||
let n = cursor.as_if_statement().unwrap();
|
||||
break Some((n.if_clause.kw_if.range.unwrap(), "if statement"L));
|
||||
break Some((n.if_clause.kw_if.range.unwrap(), L!("if statement")));
|
||||
}
|
||||
Type::switch_statement => {
|
||||
let n = cursor.as_switch_statement().unwrap();
|
||||
break Some((n.kw_switch.range.unwrap(), "switch statement"L));
|
||||
break Some((n.kw_switch.range.unwrap(), L!("switch statement")));
|
||||
}
|
||||
_ => break None,
|
||||
}
|
||||
|
@ -2919,31 +2917,29 @@ impl<'s> NodeVisitorMut for Populator<'s> {
|
|||
|
||||
/// Helper to describe a list of keywords.
|
||||
/// TODO: these need to be localized properly.
|
||||
#[widestrs]
|
||||
fn keywords_user_presentable_description(kws: &'static [ParseKeyword]) -> WString {
|
||||
assert!(!kws.is_empty(), "Should not be empty list");
|
||||
if kws.len() == 1 {
|
||||
return sprintf!("keyword '%ls'"L, kws[0]);
|
||||
return sprintf!(L!("keyword '%ls'"), kws[0]);
|
||||
}
|
||||
let mut res = "keywords "L.to_owned();
|
||||
let mut res = L!("keywords ").to_owned();
|
||||
for (i, kw) in kws.iter().enumerate() {
|
||||
if i != 0 {
|
||||
res += " or "L;
|
||||
res += L!(" or ");
|
||||
}
|
||||
res += &sprintf!("'%ls'"L, *kw)[..];
|
||||
res += &sprintf!(L!("'%ls'"), *kw)[..];
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
/// Helper to describe a list of token types.
|
||||
/// TODO: these need to be localized properly.
|
||||
#[widestrs]
|
||||
fn token_types_user_presentable_description(types: &'static [ParseTokenType]) -> WString {
|
||||
assert!(!types.is_empty(), "Should not be empty list");
|
||||
let mut res = WString::new();
|
||||
for typ in types {
|
||||
if !res.is_empty() {
|
||||
res += " or "L;
|
||||
res += L!(" or ");
|
||||
}
|
||||
res += &token_type_user_presentable_description(*typ, ParseKeyword::none)[..];
|
||||
}
|
||||
|
|
|
@ -318,7 +318,6 @@ impl AutoloadFileCache {
|
|||
}
|
||||
}
|
||||
|
||||
#[widestring_suffix::widestrs]
|
||||
#[test]
|
||||
#[serial]
|
||||
fn test_autoload() {
|
||||
|
@ -349,47 +348,53 @@ fn test_autoload() {
|
|||
let p2 = charptr2wcstring(unsafe { libc::mkdtemp(t2.as_mut_ptr().cast()) });
|
||||
|
||||
let paths = &[p1.clone(), p2.clone()];
|
||||
let mut autoload = Autoload::new("test_var"L);
|
||||
assert!(autoload.resolve_command_impl("file1"L, paths).is_none());
|
||||
assert!(autoload.resolve_command_impl("nothing"L, paths).is_none());
|
||||
let mut autoload = Autoload::new(L!("test_var"));
|
||||
assert!(autoload.resolve_command_impl(L!("file1"), paths).is_none());
|
||||
assert!(autoload
|
||||
.resolve_command_impl(L!("nothing"), paths)
|
||||
.is_none());
|
||||
assert!(autoload.get_autoloaded_commands().is_empty());
|
||||
|
||||
run!("touch %ls/file1.fish", p1);
|
||||
run!("touch %ls/file2.fish", p2);
|
||||
autoload.invalidate_cache();
|
||||
|
||||
assert!(!autoload.autoload_in_progress("file1"L));
|
||||
assert!(autoload.resolve_command_impl("file1"L, paths).is_some());
|
||||
assert!(autoload.resolve_command_impl("file1"L, paths).is_none());
|
||||
assert!(autoload.autoload_in_progress("file1"L));
|
||||
assert!(autoload.get_autoloaded_commands() == vec!["file1"L]);
|
||||
autoload.mark_autoload_finished("file1"L);
|
||||
assert!(!autoload.autoload_in_progress("file1"L));
|
||||
assert!(autoload.get_autoloaded_commands() == vec!["file1"L]);
|
||||
assert!(!autoload.autoload_in_progress(L!("file1")));
|
||||
assert!(autoload.resolve_command_impl(L!("file1"), paths).is_some());
|
||||
assert!(autoload.resolve_command_impl(L!("file1"), paths).is_none());
|
||||
assert!(autoload.autoload_in_progress(L!("file1")));
|
||||
assert!(autoload.get_autoloaded_commands() == vec![L!("file1")]);
|
||||
autoload.mark_autoload_finished(L!("file1"));
|
||||
assert!(!autoload.autoload_in_progress(L!("file1")));
|
||||
assert!(autoload.get_autoloaded_commands() == vec![L!("file1")]);
|
||||
|
||||
assert!(autoload.resolve_command_impl("file1"L, paths).is_none());
|
||||
assert!(autoload.resolve_command_impl("nothing"L, paths).is_none());
|
||||
assert!(autoload.resolve_command_impl("file2"L, paths).is_some());
|
||||
assert!(autoload.resolve_command_impl("file2"L, paths).is_none());
|
||||
autoload.mark_autoload_finished("file2"L);
|
||||
assert!(autoload.resolve_command_impl("file2"L, paths).is_none());
|
||||
assert!((autoload.get_autoloaded_commands() == vec!["file1"L, "file2"L]));
|
||||
assert!(autoload.resolve_command_impl(L!("file1"), paths).is_none());
|
||||
assert!(autoload
|
||||
.resolve_command_impl(L!("nothing"), paths)
|
||||
.is_none());
|
||||
assert!(autoload.resolve_command_impl(L!("file2"), paths).is_some());
|
||||
assert!(autoload.resolve_command_impl(L!("file2"), paths).is_none());
|
||||
autoload.mark_autoload_finished(L!("file2"));
|
||||
assert!(autoload.resolve_command_impl(L!("file2"), paths).is_none());
|
||||
assert!((autoload.get_autoloaded_commands() == vec![L!("file1"), L!("file2")]));
|
||||
|
||||
autoload.clear();
|
||||
assert!(autoload.resolve_command_impl("file1"L, paths).is_some());
|
||||
autoload.mark_autoload_finished("file1"L);
|
||||
assert!(autoload.resolve_command_impl("file1"L, paths).is_none());
|
||||
assert!(autoload.resolve_command_impl("nothing"L, paths).is_none());
|
||||
assert!(autoload.resolve_command_impl("file2"L, paths).is_some());
|
||||
assert!(autoload.resolve_command_impl("file2"L, paths).is_none());
|
||||
autoload.mark_autoload_finished("file2"L);
|
||||
assert!(autoload.resolve_command_impl(L!("file1"), paths).is_some());
|
||||
autoload.mark_autoload_finished(L!("file1"));
|
||||
assert!(autoload.resolve_command_impl(L!("file1"), paths).is_none());
|
||||
assert!(autoload
|
||||
.resolve_command_impl(L!("nothing"), paths)
|
||||
.is_none());
|
||||
assert!(autoload.resolve_command_impl(L!("file2"), paths).is_some());
|
||||
assert!(autoload.resolve_command_impl(L!("file2"), paths).is_none());
|
||||
autoload.mark_autoload_finished(L!("file2"));
|
||||
|
||||
assert!(autoload.resolve_command_impl("file1"L, paths).is_none());
|
||||
assert!(autoload.resolve_command_impl(L!("file1"), paths).is_none());
|
||||
touch_file(&sprintf!("%ls/file1.fish", p1));
|
||||
autoload.invalidate_cache();
|
||||
assert!(autoload.resolve_command_impl("file1"L, paths).is_some());
|
||||
autoload.mark_autoload_finished("file1"L);
|
||||
assert!(autoload.resolve_command_impl(L!("file1"), paths).is_some());
|
||||
autoload.mark_autoload_finished(L!("file1"));
|
||||
|
||||
run!("rm -Rf %ls"L, p1);
|
||||
run!("rm -Rf %ls"L, p2);
|
||||
run!(L!("rm -Rf %ls"), p1);
|
||||
run!(L!("rm -Rf %ls"), p2);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use super::prelude::*;
|
||||
use crate::event;
|
||||
|
||||
#[widestrs]
|
||||
pub fn emit(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> Option<c_int> {
|
||||
let cmd = argv[0];
|
||||
|
||||
|
@ -19,7 +18,7 @@ pub fn emit(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> Opt
|
|||
let Some(event_name) = argv.get(opts.optind) else {
|
||||
streams
|
||||
.err
|
||||
.append(sprintf!("%ls: expected event name\n"L, cmd));
|
||||
.append(sprintf!(L!("%ls: expected event name\n"), cmd));
|
||||
return STATUS_INVALID_ARGS;
|
||||
};
|
||||
|
||||
|
|
|
@ -14,22 +14,21 @@ struct Options {
|
|||
base: usize,
|
||||
}
|
||||
|
||||
#[widestrs]
|
||||
fn parse_cmd_opts(
|
||||
args: &mut [&wstr],
|
||||
parser: &Parser,
|
||||
streams: &mut IoStreams,
|
||||
) -> Result<(Options, usize), Option<c_int>> {
|
||||
const cmd: &wstr = "math"L;
|
||||
const cmd: &wstr = L!("math");
|
||||
let print_hints = true;
|
||||
|
||||
// This command is atypical in using the "+" (REQUIRE_ORDER) option for flag parsing.
|
||||
// This is needed because of the minus, `-`, operator in math expressions.
|
||||
const SHORT_OPTS: &wstr = "+:hs:b:"L;
|
||||
const SHORT_OPTS: &wstr = L!("+:hs:b:");
|
||||
const LONG_OPTS: &[woption] = &[
|
||||
wopt("scale"L, woption_argument_t::required_argument, 's'),
|
||||
wopt("base"L, woption_argument_t::required_argument, 'b'),
|
||||
wopt("help"L, woption_argument_t::no_argument, 'h'),
|
||||
wopt(L!("scale"), woption_argument_t::required_argument, 's'),
|
||||
wopt(L!("base"), woption_argument_t::required_argument, 'b'),
|
||||
wopt(L!("help"), woption_argument_t::no_argument, 'h'),
|
||||
];
|
||||
|
||||
let mut opts = Options {
|
||||
|
@ -158,7 +157,6 @@ fn format_double(mut v: f64, opts: &Options) -> WString {
|
|||
ret
|
||||
}
|
||||
|
||||
#[widestrs]
|
||||
fn evaluate_expression(
|
||||
cmd: &wstr,
|
||||
streams: &mut IoStreams,
|
||||
|
@ -174,11 +172,11 @@ fn evaluate_expression(
|
|||
// (e.g. infinite is the result of "x / 0"),
|
||||
// but that's much more work.
|
||||
let error_message = if n.is_infinite() {
|
||||
"Result is infinite"L
|
||||
L!("Result is infinite")
|
||||
} else if n.is_nan() {
|
||||
"Result is not a number"L
|
||||
L!("Result is not a number")
|
||||
} else if n.abs() >= MAX_CONTIGUOUS_INTEGER {
|
||||
"Result magnitude is too large"L
|
||||
L!("Result magnitude is too large")
|
||||
} else {
|
||||
let mut s = format_double(n, opts);
|
||||
s.push('\n');
|
||||
|
@ -189,24 +187,26 @@ fn evaluate_expression(
|
|||
|
||||
streams
|
||||
.err
|
||||
.append(sprintf!("%ls: Error: %ls\n"L, cmd, error_message));
|
||||
streams.err.append(sprintf!("'%ls'\n"L, expression));
|
||||
.append(sprintf!(L!("%ls: Error: %ls\n"), cmd, error_message));
|
||||
streams.err.append(sprintf!(L!("'%ls'\n"), expression));
|
||||
|
||||
STATUS_CMD_ERROR
|
||||
}
|
||||
Err(err) => {
|
||||
streams.err.append(sprintf!(
|
||||
"%ls: Error: %ls\n"L,
|
||||
L!("%ls: Error: %ls\n"),
|
||||
cmd,
|
||||
err.kind.describe_wstr()
|
||||
));
|
||||
streams.err.append(sprintf!("'%ls'\n"L, expression));
|
||||
streams.err.append(sprintf!(L!("'%ls'\n"), expression));
|
||||
let padding = WString::from_chars(vec![' '; err.position + 1]);
|
||||
if err.len >= 2 {
|
||||
let tildes = WString::from_chars(vec!['~'; err.len - 2]);
|
||||
streams.err.append(sprintf!("%ls^%ls^\n"L, padding, tildes));
|
||||
streams
|
||||
.err
|
||||
.append(sprintf!(L!("%ls^%ls^\n"), padding, tildes));
|
||||
} else {
|
||||
streams.err.append(sprintf!("%ls^\n"L, padding));
|
||||
streams.err.append(sprintf!(L!("%ls^\n"), padding));
|
||||
}
|
||||
|
||||
STATUS_CMD_ERROR
|
||||
|
@ -218,7 +218,6 @@ fn evaluate_expression(
|
|||
const MATH_CHUNK_SIZE: usize = 1024;
|
||||
|
||||
/// The math builtin evaluates math expressions.
|
||||
#[widestrs]
|
||||
pub fn math(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> Option<c_int> {
|
||||
let cmd = argv[0];
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@ use std::fs::File;
|
|||
use std::io::{BufRead, BufReader, Read};
|
||||
use std::os::fd::FromRawFd;
|
||||
use std::sync::Arc;
|
||||
use widestring_suffix::widestrs;
|
||||
|
||||
pub type BuiltinCmd = fn(&Parser, &mut IoStreams, &mut [&wstr]) -> Option<c_int>;
|
||||
|
||||
|
@ -115,250 +114,249 @@ struct BuiltinData {
|
|||
// Data about all the builtin commands in fish.
|
||||
// Functions that are bound to builtin_generic are handled directly by the parser.
|
||||
// NOTE: These must be kept in sorted order!
|
||||
#[widestrs]
|
||||
const BUILTIN_DATAS: &[BuiltinData] = &[
|
||||
BuiltinData {
|
||||
name: "."L,
|
||||
name: L!("."),
|
||||
func: source::source,
|
||||
},
|
||||
BuiltinData {
|
||||
name: ":"L,
|
||||
name: L!(":"),
|
||||
func: builtin_true,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "["L, // ]
|
||||
name: L!("["), // ]
|
||||
func: test::test,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "_"L,
|
||||
name: L!("_"),
|
||||
func: builtin_gettext,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "abbr"L,
|
||||
name: L!("abbr"),
|
||||
func: abbr::abbr,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "and"L,
|
||||
name: L!("and"),
|
||||
func: builtin_generic,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "argparse"L,
|
||||
name: L!("argparse"),
|
||||
func: argparse::argparse,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "begin"L,
|
||||
name: L!("begin"),
|
||||
func: builtin_generic,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "bg"L,
|
||||
name: L!("bg"),
|
||||
func: bg::bg,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "bind"L,
|
||||
name: L!("bind"),
|
||||
func: bind::bind,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "block"L,
|
||||
name: L!("block"),
|
||||
func: block::block,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "break"L,
|
||||
name: L!("break"),
|
||||
func: builtin_break_continue,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "breakpoint"L,
|
||||
name: L!("breakpoint"),
|
||||
func: builtin_breakpoint,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "builtin"L,
|
||||
name: L!("builtin"),
|
||||
func: builtin::builtin,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "case"L,
|
||||
name: L!("case"),
|
||||
func: builtin_generic,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "cd"L,
|
||||
name: L!("cd"),
|
||||
func: cd::cd,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "command"L,
|
||||
name: L!("command"),
|
||||
func: command::command,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "commandline"L,
|
||||
name: L!("commandline"),
|
||||
func: commandline::commandline,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "complete"L,
|
||||
name: L!("complete"),
|
||||
func: complete::complete,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "contains"L,
|
||||
name: L!("contains"),
|
||||
func: contains::contains,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "continue"L,
|
||||
name: L!("continue"),
|
||||
func: builtin_break_continue,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "count"L,
|
||||
name: L!("count"),
|
||||
func: count::count,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "disown"L,
|
||||
name: L!("disown"),
|
||||
func: disown::disown,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "echo"L,
|
||||
name: L!("echo"),
|
||||
func: echo::echo,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "else"L,
|
||||
name: L!("else"),
|
||||
func: builtin_generic,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "emit"L,
|
||||
name: L!("emit"),
|
||||
func: emit::emit,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "end"L,
|
||||
name: L!("end"),
|
||||
func: builtin_generic,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "eval"L,
|
||||
name: L!("eval"),
|
||||
func: eval::eval,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "exec"L,
|
||||
name: L!("exec"),
|
||||
func: builtin_generic,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "exit"L,
|
||||
name: L!("exit"),
|
||||
func: exit::exit,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "false"L,
|
||||
name: L!("false"),
|
||||
func: builtin_false,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "fg"L,
|
||||
name: L!("fg"),
|
||||
func: fg::fg,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "for"L,
|
||||
name: L!("for"),
|
||||
func: builtin_generic,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "function"L,
|
||||
name: L!("function"),
|
||||
func: builtin_generic,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "functions"L,
|
||||
name: L!("functions"),
|
||||
func: functions::functions,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "history"L,
|
||||
name: L!("history"),
|
||||
func: history::history,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "if"L,
|
||||
name: L!("if"),
|
||||
func: builtin_generic,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "jobs"L,
|
||||
name: L!("jobs"),
|
||||
func: jobs::jobs,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "math"L,
|
||||
name: L!("math"),
|
||||
func: math::math,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "not"L,
|
||||
name: L!("not"),
|
||||
func: builtin_generic,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "or"L,
|
||||
name: L!("or"),
|
||||
func: builtin_generic,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "path"L,
|
||||
name: L!("path"),
|
||||
func: path::path,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "printf"L,
|
||||
name: L!("printf"),
|
||||
func: printf::printf,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "pwd"L,
|
||||
name: L!("pwd"),
|
||||
func: pwd::pwd,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "random"L,
|
||||
name: L!("random"),
|
||||
func: random::random,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "read"L,
|
||||
name: L!("read"),
|
||||
func: read::read,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "realpath"L,
|
||||
name: L!("realpath"),
|
||||
func: realpath::realpath,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "return"L,
|
||||
name: L!("return"),
|
||||
func: r#return::r#return,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "set"L,
|
||||
name: L!("set"),
|
||||
func: set::set,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "set_color"L,
|
||||
name: L!("set_color"),
|
||||
func: set_color::set_color,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "source"L,
|
||||
name: L!("source"),
|
||||
func: source::source,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "status"L,
|
||||
name: L!("status"),
|
||||
func: status::status,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "string"L,
|
||||
name: L!("string"),
|
||||
func: string::string,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "switch"L,
|
||||
name: L!("switch"),
|
||||
func: builtin_generic,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "test"L,
|
||||
name: L!("test"),
|
||||
func: test::test,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "time"L,
|
||||
name: L!("time"),
|
||||
func: builtin_generic,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "true"L,
|
||||
name: L!("true"),
|
||||
func: builtin_true,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "type"L,
|
||||
name: L!("type"),
|
||||
func: r#type::r#type,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "ulimit"L,
|
||||
name: L!("ulimit"),
|
||||
func: ulimit::ulimit,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "wait"L,
|
||||
name: L!("wait"),
|
||||
func: wait::wait,
|
||||
},
|
||||
BuiltinData {
|
||||
name: "while"L,
|
||||
name: L!("while"),
|
||||
func: builtin_generic,
|
||||
},
|
||||
];
|
||||
|
@ -380,16 +378,15 @@ pub fn builtin_exists(name: &wstr) -> bool {
|
|||
}
|
||||
|
||||
/// Is the command a keyword we need to special-case the handling of `-h` and `--help`.
|
||||
#[widestrs]
|
||||
fn cmd_needs_help(cmd: &wstr) -> bool {
|
||||
[
|
||||
"for"L,
|
||||
"while"L,
|
||||
"function"L,
|
||||
"if"L,
|
||||
"end"L,
|
||||
"switch"L,
|
||||
"case"L,
|
||||
L!("for"),
|
||||
L!("while"),
|
||||
L!("function"),
|
||||
L!("if"),
|
||||
L!("end"),
|
||||
L!("switch"),
|
||||
L!("case"),
|
||||
]
|
||||
.contains(&cmd)
|
||||
}
|
||||
|
|
|
@ -47,7 +47,6 @@ fn run_test_test(expected: i32, lst: &[&str]) -> bool {
|
|||
nobracket
|
||||
}
|
||||
|
||||
#[widestrs]
|
||||
fn test_test_brackets() {
|
||||
// Ensure [ knows it needs a ].
|
||||
let parser = Parser::principal_parser();
|
||||
|
@ -57,16 +56,16 @@ fn test_test_brackets() {
|
|||
let io_chain = IoChain::new();
|
||||
let mut streams = IoStreams::new(&mut out, &mut err, &io_chain);
|
||||
|
||||
let args1 = &mut ["["L, "foo"L];
|
||||
let args1 = &mut [L!("["), L!("foo")];
|
||||
assert_eq!(
|
||||
builtin_test(parser, &mut streams, args1),
|
||||
STATUS_INVALID_ARGS
|
||||
);
|
||||
|
||||
let args2 = &mut ["["L, "foo"L, "]"L];
|
||||
let args2 = &mut [L!("["), L!("foo"), L!("]")];
|
||||
assert_eq!(builtin_test(parser, &mut streams, args2), STATUS_CMD_OK);
|
||||
|
||||
let args3 = &mut ["["L, "foo"L, "]"L, "bar"L];
|
||||
let args3 = &mut [L!("["), L!("foo"), L!("]"), L!("bar")];
|
||||
assert_eq!(
|
||||
builtin_test(parser, &mut streams, args3),
|
||||
STATUS_INVALID_ARGS
|
||||
|
|
|
@ -127,7 +127,6 @@ fn wait_for_completion(parser: &Parser, whs: &[WaitHandleRef], any_flag: bool) -
|
|||
}
|
||||
}
|
||||
|
||||
#[widestrs]
|
||||
pub fn wait(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> Option<c_int> {
|
||||
let cmd = argv[0];
|
||||
let argc = argv.len();
|
||||
|
@ -135,10 +134,10 @@ pub fn wait(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> Opt
|
|||
let mut print_help = false;
|
||||
let print_hints = false;
|
||||
|
||||
const shortopts: &wstr = ":nh"L;
|
||||
const shortopts: &wstr = L!(":nh");
|
||||
const longopts: &[woption] = &[
|
||||
wopt("any"L, woption_argument_t::no_argument, 'n'),
|
||||
wopt("help"L, woption_argument_t::no_argument, 'h'),
|
||||
wopt(L!("any"), woption_argument_t::no_argument, 'n'),
|
||||
wopt(L!("help"), woption_argument_t::no_argument, 'h'),
|
||||
];
|
||||
|
||||
let mut w = wgetopter_t::new(shortopts, longopts, argv);
|
||||
|
|
82
src/color.rs
82
src/color.rs
|
@ -231,13 +231,12 @@ impl RgbColor {
|
|||
}
|
||||
|
||||
/// Try parsing a special color name like "normal".
|
||||
#[widestrs]
|
||||
fn try_parse_special(special: &wstr) -> Option<Self> {
|
||||
// TODO: this is a very hot function, may need optimization by e.g. comparing length first,
|
||||
// depending on how well inlining of `simple_icase_compare` works
|
||||
let typ = if simple_icase_compare(special, "normal"L) == Ordering::Equal {
|
||||
let typ = if simple_icase_compare(special, L!("normal")) == Ordering::Equal {
|
||||
Type::Normal
|
||||
} else if simple_icase_compare(special, "reset"L) == Ordering::Equal {
|
||||
} else if simple_icase_compare(special, L!("reset")) == Ordering::Equal {
|
||||
Type::Reset
|
||||
} else {
|
||||
return None;
|
||||
|
@ -320,32 +319,31 @@ struct NamedColor {
|
|||
hidden: bool,
|
||||
}
|
||||
|
||||
#[widestrs]
|
||||
#[rustfmt::skip]
|
||||
const NAMED_COLORS: &[NamedColor] = &[
|
||||
// Keep this sorted alphabetically
|
||||
NamedColor {name: "black"L, idx: 0, _rgb: [0x00, 0x00, 0x00], hidden: false},
|
||||
NamedColor {name: "blue"L, idx: 4, _rgb: [0x00, 0x00, 0x80], hidden: false},
|
||||
NamedColor {name: "brblack"L, idx: 8, _rgb: [0x80, 0x80, 0x80], hidden: false},
|
||||
NamedColor {name: "brblue"L, idx: 12, _rgb: [0x00, 0x00, 0xFF], hidden: false},
|
||||
NamedColor {name: "brbrown"L, idx: 11, _rgb: [0xFF, 0xFF, 0x00], hidden: true},
|
||||
NamedColor {name: "brcyan"L, idx: 14, _rgb: [0x00, 0xFF, 0xFF], hidden: false},
|
||||
NamedColor {name: "brgreen"L, idx: 10, _rgb: [0x00, 0xFF, 0x00], hidden: false},
|
||||
NamedColor {name: "brgrey"L, idx: 8, _rgb: [0x55, 0x55, 0x55], hidden: true},
|
||||
NamedColor {name: "brmagenta"L, idx: 13, _rgb: [0xFF, 0x00, 0xFF], hidden: false},
|
||||
NamedColor {name: "brown"L, idx: 3, _rgb: [0x72, 0x50, 0x00], hidden: true},
|
||||
NamedColor {name: "brpurple"L, idx: 13, _rgb: [0xFF, 0x00, 0xFF], hidden: true},
|
||||
NamedColor {name: "brred"L, idx: 9, _rgb: [0xFF, 0x00, 0x00], hidden: false},
|
||||
NamedColor {name: "brwhite"L, idx: 15, _rgb: [0xFF, 0xFF, 0xFF], hidden: false},
|
||||
NamedColor {name: "bryellow"L, idx: 11, _rgb: [0xFF, 0xFF, 0x00], hidden: false},
|
||||
NamedColor {name: "cyan"L, idx: 6, _rgb: [0x00, 0x80, 0x80], hidden: false},
|
||||
NamedColor {name: "green"L, idx: 2, _rgb: [0x00, 0x80, 0x00], hidden: false},
|
||||
NamedColor {name: "grey"L, idx: 7, _rgb: [0xE5, 0xE5, 0xE5], hidden: true},
|
||||
NamedColor {name: "magenta"L, idx: 5, _rgb: [0x80, 0x00, 0x80], hidden: false},
|
||||
NamedColor {name: "purple"L, idx: 5, _rgb: [0x80, 0x00, 0x80], hidden: true},
|
||||
NamedColor {name: "red"L, idx: 1, _rgb: [0x80, 0x00, 0x00], hidden: false},
|
||||
NamedColor {name: "white"L, idx: 7, _rgb: [0xC0, 0xC0, 0xC0], hidden: false},
|
||||
NamedColor {name: "yellow"L, idx: 3, _rgb: [0x80, 0x80, 0x00], hidden: false},
|
||||
NamedColor {name: L!("black"), idx: 0, _rgb: [0x00, 0x00, 0x00], hidden: false},
|
||||
NamedColor {name: L!("blue"), idx: 4, _rgb: [0x00, 0x00, 0x80], hidden: false},
|
||||
NamedColor {name: L!("brblack"), idx: 8, _rgb: [0x80, 0x80, 0x80], hidden: false},
|
||||
NamedColor {name: L!("brblue"), idx: 12, _rgb: [0x00, 0x00, 0xFF], hidden: false},
|
||||
NamedColor {name: L!("brbrown"), idx: 11, _rgb: [0xFF, 0xFF, 0x00], hidden: true},
|
||||
NamedColor {name: L!("brcyan"), idx: 14, _rgb: [0x00, 0xFF, 0xFF], hidden: false},
|
||||
NamedColor {name: L!("brgreen"), idx: 10, _rgb: [0x00, 0xFF, 0x00], hidden: false},
|
||||
NamedColor {name: L!("brgrey"), idx: 8, _rgb: [0x55, 0x55, 0x55], hidden: true},
|
||||
NamedColor {name: L!("brmagenta"), idx: 13, _rgb: [0xFF, 0x00, 0xFF], hidden: false},
|
||||
NamedColor {name: L!("brown"), idx: 3, _rgb: [0x72, 0x50, 0x00], hidden: true},
|
||||
NamedColor {name: L!("brpurple"), idx: 13, _rgb: [0xFF, 0x00, 0xFF], hidden: true},
|
||||
NamedColor {name: L!("brred"), idx: 9, _rgb: [0xFF, 0x00, 0x00], hidden: false},
|
||||
NamedColor {name: L!("brwhite"), idx: 15, _rgb: [0xFF, 0xFF, 0xFF], hidden: false},
|
||||
NamedColor {name: L!("bryellow"), idx: 11, _rgb: [0xFF, 0xFF, 0x00], hidden: false},
|
||||
NamedColor {name: L!("cyan"), idx: 6, _rgb: [0x00, 0x80, 0x80], hidden: false},
|
||||
NamedColor {name: L!("green"), idx: 2, _rgb: [0x00, 0x80, 0x00], hidden: false},
|
||||
NamedColor {name: L!("grey"), idx: 7, _rgb: [0xE5, 0xE5, 0xE5], hidden: true},
|
||||
NamedColor {name: L!("magenta"), idx: 5, _rgb: [0x80, 0x00, 0x80], hidden: false},
|
||||
NamedColor {name: L!("purple"), idx: 5, _rgb: [0x80, 0x00, 0x80], hidden: true},
|
||||
NamedColor {name: L!("red"), idx: 1, _rgb: [0x80, 0x00, 0x00], hidden: false},
|
||||
NamedColor {name: L!("white"), idx: 7, _rgb: [0xC0, 0xC0, 0xC0], hidden: false},
|
||||
NamedColor {name: L!("yellow"), idx: 3, _rgb: [0x80, 0x80, 0x00], hidden: false},
|
||||
];
|
||||
|
||||
assert_sorted_by_name!(NAMED_COLORS);
|
||||
|
@ -434,28 +432,26 @@ mod tests {
|
|||
use crate::wchar::prelude::*;
|
||||
|
||||
#[test]
|
||||
#[widestrs]
|
||||
fn parse() {
|
||||
assert!(RgbColor::from_wstr("#FF00A0"L).unwrap().is_rgb());
|
||||
assert!(RgbColor::from_wstr("FF00A0"L).unwrap().is_rgb());
|
||||
assert!(RgbColor::from_wstr("#F30"L).unwrap().is_rgb());
|
||||
assert!(RgbColor::from_wstr("F30"L).unwrap().is_rgb());
|
||||
assert!(RgbColor::from_wstr("f30"L).unwrap().is_rgb());
|
||||
assert!(RgbColor::from_wstr("#FF30a5"L).unwrap().is_rgb());
|
||||
assert!(RgbColor::from_wstr("3f30"L).is_none());
|
||||
assert!(RgbColor::from_wstr("##f30"L).is_none());
|
||||
assert!(RgbColor::from_wstr("magenta"L).unwrap().is_named());
|
||||
assert!(RgbColor::from_wstr("MaGeNTa"L).unwrap().is_named());
|
||||
assert!(RgbColor::from_wstr("mooganta"L).is_none());
|
||||
assert!(RgbColor::from_wstr(L!("#FF00A0")).unwrap().is_rgb());
|
||||
assert!(RgbColor::from_wstr(L!("FF00A0")).unwrap().is_rgb());
|
||||
assert!(RgbColor::from_wstr(L!("#F30")).unwrap().is_rgb());
|
||||
assert!(RgbColor::from_wstr(L!("F30")).unwrap().is_rgb());
|
||||
assert!(RgbColor::from_wstr(L!("f30")).unwrap().is_rgb());
|
||||
assert!(RgbColor::from_wstr(L!("#FF30a5")).unwrap().is_rgb());
|
||||
assert!(RgbColor::from_wstr(L!("3f30")).is_none());
|
||||
assert!(RgbColor::from_wstr(L!("##f30")).is_none());
|
||||
assert!(RgbColor::from_wstr(L!("magenta")).unwrap().is_named());
|
||||
assert!(RgbColor::from_wstr(L!("MaGeNTa")).unwrap().is_named());
|
||||
assert!(RgbColor::from_wstr(L!("mooganta")).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[widestrs]
|
||||
fn parse_rgb() {
|
||||
assert!(RgbColor::from_wstr("##FF00A0"L) == None);
|
||||
assert!(RgbColor::from_wstr("#FF00A0"L) == Some(RgbColor::from_rgb(0xff, 0x00, 0xa0)));
|
||||
assert!(RgbColor::from_wstr("FF00A0"L) == Some(RgbColor::from_rgb(0xff, 0x00, 0xa0)));
|
||||
assert!(RgbColor::from_wstr("FAF"L) == Some(RgbColor::from_rgb(0xff, 0xaa, 0xff)));
|
||||
assert!(RgbColor::from_wstr(L!("##FF00A0")) == None);
|
||||
assert!(RgbColor::from_wstr(L!("#FF00A0")) == Some(RgbColor::from_rgb(0xff, 0x00, 0xa0)));
|
||||
assert!(RgbColor::from_wstr(L!("FF00A0")) == Some(RgbColor::from_rgb(0xff, 0x00, 0xa0)));
|
||||
assert!(RgbColor::from_wstr(L!("FAF")) == Some(RgbColor::from_rgb(0xff, 0xaa, 0xff)));
|
||||
}
|
||||
|
||||
// Regression test for multiplicative overflow in convert_color.
|
||||
|
|
|
@ -180,7 +180,6 @@ pub fn escape_string(s: &wstr, style: EscapeStringStyle) -> WString {
|
|||
}
|
||||
|
||||
/// Escape a string in a fashion suitable for using in fish script.
|
||||
#[widestrs]
|
||||
fn escape_string_script(input: &wstr, flags: EscapeFlags) -> WString {
|
||||
let escape_printables = !flags.contains(EscapeFlags::NO_PRINTABLES);
|
||||
let no_quoted = flags.contains(EscapeFlags::NO_QUOTED);
|
||||
|
@ -197,7 +196,7 @@ fn escape_string_script(input: &wstr, flags: EscapeFlags) -> WString {
|
|||
let mut need_complex_escape = false;
|
||||
|
||||
if !no_quoted && input.is_empty() {
|
||||
return "''"L.to_owned();
|
||||
return L!("''").to_owned();
|
||||
}
|
||||
|
||||
let mut out = WString::new();
|
||||
|
@ -220,7 +219,7 @@ fn escape_string_script(input: &wstr, flags: EscapeFlags) -> WString {
|
|||
if symbolic {
|
||||
out.push('␉');
|
||||
} else {
|
||||
out += "\\t"L;
|
||||
out += L!("\\t");
|
||||
}
|
||||
need_escape = true;
|
||||
need_complex_escape = true;
|
||||
|
@ -229,7 +228,7 @@ fn escape_string_script(input: &wstr, flags: EscapeFlags) -> WString {
|
|||
if symbolic {
|
||||
out.push('');
|
||||
} else {
|
||||
out += "\\n"L;
|
||||
out += L!("\\n");
|
||||
}
|
||||
need_escape = true;
|
||||
need_complex_escape = true;
|
||||
|
@ -238,7 +237,7 @@ fn escape_string_script(input: &wstr, flags: EscapeFlags) -> WString {
|
|||
if symbolic {
|
||||
out.push('␈');
|
||||
} else {
|
||||
out += "\\b"L;
|
||||
out += L!("\\b");
|
||||
}
|
||||
need_escape = true;
|
||||
need_complex_escape = true;
|
||||
|
@ -247,7 +246,7 @@ fn escape_string_script(input: &wstr, flags: EscapeFlags) -> WString {
|
|||
if symbolic {
|
||||
out.push('␍');
|
||||
} else {
|
||||
out += "\\r"L;
|
||||
out += L!("\\r");
|
||||
}
|
||||
need_escape = true;
|
||||
need_complex_escape = true;
|
||||
|
@ -256,7 +255,7 @@ fn escape_string_script(input: &wstr, flags: EscapeFlags) -> WString {
|
|||
if symbolic {
|
||||
out.push('␛');
|
||||
} else {
|
||||
out += "\\e"L;
|
||||
out += L!("\\e");
|
||||
}
|
||||
need_escape = true;
|
||||
need_complex_escape = true;
|
||||
|
@ -265,7 +264,7 @@ fn escape_string_script(input: &wstr, flags: EscapeFlags) -> WString {
|
|||
if symbolic {
|
||||
out.push('␡');
|
||||
} else {
|
||||
out += "\\x7f"L;
|
||||
out += L!("\\x7f");
|
||||
}
|
||||
need_escape = true;
|
||||
need_complex_escape = true;
|
||||
|
@ -286,7 +285,7 @@ fn escape_string_script(input: &wstr, flags: EscapeFlags) -> WString {
|
|||
out.push('*');
|
||||
}
|
||||
ANY_STRING_RECURSIVE => {
|
||||
out += "**"L;
|
||||
out += L!("**");
|
||||
}
|
||||
|
||||
'&' | '$' | ' ' | '#' | '<' | '>' | '(' | ')' | '[' | ']' | '{' | '}' | '?' | '*'
|
||||
|
@ -358,7 +357,6 @@ fn byte_to_hex(byte: u8) -> (char, char) {
|
|||
}
|
||||
|
||||
/// Escape a string in a fashion suitable for using as a URL. Store the result in out_str.
|
||||
#[widestrs]
|
||||
fn escape_string_url(input: &wstr) -> WString {
|
||||
let narrow = wcs2string(input);
|
||||
let mut out = WString::new();
|
||||
|
@ -1246,8 +1244,7 @@ fn count_ascii_prefix(inp: &[u8]) -> usize {
|
|||
}
|
||||
|
||||
// Check if we are running in the test mode, where we should suppress error output
|
||||
#[widestrs]
|
||||
pub const TESTS_PROGRAM_NAME: &wstr = "(ignore)"L;
|
||||
pub const TESTS_PROGRAM_NAME: &wstr = L!("(ignore)");
|
||||
|
||||
/// Hack to not print error messages in the tests. Do not call this from functions in this module
|
||||
/// like `debug()`. It is only intended to suppress diagnostic noise from testing things like the
|
||||
|
@ -1533,7 +1530,6 @@ pub fn read_loop<Fd: AsRawFd>(fd: &Fd, buf: &mut [u8]) -> std::io::Result<usize>
|
|||
}
|
||||
|
||||
/// Write the given paragraph of output, redoing linebreaks to fit \p termsize.
|
||||
#[widestrs]
|
||||
pub fn reformat_for_screen(msg: &wstr, termsize: &Termsize) -> WString {
|
||||
let mut buff = WString::new();
|
||||
|
||||
|
@ -1568,7 +1564,7 @@ pub fn reformat_for_screen(msg: &wstr, termsize: &Termsize) -> WString {
|
|||
if line_width != 0 {
|
||||
buff.push('\n');
|
||||
}
|
||||
buff += &sprintf!("%ls-\n"L, token)[..];
|
||||
buff += &sprintf!(L!("%ls-\n"), token)[..];
|
||||
line_width = 0;
|
||||
} else {
|
||||
// Print the token.
|
||||
|
@ -1579,7 +1575,7 @@ pub fn reformat_for_screen(msg: &wstr, termsize: &Termsize) -> WString {
|
|||
line_width = 0;
|
||||
}
|
||||
if line_width != 0 {
|
||||
buff += " "L;
|
||||
buff += L!(" ");
|
||||
}
|
||||
buff += token;
|
||||
line_width += line_width_unit + tok_width;
|
||||
|
|
37
src/env/environment_impl.rs
vendored
37
src/env/environment_impl.rs
vendored
|
@ -336,19 +336,18 @@ impl EnvScopedImpl {
|
|||
self.perproc_data.statuses = s;
|
||||
}
|
||||
|
||||
#[widestrs]
|
||||
fn try_get_computed(&self, key: &wstr) -> Option<EnvVar> {
|
||||
let ev = ElectricVar::for_name(key);
|
||||
if ev.is_none() || !ev.unwrap().computed() {
|
||||
return None;
|
||||
}
|
||||
|
||||
if key == "PWD"L {
|
||||
if key == L!("PWD") {
|
||||
Some(EnvVar::new(
|
||||
self.perproc_data.pwd.clone(),
|
||||
EnvVarFlags::EXPORT,
|
||||
))
|
||||
} else if key == "history"L {
|
||||
} else if key == L!("history") {
|
||||
// Big hack. We only allow getting the history on the main thread. Note that history_t
|
||||
// may ask for an environment variable, so don't take the lock here (we don't need it).
|
||||
if (!is_main_thread()) {
|
||||
|
@ -359,34 +358,40 @@ impl EnvScopedImpl {
|
|||
let session_id = history_session_id_from_var(fish_history_var);
|
||||
History::with_name(&session_id)
|
||||
});
|
||||
return Some(EnvVar::new_from_name_vec("history"L, history.get_history()));
|
||||
} else if key == "fish_killring"L {
|
||||
Some(EnvVar::new_from_name_vec("fish_killring"L, kill_entries()))
|
||||
} else if key == "pipestatus"L {
|
||||
return Some(EnvVar::new_from_name_vec(
|
||||
L!("history"),
|
||||
history.get_history(),
|
||||
));
|
||||
} else if key == L!("fish_killring") {
|
||||
Some(EnvVar::new_from_name_vec(
|
||||
L!("fish_killring"),
|
||||
kill_entries(),
|
||||
))
|
||||
} else if key == L!("pipestatus") {
|
||||
let js = &self.perproc_data.statuses;
|
||||
let mut result = Vec::new();
|
||||
result.reserve(js.pipestatus.len());
|
||||
for i in &js.pipestatus {
|
||||
result.push(i.to_wstring());
|
||||
}
|
||||
Some(EnvVar::new_from_name_vec("pipestatus"L, result))
|
||||
} else if key == "status"L {
|
||||
Some(EnvVar::new_from_name_vec(L!("pipestatus"), result))
|
||||
} else if key == L!("status") {
|
||||
let js = &self.perproc_data.statuses;
|
||||
Some(EnvVar::new_from_name("status"L, js.status.to_wstring()))
|
||||
} else if key == "status_generation"L {
|
||||
Some(EnvVar::new_from_name(L!("status"), js.status.to_wstring()))
|
||||
} else if key == L!("status_generation") {
|
||||
let status_generation = reader_status_count();
|
||||
Some(EnvVar::new_from_name(
|
||||
"status_generation"L,
|
||||
L!("status_generation"),
|
||||
status_generation.to_wstring(),
|
||||
))
|
||||
} else if key == "fish_kill_signal"L {
|
||||
} else if key == L!("fish_kill_signal") {
|
||||
let js = &self.perproc_data.statuses;
|
||||
let signal = js.kill_signal.map_or(0, |ks| ks.code());
|
||||
Some(EnvVar::new_from_name(
|
||||
"fish_kill_signal"L,
|
||||
L!("fish_kill_signal"),
|
||||
signal.to_wstring(),
|
||||
))
|
||||
} else if key == "umask"L {
|
||||
} else if key == L!("umask") {
|
||||
// note umask() is an absurd API: you call it to set the value and it returns the old
|
||||
// value. Thus we have to call it twice, to reset the value. The env_lock protects
|
||||
// against races. Guess what the umask is; if we guess right we don't need to reset it.
|
||||
|
@ -396,7 +401,7 @@ impl EnvScopedImpl {
|
|||
if res != guess {
|
||||
unsafe { libc::umask(res) };
|
||||
}
|
||||
Some(EnvVar::new_from_name("umask"L, sprintf!("0%0.3o", res)))
|
||||
Some(EnvVar::new_from_name(L!("umask"), sprintf!("0%0.3o", res)))
|
||||
} else {
|
||||
// We should never get here unless the electric var list is out of sync with the above code.
|
||||
panic!("Unrecognized computed var name {}", key);
|
||||
|
|
31
src/env/var.rs
vendored
31
src/env/var.rs
vendored
|
@ -1,5 +1,5 @@
|
|||
use crate::signal::Signal;
|
||||
use crate::wchar::{widestrs, wstr, WString};
|
||||
use crate::wchar::{wstr, WString, L};
|
||||
use crate::wcstringutil::join_strings;
|
||||
use bitflags::bitflags;
|
||||
use lazy_static::lazy_static;
|
||||
|
@ -253,22 +253,21 @@ pub struct ElectricVar {
|
|||
|
||||
// Keep sorted alphabetically
|
||||
#[rustfmt::skip]
|
||||
#[widestrs]
|
||||
pub const ELECTRIC_VARIABLES: &[ElectricVar] = &[
|
||||
ElectricVar{name: "FISH_VERSION"L, flags: electric::READONLY},
|
||||
ElectricVar{name: "PWD"L, flags: electric::READONLY | electric::COMPUTED | electric::EXPORTS},
|
||||
ElectricVar{name: "SHLVL"L, flags: electric::READONLY | electric::EXPORTS},
|
||||
ElectricVar{name: "_"L, flags: electric::READONLY},
|
||||
ElectricVar{name: "fish_kill_signal"L, flags:electric::READONLY | electric::COMPUTED},
|
||||
ElectricVar{name: "fish_killring"L, flags:electric::READONLY | electric::COMPUTED},
|
||||
ElectricVar{name: "fish_pid"L, flags:electric::READONLY},
|
||||
ElectricVar{name: "history"L, flags:electric::READONLY | electric::COMPUTED},
|
||||
ElectricVar{name: "hostname"L, flags:electric::READONLY},
|
||||
ElectricVar{name: "pipestatus"L, flags:electric::READONLY | electric::COMPUTED},
|
||||
ElectricVar{name: "status"L, flags:electric::READONLY | electric::COMPUTED},
|
||||
ElectricVar{name: "status_generation"L, flags:electric::READONLY | electric::COMPUTED},
|
||||
ElectricVar{name: "umask"L, flags:electric::COMPUTED},
|
||||
ElectricVar{name: "version"L, flags:electric::READONLY},
|
||||
ElectricVar{name: L!("FISH_VERSION"), flags: electric::READONLY},
|
||||
ElectricVar{name: L!("PWD"), flags: electric::READONLY | electric::COMPUTED | electric::EXPORTS},
|
||||
ElectricVar{name: L!("SHLVL"), flags: electric::READONLY | electric::EXPORTS},
|
||||
ElectricVar{name: L!("_"), flags: electric::READONLY},
|
||||
ElectricVar{name: L!("fish_kill_signal"), flags:electric::READONLY | electric::COMPUTED},
|
||||
ElectricVar{name: L!("fish_killring"), flags:electric::READONLY | electric::COMPUTED},
|
||||
ElectricVar{name: L!("fish_pid"), flags:electric::READONLY},
|
||||
ElectricVar{name: L!("history"), flags:electric::READONLY | electric::COMPUTED},
|
||||
ElectricVar{name: L!("hostname"), flags:electric::READONLY},
|
||||
ElectricVar{name: L!("pipestatus"), flags:electric::READONLY | electric::COMPUTED},
|
||||
ElectricVar{name: L!("status"), flags:electric::READONLY | electric::COMPUTED},
|
||||
ElectricVar{name: L!("status_generation"), flags:electric::READONLY | electric::COMPUTED},
|
||||
ElectricVar{name: L!("umask"), flags:electric::COMPUTED},
|
||||
ElectricVar{name: L!("version"), flags:electric::READONLY},
|
||||
];
|
||||
assert_sorted_by_name!(ELECTRIC_VARIABLES);
|
||||
|
||||
|
|
30
src/event.rs
30
src/event.rs
|
@ -76,16 +76,15 @@ impl EventDescription {
|
|||
}
|
||||
}
|
||||
|
||||
#[widestrs]
|
||||
fn name(&self) -> &'static wstr {
|
||||
match self {
|
||||
EventDescription::Any => "any"L,
|
||||
EventDescription::Signal { .. } => "signal"L,
|
||||
EventDescription::Variable { .. } => "variable"L,
|
||||
EventDescription::ProcessExit { .. } => "process-exit"L,
|
||||
EventDescription::JobExit { .. } => "job-exit"L,
|
||||
EventDescription::CallerExit { .. } => "caller-exit"L,
|
||||
EventDescription::Generic { .. } => "generic"L,
|
||||
EventDescription::Any => L!("any"),
|
||||
EventDescription::Signal { .. } => L!("signal"),
|
||||
EventDescription::Variable { .. } => L!("variable"),
|
||||
EventDescription::ProcessExit { .. } => L!("process-exit"),
|
||||
EventDescription::JobExit { .. } => L!("job-exit"),
|
||||
EventDescription::CallerExit { .. } => L!("caller-exit"),
|
||||
EventDescription::Generic { .. } => L!("generic"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -609,15 +608,14 @@ pub fn fire(parser: &Parser, event: Event) {
|
|||
}
|
||||
}
|
||||
|
||||
#[widestrs]
|
||||
pub const EVENT_FILTER_NAMES: [&wstr; 7] = [
|
||||
"signal"L,
|
||||
"variable"L,
|
||||
"exit"L,
|
||||
"process-exit"L,
|
||||
"job-exit"L,
|
||||
"caller-exit"L,
|
||||
"generic"L,
|
||||
L!("signal"),
|
||||
L!("variable"),
|
||||
L!("exit"),
|
||||
L!("process-exit"),
|
||||
L!("job-exit"),
|
||||
L!("caller-exit"),
|
||||
L!("generic"),
|
||||
];
|
||||
|
||||
/// Print all events. If type_filter is not empty, only output events with that type.
|
||||
|
|
|
@ -59,7 +59,6 @@ use std::os::fd::{FromRawFd, RawFd};
|
|||
use std::slice;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::{atomic::AtomicUsize, Arc};
|
||||
use widestring_suffix::widestrs;
|
||||
|
||||
/// Execute the processes specified by \p j in the parser \p.
|
||||
/// On a true return, the job was successfully launched and the parser will take responsibility for
|
||||
|
@ -472,7 +471,6 @@ fn can_use_posix_spawn_for_job(job: &Job, dup2s: &Dup2List) -> bool {
|
|||
!wants_terminal
|
||||
}
|
||||
|
||||
#[widestrs]
|
||||
fn internal_exec(vars: &EnvStack, j: &Job, block_io: IoChain) {
|
||||
// Do a regular launch - but without forking first...
|
||||
let mut all_ios = block_io;
|
||||
|
@ -499,8 +497,8 @@ fn internal_exec(vars: &EnvStack, j: &Job, block_io: IoChain) {
|
|||
{
|
||||
// Decrement SHLVL as we're removing ourselves from the shell "stack".
|
||||
if is_interactive_session() {
|
||||
let shlvl_var = vars.getf("SHLVL"L, EnvMode::GLOBAL | EnvMode::EXPORT);
|
||||
let mut shlvl_str = "0"L.to_owned();
|
||||
let shlvl_var = vars.getf(L!("SHLVL"), EnvMode::GLOBAL | EnvMode::EXPORT);
|
||||
let mut shlvl_str = L!("0").to_owned();
|
||||
if let Some(shlvl_var) = shlvl_var {
|
||||
if let Ok(shlvl) = fish_wcstol(&shlvl_var.as_string()) {
|
||||
if shlvl > 0 {
|
||||
|
@ -508,7 +506,7 @@ fn internal_exec(vars: &EnvStack, j: &Job, block_io: IoChain) {
|
|||
}
|
||||
}
|
||||
}
|
||||
vars.set_one("SHLVL"L, EnvMode::GLOBAL | EnvMode::EXPORT, shlvl_str);
|
||||
vars.set_one(L!("SHLVL"), EnvMode::GLOBAL | EnvMode::EXPORT, shlvl_str);
|
||||
}
|
||||
|
||||
// launch_process _never_ returns.
|
||||
|
|
|
@ -121,8 +121,7 @@ impl PartialEq<ExpandResultCode> for ExpandResult {
|
|||
}
|
||||
|
||||
/// The string represented by PROCESS_EXPAND_SELF
|
||||
#[widestrs]
|
||||
pub const PROCESS_EXPAND_SELF_STR: &wstr = "%self"L;
|
||||
pub const PROCESS_EXPAND_SELF_STR: &wstr = L!("%self");
|
||||
|
||||
/// Perform various forms of expansion on in, such as tilde expansion (\~USER becomes the users home
|
||||
/// directory), variable expansion (\$VAR_NAME becomes the value of the environment variable
|
||||
|
@ -296,26 +295,25 @@ pub fn expand_tilde(input: &mut WString, vars: &dyn Environment) {
|
|||
}
|
||||
|
||||
/// Perform the opposite of tilde expansion on the string, which is modified in place.
|
||||
#[widestrs]
|
||||
pub fn replace_home_directory_with_tilde(s: &wstr, vars: &dyn Environment) -> WString {
|
||||
let mut result = s.to_owned();
|
||||
// Only absolute paths get this treatment.
|
||||
if result.starts_with("/"L) {
|
||||
let mut home_directory = "~"L.to_owned();
|
||||
if result.starts_with(L!("/")) {
|
||||
let mut home_directory = L!("~").to_owned();
|
||||
expand_tilde(&mut home_directory, vars);
|
||||
// If we can't get a home directory, don't replace anything.
|
||||
// This is the case e.g. with --no-execute
|
||||
if home_directory.is_empty() {
|
||||
return result;
|
||||
}
|
||||
if !home_directory.ends_with("/"L) {
|
||||
if !home_directory.ends_with(L!("/")) {
|
||||
home_directory.push('/');
|
||||
}
|
||||
|
||||
// Now check if the home_directory prefixes the string.
|
||||
if result.starts_with(&home_directory) {
|
||||
// Success
|
||||
result.replace_range(0..home_directory.len(), "~/"L);
|
||||
result.replace_range(0..home_directory.len(), L!("~/"));
|
||||
}
|
||||
}
|
||||
result
|
||||
|
|
|
@ -50,37 +50,36 @@ pub struct FeatureMetadata {
|
|||
}
|
||||
|
||||
/// The metadata, indexed by flag.
|
||||
#[widestrs]
|
||||
pub const METADATA: &[FeatureMetadata] = &[
|
||||
FeatureMetadata {
|
||||
flag: FeatureFlag::stderr_nocaret,
|
||||
name: "stderr-nocaret"L,
|
||||
groups: "3.0"L,
|
||||
description: "^ no longer redirects stderr (historical, can no longer be changed)"L,
|
||||
name: L!("stderr-nocaret"),
|
||||
groups: L!("3.0"),
|
||||
description: L!("^ no longer redirects stderr (historical, can no longer be changed)"),
|
||||
default_value: true,
|
||||
read_only: true,
|
||||
},
|
||||
FeatureMetadata {
|
||||
flag: FeatureFlag::qmark_noglob,
|
||||
name: "qmark-noglob"L,
|
||||
groups: "3.0"L,
|
||||
description: "? no longer globs"L,
|
||||
name: L!("qmark-noglob"),
|
||||
groups: L!("3.0"),
|
||||
description: L!("? no longer globs"),
|
||||
default_value: false,
|
||||
read_only: false,
|
||||
},
|
||||
FeatureMetadata {
|
||||
flag: FeatureFlag::string_replace_backslash,
|
||||
name: "regex-easyesc"L,
|
||||
groups: "3.1"L,
|
||||
description: "string replace -r needs fewer \\'s"L,
|
||||
name: L!("regex-easyesc"),
|
||||
groups: L!("3.1"),
|
||||
description: L!("string replace -r needs fewer \\'s"),
|
||||
default_value: true,
|
||||
read_only: false,
|
||||
},
|
||||
FeatureMetadata {
|
||||
flag: FeatureFlag::ampersand_nobg_in_token,
|
||||
name: "ampersand-nobg-in-token"L,
|
||||
groups: "3.4"L,
|
||||
description: "& only backgrounds if followed by a separator"L,
|
||||
name: L!("ampersand-nobg-in-token"),
|
||||
groups: L!("3.4"),
|
||||
description: L!("& only backgrounds if followed by a separator"),
|
||||
default_value: true,
|
||||
read_only: false,
|
||||
},
|
||||
|
@ -155,9 +154,8 @@ impl Features {
|
|||
self.values[flag as usize].store(value, Ordering::SeqCst)
|
||||
}
|
||||
|
||||
#[widestrs]
|
||||
fn set_from_string<'a>(&self, str: &wstr) {
|
||||
let whitespace = "\t\n\0x0B\0x0C\r "L.as_char_slice();
|
||||
let whitespace = L!("\t\n\0x0B\0x0C\r ").as_char_slice();
|
||||
for entry in str.as_char_slice().split(|c| *c == ',') {
|
||||
if entry.is_empty() {
|
||||
continue;
|
||||
|
@ -169,7 +167,7 @@ impl Features {
|
|||
&entry[..entry.len() - entry.iter().take_while(|c| whitespace.contains(c)).count()];
|
||||
|
||||
// A "no-" prefix inverts the sense.
|
||||
let (name, value) = match entry.strip_prefix("no-"L.as_char_slice()) {
|
||||
let (name, value) = match entry.strip_prefix(L!("no-").as_char_slice()) {
|
||||
Some(suffix) => (suffix, false),
|
||||
None => (entry, true),
|
||||
};
|
||||
|
@ -186,7 +184,7 @@ impl Features {
|
|||
}
|
||||
} else {
|
||||
for md in METADATA {
|
||||
if md.groups == name || name == "all"L {
|
||||
if md.groups == name || name == L!("all") {
|
||||
if !md.read_only {
|
||||
self.set(md.flag, value);
|
||||
}
|
||||
|
@ -216,12 +214,11 @@ pub fn scoped_test(flag: FeatureFlag, value: bool, test_fn: impl FnOnce()) {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[widestrs]
|
||||
fn test_feature_flags() {
|
||||
let f = Features::new();
|
||||
f.set_from_string("stderr-nocaret,nonsense"L);
|
||||
f.set_from_string(L!("stderr-nocaret,nonsense"));
|
||||
assert!(f.test(FeatureFlag::stderr_nocaret));
|
||||
f.set_from_string("stderr-nocaret,no-stderr-nocaret,nonsense"L);
|
||||
f.set_from_string(L!("stderr-nocaret,no-stderr-nocaret,nonsense"));
|
||||
assert!(f.test(FeatureFlag::stderr_nocaret));
|
||||
|
||||
// Ensure every metadata is represented once.
|
||||
|
@ -235,7 +232,7 @@ fn test_feature_flags() {
|
|||
|
||||
assert_eq!(
|
||||
METADATA[FeatureFlag::stderr_nocaret as usize].name,
|
||||
"stderr-nocaret"L
|
||||
L!("stderr-nocaret")
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,6 @@ use libc::{
|
|||
};
|
||||
use lru::LruCache;
|
||||
use rand::Rng;
|
||||
use widestring_suffix::widestrs;
|
||||
|
||||
use crate::{
|
||||
ast::{Ast, Node},
|
||||
|
@ -204,7 +203,6 @@ impl LruCacheExt for LruCache<WString, HistoryItem> {
|
|||
|
||||
/// Returns the path for the history file for the given `session_id`, or `None` if it could not be
|
||||
/// loaded. If `suffix` is provided, append that suffix to the path; this is used for temporary files.
|
||||
#[widestrs]
|
||||
fn history_filename(session_id: &wstr, suffix: &wstr) -> Option<WString> {
|
||||
if session_id.is_empty() {
|
||||
return None;
|
||||
|
@ -216,7 +214,7 @@ fn history_filename(session_id: &wstr, suffix: &wstr) -> Option<WString> {
|
|||
|
||||
result.push('/');
|
||||
result.push_utfstr(session_id);
|
||||
result.push_utfstr("_history"L);
|
||||
result.push_utfstr(L!("_history"));
|
||||
result.push_utfstr(suffix);
|
||||
Some(result)
|
||||
}
|
||||
|
|
|
@ -184,21 +184,20 @@ impl Default for ParseTokenType {
|
|||
|
||||
impl ParseTokenType {
|
||||
/// Return a string describing the token type.
|
||||
#[widestrs]
|
||||
pub fn to_wstr(self) -> &'static wstr {
|
||||
match self {
|
||||
ParseTokenType::comment => "ParseTokenType::comment"L,
|
||||
ParseTokenType::error => "ParseTokenType::error"L,
|
||||
ParseTokenType::tokenizer_error => "ParseTokenType::tokenizer_error"L,
|
||||
ParseTokenType::background => "ParseTokenType::background"L,
|
||||
ParseTokenType::end => "ParseTokenType::end"L,
|
||||
ParseTokenType::pipe => "ParseTokenType::pipe"L,
|
||||
ParseTokenType::redirection => "ParseTokenType::redirection"L,
|
||||
ParseTokenType::string => "ParseTokenType::string"L,
|
||||
ParseTokenType::andand => "ParseTokenType::andand"L,
|
||||
ParseTokenType::oror => "ParseTokenType::oror"L,
|
||||
ParseTokenType::terminate => "ParseTokenType::terminate"L,
|
||||
ParseTokenType::invalid => "ParseTokenType::invalid"L,
|
||||
ParseTokenType::comment => L!("ParseTokenType::comment"),
|
||||
ParseTokenType::error => L!("ParseTokenType::error"),
|
||||
ParseTokenType::tokenizer_error => L!("ParseTokenType::tokenizer_error"),
|
||||
ParseTokenType::background => L!("ParseTokenType::background"),
|
||||
ParseTokenType::end => L!("ParseTokenType::end"),
|
||||
ParseTokenType::pipe => L!("ParseTokenType::pipe"),
|
||||
ParseTokenType::redirection => L!("ParseTokenType::redirection"),
|
||||
ParseTokenType::string => L!("ParseTokenType::string"),
|
||||
ParseTokenType::andand => L!("ParseTokenType::andand"),
|
||||
ParseTokenType::oror => L!("ParseTokenType::oror"),
|
||||
ParseTokenType::terminate => L!("ParseTokenType::terminate"),
|
||||
ParseTokenType::invalid => L!("ParseTokenType::invalid"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -211,28 +210,27 @@ impl Default for ParseKeyword {
|
|||
|
||||
impl ParseKeyword {
|
||||
/// Return the keyword as a string.
|
||||
#[widestrs]
|
||||
pub fn to_wstr(self) -> &'static wstr {
|
||||
match self {
|
||||
ParseKeyword::kw_exclam => "!"L,
|
||||
ParseKeyword::kw_and => "and"L,
|
||||
ParseKeyword::kw_begin => "begin"L,
|
||||
ParseKeyword::kw_builtin => "builtin"L,
|
||||
ParseKeyword::kw_case => "case"L,
|
||||
ParseKeyword::kw_command => "command"L,
|
||||
ParseKeyword::kw_else => "else"L,
|
||||
ParseKeyword::kw_end => "end"L,
|
||||
ParseKeyword::kw_exec => "exec"L,
|
||||
ParseKeyword::kw_for => "for"L,
|
||||
ParseKeyword::kw_function => "function"L,
|
||||
ParseKeyword::kw_if => "if"L,
|
||||
ParseKeyword::kw_in => "in"L,
|
||||
ParseKeyword::kw_not => "not"L,
|
||||
ParseKeyword::kw_or => "or"L,
|
||||
ParseKeyword::kw_switch => "switch"L,
|
||||
ParseKeyword::kw_time => "time"L,
|
||||
ParseKeyword::kw_while => "while"L,
|
||||
_ => "unknown_keyword"L,
|
||||
ParseKeyword::kw_exclam => L!("!"),
|
||||
ParseKeyword::kw_and => L!("and"),
|
||||
ParseKeyword::kw_begin => L!("begin"),
|
||||
ParseKeyword::kw_builtin => L!("builtin"),
|
||||
ParseKeyword::kw_case => L!("case"),
|
||||
ParseKeyword::kw_command => L!("command"),
|
||||
ParseKeyword::kw_else => L!("else"),
|
||||
ParseKeyword::kw_end => L!("end"),
|
||||
ParseKeyword::kw_exec => L!("exec"),
|
||||
ParseKeyword::kw_for => L!("for"),
|
||||
ParseKeyword::kw_function => L!("function"),
|
||||
ParseKeyword::kw_if => L!("if"),
|
||||
ParseKeyword::kw_in => L!("in"),
|
||||
ParseKeyword::kw_not => L!("not"),
|
||||
ParseKeyword::kw_or => L!("or"),
|
||||
ParseKeyword::kw_switch => L!("switch"),
|
||||
ParseKeyword::kw_time => L!("time"),
|
||||
ParseKeyword::kw_while => L!("while"),
|
||||
_ => L!("unknown_keyword"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -244,27 +242,26 @@ impl printf_compat::args::ToArg<'static> for ParseKeyword {
|
|||
}
|
||||
|
||||
impl From<&wstr> for ParseKeyword {
|
||||
#[widestrs]
|
||||
fn from(s: &wstr) -> Self {
|
||||
match s {
|
||||
_ if s == "!"L => ParseKeyword::kw_exclam,
|
||||
_ if s == "and"L => ParseKeyword::kw_and,
|
||||
_ if s == "begin"L => ParseKeyword::kw_begin,
|
||||
_ if s == "builtin"L => ParseKeyword::kw_builtin,
|
||||
_ if s == "case"L => ParseKeyword::kw_case,
|
||||
_ if s == "command"L => ParseKeyword::kw_command,
|
||||
_ if s == "else"L => ParseKeyword::kw_else,
|
||||
_ if s == "end"L => ParseKeyword::kw_end,
|
||||
_ if s == "exec"L => ParseKeyword::kw_exec,
|
||||
_ if s == "for"L => ParseKeyword::kw_for,
|
||||
_ if s == "function"L => ParseKeyword::kw_function,
|
||||
_ if s == "if"L => ParseKeyword::kw_if,
|
||||
_ if s == "in"L => ParseKeyword::kw_in,
|
||||
_ if s == "not"L => ParseKeyword::kw_not,
|
||||
_ if s == "or"L => ParseKeyword::kw_or,
|
||||
_ if s == "switch"L => ParseKeyword::kw_switch,
|
||||
_ if s == "time"L => ParseKeyword::kw_time,
|
||||
_ if s == "while"L => ParseKeyword::kw_while,
|
||||
_ if s == L!("!") => ParseKeyword::kw_exclam,
|
||||
_ if s == L!("and") => ParseKeyword::kw_and,
|
||||
_ if s == L!("begin") => ParseKeyword::kw_begin,
|
||||
_ if s == L!("builtin") => ParseKeyword::kw_builtin,
|
||||
_ if s == L!("case") => ParseKeyword::kw_case,
|
||||
_ if s == L!("command") => ParseKeyword::kw_command,
|
||||
_ if s == L!("else") => ParseKeyword::kw_else,
|
||||
_ if s == L!("end") => ParseKeyword::kw_end,
|
||||
_ if s == L!("exec") => ParseKeyword::kw_exec,
|
||||
_ if s == L!("for") => ParseKeyword::kw_for,
|
||||
_ if s == L!("function") => ParseKeyword::kw_function,
|
||||
_ if s == L!("if") => ParseKeyword::kw_if,
|
||||
_ if s == L!("in") => ParseKeyword::kw_in,
|
||||
_ if s == L!("not") => ParseKeyword::kw_not,
|
||||
_ if s == L!("or") => ParseKeyword::kw_or,
|
||||
_ if s == L!("switch") => ParseKeyword::kw_switch,
|
||||
_ if s == L!("time") => ParseKeyword::kw_time,
|
||||
_ if s == L!("while") => ParseKeyword::kw_while,
|
||||
_ => ParseKeyword::none,
|
||||
}
|
||||
}
|
||||
|
@ -402,27 +399,26 @@ impl ParseError {
|
|||
}
|
||||
}
|
||||
|
||||
#[widestrs]
|
||||
pub fn token_type_user_presentable_description(
|
||||
type_: ParseTokenType,
|
||||
keyword: ParseKeyword,
|
||||
) -> WString {
|
||||
if keyword != ParseKeyword::none {
|
||||
return sprintf!("keyword: '%ls'"L, keyword.to_wstr());
|
||||
return sprintf!(L!("keyword: '%ls'"), keyword.to_wstr());
|
||||
}
|
||||
match type_ {
|
||||
ParseTokenType::string => "a string"L.to_owned(),
|
||||
ParseTokenType::pipe => "a pipe"L.to_owned(),
|
||||
ParseTokenType::redirection => "a redirection"L.to_owned(),
|
||||
ParseTokenType::background => "a '&'"L.to_owned(),
|
||||
ParseTokenType::andand => "'&&'"L.to_owned(),
|
||||
ParseTokenType::oror => "'||'"L.to_owned(),
|
||||
ParseTokenType::end => "end of the statement"L.to_owned(),
|
||||
ParseTokenType::terminate => "end of the input"L.to_owned(),
|
||||
ParseTokenType::error => "a parse error"L.to_owned(),
|
||||
ParseTokenType::tokenizer_error => "an incomplete token"L.to_owned(),
|
||||
ParseTokenType::comment => "a comment"L.to_owned(),
|
||||
_ => sprintf!("a %ls"L, type_.to_wstr()),
|
||||
ParseTokenType::string => L!("a string").to_owned(),
|
||||
ParseTokenType::pipe => L!("a pipe").to_owned(),
|
||||
ParseTokenType::redirection => L!("a redirection").to_owned(),
|
||||
ParseTokenType::background => L!("a '&'").to_owned(),
|
||||
ParseTokenType::andand => L!("'&&'").to_owned(),
|
||||
ParseTokenType::oror => L!("'||'").to_owned(),
|
||||
ParseTokenType::end => L!("end of the statement").to_owned(),
|
||||
ParseTokenType::terminate => L!("end of the input").to_owned(),
|
||||
ParseTokenType::error => L!("a parse error").to_owned(),
|
||||
ParseTokenType::tokenizer_error => L!("an incomplete token").to_owned(),
|
||||
ParseTokenType::comment => L!("a comment").to_owned(),
|
||||
_ => sprintf!(L!("a %ls"), type_.to_wstr()),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -626,15 +626,20 @@ pub fn parse_util_escape_wildcards(s: &wstr) -> WString {
|
|||
}
|
||||
|
||||
/// Checks if the specified string is a help option.
|
||||
#[widestrs]
|
||||
pub fn parse_util_argument_is_help(s: &wstr) -> bool {
|
||||
["-h"L, "--help"L].contains(&s)
|
||||
[L!("-h"), L!("--help")].contains(&s)
|
||||
}
|
||||
|
||||
/// Returns true if the specified command is a builtin that may not be used in a pipeline.
|
||||
#[widestrs]
|
||||
fn parser_is_pipe_forbidden(word: &wstr) -> bool {
|
||||
["exec"L, "case"L, "break"L, "return"L, "continue"L].contains(&word)
|
||||
[
|
||||
L!("exec"),
|
||||
L!("case"),
|
||||
L!("break"),
|
||||
L!("return"),
|
||||
L!("continue"),
|
||||
]
|
||||
.contains(&word)
|
||||
}
|
||||
|
||||
// \return a pointer to the first argument node of an argument_or_redirection_list_t, or nullptr if
|
||||
|
|
|
@ -46,7 +46,6 @@ use std::sync::{
|
|||
atomic::{AtomicIsize, AtomicU64, Ordering},
|
||||
Arc,
|
||||
};
|
||||
use widestring_suffix::widestrs;
|
||||
|
||||
/// block_t represents a block of commands.
|
||||
#[derive(Default)]
|
||||
|
@ -97,22 +96,21 @@ impl Block {
|
|||
}
|
||||
|
||||
/// Description of the block, for debugging.
|
||||
#[widestrs]
|
||||
pub fn description(&self) -> WString {
|
||||
let mut result = match self.typ() {
|
||||
BlockType::while_block => "while"L,
|
||||
BlockType::for_block => "for"L,
|
||||
BlockType::if_block => "if"L,
|
||||
BlockType::function_call => "function_call"L,
|
||||
BlockType::function_call_no_shadow => "function_call_no_shadow"L,
|
||||
BlockType::switch_block => "switch"L,
|
||||
BlockType::subst => "substitution"L,
|
||||
BlockType::top => "top"L,
|
||||
BlockType::begin => "begin"L,
|
||||
BlockType::source => "source"L,
|
||||
BlockType::event => "event"L,
|
||||
BlockType::breakpoint => "breakpoint"L,
|
||||
BlockType::variable_assignment => "variable_assignment"L,
|
||||
BlockType::while_block => L!("while"),
|
||||
BlockType::for_block => L!("for"),
|
||||
BlockType::if_block => L!("if"),
|
||||
BlockType::function_call => L!("function_call"),
|
||||
BlockType::function_call_no_shadow => L!("function_call_no_shadow"),
|
||||
BlockType::switch_block => L!("switch"),
|
||||
BlockType::subst => L!("substitution"),
|
||||
BlockType::top => L!("top"),
|
||||
BlockType::begin => L!("begin"),
|
||||
BlockType::source => L!("source"),
|
||||
BlockType::event => L!("event"),
|
||||
BlockType::breakpoint => L!("breakpoint"),
|
||||
BlockType::variable_assignment => L!("variable_assignment"),
|
||||
}
|
||||
.to_owned();
|
||||
|
||||
|
|
|
@ -2,33 +2,45 @@
|
|||
|
||||
use crate::wchar::prelude::*;
|
||||
|
||||
#[widestrs]
|
||||
const SKIP_KEYWORDS: &[&wstr] = &["else"L, "begin"L];
|
||||
#[widestrs]
|
||||
const SKIP_KEYWORDS: &[&wstr] = &[L!("else"), L!("begin")];
|
||||
const SUBCOMMAND_KEYWORDS: &[&wstr] = &[
|
||||
"command"L, "builtin"L, "while"L, "exec"L, "if"L, "and"L, "or"L, "not"L, "time"L, "begin"L,
|
||||
L!("command"),
|
||||
L!("builtin"),
|
||||
L!("while"),
|
||||
L!("exec"),
|
||||
L!("if"),
|
||||
L!("and"),
|
||||
L!("or"),
|
||||
L!("not"),
|
||||
L!("time"),
|
||||
L!("begin"),
|
||||
];
|
||||
const BLOCK_KEYWORDS: &[&wstr] = &[
|
||||
L!("for"),
|
||||
L!("while"),
|
||||
L!("if"),
|
||||
L!("function"),
|
||||
L!("switch"),
|
||||
L!("begin"),
|
||||
];
|
||||
#[widestrs]
|
||||
const BLOCK_KEYWORDS: &[&wstr] = &["for"L, "while"L, "if"L, "function"L, "switch"L, "begin"L];
|
||||
|
||||
// Don't forget to add any new reserved keywords to the documentation
|
||||
#[widestrs]
|
||||
const RESERVED_KEYWORDS: &[&wstr] = &[
|
||||
"end"L,
|
||||
"case"L,
|
||||
"else"L,
|
||||
"return"L,
|
||||
"continue"L,
|
||||
"break"L,
|
||||
"argparse"L,
|
||||
"read"L,
|
||||
"string"L,
|
||||
"set"L,
|
||||
"status"L,
|
||||
"test"L,
|
||||
"["L,
|
||||
"_"L,
|
||||
"eval"L,
|
||||
L!("end"),
|
||||
L!("case"),
|
||||
L!("else"),
|
||||
L!("return"),
|
||||
L!("continue"),
|
||||
L!("break"),
|
||||
L!("argparse"),
|
||||
L!("read"),
|
||||
L!("string"),
|
||||
L!("set"),
|
||||
L!("status"),
|
||||
L!("test"),
|
||||
L!("["),
|
||||
L!("_"),
|
||||
L!("eval"),
|
||||
];
|
||||
|
||||
// The lists above are purposely implemented separately from the logic below, so that future
|
||||
|
|
62
src/path.rs
62
src/path.rs
|
@ -71,15 +71,14 @@ pub fn path_get_config_remoteness() -> DirRemoteness {
|
|||
|
||||
/// Emit any errors if config directories are missing.
|
||||
/// Use the given environment stack to ensure this only occurs once.
|
||||
#[widestrs]
|
||||
pub fn path_emit_config_directory_messages(vars: &EnvStack) {
|
||||
let data = get_data_directory();
|
||||
if !data.success() {
|
||||
maybe_issue_path_warning(
|
||||
"data"L,
|
||||
L!("data"),
|
||||
&wgettext!("can not save history"),
|
||||
data.used_xdg,
|
||||
"XDG_DATA_HOME"L,
|
||||
L!("XDG_DATA_HOME"),
|
||||
&data.path,
|
||||
data.err,
|
||||
vars,
|
||||
|
@ -92,10 +91,10 @@ pub fn path_emit_config_directory_messages(vars: &EnvStack) {
|
|||
let config = get_config_directory();
|
||||
if !config.success() {
|
||||
maybe_issue_path_warning(
|
||||
"config"L,
|
||||
L!("config"),
|
||||
&wgettext!("can not save universal variables or functions"),
|
||||
config.used_xdg,
|
||||
"XDG_CONFIG_HOME"L,
|
||||
L!("XDG_CONFIG_HOME"),
|
||||
&config.path,
|
||||
config.err,
|
||||
vars,
|
||||
|
@ -110,7 +109,6 @@ pub fn path_emit_config_directory_messages(vars: &EnvStack) {
|
|||
/// problem, and thus is not central to the behavior of that function. Second, we only want to issue
|
||||
/// the message once. If the current shell starts a new fish shell (e.g., by running `fish -c` from
|
||||
/// a function) we don't want that subshell to issue the same warnings.
|
||||
#[widestrs]
|
||||
fn maybe_issue_path_warning(
|
||||
which_dir: &wstr,
|
||||
custom_error_msg: &wstr,
|
||||
|
@ -120,7 +118,7 @@ fn maybe_issue_path_warning(
|
|||
saved_errno: libc::c_int,
|
||||
vars: &EnvStack,
|
||||
) {
|
||||
let warning_var_name = "_FISH_WARNED_"L.to_owned() + which_dir;
|
||||
let warning_var_name = L!("_FISH_WARNED_").to_owned() + which_dir;
|
||||
if vars
|
||||
.getf(&warning_var_name, EnvMode::GLOBAL | EnvMode::EXPORT)
|
||||
.is_some()
|
||||
|
@ -130,7 +128,7 @@ fn maybe_issue_path_warning(
|
|||
vars.set_one(
|
||||
&warning_var_name,
|
||||
EnvMode::GLOBAL | EnvMode::EXPORT,
|
||||
"1"L.to_owned(),
|
||||
L!("1").to_owned(),
|
||||
);
|
||||
|
||||
FLOG!(error, custom_error_msg);
|
||||
|
@ -147,7 +145,7 @@ fn maybe_issue_path_warning(
|
|||
)
|
||||
);
|
||||
} else {
|
||||
let env_var = if using_xdg { xdg_var } else { "HOME"L };
|
||||
let env_var = if using_xdg { xdg_var } else { L!("HOME") };
|
||||
FLOG!(
|
||||
warning_path,
|
||||
wgettext_fmt!(
|
||||
|
@ -184,13 +182,12 @@ pub fn path_get_path(cmd: &wstr, vars: &dyn Environment) -> Option<WString> {
|
|||
}
|
||||
|
||||
// PREFIX is defined at build time.
|
||||
#[widestrs]
|
||||
pub static DEFAULT_PATH: Lazy<[WString; 3]> = Lazy::new(|| {
|
||||
[
|
||||
// TODO This should use env!. The fallback is only to appease "cargo test" for now.
|
||||
WString::from_str(option_env!("PREFIX").unwrap_or("/usr/local")) + "/bin"L,
|
||||
"/usr/bin"L.to_owned(),
|
||||
"/bin"L.to_owned(),
|
||||
WString::from_str(option_env!("PREFIX").unwrap_or("/usr/local")) + L!("/bin"),
|
||||
L!("/usr/bin").to_owned(),
|
||||
L!("/bin").to_owned(),
|
||||
]
|
||||
});
|
||||
|
||||
|
@ -357,23 +354,25 @@ pub fn path_get_cdpath(dir: &wstr, wd: &wstr, vars: &dyn Environment) -> Option<
|
|||
}
|
||||
|
||||
/// Returns the given directory with all CDPATH components applied.
|
||||
#[widestrs]
|
||||
pub fn path_apply_cdpath(dir: &wstr, wd: &wstr, env_vars: &dyn Environment) -> Vec<WString> {
|
||||
let mut paths = vec![];
|
||||
if dir.chars().next() == Some('/') {
|
||||
// Absolute path.
|
||||
paths.push(dir.to_owned());
|
||||
} else if dir.starts_with("./"L) || dir.starts_with("../"L) || ["."L, ".."L].contains(&dir) {
|
||||
} else if dir.starts_with(L!("./"))
|
||||
|| dir.starts_with(L!("../"))
|
||||
|| [L!("."), L!("..")].contains(&dir)
|
||||
{
|
||||
// Path is relative to the working directory.
|
||||
paths.push(path_normalize_for_cd(wd, dir));
|
||||
} else {
|
||||
// Respect CDPATH.
|
||||
let mut cdpathsv = vec![];
|
||||
if let Some(cdpaths) = env_vars.get("CDPATH"L) {
|
||||
if let Some(cdpaths) = env_vars.get(L!("CDPATH")) {
|
||||
cdpathsv = cdpaths.as_list().to_vec();
|
||||
}
|
||||
// Always append $PWD
|
||||
cdpathsv.push("."L.to_owned());
|
||||
cdpathsv.push(L!(".").to_owned());
|
||||
for path in cdpathsv {
|
||||
let mut abspath = WString::new();
|
||||
// We want to return an absolute path (see issue 6220)
|
||||
|
@ -399,15 +398,14 @@ pub fn path_apply_cdpath(dir: &wstr, wd: &wstr, env_vars: &dyn Environment) -> V
|
|||
|
||||
/// Returns the path resolved as an implicit cd command, or none() if none. This requires it to
|
||||
/// start with one of the allowed prefixes (., .., ~) and resolve to a directory.
|
||||
#[widestrs]
|
||||
pub fn path_as_implicit_cd(path: &wstr, wd: &wstr, vars: &dyn Environment) -> Option<WString> {
|
||||
let mut exp_path = path.to_owned();
|
||||
expand_tilde(&mut exp_path, vars);
|
||||
if exp_path.starts_with("/"L)
|
||||
|| exp_path.starts_with("./"L)
|
||||
|| exp_path.starts_with("../"L)
|
||||
|| exp_path.ends_with("/"L)
|
||||
|| exp_path == ".."L
|
||||
if exp_path.starts_with(L!("/"))
|
||||
|| exp_path.starts_with(L!("./"))
|
||||
|| exp_path.starts_with(L!("../"))
|
||||
|| exp_path.ends_with(L!("/"))
|
||||
|| exp_path == L!("..")
|
||||
{
|
||||
// These paths can be implicit cd, so see if you cd to the path. Note that a single period
|
||||
// cannot (that's used for sourcing files anyways).
|
||||
|
@ -495,15 +493,14 @@ pub fn paths_are_equivalent(p1: &wstr, p2: &wstr) -> bool {
|
|||
idx1 == len1 && idx2 == len2
|
||||
}
|
||||
|
||||
#[widestrs]
|
||||
pub fn path_is_valid(path: &wstr, working_directory: &wstr) -> bool {
|
||||
// Some special paths are always valid.
|
||||
if path.is_empty() {
|
||||
false
|
||||
} else if ["."L, "./"L].contains(&path) {
|
||||
} else if [L!("."), L!("./")].contains(&path) {
|
||||
true
|
||||
} else if [".."L, "../"L].contains(&path) {
|
||||
!working_directory.is_empty() && working_directory != "/"L
|
||||
} else if [L!(".."), L!("../")].contains(&path) {
|
||||
!working_directory.is_empty() && working_directory != L!("/")
|
||||
} else if path.chars().next() != Some('/') {
|
||||
// Prepend the working directory. Note that we know path is not empty here.
|
||||
let mut tmp = working_directory.to_owned();
|
||||
|
@ -582,7 +579,6 @@ impl BaseDirectory {
|
|||
/// Attempt to get a base directory, creating it if necessary. If a variable named \p xdg_var is
|
||||
/// set, use that directory; otherwise use the path \p non_xdg_homepath rooted in $HOME. \return the
|
||||
/// result; see the base_directory_t fields.
|
||||
#[widestrs]
|
||||
fn make_base_directory(xdg_var: &wstr, non_xdg_homepath: &wstr) -> BaseDirectory {
|
||||
// The vars we fetch must be exported. Allowing them to be universal doesn't make sense and
|
||||
// allowing that creates a lock inversion that deadlocks the shell since we're called before
|
||||
|
@ -592,10 +588,10 @@ fn make_base_directory(xdg_var: &wstr, non_xdg_homepath: &wstr) -> BaseDirectory
|
|||
let mut path = WString::new();
|
||||
let used_xdg;
|
||||
if let Some(xdg_dir) = vars.getf_unless_empty(xdg_var, EnvMode::GLOBAL | EnvMode::EXPORT) {
|
||||
path = xdg_dir.as_string() + "/fish"L;
|
||||
path = xdg_dir.as_string() + L!("/fish");
|
||||
used_xdg = true;
|
||||
} else {
|
||||
if let Some(home) = vars.getf_unless_empty("HOME"L, EnvMode::GLOBAL | EnvMode::EXPORT) {
|
||||
if let Some(home) = vars.getf_unless_empty(L!("HOME"), EnvMode::GLOBAL | EnvMode::EXPORT) {
|
||||
path = home.as_string() + non_xdg_homepath;
|
||||
}
|
||||
used_xdg = false;
|
||||
|
@ -706,17 +702,15 @@ fn path_remoteness(path: &wstr) -> DirRemoteness {
|
|||
}
|
||||
}
|
||||
|
||||
#[widestrs]
|
||||
fn get_data_directory() -> &'static BaseDirectory {
|
||||
static DIR: Lazy<BaseDirectory> =
|
||||
Lazy::new(|| make_base_directory("XDG_DATA_HOME"L, "/.local/share/fish"L));
|
||||
Lazy::new(|| make_base_directory(L!("XDG_DATA_HOME"), L!("/.local/share/fish")));
|
||||
&*DIR
|
||||
}
|
||||
|
||||
#[widestrs]
|
||||
fn get_config_directory() -> &'static BaseDirectory {
|
||||
static DIR: Lazy<BaseDirectory> =
|
||||
Lazy::new(|| make_base_directory("XDG_CONFIG_HOME"L, "/.config/fish"L));
|
||||
Lazy::new(|| make_base_directory(L!("XDG_CONFIG_HOME"), L!("/.config/fish")));
|
||||
&*DIR
|
||||
}
|
||||
|
||||
|
|
16
src/proc.rs
16
src/proc.rs
|
@ -38,7 +38,6 @@ use std::os::fd::RawFd;
|
|||
use std::rc::Rc;
|
||||
use std::sync::atomic::{AtomicBool, AtomicI32, AtomicU64, AtomicU8, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use widestring_suffix::widestrs;
|
||||
|
||||
/// Types of processes.
|
||||
#[derive(Default, Eq, PartialEq)]
|
||||
|
@ -844,15 +843,14 @@ impl Job {
|
|||
/// due to reuse of freed job ids. Prevents overloading the debug comments with the full,
|
||||
/// untruncated job string when we don't care what the job is, only which of the currently
|
||||
/// running jobs it is.
|
||||
#[widestrs]
|
||||
pub fn preview(&self) -> WString {
|
||||
if self.processes().is_empty() {
|
||||
return ""L.to_owned();
|
||||
return L!("").to_owned();
|
||||
}
|
||||
// Note argv0 may be empty in e.g. a block process.
|
||||
let procs = self.processes();
|
||||
let result = procs.first().unwrap().argv0().unwrap_or("null"L);
|
||||
result.to_owned() + "..."L
|
||||
let result = procs.first().unwrap().argv0().unwrap_or(L!("null"));
|
||||
result.to_owned() + L!("...")
|
||||
}
|
||||
|
||||
/// \return our pgid, or none if we don't have one, or are internal to fish
|
||||
|
@ -1185,7 +1183,6 @@ pub fn jobs_requiring_warning_on_exit(parser: &Parser) -> JobList {
|
|||
|
||||
/// Print the exit warning for the given jobs, which should have been obtained via
|
||||
/// jobs_requiring_warning_on_exit().
|
||||
#[widestrs]
|
||||
pub fn print_exit_warning_for_jobs(jobs: &JobList) {
|
||||
printf!("%s", wgettext!("There are still jobs active:\n"));
|
||||
printf!("%s", wgettext!("\n PID Command\n"));
|
||||
|
@ -1581,9 +1578,8 @@ fn call_job_summary(parser: &Parser, cmd: &wstr) {
|
|||
// \return a command which invokes fish_job_summary.
|
||||
// The process pointer may be null, in which case it represents the entire job.
|
||||
// Note this implements the arguments which fish_job_summary expects.
|
||||
#[widestrs]
|
||||
fn summary_command(j: &Job, p: Option<&Process>) -> WString {
|
||||
let mut buffer = "fish_job_summary"L.to_owned();
|
||||
let mut buffer = L!("fish_job_summary").to_owned();
|
||||
|
||||
// Job id.
|
||||
buffer += &sprintf!(" %s", j.job_id().to_wstring())[..];
|
||||
|
@ -1599,9 +1595,9 @@ fn summary_command(j: &Job, p: Option<&Process>) -> WString {
|
|||
None => {
|
||||
// No process, we are summarizing the whole job.
|
||||
buffer += if j.is_stopped() {
|
||||
" STOPPED"L
|
||||
L!(" STOPPED")
|
||||
} else {
|
||||
" ENDED"L
|
||||
L!(" ENDED")
|
||||
};
|
||||
}
|
||||
Some(p) => {
|
||||
|
|
|
@ -357,60 +357,59 @@ impl LookupEntry {
|
|||
|
||||
// Lookup table used to convert between signal names and signal ids, etc.
|
||||
#[rustfmt::skip]
|
||||
#[widestrs]
|
||||
const SIGNAL_TABLE : &[LookupEntry] = &[
|
||||
LookupEntry::new(libc::SIGHUP, "SIGHUP"L, "Terminal hung up"L),
|
||||
LookupEntry::new(libc::SIGINT, "SIGINT"L, "Quit request from job control (^C)"L),
|
||||
LookupEntry::new(libc::SIGQUIT, "SIGQUIT"L, "Quit request from job control with core dump (^\\)"L),
|
||||
LookupEntry::new(libc::SIGILL, "SIGILL"L, "Illegal instruction"L),
|
||||
LookupEntry::new(libc::SIGTRAP, "SIGTRAP"L, "Trace or breakpoint trap"L),
|
||||
LookupEntry::new(libc::SIGABRT, "SIGABRT"L, "Abort"L),
|
||||
LookupEntry::new(libc::SIGBUS, "SIGBUS"L, "Misaligned address error"L),
|
||||
LookupEntry::new(libc::SIGFPE, "SIGFPE"L, "Floating point exception"L),
|
||||
LookupEntry::new(libc::SIGKILL, "SIGKILL"L, "Forced quit"L),
|
||||
LookupEntry::new(libc::SIGUSR1, "SIGUSR1"L, "User defined signal 1"L),
|
||||
LookupEntry::new(libc::SIGUSR2, "SIGUSR2"L, "User defined signal 2"L),
|
||||
LookupEntry::new(libc::SIGSEGV, "SIGSEGV"L, "Address boundary error"L),
|
||||
LookupEntry::new(libc::SIGPIPE, "SIGPIPE"L, "Broken pipe"L),
|
||||
LookupEntry::new(libc::SIGALRM, "SIGALRM"L, "Timer expired"L),
|
||||
LookupEntry::new(libc::SIGTERM, "SIGTERM"L, "Polite quit request"L),
|
||||
LookupEntry::new(libc::SIGCHLD, "SIGCHLD"L, "Child process status changed"L),
|
||||
LookupEntry::new(libc::SIGCONT, "SIGCONT"L, "Continue previously stopped process"L),
|
||||
LookupEntry::new(libc::SIGSTOP, "SIGSTOP"L, "Forced stop"L),
|
||||
LookupEntry::new(libc::SIGTSTP, "SIGTSTP"L, "Stop request from job control (^Z)"L),
|
||||
LookupEntry::new(libc::SIGTTIN, "SIGTTIN"L, "Stop from terminal input"L),
|
||||
LookupEntry::new(libc::SIGTTOU, "SIGTTOU"L, "Stop from terminal output"L),
|
||||
LookupEntry::new(libc::SIGURG, "SIGURG"L, "Urgent socket condition"L),
|
||||
LookupEntry::new(libc::SIGXCPU, "SIGXCPU"L, "CPU time limit exceeded"L),
|
||||
LookupEntry::new(libc::SIGXFSZ, "SIGXFSZ"L, "File size limit exceeded"L),
|
||||
LookupEntry::new(libc::SIGVTALRM, "SIGVTALRM"L, "Virtual timefr expired"L),
|
||||
LookupEntry::new(libc::SIGPROF, "SIGPROF"L, "Profiling timer expired"L),
|
||||
LookupEntry::new(libc::SIGWINCH, "SIGWINCH"L, "Window size change"L),
|
||||
LookupEntry::new(libc::SIGIO, "SIGIO"L, "I/O on asynchronous file descriptor is possible"L),
|
||||
LookupEntry::new(libc::SIGSYS, "SIGSYS"L, "Bad system call"L),
|
||||
LookupEntry::new(libc::SIGIOT, "SIGIOT"L, "Abort (Alias for SIGABRT)"L),
|
||||
LookupEntry::new(libc::SIGHUP, L!("SIGHUP"), L!("Terminal hung up")),
|
||||
LookupEntry::new(libc::SIGINT, L!("SIGINT"), L!("Quit request from job control (^C)")),
|
||||
LookupEntry::new(libc::SIGQUIT, L!("SIGQUIT"), L!("Quit request from job control with core dump (^\\)")),
|
||||
LookupEntry::new(libc::SIGILL, L!("SIGILL"), L!("Illegal instruction")),
|
||||
LookupEntry::new(libc::SIGTRAP, L!("SIGTRAP"), L!("Trace or breakpoint trap")),
|
||||
LookupEntry::new(libc::SIGABRT, L!("SIGABRT"), L!("Abort")),
|
||||
LookupEntry::new(libc::SIGBUS, L!("SIGBUS"), L!("Misaligned address error")),
|
||||
LookupEntry::new(libc::SIGFPE, L!("SIGFPE"), L!("Floating point exception")),
|
||||
LookupEntry::new(libc::SIGKILL, L!("SIGKILL"), L!("Forced quit")),
|
||||
LookupEntry::new(libc::SIGUSR1, L!("SIGUSR1"), L!("User defined signal 1")),
|
||||
LookupEntry::new(libc::SIGUSR2, L!("SIGUSR2"), L!("User defined signal 2")),
|
||||
LookupEntry::new(libc::SIGSEGV, L!("SIGSEGV"), L!("Address boundary error")),
|
||||
LookupEntry::new(libc::SIGPIPE, L!("SIGPIPE"), L!("Broken pipe")),
|
||||
LookupEntry::new(libc::SIGALRM, L!("SIGALRM"), L!("Timer expired")),
|
||||
LookupEntry::new(libc::SIGTERM, L!("SIGTERM"), L!("Polite quit request")),
|
||||
LookupEntry::new(libc::SIGCHLD, L!("SIGCHLD"), L!("Child process status changed")),
|
||||
LookupEntry::new(libc::SIGCONT, L!("SIGCONT"), L!("Continue previously stopped process")),
|
||||
LookupEntry::new(libc::SIGSTOP, L!("SIGSTOP"), L!("Forced stop")),
|
||||
LookupEntry::new(libc::SIGTSTP, L!("SIGTSTP"), L!("Stop request from job control (^Z)")),
|
||||
LookupEntry::new(libc::SIGTTIN, L!("SIGTTIN"), L!("Stop from terminal input")),
|
||||
LookupEntry::new(libc::SIGTTOU, L!("SIGTTOU"), L!("Stop from terminal output")),
|
||||
LookupEntry::new(libc::SIGURG, L!("SIGURG"), L!("Urgent socket condition")),
|
||||
LookupEntry::new(libc::SIGXCPU, L!("SIGXCPU"), L!("CPU time limit exceeded")),
|
||||
LookupEntry::new(libc::SIGXFSZ, L!("SIGXFSZ"), L!("File size limit exceeded")),
|
||||
LookupEntry::new(libc::SIGVTALRM, L!("SIGVTALRM"), L!("Virtual timefr expired")),
|
||||
LookupEntry::new(libc::SIGPROF, L!("SIGPROF"), L!("Profiling timer expired")),
|
||||
LookupEntry::new(libc::SIGWINCH, L!("SIGWINCH"), L!("Window size change")),
|
||||
LookupEntry::new(libc::SIGIO, L!("SIGIO"), L!("I/O on asynchronous file descriptor is possible")),
|
||||
LookupEntry::new(libc::SIGSYS, L!("SIGSYS"), L!("Bad system call")),
|
||||
LookupEntry::new(libc::SIGIOT, L!("SIGIOT"), L!("Abort (Alias for SIGABRT)")),
|
||||
|
||||
#[cfg(any(feature = "bsd", target_os = "macos"))]
|
||||
LookupEntry::new(libc::SIGEMT, "SIGEMT"L, "Unused signal"L),
|
||||
LookupEntry::new(libc::SIGEMT, L!("SIGEMT"), L!("Unused signal")),
|
||||
|
||||
#[cfg(any(feature = "bsd", target_os = "macos"))]
|
||||
LookupEntry::new(libc::SIGINFO, "SIGINFO"L, "Information request"L),
|
||||
LookupEntry::new(libc::SIGINFO, L!("SIGINFO"), L!("Information request")),
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
LookupEntry::new(libc::SIGSTKFLT, "SISTKFLT"L, "Stack fault"L),
|
||||
LookupEntry::new(libc::SIGSTKFLT, L!("SISTKFLT"), L!("Stack fault")),
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
LookupEntry::new(libc::SIGIOT, "SIGIOT"L, "Abort (Alias for SIGABRT)"L),
|
||||
LookupEntry::new(libc::SIGIOT, L!("SIGIOT"), L!("Abort (Alias for SIGABRT)")),
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[allow(deprecated)]
|
||||
LookupEntry::new(libc::SIGUNUSED, "SIGUNUSED"L, "Unused signal"L),
|
||||
LookupEntry::new(libc::SIGUNUSED, L!("SIGUNUSED"), L!("Unused signal")),
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
LookupEntry::new(libc::SIGPWR, "SIGPWR"L, "Power failure"L),
|
||||
LookupEntry::new(libc::SIGPWR, L!("SIGPWR"), L!("Power failure")),
|
||||
|
||||
// TODO: determine whether SIGWIND is defined on any platform.
|
||||
//LookupEntry::new(libc::SIGWIND, "SIGWIND"L, "Window size change"L),
|
||||
//LookupEntry::new(libc::SIGWIND, L!("SIGWIND"), L!("Window size change")),
|
||||
];
|
||||
|
||||
// Return true if two strings are equal, ignoring ASCII case.
|
||||
|
|
|
@ -5,7 +5,6 @@ use crate::wchar::prelude::*;
|
|||
use crate::wutil::wgetcwd;
|
||||
use std::collections::HashMap;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use widestring_suffix::widestrs;
|
||||
|
||||
/// An environment built around an std::map.
|
||||
#[derive(Clone, Default)]
|
||||
|
@ -40,10 +39,9 @@ impl PwdEnvironment {
|
|||
Self::default()
|
||||
}
|
||||
}
|
||||
#[widestrs]
|
||||
impl Environment for PwdEnvironment {
|
||||
fn getf(&self, name: &wstr, mode: EnvMode) -> Option<EnvVar> {
|
||||
if name == "PWD"L {
|
||||
if name == L!("PWD") {
|
||||
return Some(EnvVar::new(wgetcwd(), EnvVarFlags::default()));
|
||||
}
|
||||
self.parent.getf(name, mode)
|
||||
|
@ -51,8 +49,8 @@ impl Environment for PwdEnvironment {
|
|||
|
||||
fn get_names(&self, flags: EnvMode) -> Vec<WString> {
|
||||
let mut res = self.parent.get_names(flags);
|
||||
if !res.iter().any(|n| n == "PWD"L) {
|
||||
res.push("PWD"L.to_owned());
|
||||
if !res.iter().any(|n| n == L!("PWD")) {
|
||||
res.push(L!("PWD").to_owned());
|
||||
}
|
||||
res
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::common::{
|
|||
escape_string, str2wcstring, unescape_string, wcs2string, EscapeFlags, EscapeStringStyle,
|
||||
UnescapeStringStyle, ENCODE_DIRECT_BASE, ENCODE_DIRECT_END,
|
||||
};
|
||||
use crate::wchar::{widestrs, wstr, WString};
|
||||
use crate::wchar::{wstr, WString, L};
|
||||
use crate::wutil::encoding::{wcrtomb, zero_mbstate, AT_LEAST_MB_LEN_MAX};
|
||||
use rand::{Rng, RngCore};
|
||||
use rand_pcg::Pcg64Mcg;
|
||||
|
@ -31,41 +31,39 @@ fn setlocale() {
|
|||
panic!("No UTF-8 locale found");
|
||||
}
|
||||
|
||||
#[widestrs]
|
||||
#[test]
|
||||
fn test_escape_string() {
|
||||
let regex = |input| escape_string(input, EscapeStringStyle::Regex);
|
||||
|
||||
// plain text should not be needlessly escaped
|
||||
assert_eq!(regex("hello world!"L), "hello world!"L);
|
||||
assert_eq!(regex(L!("hello world!")), L!("hello world!"));
|
||||
|
||||
// all the following are intended to be ultimately matched literally - even if they
|
||||
// don't look like that's the intent - so we escape them.
|
||||
assert_eq!(regex(".ext"L), "\\.ext"L);
|
||||
assert_eq!(regex("{word}"L), "\\{word\\}"L);
|
||||
assert_eq!(regex("hola-mundo"L), "hola\\-mundo"L);
|
||||
assert_eq!(regex(L!(".ext")), L!("\\.ext"));
|
||||
assert_eq!(regex(L!("{word}")), L!("\\{word\\}"));
|
||||
assert_eq!(regex(L!("hola-mundo")), L!("hola\\-mundo"));
|
||||
assert_eq!(
|
||||
regex("$17.42 is your total?"L),
|
||||
"\\$17\\.42 is your total\\?"L
|
||||
regex(L!("$17.42 is your total?")),
|
||||
L!("\\$17\\.42 is your total\\?")
|
||||
);
|
||||
assert_eq!(
|
||||
regex("not really escaped\\?"L),
|
||||
"not really escaped\\\\\\?"L
|
||||
regex(L!("not really escaped\\?")),
|
||||
L!("not really escaped\\\\\\?")
|
||||
);
|
||||
}
|
||||
|
||||
#[widestrs]
|
||||
#[test]
|
||||
pub fn test_unescape_sane() {
|
||||
const TEST_CASES: &[(&wstr, &wstr)] = &[
|
||||
("abcd"L, "abcd"L),
|
||||
("'abcd'"L, "abcd"L),
|
||||
("'abcd\\n'"L, "abcd\\n"L),
|
||||
("\"abcd\\n\""L, "abcd\\n"L),
|
||||
("\"abcd\\n\""L, "abcd\\n"L),
|
||||
("\\143"L, "c"L),
|
||||
("'\\143'"L, "\\143"L),
|
||||
("\\n"L, "\n"L), // \n normally becomes newline
|
||||
(L!("abcd"), L!("abcd")),
|
||||
(L!("'abcd'"), L!("abcd")),
|
||||
(L!("'abcd\\n'"), L!("abcd\\n")),
|
||||
(L!("\"abcd\\n\""), L!("abcd\\n")),
|
||||
(L!("\"abcd\\n\""), L!("abcd\\n")),
|
||||
(L!("\\143"), L!("c")),
|
||||
(L!("'\\143'"), L!("\\143")),
|
||||
(L!("\\n"), L!("\n")), // \n normally becomes newline
|
||||
];
|
||||
|
||||
for (input, expected) in TEST_CASES {
|
||||
|
@ -80,17 +78,16 @@ pub fn test_unescape_sane() {
|
|||
}
|
||||
}
|
||||
|
||||
#[widestrs]
|
||||
#[test]
|
||||
fn test_escape_var() {
|
||||
const TEST_CASES: &[(&wstr, &wstr)] = &[
|
||||
(" a"L, "_20_a"L),
|
||||
("a B "L, "a_20_42_20_"L),
|
||||
("a b "L, "a_20_b_20_"L),
|
||||
(" B"L, "_20_42_"L),
|
||||
(" f"L, "_20_f"L),
|
||||
(" 1"L, "_20_31_"L),
|
||||
("a\nghi_"L, "a_0A_ghi__"L),
|
||||
(L!(" a"), L!("_20_a")),
|
||||
(L!("a B "), L!("a_20_42_20_")),
|
||||
(L!("a b "), L!("a_20_b_20_")),
|
||||
(L!(" B"), L!("_20_42_")),
|
||||
(L!(" f"), L!("_20_f")),
|
||||
(L!(" 1"), L!("_20_31_")),
|
||||
(L!("a\nghi_"), L!("a_0A_ghi__")),
|
||||
];
|
||||
|
||||
for (input, expected) in TEST_CASES {
|
||||
|
@ -142,11 +139,10 @@ fn test_escape_random_url() {
|
|||
escape_test(EscapeStringStyle::Url, UnescapeStringStyle::Url);
|
||||
}
|
||||
|
||||
#[widestrs]
|
||||
#[test]
|
||||
fn test_escape_no_printables() {
|
||||
// Verify that ESCAPE_NO_PRINTABLES also escapes backslashes so we don't regress on issue #3892.
|
||||
let random_string = "line 1\\n\nline 2"L.to_owned();
|
||||
let random_string = L!("line 1\\n\nline 2").to_owned();
|
||||
let escaped_string = escape_string(
|
||||
&random_string,
|
||||
EscapeStringStyle::Script(EscapeFlags::NO_PRINTABLES | EscapeFlags::NO_QUOTED),
|
||||
|
|
|
@ -95,7 +95,6 @@ pub enum ErrorKind {
|
|||
Unknown,
|
||||
}
|
||||
|
||||
#[widestrs]
|
||||
impl ErrorKind {
|
||||
pub fn describe_wstr(&self) -> &'static wstr {
|
||||
match self {
|
||||
|
@ -273,50 +272,49 @@ fn npr(n: f64, r: f64) -> f64 {
|
|||
ncr(n, r) * fac(r)
|
||||
}
|
||||
|
||||
#[widestrs]
|
||||
const BUILTINS: &[(&wstr, Function)] = &[
|
||||
// must be in alphabetical order
|
||||
("abs"L, Function::Fn1(f64::abs)),
|
||||
("acos"L, Function::Fn1(f64::acos)),
|
||||
("asin"L, Function::Fn1(f64::asin)),
|
||||
("atan"L, Function::Fn1(f64::atan)),
|
||||
("atan2"L, Function::Fn2(f64::atan2)),
|
||||
(L!("abs"), Function::Fn1(f64::abs)),
|
||||
(L!("acos"), Function::Fn1(f64::acos)),
|
||||
(L!("asin"), Function::Fn1(f64::asin)),
|
||||
(L!("atan"), Function::Fn1(f64::atan)),
|
||||
(L!("atan2"), Function::Fn2(f64::atan2)),
|
||||
(
|
||||
"bitand"L,
|
||||
L!("bitand"),
|
||||
Function::Fn2(|a, b| bitwise_op(a, b, BitAnd::bitand)),
|
||||
),
|
||||
(
|
||||
"bitor"L,
|
||||
L!("bitor"),
|
||||
Function::Fn2(|a, b| bitwise_op(a, b, BitOr::bitor)),
|
||||
),
|
||||
(
|
||||
"bitxor"L,
|
||||
L!("bitxor"),
|
||||
Function::Fn2(|a, b| bitwise_op(a, b, BitXor::bitxor)),
|
||||
),
|
||||
("ceil"L, Function::Fn1(f64::ceil)),
|
||||
("cos"L, Function::Fn1(f64::cos)),
|
||||
("cosh"L, Function::Fn1(f64::cosh)),
|
||||
("e"L, Function::Constant(E)),
|
||||
("exp"L, Function::Fn1(f64::exp)),
|
||||
("fac"L, Function::Fn1(fac)),
|
||||
("floor"L, Function::Fn1(f64::floor)),
|
||||
("ln"L, Function::Fn1(f64::ln)),
|
||||
("log"L, Function::Fn1(f64::log10)),
|
||||
("log10"L, Function::Fn1(f64::log10)),
|
||||
("log2"L, Function::Fn1(f64::log2)),
|
||||
("max"L, Function::FnN(maximum)),
|
||||
("min"L, Function::FnN(minimum)),
|
||||
("ncr"L, Function::Fn2(ncr)),
|
||||
("npr"L, Function::Fn2(npr)),
|
||||
("pi"L, Function::Constant(PI)),
|
||||
("pow"L, Function::Fn2(f64::powf)),
|
||||
("round"L, Function::Fn1(f64::round)),
|
||||
("sin"L, Function::Fn1(f64::sin)),
|
||||
("sinh"L, Function::Fn1(f64::sinh)),
|
||||
("sqrt"L, Function::Fn1(f64::sqrt)),
|
||||
("tan"L, Function::Fn1(f64::tan)),
|
||||
("tanh"L, Function::Fn1(f64::tanh)),
|
||||
("tau"L, Function::Constant(TAU)),
|
||||
(L!("ceil"), Function::Fn1(f64::ceil)),
|
||||
(L!("cos"), Function::Fn1(f64::cos)),
|
||||
(L!("cosh"), Function::Fn1(f64::cosh)),
|
||||
(L!("e"), Function::Constant(E)),
|
||||
(L!("exp"), Function::Fn1(f64::exp)),
|
||||
(L!("fac"), Function::Fn1(fac)),
|
||||
(L!("floor"), Function::Fn1(f64::floor)),
|
||||
(L!("ln"), Function::Fn1(f64::ln)),
|
||||
(L!("log"), Function::Fn1(f64::log10)),
|
||||
(L!("log10"), Function::Fn1(f64::log10)),
|
||||
(L!("log2"), Function::Fn1(f64::log2)),
|
||||
(L!("max"), Function::FnN(maximum)),
|
||||
(L!("min"), Function::FnN(minimum)),
|
||||
(L!("ncr"), Function::Fn2(ncr)),
|
||||
(L!("npr"), Function::Fn2(npr)),
|
||||
(L!("pi"), Function::Constant(PI)),
|
||||
(L!("pow"), Function::Fn2(f64::powf)),
|
||||
(L!("round"), Function::Fn1(f64::round)),
|
||||
(L!("sin"), Function::Fn1(f64::sin)),
|
||||
(L!("sinh"), Function::Fn1(f64::sinh)),
|
||||
(L!("sqrt"), Function::Fn1(f64::sqrt)),
|
||||
(L!("tan"), Function::Fn1(f64::tan)),
|
||||
(L!("tanh"), Function::Fn1(f64::tanh)),
|
||||
(L!("tau"), Function::Constant(TAU)),
|
||||
];
|
||||
|
||||
assert_sorted_by_name!(BUILTINS, 0);
|
||||
|
|
|
@ -143,10 +143,9 @@ pub const TOK_SHOW_BLANK_LINES: TokFlags = TokFlags(4);
|
|||
pub const TOK_CONTINUE_AFTER_ERROR: TokFlags = TokFlags(8);
|
||||
|
||||
impl From<TokenizerError> for &'static wstr {
|
||||
#[widestrs]
|
||||
fn from(err: TokenizerError) -> Self {
|
||||
match err {
|
||||
TokenizerError::none => ""L,
|
||||
TokenizerError::none => L!(""),
|
||||
TokenizerError::unterminated_quote => {
|
||||
wgettext!("Unexpected end of string, quotes are not balanced")
|
||||
}
|
||||
|
|
|
@ -32,7 +32,6 @@ use std::mem;
|
|||
use std::pin::Pin;
|
||||
use std::sync::atomic::{AtomicU8, Ordering};
|
||||
use std::sync::{Condvar, Mutex, MutexGuard};
|
||||
use widestring_suffix::widestrs;
|
||||
|
||||
/// The list of topics which may be observed.
|
||||
#[repr(u8)]
|
||||
|
@ -73,7 +72,6 @@ pub fn all_topics() -> [topic_t; 3] {
|
|||
[topic_t::sighupint, topic_t::sigchld, topic_t::internal_exit]
|
||||
}
|
||||
|
||||
#[widestrs]
|
||||
impl GenerationsList {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
|
|
12
src/wchar.rs
12
src/wchar.rs
|
@ -16,7 +16,6 @@ pub mod prelude {
|
|||
wchar_ext::{ToWString, WExt},
|
||||
wutil::{sprintf, wgettext, wgettext_fmt, wgettext_maybe_fmt, wgettext_str},
|
||||
};
|
||||
pub use widestring_suffix::widestrs;
|
||||
}
|
||||
|
||||
/// Creates a wstr string slice, like the "L" prefix of C++.
|
||||
|
@ -30,17 +29,6 @@ macro_rules! L {
|
|||
}
|
||||
pub use L;
|
||||
|
||||
/// A proc-macro for creating wide string literals using an L *suffix*.
|
||||
/// Example usage:
|
||||
/// ```ignore
|
||||
/// #[widestrs]
|
||||
/// pub fn func() {
|
||||
/// let s = "hello"L; // type &'static wstr
|
||||
/// }
|
||||
/// ```
|
||||
/// Note: the resulting string is NOT nul-terminated.
|
||||
pub use widestring_suffix::widestrs;
|
||||
|
||||
/// Encode a literal byte in a UTF-32 character. This is required for e.g. the echo builtin, whose
|
||||
/// escape sequences can be used to construct raw byte sequences which are then interpreted as e.g.
|
||||
/// UTF-8 by the terminal. If we were to interpret each of those bytes as a codepoint and encode it
|
||||
|
|
|
@ -27,7 +27,6 @@ use std::io::{self, Write};
|
|||
use std::os::unix::prelude::*;
|
||||
|
||||
pub use wcstoi::*;
|
||||
use widestring_suffix::widestrs;
|
||||
|
||||
/// Wide character version of opendir(). Note that opendir() is guaranteed to set close-on-exec by
|
||||
/// POSIX (hooray).
|
||||
|
@ -274,7 +273,6 @@ fn test_normalize_path() {
|
|||
/// appropriate for cd. That is, return effectively wd + path while resolving leading ../s from
|
||||
/// path. The intent here is to allow 'cd' out of a directory which may no longer exist, without
|
||||
/// allowing 'cd' into a directory that may not exist; see #5341.
|
||||
#[widestrs]
|
||||
pub fn path_normalize_for_cd(wd: &wstr, path: &wstr) -> WString {
|
||||
// Fast paths.
|
||||
const sep: char = '/';
|
||||
|
@ -302,9 +300,9 @@ pub fn path_normalize_for_cd(wd: &wstr, path: &wstr) -> WString {
|
|||
let mut erase_count = 0;
|
||||
for comp in &path_comps {
|
||||
let mut erase_it = false;
|
||||
if comp.is_empty() || comp == "."L {
|
||||
if comp.is_empty() || comp == L!(".") {
|
||||
erase_it = true;
|
||||
} else if comp == ".."L && !wd_comps.is_empty() {
|
||||
} else if comp == L!("..") && !wd_comps.is_empty() {
|
||||
erase_it = true;
|
||||
wd_comps.pop();
|
||||
}
|
||||
|
|
|
@ -8,23 +8,22 @@ use crate::fallback::fish_mkstemp_cloexec;
|
|||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[widestrs]
|
||||
fn test_wdirname_wbasename() {
|
||||
// path, dir, base
|
||||
struct Test(&'static wstr, &'static wstr, &'static wstr);
|
||||
const testcases: &[Test] = &[
|
||||
Test(""L, "."L, "."L),
|
||||
Test("foo//"L, "."L, "foo"L),
|
||||
Test("foo//////"L, "."L, "foo"L),
|
||||
Test("/////foo"L, "/"L, "foo"L),
|
||||
Test("//foo/////bar"L, "//foo"L, "bar"L),
|
||||
Test("foo/////bar"L, "foo"L, "bar"L),
|
||||
Test(L!(""), L!("."), L!(".")),
|
||||
Test(L!("foo//"), L!("."), L!("foo")),
|
||||
Test(L!("foo//////"), L!("."), L!("foo")),
|
||||
Test(L!("/////foo"), L!("/"), L!("foo")),
|
||||
Test(L!("//foo/////bar"), L!("//foo"), L!("bar")),
|
||||
Test(L!("foo/////bar"), L!("foo"), L!("bar")),
|
||||
// Examples given in XPG4.2.
|
||||
Test("/usr/lib"L, "/usr"L, "lib"L),
|
||||
Test("usr"L, "."L, "usr"L),
|
||||
Test("/"L, "/"L, "/"L),
|
||||
Test("."L, "."L, "."L),
|
||||
Test(".."L, "."L, ".."L),
|
||||
Test(L!("/usr/lib"), L!("/usr"), L!("lib")),
|
||||
Test(L!("usr"), L!("."), L!("usr")),
|
||||
Test(L!("/"), L!("/"), L!("/")),
|
||||
Test(L!("."), L!("."), L!(".")),
|
||||
Test(L!(".."), L!("."), L!("..")),
|
||||
];
|
||||
|
||||
for tc in testcases {
|
||||
|
@ -54,7 +53,7 @@ fn test_wdirname_wbasename() {
|
|||
let last_slash = longpath.chars().rposition(|c| c == '/').unwrap();
|
||||
let longpath_dir = &longpath[..last_slash];
|
||||
assert_eq!(wdirname(&longpath), longpath_dir);
|
||||
assert_eq!(wbasename(&longpath), "overlong"L);
|
||||
assert_eq!(wbasename(&longpath), L!("overlong"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
Loading…
Reference in New Issue
Block a user