Move remaining builtin implementations to dedicated files

This makes them a bit easier to find I guess.
This commit is contained in:
Johannes Altmanninger
2025-10-11 09:32:05 +02:00
parent b5feb79a7c
commit fef358fc74
8 changed files with 93 additions and 76 deletions

5
src/builtins/break.rs Normal file
View File

@@ -0,0 +1,5 @@
use super::prelude::*;
pub fn r#break(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> BuiltinResult {
builtin_break_continue(parser, streams, argv)
}

View File

@@ -0,0 +1,44 @@
use super::prelude::*;
use crate::parser::{Block, BlockType};
use crate::reader::reader_read;
use libc::STDIN_FILENO;
/// Implementation of the builtin breakpoint command, used to launch the interactive debugger.
pub fn breakpoint(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> BuiltinResult {
let cmd = argv[0];
if argv.len() != 1 {
streams.err.append(wgettext_fmt!(
BUILTIN_ERR_ARG_COUNT1,
cmd,
0,
argv.len() - 1
));
return Err(STATUS_INVALID_ARGS);
}
// If we're not interactive then we can't enter the debugger. So treat this command as a no-op.
if !parser.is_interactive() {
return Err(STATUS_CMD_ERROR);
}
// Ensure we don't allow creating a breakpoint at an interactive prompt. There may be a simpler
// or clearer way to do this but this works.
{
if parser
.block_at_index(1)
.map_or(true, |b| b.typ() == BlockType::breakpoint)
{
streams.err.append(wgettext_fmt!(
"%s: Command not valid at an interactive prompt\n",
cmd,
));
return Err(STATUS_ILLEGAL_CMD);
}
}
let bpb = parser.push_block(Block::breakpoint_block());
let io_chain = &streams.io_chain;
reader_read(parser, STDIN_FILENO, io_chain)?;
parser.pop_block(bpb);
BuiltinResult::from_dynamic(parser.get_last_status())
}

5
src/builtins/continue.rs Normal file
View File

@@ -0,0 +1,5 @@
use super::prelude::*;
pub fn r#continue(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> BuiltinResult {
builtin_break_continue(parser, streams, argv)
}

5
src/builtins/false.rs Normal file
View File

@@ -0,0 +1,5 @@
use super::prelude::*;
pub fn r#false(_parser: &Parser, _streams: &mut IoStreams, _argv: &mut [&wstr]) -> BuiltinResult {
Err(STATUS_CMD_ERROR)
}

14
src/builtins/gettext.rs Normal file
View File

@@ -0,0 +1,14 @@
use super::prelude::*;
/// Used for the fish `_` builtin for requesting translations.
/// For scripts in `share/`, the corresponding strings are extracted from the scripts using
/// `build_tools/fish_xgettext.fish`.
/// Strings not present in our repo would require a custom MO file for translation to be possible.
pub fn gettext(_parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> BuiltinResult {
for arg in &argv[1..] {
streams.out.append(
crate::wutil::LocalizableString::from_external_source((*arg).to_owned()).localize(),
);
}
Ok(SUCCESS)
}

View File

@@ -5,23 +5,28 @@
pub mod bg;
pub mod bind;
pub mod block;
pub mod r#break;
pub mod breakpoint;
pub mod builtin;
pub mod cd;
pub mod command;
pub mod commandline;
pub mod complete;
pub mod contains;
pub mod r#continue;
pub mod count;
pub mod disown;
pub mod echo;
pub mod emit;
pub mod eval;
pub mod exit;
pub mod r#false;
pub mod fg;
pub mod fish_indent;
pub mod fish_key_reader;
pub mod function;
pub mod functions;
pub mod r#gettext;
pub mod history;
pub mod jobs;
pub mod math;
@@ -38,6 +43,7 @@
pub mod status;
pub mod string;
pub mod test;
pub mod r#true;
pub mod r#type;
pub mod ulimit;
pub mod wait;

View File

@@ -4,12 +4,10 @@
use crate::io::OutputStream;
use crate::parse_constants::UNKNOWN_BUILTIN_ERR_MSG;
use crate::parse_util::parse_util_argument_is_help;
use crate::parser::{Block, BlockType, LoopStatus};
use crate::parser::{BlockType, LoopStatus};
use crate::proc::{no_exec, ProcStatus};
use crate::reader::reader_read;
use crate::wchar::L;
use errno::errno;
use libc::STDIN_FILENO;
use std::fs::File;
use std::io::{BufRead, BufReader, Read};
@@ -193,7 +191,7 @@ struct BuiltinData {
},
BuiltinData {
name: L!(":"),
func: builtin_true,
func: r#true::r#true,
},
BuiltinData {
name: L!("["), // ]
@@ -201,7 +199,7 @@ struct BuiltinData {
},
BuiltinData {
name: L!("_"),
func: builtin_gettext,
func: gettext::gettext,
},
BuiltinData {
name: L!("abbr"),
@@ -233,11 +231,11 @@ struct BuiltinData {
},
BuiltinData {
name: L!("break"),
func: builtin_break_continue,
func: r#break::r#break,
},
BuiltinData {
name: L!("breakpoint"),
func: builtin_breakpoint,
func: breakpoint::breakpoint,
},
BuiltinData {
name: L!("builtin"),
@@ -269,7 +267,7 @@ struct BuiltinData {
},
BuiltinData {
name: L!("continue"),
func: builtin_break_continue,
func: r#continue::r#continue,
},
BuiltinData {
name: L!("count"),
@@ -309,7 +307,7 @@ struct BuiltinData {
},
BuiltinData {
name: L!("false"),
func: builtin_false,
func: r#false::r#false,
},
BuiltinData {
name: L!("fg"),
@@ -421,7 +419,7 @@ struct BuiltinData {
},
BuiltinData {
name: L!("true"),
func: builtin_true,
func: r#true::r#true,
},
BuiltinData {
name: L!("type"),
@@ -954,7 +952,7 @@ fn builtin_generic(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr])
/// This function handles both the 'continue' and the 'break' builtins that are used for loop
/// control.
fn builtin_break_continue(
pub fn builtin_break_continue(
parser: &Parser,
streams: &mut IoStreams,
argv: &mut [&wstr],
@@ -1003,68 +1001,3 @@ fn builtin_break_continue(
};
Ok(SUCCESS)
}
/// Implementation of the builtin breakpoint command, used to launch the interactive debugger.
fn builtin_breakpoint(
parser: &Parser,
streams: &mut IoStreams,
argv: &mut [&wstr],
) -> BuiltinResult {
let cmd = argv[0];
if argv.len() != 1 {
streams.err.append(wgettext_fmt!(
BUILTIN_ERR_ARG_COUNT1,
cmd,
0,
argv.len() - 1
));
return Err(STATUS_INVALID_ARGS);
}
// If we're not interactive then we can't enter the debugger. So treat this command as a no-op.
if !parser.is_interactive() {
return Err(STATUS_CMD_ERROR);
}
// Ensure we don't allow creating a breakpoint at an interactive prompt. There may be a simpler
// or clearer way to do this but this works.
{
if parser
.block_at_index(1)
.map_or(true, |b| b.typ() == BlockType::breakpoint)
{
streams.err.append(wgettext_fmt!(
"%s: Command not valid at an interactive prompt\n",
cmd,
));
return Err(STATUS_ILLEGAL_CMD);
}
}
let bpb = parser.push_block(Block::breakpoint_block());
let io_chain = &streams.io_chain;
reader_read(parser, STDIN_FILENO, io_chain)?;
parser.pop_block(bpb);
BuiltinResult::from_dynamic(parser.get_last_status())
}
fn builtin_true(_parser: &Parser, _streams: &mut IoStreams, _argv: &mut [&wstr]) -> BuiltinResult {
Ok(SUCCESS)
}
fn builtin_false(_parser: &Parser, _streams: &mut IoStreams, _argv: &mut [&wstr]) -> BuiltinResult {
Err(STATUS_CMD_ERROR)
}
/// Used for the fish `_` builtin for requesting translations.
/// For scripts in `share/`, the corresponding strings are extracted from the scripts using
/// `build_tools/fish_xgettext.fish`.
/// Strings not present in our repo would require a custom MO file for translation to be possible.
fn builtin_gettext(_parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> BuiltinResult {
for arg in &argv[1..] {
streams.out.append(
crate::wutil::LocalizableString::from_external_source((*arg).to_owned()).localize(),
);
}
Ok(SUCCESS)
}

5
src/builtins/true.rs Normal file
View File

@@ -0,0 +1,5 @@
use super::prelude::*;
pub fn r#true(_parser: &Parser, _streams: &mut IoStreams, _argv: &mut [&wstr]) -> BuiltinResult {
Ok(SUCCESS)
}