mirror of
https://github.com/fish-shell/fish-shell.git
synced 2024-12-18 12:33:38 +08:00
Clean up builtin status
This is a cleanup with no user-visible changes. In particular we stop using num_derive and num_traits.
This commit is contained in:
parent
3ce6a5fdd1
commit
26abb97198
|
@ -10,25 +10,19 @@ use crate::wutil::{waccess, wbasename, wdirname, wrealpath, Error};
|
||||||
use libc::F_OK;
|
use libc::F_OK;
|
||||||
use nix::errno::Errno;
|
use nix::errno::Errno;
|
||||||
use nix::NixPath;
|
use nix::NixPath;
|
||||||
use num_derive::FromPrimitive;
|
|
||||||
use num_traits::FromPrimitive;
|
|
||||||
|
|
||||||
macro_rules! str_enum {
|
macro_rules! str_enum {
|
||||||
($name:ident, $(($val:ident, $str:expr)),* $(,)?) => {
|
($name:ident, $(($val:ident, $str:expr)),* $(,)?) => {
|
||||||
impl TryFrom<&str> for $name {
|
impl $name {
|
||||||
type Error = ();
|
fn from_wstr(s: &str) -> Option<Self> {
|
||||||
|
|
||||||
fn try_from(s: &str) -> Result<Self, Self::Error> {
|
|
||||||
// matching on str's lets us avoid having to do binary search and friends ourselves,
|
// matching on str's lets us avoid having to do binary search and friends ourselves,
|
||||||
// this is ascii only anyways
|
// this is ascii only anyways
|
||||||
match s {
|
match s {
|
||||||
$($str => Ok(Self::$val)),*,
|
$($str => Some(Self::$val)),*,
|
||||||
_ => Err(()),
|
_ => None,
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl $name {
|
|
||||||
fn to_wstr(self) -> &'static wstr {
|
fn to_wstr(self) -> &'static wstr {
|
||||||
// There can be multiple vals => str mappings, and that's okay
|
// There can be multiple vals => str mappings, and that's okay
|
||||||
#[allow(unreachable_patterns)]
|
#[allow(unreachable_patterns)]
|
||||||
|
@ -41,7 +35,7 @@ macro_rules! str_enum {
|
||||||
}
|
}
|
||||||
|
|
||||||
use StatusCmd::*;
|
use StatusCmd::*;
|
||||||
#[derive(PartialEq, FromPrimitive, Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
enum StatusCmd {
|
enum StatusCmd {
|
||||||
STATUS_CURRENT_CMD = 1,
|
STATUS_CURRENT_CMD = 1,
|
||||||
STATUS_BASENAME,
|
STATUS_BASENAME,
|
||||||
|
@ -95,15 +89,6 @@ str_enum!(
|
||||||
(STATUS_TEST_FEATURE, "test-feature"),
|
(STATUS_TEST_FEATURE, "test-feature"),
|
||||||
);
|
);
|
||||||
|
|
||||||
impl StatusCmd {
|
|
||||||
const fn as_char(self) -> char {
|
|
||||||
match char::from_u32(self as u32) {
|
|
||||||
Some(c) => c,
|
|
||||||
None => panic!("Should be a valid char"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Values that may be returned from the test-feature option to status.
|
/// Values that may be returned from the test-feature option to status.
|
||||||
#[repr(i32)]
|
#[repr(i32)]
|
||||||
enum TestFeatureRetVal {
|
enum TestFeatureRetVal {
|
||||||
|
@ -119,6 +104,25 @@ struct StatusCmdOpts {
|
||||||
print_help: bool,
|
print_help: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl StatusCmdOpts {
|
||||||
|
// Set the status command to the given command.
|
||||||
|
// Returns true on success, false if there's already a status command, in which case an error is printed.
|
||||||
|
fn try_set_status_cmd(&mut self, subcmd: StatusCmd, streams: &mut IoStreams) -> bool {
|
||||||
|
match self.status_cmd.replace(subcmd) {
|
||||||
|
Some(existing) => {
|
||||||
|
streams.err.append(wgettext_fmt!(
|
||||||
|
BUILTIN_ERR_COMBO2_EXCLUSIVE,
|
||||||
|
"status",
|
||||||
|
existing.to_wstr(),
|
||||||
|
subcmd.to_wstr(),
|
||||||
|
));
|
||||||
|
false
|
||||||
|
}
|
||||||
|
None => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for StatusCmdOpts {
|
impl Default for StatusCmdOpts {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -130,32 +134,34 @@ impl Default for StatusCmdOpts {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Short options for long options that have no corresponding short options.
|
||||||
|
const FISH_PATH_SHORT: char = '\x01';
|
||||||
|
const IS_FULL_JOB_CTRL_SHORT: char = '\x02';
|
||||||
|
const IS_INTERACTIVE_JOB_CTRL_SHORT: char = '\x03';
|
||||||
|
const IS_NO_JOB_CTRL_SHORT: char = '\x04';
|
||||||
|
|
||||||
const SHORT_OPTIONS: &wstr = L!(":L:cbilfnhj:t");
|
const SHORT_OPTIONS: &wstr = L!(":L:cbilfnhj:t");
|
||||||
const LONG_OPTIONS: &[woption] = &[
|
const LONG_OPTIONS: &[woption] = &[
|
||||||
wopt(L!("help"), no_argument, 'h'),
|
wopt(L!("help"), no_argument, 'h'),
|
||||||
wopt(L!("current-filename"), no_argument, 'f'),
|
wopt(L!("current-filename"), no_argument, 'f'),
|
||||||
wopt(L!("current-line-number"), no_argument, 'n'),
|
wopt(L!("current-line-number"), no_argument, 'n'),
|
||||||
wopt(L!("filename"), no_argument, 'f'),
|
wopt(L!("filename"), no_argument, 'f'),
|
||||||
wopt(L!("fish-path"), no_argument, STATUS_FISH_PATH.as_char()),
|
wopt(L!("fish-path"), no_argument, FISH_PATH_SHORT),
|
||||||
wopt(L!("is-block"), no_argument, 'b'),
|
wopt(L!("is-block"), no_argument, 'b'),
|
||||||
wopt(L!("is-command-substitution"), no_argument, 'c'),
|
wopt(L!("is-command-substitution"), no_argument, 'c'),
|
||||||
wopt(
|
wopt(
|
||||||
L!("is-full-job-control"),
|
L!("is-full-job-control"),
|
||||||
no_argument,
|
no_argument,
|
||||||
STATUS_IS_FULL_JOB_CTRL.as_char(),
|
IS_FULL_JOB_CTRL_SHORT,
|
||||||
),
|
),
|
||||||
wopt(L!("is-interactive"), no_argument, 'i'),
|
wopt(L!("is-interactive"), no_argument, 'i'),
|
||||||
wopt(
|
wopt(
|
||||||
L!("is-interactive-job-control"),
|
L!("is-interactive-job-control"),
|
||||||
no_argument,
|
no_argument,
|
||||||
STATUS_IS_INTERACTIVE_JOB_CTRL.as_char(),
|
IS_INTERACTIVE_JOB_CTRL_SHORT,
|
||||||
),
|
),
|
||||||
wopt(L!("is-login"), no_argument, 'l'),
|
wopt(L!("is-login"), no_argument, 'l'),
|
||||||
wopt(
|
wopt(L!("is-no-job-control"), no_argument, IS_NO_JOB_CTRL_SHORT),
|
||||||
L!("is-no-job-control"),
|
|
||||||
no_argument,
|
|
||||||
STATUS_IS_NO_JOB_CTRL.as_char(),
|
|
||||||
),
|
|
||||||
wopt(L!("job-control"), required_argument, 'j'),
|
wopt(L!("job-control"), required_argument, 'j'),
|
||||||
wopt(L!("level"), required_argument, 'L'),
|
wopt(L!("level"), required_argument, 'L'),
|
||||||
wopt(L!("line"), no_argument, 'n'),
|
wopt(L!("line"), no_argument, 'n'),
|
||||||
|
@ -235,25 +241,12 @@ fn parse_cmd_opts(
|
||||||
't' => STATUS_STACK_TRACE,
|
't' => STATUS_STACK_TRACE,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
if let Some(existing) = opts.status_cmd.replace(subcmd) {
|
if !opts.try_set_status_cmd(subcmd, streams) {
|
||||||
streams.err.append(wgettext_fmt!(
|
|
||||||
BUILTIN_ERR_COMBO2_EXCLUSIVE,
|
|
||||||
cmd,
|
|
||||||
existing.to_wstr(),
|
|
||||||
subcmd.to_wstr(),
|
|
||||||
));
|
|
||||||
return STATUS_CMD_ERROR;
|
return STATUS_CMD_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'j' => {
|
'j' => {
|
||||||
let subcmd = STATUS_SET_JOB_CONTROL;
|
if !opts.try_set_status_cmd(STATUS_SET_JOB_CONTROL, streams) {
|
||||||
if let Some(existing) = opts.status_cmd.replace(subcmd) {
|
|
||||||
streams.err.append(wgettext_fmt!(
|
|
||||||
BUILTIN_ERR_COMBO2_EXCLUSIVE,
|
|
||||||
cmd,
|
|
||||||
existing.to_wstr(),
|
|
||||||
subcmd.to_wstr(),
|
|
||||||
));
|
|
||||||
return STATUS_CMD_ERROR;
|
return STATUS_CMD_ERROR;
|
||||||
}
|
}
|
||||||
let Ok(job_mode) = w.woptarg.unwrap().try_into() else {
|
let Ok(job_mode) = w.woptarg.unwrap().try_into() else {
|
||||||
|
@ -266,6 +259,26 @@ fn parse_cmd_opts(
|
||||||
};
|
};
|
||||||
opts.new_job_control_mode = Some(job_mode);
|
opts.new_job_control_mode = Some(job_mode);
|
||||||
}
|
}
|
||||||
|
IS_FULL_JOB_CTRL_SHORT => {
|
||||||
|
if !opts.try_set_status_cmd(STATUS_IS_FULL_JOB_CTRL, streams) {
|
||||||
|
return STATUS_CMD_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IS_INTERACTIVE_JOB_CTRL_SHORT => {
|
||||||
|
if !opts.try_set_status_cmd(STATUS_IS_INTERACTIVE_JOB_CTRL, streams) {
|
||||||
|
return STATUS_CMD_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IS_NO_JOB_CTRL_SHORT => {
|
||||||
|
if !opts.try_set_status_cmd(STATUS_IS_NO_JOB_CTRL, streams) {
|
||||||
|
return STATUS_CMD_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FISH_PATH_SHORT => {
|
||||||
|
if !opts.try_set_status_cmd(STATUS_FISH_PATH, streams) {
|
||||||
|
return STATUS_CMD_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
'h' => opts.print_help = true,
|
'h' => opts.print_help = true,
|
||||||
':' => {
|
':' => {
|
||||||
builtin_missing_argument(parser, streams, cmd, args[w.woptind - 1], false);
|
builtin_missing_argument(parser, streams, cmd, args[w.woptind - 1], false);
|
||||||
|
@ -275,30 +288,9 @@ fn parse_cmd_opts(
|
||||||
builtin_unknown_option(parser, streams, cmd, args[w.woptind - 1], false);
|
builtin_unknown_option(parser, streams, cmd, args[w.woptind - 1], false);
|
||||||
return STATUS_INVALID_ARGS;
|
return STATUS_INVALID_ARGS;
|
||||||
}
|
}
|
||||||
c => {
|
|
||||||
let Some(opt_cmd) = StatusCmd::from_u32(c.into()) else {
|
|
||||||
panic!("unexpected retval from wgetopt_long")
|
|
||||||
};
|
|
||||||
match opt_cmd {
|
|
||||||
STATUS_IS_FULL_JOB_CTRL
|
|
||||||
| STATUS_IS_INTERACTIVE_JOB_CTRL
|
|
||||||
| STATUS_IS_NO_JOB_CTRL
|
|
||||||
| STATUS_FISH_PATH => {
|
|
||||||
if let Some(existing) = opts.status_cmd.replace(opt_cmd) {
|
|
||||||
streams.err.append(wgettext_fmt!(
|
|
||||||
BUILTIN_ERR_COMBO2_EXCLUSIVE,
|
|
||||||
cmd,
|
|
||||||
existing.to_wstr(),
|
|
||||||
opt_cmd.to_wstr(),
|
|
||||||
));
|
|
||||||
return STATUS_CMD_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => panic!("unexpected retval from wgetopt_long"),
|
_ => panic!("unexpected retval from wgetopt_long"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*optind = w.woptind;
|
*optind = w.woptind;
|
||||||
|
|
||||||
|
@ -324,20 +316,14 @@ pub fn status(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) -> O
|
||||||
// If a status command hasn't already been specified via a flag check the first word.
|
// If a status command hasn't already been specified via a flag check the first word.
|
||||||
// Note that this can be simplified after we eliminate allowing subcommands as flags.
|
// Note that this can be simplified after we eliminate allowing subcommands as flags.
|
||||||
if optind < argc {
|
if optind < argc {
|
||||||
match StatusCmd::try_from(args[optind].to_string().as_str()) {
|
match StatusCmd::from_wstr(args[optind].to_string().as_str()) {
|
||||||
Ok(s) => {
|
Some(s) => {
|
||||||
if let Some(existing) = opts.status_cmd.replace(s) {
|
if !opts.try_set_status_cmd(s, streams) {
|
||||||
streams.err.append(wgettext_fmt!(
|
|
||||||
BUILTIN_ERR_COMBO2_EXCLUSIVE,
|
|
||||||
cmd,
|
|
||||||
existing.to_wstr(),
|
|
||||||
s.to_wstr(),
|
|
||||||
));
|
|
||||||
return STATUS_CMD_ERROR;
|
return STATUS_CMD_ERROR;
|
||||||
}
|
}
|
||||||
optind += 1;
|
optind += 1;
|
||||||
}
|
}
|
||||||
Err(_) => {
|
None => {
|
||||||
streams
|
streams
|
||||||
.err
|
.err
|
||||||
.append(wgettext_fmt!(BUILTIN_ERR_INVALID_SUBCMD, cmd, args[1]));
|
.append(wgettext_fmt!(BUILTIN_ERR_INVALID_SUBCMD, cmd, args[1]));
|
||||||
|
|
Loading…
Reference in New Issue
Block a user