Merge branch 'main' into ls-version-cmp

This commit is contained in:
Sylvestre Ledru
2023-07-09 09:24:39 +02:00
committed by GitHub
68 changed files with 1336 additions and 660 deletions
+7 -9
View File
@@ -31,12 +31,12 @@ jobs:
id: vars
shell: bash
run: |
## VARs setup
outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; }
# surface MSRV from CICD workflow
RUST_MIN_SRV=$(grep -P "^\s+RUST_MIN_SRV:" .github/workflows/CICD.yml | grep -Po "(?<=\x22)\d+[.]\d+(?:[.]\d+)?(?=\x22)" )
outputs RUST_MIN_SRV
- uses: dtolnay/rust-toolchain@${{ steps.vars.outputs.RUST_MIN_SRV }}
echo "RUST_MIN_SRV=${RUST_MIN_SRV}" >> $GITHUB_OUTPUT
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ steps.vars.outputs.RUST_MIN_SRV }}
- uses: Swatinem/rust-cache@v2
- name: Ensure updated 'Cargo.lock'
shell: bash
@@ -67,7 +67,7 @@ jobs:
- name: Commit any changes (to '${{ env.BRANCH_TARGET }}')
uses: EndBug/add-and-commit@v9
with:
branch: ${{ env.BRANCH_TARGET }}
new_branch: ${{ env.BRANCH_TARGET }}
default_author: github_actions
message: "maint ~ refresh 'Cargo.lock'"
add: Cargo.lock
@@ -90,13 +90,11 @@ jobs:
id: vars
shell: bash
run: |
## VARs setup
outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; }
# target-specific options
# * CARGO_FEATURES_OPTION
CARGO_FEATURES_OPTION='' ;
if [ -n "${{ matrix.job.features }}" ]; then CARGO_FEATURES_OPTION='--features "${{ matrix.job.features }}"' ; fi
outputs CARGO_FEATURES_OPTION
echo "CARGO_FEATURES_OPTION=${CARGO_FEATURES_OPTION}" >> $GITHUB_OUTPUT
- uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
@@ -114,7 +112,7 @@ jobs:
- name: Commit any changes (to '${{ env.BRANCH_TARGET }}')
uses: EndBug/add-and-commit@v9
with:
branch: ${{ env.BRANCH_TARGET }}
new_branch: ${{ env.BRANCH_TARGET }}
default_author: github_actions
message: "maint ~ rustfmt (`cargo fmt`)"
env:
+1 -1
View File
@@ -205,7 +205,7 @@ jobs:
path_UUTILS='${{ steps.vars.outputs.path_UUTILS }}'
# https://github.com/uutils/coreutils/issues/4294
# https://github.com/uutils/coreutils/issues/4295
IGNORE_INTERMITTENT='${path_UUTILS}/.github/workflows/ignore-intermittent.txt'
IGNORE_INTERMITTENT="${path_UUTILS}/.github/workflows/ignore-intermittent.txt"
mkdir -p ${{ steps.vars.outputs.path_reference }}
+2 -2
View File
@@ -35,7 +35,7 @@ jobs:
- name: Run sccache-cache
uses: mozilla-actions/sccache-action@v0.0.3
- name: Prepare, build and test
uses: vmactions/freebsd-vm@v0.3.0
uses: vmactions/freebsd-vm@v0.3.1
with:
usesh: true
# We need jq to run show-utils.sh and bash to use inline shell string replacement
@@ -125,7 +125,7 @@ jobs:
- name: Run sccache-cache
uses: mozilla-actions/sccache-action@v0.0.3
- name: Prepare, build and test
uses: vmactions/freebsd-vm@v0.3.0
uses: vmactions/freebsd-vm@v0.3.1
with:
usesh: true
# sync: sshfs
+1
View File
@@ -5,6 +5,7 @@ target/
/busybox/
/.vscode/
/.vs/
/public/
*~
.*.swp
.*.swo
+1
View File
@@ -19,6 +19,7 @@
// files to ignore (globs supported)
"ignorePaths": [
"Cargo.lock",
"oranda.json",
"target/**",
"tests/**/fixtures/**",
"src/uu/dd/test-resources/**",
Generated
+153 -217
View File
File diff suppressed because it is too large Load Diff
+16 -15
View File
@@ -1,7 +1,7 @@
# coreutils (uutils)
# * see the repository LICENSE, README, and CONTRIBUTING files for more information
# spell-checker:ignore (libs) libselinux gethostid procfs bigdecimal kqueue fundu mangen datetime uuhelp
# spell-checker:ignore (libs) bigdecimal datetime fundu gethostid kqueue libselinux mangen memmap procfs uuhelp
[package]
name = "coreutils"
@@ -257,9 +257,9 @@ feat_os_windows_legacy = [
test = ["uu_test"]
[workspace.dependencies]
bigdecimal = "0.3"
bigdecimal = "0.4"
binary-heap-plus = "0.5.0"
bstr = "1.5"
bstr = "1.6"
bytecount = "0.6.3"
byteorder = "1.4.3"
chrono = { version = "^0.4.26", default-features = false, features = [
@@ -280,18 +280,19 @@ filetime = "0.2"
fnv = "1.0.7"
fs_extra = "1.3.0"
fts-sys = "0.2"
fundu = "1.0.0"
fundu = "1.1.0"
gcd = "2.3"
glob = "0.3.1"
half = "2.2"
indicatif = "0.17"
is-terminal = "0.4.7"
itertools = "0.10.5"
libc = "0.2.146"
itertools = "0.11.0"
libc = "0.2.147"
lscolors = { version = "0.14.0", default-features = false, features = [
"nu-ansi-term",
] }
memchr = "2"
memmap2 = "0.7"
nix = { version = "0.26", default-features = false }
nom = "7.1.3"
notify = { version = "=6.0.1", features = ["macos_kqueue"] }
@@ -300,23 +301,23 @@ num-traits = "0.2.15"
number_prefix = "0.4"
once_cell = "1.18.0"
onig = { version = "~6.4", default-features = false }
ouroboros = "0.15.6"
parse_datetime = "0.4.0"
phf = "0.11.1"
phf_codegen = "0.11.1"
phf = "0.11.2"
phf_codegen = "0.11.2"
platform-info = "2.0.1"
quick-error = "2.0.1"
rand = { version = "0.8", features = ["small_rng"] }
rand_core = "0.6"
rayon = "1.7"
redox_syscall = "0.3"
regex = "1.8.4"
rstest = "0.17.0"
rust-ini = "0.18.0"
regex = "1.9.1"
rstest = "0.18.1"
rust-ini = "0.19.0"
same-file = "1.0.6"
self_cell = "1.0.1"
selinux = "0.4"
signal-hook = "0.3.15"
smallvec = { version = "1.10", features = ["union"] }
smallvec = { version = "1.11", features = ["union"] }
tempfile = "3.6.0"
term_grid = "0.1.5"
terminal_size = "0.2.6"
@@ -491,11 +492,11 @@ uucore = { workspace = true, features = ["entries", "process", "signals"] }
walkdir = { workspace = true }
is-terminal = { workspace = true }
hex-literal = "0.4.1"
rstest = "0.17.0"
rstest = { workspace = true }
[target.'cfg(any(target_os = "linux", target_os = "android"))'.dev-dependencies]
procfs = { version = "0.15", default-features = false }
rlimit = "0.9.1"
rlimit = "0.10.0"
[target.'cfg(unix)'.dev-dependencies]
nix = { workspace = true, features = ["process", "signal", "user"] }
+12 -1
View File
@@ -1,6 +1,7 @@
<!-- markdownlint-disable MD033 MD041 MD002 -->
<!-- markdownlint-disable commands-show-output no-duplicate-heading -->
<!-- spell-checker:ignore markdownlint ; (options) DESTDIR UTILNAME manpages reimplementation -->
<!-- spell-checker:ignore markdownlint ; (options) DESTDIR UTILNAME manpages reimplementation oranda -->
<div class="oranda-hide">
<div align="center">
![uutils logo](docs/src/logo.svg)
@@ -19,11 +20,14 @@
---
</div>
uutils coreutils is a cross-platform reimplementation of the GNU coreutils in
[Rust](http://www.rust-lang.org). While all programs have been implemented, some
options might be missing or different behavior might be experienced.
<div class="oranda-hide">
To install it:
```shell
@@ -31,6 +35,8 @@ cargo install coreutils
~/.cargo/bin/coreutils
```
</div>
<!-- markdownlint-disable-next-line MD026 -->
## Goals
@@ -42,6 +48,8 @@ uutils aims to work on as many platforms as possible, to be able to use the same
utils on Linux, Mac, Windows and other platforms. This ensures, for example,
that scripts can be easily transferred between platforms.
<div class="oranda-hide">
## Documentation
uutils has both user and developer documentation available:
@@ -52,6 +60,7 @@ uutils has both user and developer documentation available:
Both can also be generated locally, the instructions for that can be found in
the [coreutils docs](https://github.com/uutils/uutils.github.io) repository.
<!-- ANCHOR: build (this mark is needed for mdbook) -->
## Requirements
@@ -301,6 +310,8 @@ See <https://github.com/uutils/coreutils/issues/3336> for the main meta bugs
![Evolution over time](https://github.com/uutils/coreutils-tracking/blob/main/gnu-results.png?raw=true)
</div> <!-- close oranda-hide div -->
## Contributing
To contribute to uutils, please see [CONTRIBUTING](CONTRIBUTING.md).
+4 -2
View File
@@ -59,8 +59,6 @@ highlight = "all"
# introduces it.
# spell-checker: disable
skip = [
# is-terminal
{ name = "hermit-abi", version = "0.3.1" },
# procfs
{ name = "rustix", version = "0.36.14" },
# rustix
@@ -87,6 +85,10 @@ skip = [
{ name = "redox_syscall", version = "0.3.5" },
# cpp_macros
{ name = "aho-corasick", version = "0.7.19" },
# ordered-multimap (via rust-ini)
{ name = "hashbrown", version = "0.13.2" },
# various crates
{ name = "syn", version = "1.0.109" },
]
# spell-checker: enable
+16 -3
View File
@@ -61,7 +61,20 @@ feature is adopted from [FreeBSD](https://www.freebsd.org/cgi/man.cgi?cut).
## `fmt`
`fmt` has additional flags for prefixes: `-P/--skip-prefix`, `-x/--exact-prefix`, and
`-X/--exact-skip-prefix`. With `-m/--preserve-headers`, an attempt is made to detect and preserve
mail headers in the input. `-q/--quick` breaks lines more quickly. And `-T/--tab-width` defines the
`fmt` has additional flags for prefixes: `-P`/`--skip-prefix`, `-x`/`--exact-prefix`, and
`-X`/`--exact-skip-prefix`. With `-m`/`--preserve-headers`, an attempt is made to detect and preserve
mail headers in the input. `-q`/`--quick` breaks lines more quickly. And `-T`/`--tab-width` defines the
number of spaces representing a tab when determining the line length.
## `seq`
`seq` provides `-t`/`--terminator` to set the terminator character.
## `ls`
GNU `ls` provides two ways to use a long listing format: `-l` and `--format=long`. We support a
third way: `--long`.
## `du`
`du` allows `birth` and `creation` as values for the `--time` argument to show the creation time.
+4
View File
@@ -0,0 +1,4 @@
.logo {
display: block;
height: 170px;
}
+13
View File
@@ -0,0 +1,13 @@
{
"project": {
"name": "uutils coreutils"
},
"components": {
"changelog": true
},
"styles": {
"theme": "light",
"logo": "docs/src/logo.svg",
"additional_css": ["docs/src/oranda.css"]
}
}
+1
View File
@@ -383,6 +383,7 @@ pub fn uu_app() -> Command {
backup_control::BACKUP_CONTROL_LONG_HELP
))
.infer_long_args(true)
.args_override_self(true)
.arg(
Arg::new(options::TARGET_DIRECTORY)
.short('t')
+10 -9
View File
@@ -26,14 +26,13 @@ use uucore::{format_usage, help_about, help_usage, show};
#[cfg(windows)]
use windows_sys::Win32::{Foundation::SYSTEMTIME, System::SystemInformation::SetSystemTime};
use uucore::shortcut_value_parser::ShortcutValueParser;
// Options
const DATE: &str = "date";
const HOURS: &str = "hours";
const MINUTES: &str = "minutes";
const SECONDS: &str = "seconds";
const HOUR: &str = "hour";
const MINUTE: &str = "minute";
const SECOND: &str = "second";
const NS: &str = "ns";
const ABOUT: &str = help_about!("date.md");
@@ -110,9 +109,9 @@ enum Iso8601Format {
impl<'a> From<&'a str> for Iso8601Format {
fn from(s: &str) -> Self {
match s {
HOURS | HOUR => Self::Hours,
MINUTES | MINUTE => Self::Minutes,
SECONDS | SECOND => Self::Seconds,
HOURS => Self::Hours,
MINUTES => Self::Minutes,
SECONDS => Self::Seconds,
NS => Self::Ns,
DATE => Self::Date,
// Note: This is caught by clap via `possible_values`
@@ -131,7 +130,7 @@ impl<'a> From<&'a str> for Rfc3339Format {
fn from(s: &str) -> Self {
match s {
DATE => Self::Date,
SECONDS | SECOND => Self::Seconds,
SECONDS => Self::Seconds,
NS => Self::Ns,
// Should be caught by clap
_ => panic!("Invalid format: {s}"),
@@ -317,7 +316,9 @@ pub fn uu_app() -> Command {
.short('I')
.long(OPT_ISO_8601)
.value_name("FMT")
.value_parser([DATE, HOUR, HOURS, MINUTE, MINUTES, SECOND, SECONDS, NS])
.value_parser(ShortcutValueParser::new([
DATE, HOURS, MINUTES, SECONDS, NS,
]))
.num_args(0..=1)
.default_missing_value(OPT_DATE)
.help(ISO_8601_HELP_STRING),
@@ -333,7 +334,7 @@ pub fn uu_app() -> Command {
Arg::new(OPT_RFC_3339)
.long(OPT_RFC_3339)
.value_name("FMT")
.value_parser([DATE, SECOND, SECONDS, NS])
.value_parser(ShortcutValueParser::new([DATE, SECONDS, NS]))
.help(RFC_3339_HELP_STRING),
)
.arg(
+2 -2
View File
@@ -13,7 +13,7 @@ Copy, and optionally convert, a file system resource
### Operands
- `Bs=BYTES` : read and write up to BYTES bytes at a time (default: 512);
- `bs=BYTES` : read and write up to BYTES bytes at a time (default: 512);
overwrites `ibs` and `obs`.
- `cbs=BYTES` : the 'conversion block size' in bytes. Applies to the
`conv=block`, and `conv=unblock` operations.
@@ -114,7 +114,7 @@ Copy, and optionally convert, a file system resource
### General Flags
- `Direct` : use direct I/O for data.
- `direct` : use direct I/O for data.
- `directory` : fail unless the given input (if used as an iflag) or
output (if used as an oflag) is a directory.
- `dsync` : use synchronized I/O for data.
+54 -8
View File
@@ -36,9 +36,12 @@ use std::os::unix::{
io::{AsRawFd, FromRawFd},
};
use std::path::Path;
use std::sync::mpsc;
use std::sync::{
atomic::{AtomicBool, Ordering::Relaxed},
mpsc, Arc,
};
use std::thread;
use std::time;
use std::time::{Duration, Instant};
use clap::{crate_version, Arg, Command};
use gcd::Gcd;
@@ -75,6 +78,45 @@ struct Settings {
status: Option<StatusLevel>,
}
/// A timer which triggers on a given interval
///
/// After being constructed with [`Alarm::with_interval`], [`Alarm::is_triggered`]
/// will return true once per the given [`Duration`].
///
/// Can be cloned, but the trigger status is shared across all instances so only
/// the first caller each interval will yield true.
///
/// When all instances are dropped the background thread will exit on the next interval.
#[derive(Debug, Clone)]
pub struct Alarm {
interval: Duration,
trigger: Arc<AtomicBool>,
}
impl Alarm {
pub fn with_interval(interval: Duration) -> Self {
let trigger = Arc::new(AtomicBool::default());
let weak_trigger = Arc::downgrade(&trigger);
thread::spawn(move || {
while let Some(trigger) = weak_trigger.upgrade() {
thread::sleep(interval);
trigger.store(true, Relaxed);
}
});
Self { interval, trigger }
}
pub fn is_triggered(&self) -> bool {
self.trigger.swap(false, Relaxed)
}
pub fn get_interval(&self) -> Duration {
self.interval
}
}
/// A number in blocks or bytes
///
/// Some values (seek, skip, iseek, oseek) can have values either in blocks or in bytes.
@@ -760,7 +802,7 @@ fn dd_copy(mut i: Input, mut o: Output) -> std::io::Result<()> {
// of its report includes the throughput in bytes per second,
// which requires knowing how long the process has been
// running.
let start = time::Instant::now();
let start = Instant::now();
// A good buffer size for reading.
//
@@ -780,7 +822,6 @@ fn dd_copy(mut i: Input, mut o: Output) -> std::io::Result<()> {
// information.
let (prog_tx, rx) = mpsc::channel();
let output_thread = thread::spawn(gen_prog_updater(rx, i.settings.status));
let mut progress_as_secs = 0;
// Optimization: if no blocks are to be written, then don't
// bother allocating any buffers.
@@ -813,6 +854,12 @@ fn dd_copy(mut i: Input, mut o: Output) -> std::io::Result<()> {
// This is the max size needed.
let mut buf = vec![BUF_INIT_BYTE; bsize];
// Spawn a timer thread to provide a scheduled signal indicating when we
// should send an update of our progress to the reporting thread.
//
// This avoids the need to query the OS monotonic clock for every block.
let alarm = Alarm::with_interval(Duration::from_secs(1));
// Index in the input file where we are reading bytes and in
// the output file where we are writing bytes.
//
@@ -871,9 +918,8 @@ fn dd_copy(mut i: Input, mut o: Output) -> std::io::Result<()> {
// error.
rstat += rstat_update;
wstat += wstat_update;
let prog_update = ProgUpdate::new(rstat, wstat, start.elapsed(), false);
if prog_update.duration.as_secs() >= progress_as_secs {
progress_as_secs = prog_update.duration.as_secs() + 1;
if alarm.is_triggered() {
let prog_update = ProgUpdate::new(rstat, wstat, start.elapsed(), false);
prog_tx.send(prog_update).unwrap_or(());
}
}
@@ -885,7 +931,7 @@ fn finalize<T>(
output: &mut Output,
rstat: ReadStat,
wstat: WriteStat,
start: time::Instant,
start: Instant,
prog_tx: &mpsc::Sender<ProgUpdate>,
output_thread: thread::JoinHandle<T>,
) -> std::io::Result<()> {
+2 -2
View File
@@ -145,7 +145,7 @@ impl Stat {
return Ok(Self {
path: path.to_path_buf(),
is_dir: metadata.is_dir(),
size: metadata.len(),
size: if path.is_dir() { 0 } else { metadata.len() },
blocks: metadata.blocks(),
inodes: 1,
inode: Some(file_info),
@@ -162,7 +162,7 @@ impl Stat {
Ok(Self {
path: path.to_path_buf(),
is_dir: metadata.is_dir(),
size: metadata.len(),
size: if path.is_dir() { 0 } else { metadata.len() },
blocks: size_on_disk / 1024 * 2,
inode: file_info,
inodes: 1,
+1 -1
View File
@@ -306,7 +306,7 @@ pub fn uumain(mut args: impl uucore::Args) -> UResult<()> {
// if there is no program name for some reason, default to "hashsum"
let program = args.next().unwrap_or_else(|| OsString::from(NAME));
let binary_name = Path::new(&program)
.file_name()
.file_stem()
.unwrap_or_else(|| OsStr::new(NAME))
.to_string_lossy();
+14
View File
@@ -3010,6 +3010,20 @@ fn display_inode(metadata: &Metadata) -> String {
#[allow(unused_variables)]
fn get_security_context(config: &Config, p_buf: &Path, must_dereference: bool) -> String {
let substitute_string = "?".to_string();
// If we must dereference, ensure that the symlink is actually valid even if the system
// does not support SELinux.
// Conforms to the GNU coreutils where a dangling symlink results in exit code 1.
if must_dereference {
match get_metadata(p_buf, must_dereference) {
Err(err) => {
// The Path couldn't be dereferenced, so return early and set exit code 1
// to indicate a minor error
show!(LsError::IOErrorContext(err, p_buf.to_path_buf(), false));
return substitute_string;
}
Ok(md) => (),
}
}
if config.selinux_supported {
#[cfg(feature = "selinux")]
{
+54 -28
View File
@@ -50,10 +50,11 @@ pub mod options {
pub const FILES: &str = "files";
}
const MULTI_FILE_TOP_PROMPT: &str = "::::::::::::::\n{}\n::::::::::::::\n";
const MULTI_FILE_TOP_PROMPT: &str = "\r::::::::::::::\n\r{}\n\r::::::::::::::\n";
struct Options {
clean_print: bool,
from_line: usize,
lines: Option<u16>,
print_over: bool,
silent: bool,
@@ -72,8 +73,13 @@ impl Options {
(None, Some(number)) if number > 0 => Some(number + 1),
(_, _) => None,
};
let from_line = match matches.get_one::<usize>(options::FROM_LINE).copied() {
Some(number) if number > 1 => number - 1,
_ => 0,
};
Self {
clean_print: matches.get_flag(options::CLEAN_PRINT),
from_line,
lines,
print_over: matches.get_flag(options::PRINT_OVER),
silent: matches.get_flag(options::SILENT),
@@ -90,7 +96,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
Err(e) => return Err(e.into()),
};
let options = Options::from(&matches);
let mut options = Options::from(&matches);
let mut buff = String::new();
@@ -115,9 +121,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
format!("cannot open {}: No such file or directory", file.quote()),
));
}
if length > 1 {
buff.push_str(&MULTI_FILE_TOP_PROMPT.replace("{}", file.to_str().unwrap()));
}
let opened_file = match File::open(file) {
Err(why) => {
terminal::disable_raw_mode().unwrap();
@@ -130,14 +133,21 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
};
let mut reader = BufReader::new(opened_file);
reader.read_to_string(&mut buff).unwrap();
more(&buff, &mut stdout, next_file.copied(), &options)?;
more(
&buff,
&mut stdout,
length > 1,
file.to_str(),
next_file.copied(),
&mut options,
)?;
buff.clear();
}
reset_term(&mut stdout);
} else if !std::io::stdin().is_terminal() {
stdin().read_to_string(&mut buff).unwrap();
let mut stdout = setup_term();
more(&buff, &mut stdout, None, &options)?;
more(&buff, &mut stdout, false, None, None, &mut options)?;
reset_term(&mut stdout);
} else {
return Err(UUsageError::new(1, "bad usage"));
@@ -179,6 +189,22 @@ pub fn uu_app() -> Command {
.help("Squeeze multiple blank lines into one")
.action(ArgAction::SetTrue),
)
.arg(
Arg::new(options::PLAIN)
.short('u')
.long(options::PLAIN)
.action(ArgAction::SetTrue)
.hide(true),
)
.arg(
Arg::new(options::FROM_LINE)
.short('F')
.long(options::FROM_LINE)
.num_args(1)
.value_name("number")
.value_parser(value_parser!(usize))
.help("Display file beginning from line number"),
)
.arg(
Arg::new(options::LINES)
.short('n')
@@ -191,7 +217,6 @@ pub fn uu_app() -> Command {
.arg(
Arg::new(options::NUMBER)
.long(options::NUMBER)
.required(false)
.num_args(1)
.value_parser(value_parser!(u16).range(0..))
.help("Same as --lines"),
@@ -210,21 +235,6 @@ pub fn uu_app() -> Command {
.long(options::NO_PAUSE)
.help("Suppress pause after form feed"),
)
.arg(
Arg::new(options::PLAIN)
.short('u')
.long(options::PLAIN)
.help("Suppress underlining and bold"),
)
.arg(
Arg::new(options::FROM_LINE)
.short('F')
.allow_hyphen_values(true)
.required(false)
.takes_value(true)
.value_name("number")
.help("Display file beginning from line number"),
)
.arg(
Arg::new(options::PATTERN)
.short('P')
@@ -273,8 +283,10 @@ fn reset_term(_: &mut usize) {}
fn more(
buff: &str,
stdout: &mut Stdout,
multiple_file: bool,
file: Option<&str>,
next_file: Option<&str>,
options: &Options,
options: &mut Options,
) -> UResult<()> {
let (cols, mut rows) = terminal::size().unwrap();
if let Some(number) = options.lines {
@@ -284,8 +296,23 @@ fn more(
let lines = break_buff(buff, usize::from(cols));
let mut pager = Pager::new(rows, lines, next_file, options);
if multiple_file {
execute!(stdout, terminal::Clear(terminal::ClearType::CurrentLine)).unwrap();
stdout.write_all(
MULTI_FILE_TOP_PROMPT
.replace("{}", file.unwrap_or_default())
.as_bytes(),
)?;
pager.content_rows -= 3;
}
pager.draw(stdout, None);
if pager.should_close() {
if multiple_file {
options.from_line = 0;
pager.content_rows += 3;
}
if pager.should_close() && next_file.is_none() {
return Ok(());
}
@@ -406,7 +433,7 @@ impl<'a> Pager<'a> {
fn new(rows: u16, lines: Vec<String>, next_file: Option<&'a str>, options: &Options) -> Self {
let line_count = lines.len();
Self {
upper_mark: 0,
upper_mark: options.from_line,
content_rows: rows.saturating_sub(1),
lines,
next_file,
@@ -472,10 +499,10 @@ impl<'a> Pager<'a> {
}
fn draw(&mut self, stdout: &mut std::io::Stdout, wrong_key: Option<char>) {
self.draw_lines(stdout);
let lower_mark = self
.line_count
.min(self.upper_mark.saturating_add(self.content_rows.into()));
self.draw_lines(stdout);
self.draw_prompt(stdout, lower_mark, wrong_key);
stdout.flush().unwrap();
}
@@ -535,7 +562,6 @@ impl<'a> Pager<'a> {
};
let status = format!("--More--({status_inner})");
let banner = match (self.silent, wrong_key) {
(true, Some(key)) => format!(
"{status} [Unknown key: '{key}'. Press 'h' for instructions. (unimplemented)]"

Some files were not shown because too many files have changed in this diff Show More