mirror of
https://github.com/fish-shell/fish-shell.git
synced 2025-02-21 05:25:54 +08:00
Port parse_util
Except for the indent visitor bits. Tests for parse_util_detect_errors* are not ported yet because they depend on expand.h (and operation_context.h which depends on env.h).
This commit is contained in:
parent
36ba912779
commit
12afb320a3
@ -151,6 +151,10 @@ pub trait Node: Acceptor + ConcreteNode + std::fmt::Debug {
|
||||
|
||||
// The address of the object, for comparison.
|
||||
fn as_ptr(&self) -> *const ();
|
||||
|
||||
fn pointer_eq(&self, rhs: &dyn Node) -> bool {
|
||||
std::ptr::eq(self.as_ptr(), rhs.as_ptr())
|
||||
}
|
||||
}
|
||||
|
||||
/// NodeMut is a mutable node.
|
||||
@ -626,9 +630,12 @@ macro_rules! define_list_node {
|
||||
}
|
||||
impl $name {
|
||||
/// Iteration support.
|
||||
fn iter<F>(&self) -> impl Iterator<Item = &<$name as List>::ContentsNode> {
|
||||
pub fn iter(&self) -> impl Iterator<Item = &<$name as List>::ContentsNode> {
|
||||
self.contents().iter().map(|b| &**b)
|
||||
}
|
||||
pub fn get(&self, index: usize) -> Option<&$contents> {
|
||||
self.contents().get(index).map(|b| &**b)
|
||||
}
|
||||
}
|
||||
impl Index<usize> for $name {
|
||||
type Output = <$name as List>::ContentsNode;
|
||||
|
@ -1,7 +1,51 @@
|
||||
use crate::common::{char_offset, EXPAND_RESERVED_BASE, EXPAND_RESERVED_END};
|
||||
use crate::wchar::wstr;
|
||||
use crate::operation_context::OperationContext;
|
||||
use crate::parse_constants::ParseErrorList;
|
||||
use crate::wchar::{wstr, WString};
|
||||
use bitflags::bitflags;
|
||||
use widestring_suffix::widestrs;
|
||||
|
||||
bitflags! {
|
||||
/// Set of flags controlling expansions.
|
||||
pub struct ExpandFlags : u16 {
|
||||
/// Skip command substitutions.
|
||||
const SKIP_CMDSUBST = 1 << 0;
|
||||
/// Skip variable expansion.
|
||||
const SKIP_VARIABLES = 1 << 1;
|
||||
/// Skip wildcard expansion.
|
||||
const SKIP_WILDCARDS = 1 << 2;
|
||||
/// The expansion is being done for tab or auto completions. Returned completions may have the
|
||||
/// wildcard as a prefix instead of a match.
|
||||
const FOR_COMPLETIONS = 1 << 3;
|
||||
/// Only match files that are executable by the current user.
|
||||
const EXECUTABLES_ONLY = 1 << 4;
|
||||
/// Only match directories.
|
||||
const DIRECTORIES_ONLY = 1 << 5;
|
||||
/// Generate descriptions, stored in the description field of completions.
|
||||
const GEN_DESCRIPTIONS = 1 << 6;
|
||||
/// Un-expand home directories to tildes after.
|
||||
const PRESERVE_HOME_TILDES = 1 << 7;
|
||||
/// Allow fuzzy matching.
|
||||
const FUZZY_MATCH = 1 << 8;
|
||||
/// Disallow directory abbreviations like /u/l/b for /usr/local/bin. Only applicable if
|
||||
/// fuzzy_match is set.
|
||||
const NO_FUZZY_DIRECTORIES = 1 << 9;
|
||||
/// Allows matching a leading dot even if the wildcard does not contain one.
|
||||
/// By default, wildcards only match a leading dot literally; this is why e.g. '*' does not
|
||||
/// match hidden files.
|
||||
const ALLOW_NONLITERAL_LEADING_DOT = 1 << 10;
|
||||
/// Do expansions specifically to support cd. This means using CDPATH as a list of potential
|
||||
/// working directories, and to use logical instead of physical paths.
|
||||
const SPECIAL_FOR_CD = 1 << 11;
|
||||
/// Do expansions specifically for cd autosuggestion. This is to differentiate between cd
|
||||
/// completions and cd autosuggestions.
|
||||
const SPECIAL_FOR_CD_AUTOSUGGESTION = 1 << 12;
|
||||
/// Do expansions specifically to support external command completions. This means using PATH as
|
||||
/// a list of potential working directories.
|
||||
const SPECIAL_FOR_COMMAND = 1 << 13;
|
||||
}
|
||||
}
|
||||
|
||||
/// Character representing a home directory.
|
||||
pub const HOME_DIRECTORY: char = char_offset(EXPAND_RESERVED_BASE, 0);
|
||||
/// Character representing process expansion for %self.
|
||||
@ -29,6 +73,70 @@ const _: () = assert!(
|
||||
"Characters used in expansions must stay within private use area"
|
||||
);
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
pub enum ExpandResultCode {
|
||||
/// There was an error, for example, unmatched braces.
|
||||
error,
|
||||
/// Expansion succeeded.
|
||||
ok,
|
||||
/// Expansion was cancelled (e.g. control-C).
|
||||
cancel,
|
||||
/// Expansion succeeded, but a wildcard in the string matched no files,
|
||||
/// so the output is empty.
|
||||
wildcard_no_match,
|
||||
}
|
||||
|
||||
/// These are the possible return values for expand_string.
|
||||
pub struct ExpandResult {
|
||||
// todo!
|
||||
pub result: ExpandResultCode,
|
||||
}
|
||||
|
||||
impl PartialEq<ExpandResultCode> for ExpandResult {
|
||||
fn eq(&self, other: &ExpandResultCode) -> bool {
|
||||
self.result == *other
|
||||
}
|
||||
}
|
||||
|
||||
/// The string represented by PROCESS_EXPAND_SELF
|
||||
#[widestrs]
|
||||
pub const PROCESS_EXPAND_SELF_STR: &wstr = "%self"L;
|
||||
|
||||
/// expand_one is identical to expand_string, except it will fail if in expands to more than one
|
||||
/// string. This is used for expanding command names.
|
||||
///
|
||||
/// \param inout_str The parameter to expand in-place
|
||||
/// \param flags Specifies if any expansion pass should be skipped. Legal values are any combination
|
||||
/// of skip_cmdsubst skip_variables and skip_wildcards
|
||||
/// \param ctx The parser, variables, and cancellation checker for this operation. The parser may be
|
||||
/// null. \param errors Resulting errors, or nullptr to ignore
|
||||
///
|
||||
/// \return Whether expansion succeeded.
|
||||
#[allow(unused_variables)]
|
||||
pub fn expand_one(
|
||||
s: &mut WString,
|
||||
flags: ExpandFlags,
|
||||
ctx: &OperationContext,
|
||||
errors: Option<&mut ParseErrorList>,
|
||||
) -> bool {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Expand a command string like $HOME/bin/cmd into a command and list of arguments.
|
||||
/// Return the command and arguments by reference.
|
||||
/// If the expansion resulted in no or an empty command, the command will be an empty string. Note
|
||||
/// that API does not distinguish between expansion resulting in an empty command (''), and
|
||||
/// expansion resulting in no command (e.g. unset variable).
|
||||
/// If \p skip_wildcards is true, then do not do wildcard expansion
|
||||
/// \return an expand error.
|
||||
#[allow(unused_variables)]
|
||||
pub fn expand_to_command_and_args(
|
||||
instr: &wstr,
|
||||
ctx: &OperationContext,
|
||||
out_cmd: &mut WString,
|
||||
out_args: Option<&Vec<WString>>,
|
||||
errors: &mut ParseErrorList,
|
||||
skip_wildcards: bool,
|
||||
) -> ExpandResult {
|
||||
todo!()
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
#![allow(clippy::bool_assert_comparison)]
|
||||
#![allow(clippy::uninlined_format_args)]
|
||||
#![allow(clippy::derivable_impls)]
|
||||
#![allow(clippy::option_map_unit_fn)]
|
||||
|
||||
#[macro_use]
|
||||
mod common;
|
||||
@ -40,6 +41,7 @@ mod job_group;
|
||||
mod locale;
|
||||
mod nix;
|
||||
mod null_terminated_array;
|
||||
mod operation_context;
|
||||
mod parse_constants;
|
||||
mod parse_tree;
|
||||
mod parse_util;
|
||||
|
7
fish-rust/src/operation_context.rs
Normal file
7
fish-rust/src/operation_context.rs
Normal file
@ -0,0 +1,7 @@
|
||||
pub struct OperationContext {}
|
||||
|
||||
impl OperationContext {
|
||||
pub fn empty() -> OperationContext {
|
||||
todo!()
|
||||
}
|
||||
}
|
@ -52,7 +52,7 @@ impl BitOrAssign for ParseTreeFlags {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Copy, Clone)]
|
||||
#[derive(PartialEq, Eq, Copy, Clone, Default)]
|
||||
pub struct ParserTestErrorBits(u8);
|
||||
|
||||
pub const PARSER_TEST_ERROR: ParserTestErrorBits = ParserTestErrorBits(1);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -439,38 +439,6 @@ static void test_escape_crazy() {
|
||||
}
|
||||
}
|
||||
|
||||
static void test_escape_quotes() {
|
||||
say(L"Testing escaping with quotes");
|
||||
// These are "raw string literals"
|
||||
do_test(parse_util_escape_string_with_quote(L"abc", L'\0') == L"abc");
|
||||
do_test(parse_util_escape_string_with_quote(L"abc~def", L'\0') == L"abc\\~def");
|
||||
do_test(parse_util_escape_string_with_quote(L"abc~def", L'\0', true) == L"abc~def");
|
||||
do_test(parse_util_escape_string_with_quote(L"abc\\~def", L'\0') == L"abc\\\\\\~def");
|
||||
do_test(parse_util_escape_string_with_quote(L"abc\\~def", L'\0', true) == L"abc\\\\~def");
|
||||
do_test(parse_util_escape_string_with_quote(L"~abc", L'\0') == L"\\~abc");
|
||||
do_test(parse_util_escape_string_with_quote(L"~abc", L'\0', true) == L"~abc");
|
||||
do_test(parse_util_escape_string_with_quote(L"~abc|def", L'\0') == L"\\~abc\\|def");
|
||||
do_test(parse_util_escape_string_with_quote(L"|abc~def", L'\0') == L"\\|abc\\~def");
|
||||
do_test(parse_util_escape_string_with_quote(L"|abc~def", L'\0', true) == L"\\|abc~def");
|
||||
do_test(parse_util_escape_string_with_quote(L"foo\nbar", L'\0') == L"foo\\nbar");
|
||||
|
||||
// Note tildes are not expanded inside quotes, so no_tilde is ignored with a quote.
|
||||
do_test(parse_util_escape_string_with_quote(L"abc", L'\'') == L"abc");
|
||||
do_test(parse_util_escape_string_with_quote(L"abc\\def", L'\'') == L"abc\\\\def");
|
||||
do_test(parse_util_escape_string_with_quote(L"abc'def", L'\'') == L"abc\\'def");
|
||||
do_test(parse_util_escape_string_with_quote(L"~abc'def", L'\'') == L"~abc\\'def");
|
||||
do_test(parse_util_escape_string_with_quote(L"~abc'def", L'\'', true) == L"~abc\\'def");
|
||||
do_test(parse_util_escape_string_with_quote(L"foo\nba'r", L'\'') == L"foo'\\n'ba\\'r");
|
||||
do_test(parse_util_escape_string_with_quote(L"foo\\\\bar", L'\'') == L"foo\\\\\\\\bar");
|
||||
|
||||
do_test(parse_util_escape_string_with_quote(L"abc", L'"') == L"abc");
|
||||
do_test(parse_util_escape_string_with_quote(L"abc\\def", L'"') == L"abc\\\\def");
|
||||
do_test(parse_util_escape_string_with_quote(L"~abc'def", L'"') == L"~abc'def");
|
||||
do_test(parse_util_escape_string_with_quote(L"~abc'def", L'"', true) == L"~abc'def");
|
||||
do_test(parse_util_escape_string_with_quote(L"foo\nba'r", L'"') == L"foo\"\\n\"ba'r");
|
||||
do_test(parse_util_escape_string_with_quote(L"foo\\\\bar", L'"') == L"foo\\\\\\\\bar");
|
||||
}
|
||||
|
||||
static void test_format() {
|
||||
say(L"Testing formatting functions");
|
||||
struct {
|
||||
@ -1424,38 +1392,6 @@ static void test_indents() {
|
||||
}
|
||||
}
|
||||
|
||||
static void test_parse_util_cmdsubst_extent() {
|
||||
const wchar_t *a = L"echo (echo (echo hi";
|
||||
const wchar_t *begin = nullptr, *end = nullptr;
|
||||
|
||||
parse_util_cmdsubst_extent(a, 0, &begin, &end);
|
||||
if (begin != a || end != begin + std::wcslen(begin)) {
|
||||
err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__);
|
||||
}
|
||||
parse_util_cmdsubst_extent(a, 1, &begin, &end);
|
||||
if (begin != a || end != begin + std::wcslen(begin)) {
|
||||
err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__);
|
||||
}
|
||||
parse_util_cmdsubst_extent(a, 2, &begin, &end);
|
||||
if (begin != a || end != begin + std::wcslen(begin)) {
|
||||
err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__);
|
||||
}
|
||||
parse_util_cmdsubst_extent(a, 3, &begin, &end);
|
||||
if (begin != a || end != begin + std::wcslen(begin)) {
|
||||
err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__);
|
||||
}
|
||||
|
||||
parse_util_cmdsubst_extent(a, 8, &begin, &end);
|
||||
if (begin != a + const_strlen(L"echo (")) {
|
||||
err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__);
|
||||
}
|
||||
|
||||
parse_util_cmdsubst_extent(a, 17, &begin, &end);
|
||||
if (begin != a + const_strlen(L"echo (echo (")) {
|
||||
err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_const_strlen() {
|
||||
do_test(const_strlen("") == 0);
|
||||
do_test(const_strlen(L"") == 0);
|
||||
@ -1599,7 +1535,6 @@ void test_dir_iter() {
|
||||
|
||||
static void test_utility_functions() {
|
||||
say(L"Testing utility functions");
|
||||
test_parse_util_cmdsubst_extent();
|
||||
test_const_strlen();
|
||||
test_const_strcmp();
|
||||
test_is_sorted_by_name();
|
||||
@ -6677,7 +6612,6 @@ static const test_t s_tests[]{
|
||||
{TEST_GROUP("error_messages"), test_error_messages},
|
||||
{TEST_GROUP("escape"), test_unescape_sane},
|
||||
{TEST_GROUP("escape"), test_escape_crazy},
|
||||
{TEST_GROUP("escape"), test_escape_quotes},
|
||||
{TEST_GROUP("format"), test_format},
|
||||
{TEST_GROUP("convert"), test_convert},
|
||||
{TEST_GROUP("convert"), test_convert_private_use},
|
||||
|
Loading…
x
Reference in New Issue
Block a user