contains: port contains builtin to rust

This commit is contained in:
Neeraj Jaiswal
2023-02-20 23:27:02 +05:30
committed by Johannes Altmanninger
parent a601babcf0
commit 3b60bc1de0
8 changed files with 104 additions and 100 deletions

View File

@@ -102,7 +102,7 @@ set(FISH_BUILTIN_SRCS
src/builtin.cpp src/builtins/abbr.cpp src/builtins/argparse.cpp
src/builtins/bg.cpp src/builtins/bind.cpp src/builtins/block.cpp
src/builtins/builtin.cpp src/builtins/cd.cpp src/builtins/command.cpp
src/builtins/commandline.cpp src/builtins/complete.cpp src/builtins/contains.cpp
src/builtins/commandline.cpp src/builtins/complete.cpp
src/builtins/disown.cpp
src/builtins/eval.cpp src/builtins/fg.cpp
src/builtins/function.cpp src/builtins/functions.cpp src/builtins/history.cpp

View File

@@ -0,0 +1,93 @@
// Implementation of the contains builtin.
use super::shared::{
builtin_missing_argument, builtin_print_help, io_streams_t, STATUS_CMD_ERROR, STATUS_CMD_OK,
STATUS_INVALID_ARGS,
};
use crate::builtins::shared::builtin_unknown_option;
use crate::ffi::parser_t;
use crate::wchar::{wstr, L};
use crate::wgetopt::{wgetopter_t, wopt, woption, woption_argument_t};
use crate::wutil::wgettext_fmt;
use libc::c_int;
#[derive(Debug, Clone, Copy, Default)]
struct Options {
print_help: bool,
print_index: bool,
}
fn parse_options(
args: &mut [&wstr],
parser: &mut parser_t,
streams: &mut io_streams_t,
) -> Result<(Options, usize), Option<c_int>> {
let cmd = args[0];
const SHORT_OPTS: &wstr = L!("+:hi");
const LONG_OPTS: &[woption] = &[
wopt(L!("help"), woption_argument_t::no_argument, 'h'),
wopt(L!("index"), woption_argument_t::no_argument, 'i'),
];
let mut opts = Options::default();
let mut w = wgetopter_t::new(SHORT_OPTS, LONG_OPTS, args);
while let Some(c) = w.wgetopt_long() {
match c {
'h' => opts.print_help = true,
'i' => opts.print_index = true,
':' => {
builtin_missing_argument(parser, streams, cmd, args[w.woptind - 1], false);
return Err(STATUS_INVALID_ARGS);
}
'?' => {
builtin_unknown_option(parser, streams, cmd, args[w.woptind - 1], false);
return Err(STATUS_INVALID_ARGS);
}
_ => {
panic!("unexpected retval from wgetopt_long");
}
}
}
Ok((opts, w.woptind))
}
/// Implementation of the builtin contains command, used to check if a specified string is part of
/// a list.
pub fn contains(
parser: &mut parser_t,
streams: &mut io_streams_t,
args: &mut [&wstr],
) -> Option<c_int> {
let cmd = args[0];
let (opts, optind) = match parse_options(args, parser, streams) {
Ok((opts, optind)) => (opts, optind),
Err(err @ Some(_)) if err != STATUS_CMD_OK => return err,
Err(err) => panic!("Illogical exit code from parse_options(): {err:?}"),
};
if opts.print_help {
builtin_print_help(parser, streams, cmd);
return STATUS_CMD_OK;
}
let needle = args.get(optind);
if let Some(needle) = needle {
for (i, arg) in args[optind..].iter().enumerate().skip(1) {
if needle == arg {
if opts.print_index {
streams.out.append(wgettext_fmt!("%d\n", i));
}
return STATUS_CMD_OK;
}
}
} else {
streams
.err
.append(wgettext_fmt!("%ls: Key not specified\n", cmd));
}
return STATUS_CMD_ERROR;
}

View File

@@ -1,5 +1,6 @@
pub mod shared;
pub mod contains;
pub mod echo;
pub mod emit;
pub mod exit;

View File

@@ -40,6 +40,9 @@ impl Vec<wcharz_t> {}
/// A handy return value for successful builtins.
pub const STATUS_CMD_OK: Option<c_int> = Some(0);
/// The status code used for failure exit in a command (but not if the args were invalid).
pub const STATUS_CMD_ERROR: Option<c_int> = Some(1);
/// A handy return value for invalid args.
pub const STATUS_INVALID_ARGS: Option<c_int> = Some(2);
@@ -115,6 +118,7 @@ pub fn run_builtin(
builtin: RustBuiltin,
) -> Option<c_int> {
match builtin {
RustBuiltin::Contains => super::contains::contains(parser, streams, args),
RustBuiltin::Echo => super::echo::echo(parser, streams, args),
RustBuiltin::Emit => super::emit::emit(parser, streams, args),
RustBuiltin::Exit => super::exit::exit(parser, streams, args),

View File

@@ -39,7 +39,6 @@
#include "builtins/command.h"
#include "builtins/commandline.h"
#include "builtins/complete.h"
#include "builtins/contains.h"
#include "builtins/disown.h"
#include "builtins/eval.h"
#include "builtins/fg.h"
@@ -375,7 +374,7 @@ static constexpr builtin_data_t builtin_datas[] = {
{L"command", &builtin_command, N_(L"Run a command specifically")},
{L"commandline", &builtin_commandline, N_(L"Set or get the commandline")},
{L"complete", &builtin_complete, N_(L"Edit command specific completions")},
{L"contains", &builtin_contains, N_(L"Search for a specified string in a list")},
{L"contains", &implemented_in_rust, N_(L"Search for a specified string in a list")},
{L"continue", &builtin_break_continue, N_(L"Skip over remaining innermost loop")},
{L"count", &builtin_count, N_(L"Count the number of arguments")},
{L"disown", &builtin_disown, N_(L"Remove job from job list")},
@@ -524,6 +523,9 @@ const wchar_t *builtin_get_desc(const wcstring &name) {
}
static maybe_t<RustBuiltin> try_get_rust_builtin(const wcstring &cmd) {
if (cmd == L"contains") {
return RustBuiltin::Contains;
}
if (cmd == L"echo") {
return RustBuiltin::Echo;
}

View File

@@ -109,6 +109,7 @@ int parse_help_only_cmd_opts(help_only_cmd_opts_t &opts, int *optind, int argc,
/// An enum of the builtins implemented in Rust.
enum RustBuiltin : int32_t {
Contains,
Echo,
Emit,
Exit,

View File

@@ -1,86 +0,0 @@
// Implementation of the contains builtin.
#include "config.h" // IWYU pragma: keep
#include "contains.h"
#include <cwchar>
#include "../builtin.h"
#include "../common.h"
#include "../fallback.h" // IWYU pragma: keep
#include "../io.h"
#include "../maybe.h"
#include "../wgetopt.h"
#include "../wutil.h" // IWYU pragma: keep
struct contains_cmd_opts_t {
bool print_help = false;
bool print_index = false;
};
static const wchar_t *const short_options = L"+:hi";
static const struct woption long_options[] = {
{L"help", no_argument, 'h'}, {L"index", no_argument, 'i'}, {}};
static int parse_cmd_opts(contains_cmd_opts_t &opts, int *optind, int argc, const wchar_t **argv,
parser_t &parser, io_streams_t &streams) {
const wchar_t *cmd = argv[0];
int opt;
wgetopter_t w;
while ((opt = w.wgetopt_long(argc, argv, short_options, long_options, nullptr)) != -1) {
switch (opt) {
case 'h': {
opts.print_help = true;
break;
}
case 'i': {
opts.print_index = true;
break;
}
case ':': {
builtin_missing_argument(parser, streams, cmd, argv[w.woptind - 1]);
return STATUS_INVALID_ARGS;
}
case '?': {
builtin_unknown_option(parser, streams, cmd, argv[w.woptind - 1]);
return STATUS_INVALID_ARGS;
}
default: {
DIE("unexpected retval from wgetopt_long");
}
}
}
*optind = w.woptind;
return STATUS_CMD_OK;
}
/// Implementation of the builtin contains command, used to check if a specified string is part of
/// a list.
maybe_t<int> builtin_contains(parser_t &parser, io_streams_t &streams, const wchar_t **argv) {
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
contains_cmd_opts_t opts;
int optind;
int retval = parse_cmd_opts(opts, &optind, argc, argv, parser, streams);
if (retval != STATUS_CMD_OK) return retval;
if (opts.print_help) {
builtin_print_help(parser, streams, cmd);
return STATUS_CMD_OK;
}
const wchar_t *needle = argv[optind];
if (!needle) {
streams.err.append_format(_(L"%ls: Key not specified\n"), cmd);
} else {
for (int i = optind + 1; i < argc; i++) {
if (!std::wcscmp(needle, argv[i])) {
if (opts.print_index) streams.out.append_format(L"%d\n", i - optind);
return STATUS_CMD_OK;
}
}
}
return STATUS_CMD_ERROR;
}

View File

@@ -1,11 +0,0 @@
// Prototypes for executing builtin_contains function.
#ifndef FISH_BUILTIN_CONTAINS_H
#define FISH_BUILTIN_CONTAINS_H
#include "../maybe.h"
class parser_t;
struct io_streams_t;
maybe_t<int> builtin_contains(parser_t &parser, io_streams_t &streams, const wchar_t **argv);
#endif