Skip to content

Commit

Permalink
Format options are set in the string itself.
Browse files Browse the repository at this point in the history
`header` and `table` options are now part of the format string, instead of
fields of the builtin state.
  • Loading branch information
ayosec committed Aug 26, 2021
1 parent d973f87 commit 9903c4e
Show file tree
Hide file tree
Showing 10 changed files with 154 additions and 50 deletions.
18 changes: 18 additions & 0 deletions FORMAT.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,24 @@ The following resource specifiers are accepted in the format string:
|`%x`<br>`%(status)` | Exit status of command. |
|`%Z`<br>`%(page_size)` | Page size. |

## Options

Options are surrounded by brackets at the beginning of the format string. There
are two valid options:

* `header`

Print a header containing the field labels.

* `table`

Render the history list as a table. Columns are separated by the tab
character.

Example:

[header,table]%n\t%e\t%C

## Date/Time Format

The syntax for the `%(time)` specifier is from the [chrono library].
Expand Down
18 changes: 18 additions & 0 deletions generator/src/doc.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,24 @@ The following resource specifiers are accepted in the format string:
|------------|-------------|
%SPECS%

## Options

Options are surrounded by brackets at the beginning of the format string. There
are two valid options:

* `header`

Print a header containing the field labels.

* `table`

Render the history list as a table. Columns are separated by the tab
character.

Example:

[header,table]%n\t%e\t%C

## Date/Time Format

The syntax for the `%(time)` specifier is from the [chrono library].
Expand Down
14 changes: 14 additions & 0 deletions generator/src/doc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,20 @@ SPECIFIERS
%SPECS%


OPTIONS

Options are surrounded by brackets at the beginning of the format string.
There are two valid options:

header Print a header containing the field labels.
table Render the history list as a table. Columns are separated by
the tab character.

Example:

[header,table]%n\t%e\t%C


DATE/TIME FORMAT

The syntax for the %(time) specifier is from the [1]chrono library.
Expand Down
2 changes: 2 additions & 0 deletions src/format/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ use std::mem;
use std::os::unix::ffi::OsStrExt;

mod escapes;
mod options;
mod tables;

#[cfg(test)]
mod tests;

pub use escapes::EscapeArgument;
pub use options::FormatOptions;
pub use tables::TableWriter;

pub const HELP: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/doc.txt"));
Expand Down
81 changes: 81 additions & 0 deletions src/format/options.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
//! Extract options from a format string.

#[cfg_attr(test, derive(PartialEq, Debug))]
pub struct FormatOptions<'a> {
pub header: bool,
pub table: bool,
pub format: &'a str,
}

impl FormatOptions<'_> {
pub fn parse(mut format: &str) -> FormatOptions {
let mut header = false;
let mut table = false;

if format.starts_with('[') {
if let Some(end) = format.find(']') {
let (options, fmt) = format[1..].split_at(end - 1);
format = &fmt[1..];

for option in options.split(',') {
match option {
"header" => header = true,
"table" => table = true,
o => bash_builtins::warning!("'{}': invalid format option.", o),
}
}
}
}

FormatOptions {
header,
table,
format,
}
}
}

#[test]
fn parse_options() {
assert_eq!(
FormatOptions::parse("abc"),
FormatOptions {
header: false,
table: false,
format: "abc"
}
);

assert_eq!(
FormatOptions::parse("[header]abc"),
FormatOptions {
header: true,
table: false,
format: "abc"
}
);

assert_eq!(
FormatOptions::parse("[table,header]abc"),
FormatOptions {
header: true,
table: true,
format: "abc"
}
);

assert_eq!(
FormatOptions::parse("[]abc"),
FormatOptions {
header: false,
table: false,
format: "abc"
}
);
}

#[cfg(test)]
mod mock_bash_fns {
#[no_mangle]
extern "C" fn builtin_warning(_: *const libc::c_char) {}
}
53 changes: 10 additions & 43 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,7 @@ builtin_metadata!(
The following settings are available:
format\tDefault format string.
header\tShow a header with the labels of every resource.
limit\tHistory limit.
table\tRender the history list as a table.
To change a setting, use '-s name=value', where 'name' is any of the
previous values. Use one '-s' for every setting to change.
Expand All @@ -54,17 +52,11 @@ mod tests;

use std::time::Duration;

const DEFAULT_FORMAT: &str = "%n\\t%(time:%X)\\t%P\\t%e\\t%C";
const DEFAULT_FORMAT: &str = "[header,table]%n\\t%(time:%X)\\t%P\\t%e\\t%C";

struct TimeHistory {
/// Default format to print history entries.
default_format: String,

/// Show header with field labels.
show_header: bool,

/// Render lists as a table.
render_table: bool,
}

#[derive(BuiltinOptions)]
Expand Down Expand Up @@ -115,8 +107,6 @@ impl TimeHistory {

Ok(TimeHistory {
default_format: DEFAULT_FORMAT.into(),
show_header: false,
render_table: false,
})
}
}
Expand Down Expand Up @@ -176,22 +166,6 @@ impl Builtin for TimeHistory {
history.set_size(value.parse()?);
}

(Some("header"), None) => {
self.show_header = true;
}

(Some("header"), Some(value)) => {
self.show_header = value.parse()?;
}

(Some("table"), Some(value)) => {
self.render_table = value.parse()?;
}

(Some("table"), None) => {
self.render_table = true;
}

(Some("format"), Some(value)) => {
self.default_format = if value.is_empty() {
DEFAULT_FORMAT.into()
Expand Down Expand Up @@ -246,25 +220,22 @@ impl Builtin for TimeHistory {
Some(Output::Json) => None,
};

// Use headers/tables.
let decorate = matches!(&output_format, None | Some(Output::Format(_)));
let format = format.map(format::FormatOptions::parse);

// Render output as a table.
if decorate && self.render_table {
table_writer = format::tables::TableWriter::new(output);
output = &mut table_writer as &mut dyn Write;
}
if let Some(options) = &format {
if options.table {
table_writer = format::TableWriter::new(output);
output = &mut table_writer as &mut dyn Write;
}

if decorate && self.show_header {
if let Some(fmt) = &format {
format::labels(fmt, &mut output)?;
if options.header {
format::labels(options.format, &mut output)?;
output.write_all(b"\n")?;
} else {
bash_builtins::warning!("header not available in JSON output.");
}
}

match (action, format) {
match (action, format.map(|f| f.format)) {
(Action::List, None) => {
let mut first = true;
output.write_all(b"[\n")?;
Expand Down Expand Up @@ -315,14 +286,10 @@ impl TimeHistory {
&mut output,
"\
format = {}\n\
header = {}\n\
limit = {}\n\
table = {}\n\
",
self.default_format,
self.show_header,
history.size(),
self.render_table,
)?;

Ok(())
Expand Down
2 changes: 0 additions & 2 deletions src/tests/shell/change-config.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ ASSERT_OUTPUT \
"timehistory -s" \
<<-'ITEMS'
format = %n\t%P\t%C
header = false
limit = 5000
table = false
ITEMS

timehistory -s format='> %C'
Expand Down
2 changes: 2 additions & 0 deletions src/tests/shell/clear-history.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

load_builtin

timehistory -s format='%n'

/bin/true
test -n "$(timehistory)"

Expand Down
3 changes: 1 addition & 2 deletions src/tests/shell/headers.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

load_builtin

timehistory -s header=true
ASSERT_OUTPUT \
"timehistory -f '%n %C'" \
"timehistory -f '[header]%n %C'" \
"NUMBER COMMAND"
11 changes: 8 additions & 3 deletions src/tests/shell/tables.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,17 @@ load_builtin
/bin/true 1
/bin/true 2

timehistory -s header=true -s table=true

ASSERT_OUTPUT \
"timehistory -f '%n\t%C'" \
"timehistory -f '[header,table]%n\t%C'" \
<<-ITEMS
NUMBER COMMAND
1 /bin/true 1
2 /bin/true 2
ITEMS

ASSERT_OUTPUT \
"timehistory -f '[table]%n\t%C'" \
<<-ITEMS
1 /bin/true 1
2 /bin/true 2
ITEMS

0 comments on commit 9903c4e

Please sign in to comment.