refactor: rename Match -> Span

This commit is contained in:
graelo 2021-03-22 23:56:35 +01:00
parent 4fc7a75046
commit 9fbfff70f3
16 changed files with 316 additions and 330 deletions

View file

@ -134,7 +134,7 @@ set -g @thumbs-reverse
`default: disabled`
Choose if you want to assign the same hint for the same matched strings.
Choose if you want to assign the same hint for the same text spans.
For example:
@ -146,7 +146,7 @@ set -g @thumbs-unique
`default: left`
Choose where do you want to show the hint in the matched string. Options (left, right).
Choose where do you want to show the hint in the text spans. Options (left, right).
For example:
@ -193,7 +193,7 @@ set -g @thumbs-upcase-command 'echo -n {} | pbcopy'
`default: black`
Sets the background color for matches
Sets the background color for spans
For example:
@ -205,7 +205,7 @@ set -g @thumbs-bg-color blue
`default: green`
Sets the foreground color for matches
Sets the foreground color for spans
For example:
@ -314,7 +314,7 @@ This is the list of available alphabets:
## Extra features
- **Arrow navigation:** You can use the arrows to move around between all matched items.
- **Arrow navigation:** You can use the arrows to move around between all spans.
- **Auto paste:** If your last typed hint character is uppercase, you are going to pick and paste the desired hint.
- **Multi selection:** If you run thumb with multi selection mode you will be able to choose multiple hints pressing the desired letter and `Space` to finalize the selection.
@ -361,13 +361,13 @@ FLAGS:
-h, --help Prints help information
-m, --multi Enable multi-selection
-r, --reverse Reverse the order for assigned hints
-u, --unique Don't show duplicated hints for the same match
-u, --unique Don't show duplicated hints for the same span
-V, --version Prints version information
OPTIONS:
-a, --alphabet <alphabet> Sets the alphabet [default: qwerty]
--bg-color <background_color> Sets the background color for matches [default: black]
--fg-color <foreground_color> Sets the foregroud color for matches [default: green]
--bg-color <background_color> Sets the background color for spans [default: black]
--fg-color <foreground_color> Sets the foregroud color for spans [default: green]
-f, --format <format>
Specifies the out format for the picked hint. (%U: Upcase, %H: Hint) [default: %H]

View file

@ -7,7 +7,7 @@
#
# set -g @copyrat-keytable "foobar"
# set -g @copyrat-keyswitch "z"
# set -g @copyrat-match-bg "magenta"
# set -g @copyrat-span-bg "magenta"
#
# and bindings like
#

View file

@ -15,7 +15,7 @@ fn main() {
let lines = buffer.split('\n').collect::<Vec<_>>();
// Execute copyrat over the buffer (will take control over stdout).
// This returns the selected matche.
// This returns the selected span of text.
let selection: Option<Selection> = run(&lines, &opt);
// Early exit, signaling no selections were found.

View file

@ -40,18 +40,18 @@ pub struct Config {
#[clap(short, long)]
pub reverse: bool,
/// Keep the same hint for identical matches.
/// Keep the same hint for identical spans.
#[clap(short, long)]
pub unique_hint: bool,
/// Move focus back to first/last match.
/// Move focus back to first/last span.
#[clap(short = 'w', long)]
pub focus_wrap_around: bool,
#[clap(flatten)]
pub colors: ui::colors::UiColors,
/// Align hint with its match.
/// Align hint with its span.
#[clap(long, arg_enum, default_value = "leading")]
pub hint_alignment: ui::HintAlignment,

View file

@ -80,12 +80,8 @@ impl ConfigExt {
wrapped.unique_hint = value.parse::<bool>()?;
}
"@copyrat-match-fg" => {
wrapped.colors.match_fg = ui::colors::parse_color(value)?
}
"@copyrat-match-bg" => {
wrapped.colors.match_bg = ui::colors::parse_color(value)?
}
"@copyrat-span-fg" => wrapped.colors.span_fg = ui::colors::parse_color(value)?,
"@copyrat-span-bg" => wrapped.colors.span_bg = ui::colors::parse_color(value)?,
"@copyrat-focused-fg" => {
wrapped.colors.focused_fg = ui::colors::parse_color(value)?
}

View file

@ -20,7 +20,7 @@ pub fn run(lines: &[&str], opt: &config::basic::Config) -> Option<ui::Selection>
opt.unique_hint,
);
if model.matches.is_empty() {
if model.spans.is_empty() {
return None;
}

View file

@ -139,35 +139,35 @@ mod tests {
use super::*;
#[test]
fn simple_matches() {
fn simple_hints() {
let alphabet = Alphabet("abcd".to_string());
let hints = alphabet.make_hints(3);
assert_eq!(hints, ["a", "b", "c"]);
}
#[test]
fn composed_matches() {
fn composed_hints() {
let alphabet = Alphabet("abcd".to_string());
let hints = alphabet.make_hints(6);
assert_eq!(hints, ["a", "b", "c", "da", "db", "dc"]);
}
#[test]
fn composed_matches_multiple() {
fn composed_hints_multiple() {
let alphabet = Alphabet("abcd".to_string());
let hints = alphabet.make_hints(8);
assert_eq!(hints, ["a", "b", "ca", "cb", "da", "db", "dc", "dd"]);
}
#[test]
fn composed_matches_max_2() {
fn composed_hints_max_2() {
let alphabet = Alphabet("ab".to_string());
let hints = alphabet.make_hints(4);
assert_eq!(hints, ["aa", "ab", "ba", "bb"]);
}
#[test]
fn composed_matches_max_4() {
fn composed_hints_max_4() {
let alphabet = Alphabet("abcd".to_string());
let hints = alphabet.make_hints(13);
assert_eq!(
@ -177,7 +177,7 @@ mod tests {
}
#[test]
fn matches_with_longest_alphabet() {
fn hints_with_longest_alphabet() {
let alphabet = Alphabet("ab".to_string());
let hints = alphabet.make_hints(2500);
assert_eq!(hints.len(), 2500);
@ -186,7 +186,7 @@ mod tests {
}
#[test]
fn matches_exceed_longest_alphabet() {
fn hints_exceed_longest_alphabet() {
let alphabet = Alphabet("ab".to_string());
let hints = alphabet.make_hints(10000);
// 2500 unique hints are produced from the longest alphabet

View file

@ -1,10 +0,0 @@
/// Represents matched text, its location on screen, the pattern that created
/// it, and the associated hint.
#[derive(Debug)]
pub struct Match<'a> {
pub x: i32,
pub y: i32,
pub pattern: &'a str,
pub text: &'a str,
pub hint: String,
}

View file

@ -1,11 +1,11 @@
pub(crate) mod alphabet;
mod matches;
mod model;
mod raw_match;
mod raw_span;
pub(crate) mod regexes;
mod span;
pub use matches::Match;
pub use model::Model;
pub use span::Span;
#[cfg(test)]
mod tests {
@ -22,7 +22,7 @@ mod tests {
let alphabet = Alphabet("abcd".to_string());
let reverse = false;
let unique_hint = false;
let results = Model::new(
let spans = Model::new(
&lines,
&alphabet,
use_all_patterns,
@ -31,11 +31,11 @@ mod tests {
reverse,
unique_hint,
)
.matches;
.spans;
assert_eq!(results.len(), 3);
assert_eq!(results.first().unwrap().hint, "a");
assert_eq!(results.last().unwrap().hint, "c");
assert_eq!(spans.len(), 3);
assert_eq!(spans.first().unwrap().hint, "a");
assert_eq!(spans.last().unwrap().hint, "c");
}
#[test]
@ -48,7 +48,7 @@ mod tests {
let alphabet = Alphabet("abcd".to_string());
let reverse = false;
let unique_hint = true;
let results = Model::new(
let spans = Model::new(
&lines,
&alphabet,
use_all_patterns,
@ -57,11 +57,11 @@ mod tests {
reverse,
unique_hint,
)
.matches;
.spans;
assert_eq!(results.len(), 3);
assert_eq!(results.first().unwrap().hint, "a");
assert_eq!(results.last().unwrap().hint, "a");
assert_eq!(spans.len(), 3);
assert_eq!(spans.first().unwrap().hint, "a");
assert_eq!(spans.last().unwrap().hint, "a");
}
#[test]
@ -74,7 +74,7 @@ mod tests {
let alphabet = Alphabet("abcd".to_string());
let reverse = false;
let unique_hint = false;
let results = Model::new(
let spans = Model::new(
&lines,
&alphabet,
use_all_patterns,
@ -83,11 +83,11 @@ mod tests {
reverse,
unique_hint,
)
.matches;
.spans;
assert_eq!(results.len(), 1);
assert_eq!(spans.len(), 1);
assert_eq!(
results.get(0).unwrap().text,
spans.get(0).unwrap().text,
"30557a29d5abc51e5f1d5b472e79b7e296f595abcf19fe6b9199dbbc809c6ff4"
);
}
@ -103,7 +103,7 @@ mod tests {
let alphabet = Alphabet("abcd".to_string());
let reverse = true;
let unique_hint = false;
let results = Model::new(
let spans = Model::new(
&lines,
&alphabet,
use_all_patterns,
@ -112,12 +112,12 @@ mod tests {
reverse,
unique_hint,
)
.matches;
.spans;
assert_eq!(results.len(), 3);
assert_eq!(results.get(0).unwrap().text, "/var/log/nginx.log");
assert_eq!(results.get(1).unwrap().text, "test/log/nginx-2.log");
assert_eq!(results.get(2).unwrap().text, "folder/.nginx@4df2.log");
assert_eq!(spans.len(), 3);
assert_eq!(spans.get(0).unwrap().text, "/var/log/nginx.log");
assert_eq!(spans.get(1).unwrap().text, "test/log/nginx-2.log");
assert_eq!(spans.get(2).unwrap().text, "folder/.nginx@4df2.log");
}
#[test]
@ -131,7 +131,7 @@ mod tests {
let alphabet = Alphabet("abcd".to_string());
let reverse = false;
let unique_hint = false;
let results = Model::new(
let spans = Model::new(
&lines,
&alphabet,
use_all_patterns,
@ -140,12 +140,12 @@ mod tests {
reverse,
unique_hint,
)
.matches;
.spans;
assert_eq!(results.len(), 3);
assert_eq!(results.get(0).unwrap().text, "/tmp/foo/bar_lol");
assert_eq!(results.get(1).unwrap().text, "/var/log/boot-strap.log");
assert_eq!(results.get(2).unwrap().text, "../log/kern.log");
assert_eq!(spans.len(), 3);
assert_eq!(spans.get(0).unwrap().text, "/tmp/foo/bar_lol");
assert_eq!(spans.get(1).unwrap().text, "/var/log/boot-strap.log");
assert_eq!(spans.get(2).unwrap().text, "../log/kern.log");
}
#[test]
@ -158,7 +158,7 @@ mod tests {
let alphabet = Alphabet("abcd".to_string());
let reverse = false;
let unique_hint = false;
let results = Model::new(
let spans = Model::new(
&lines,
&alphabet,
use_all_patterns,
@ -167,10 +167,10 @@ mod tests {
reverse,
unique_hint,
)
.matches;
.spans;
assert_eq!(results.len(), 1);
assert_eq!(results.get(0).unwrap().text, "~/.gnu/.config.txt");
assert_eq!(spans.len(), 1);
assert_eq!(spans.get(0).unwrap().text, "~/.gnu/.config.txt");
}
#[test]
@ -183,7 +183,7 @@ mod tests {
let alphabet = Alphabet("abcd".to_string());
let reverse = false;
let unique_hint = false;
let results = Model::new(
let spans = Model::new(
&lines,
&alphabet,
use_all_patterns,
@ -192,9 +192,9 @@ mod tests {
reverse,
unique_hint,
)
.matches;
.spans;
assert_eq!(results.len(), 1);
assert_eq!(spans.len(), 1);
}
#[test]
@ -207,7 +207,7 @@ mod tests {
let alphabet = Alphabet("abcd".to_string());
let reverse = false;
let unique_hint = false;
let results = Model::new(
let spans = Model::new(
&lines,
&alphabet,
use_all_patterns,
@ -216,14 +216,14 @@ mod tests {
reverse,
unique_hint,
)
.matches;
.spans;
assert_eq!(results.len(), 4);
assert_eq!(results.get(0).unwrap().text, "fd70b5695");
assert_eq!(results.get(1).unwrap().text, "5246ddf");
assert_eq!(results.get(2).unwrap().text, "f924213");
assert_eq!(spans.len(), 4);
assert_eq!(spans.get(0).unwrap().text, "fd70b5695");
assert_eq!(spans.get(1).unwrap().text, "5246ddf");
assert_eq!(spans.get(2).unwrap().text, "f924213");
assert_eq!(
results.get(3).unwrap().text,
spans.get(3).unwrap().text,
"973113963b491874ab2e372ee60d4b4cb75f717c"
);
}
@ -238,7 +238,7 @@ mod tests {
let alphabet = Alphabet("abcd".to_string());
let reverse = false;
let unique_hint = false;
let results = Model::new(
let spans = Model::new(
&lines,
&alphabet,
use_all_patterns,
@ -247,15 +247,15 @@ mod tests {
reverse,
unique_hint,
)
.matches;
.spans;
assert_eq!(results.len(), 3);
assert_eq!(results.get(0).unwrap().pattern, "ipv4");
assert_eq!(results.get(0).unwrap().text, "127.0.0.1");
assert_eq!(results.get(1).unwrap().pattern, "ipv4");
assert_eq!(results.get(1).unwrap().text, "255.255.10.255");
assert_eq!(results.get(2).unwrap().pattern, "ipv4");
assert_eq!(results.get(2).unwrap().text, "127.0.0.1");
assert_eq!(spans.len(), 3);
assert_eq!(spans.get(0).unwrap().pattern, "ipv4");
assert_eq!(spans.get(0).unwrap().text, "127.0.0.1");
assert_eq!(spans.get(1).unwrap().pattern, "ipv4");
assert_eq!(spans.get(1).unwrap().text, "255.255.10.255");
assert_eq!(spans.get(2).unwrap().pattern, "ipv4");
assert_eq!(spans.get(2).unwrap().text, "127.0.0.1");
}
#[test]
@ -268,7 +268,7 @@ mod tests {
let alphabet = Alphabet("abcd".to_string());
let reverse = false;
let unique_hint = false;
let results = Model::new(
let spans = Model::new(
&lines,
&alphabet,
use_all_patterns,
@ -277,16 +277,16 @@ mod tests {
reverse,
unique_hint,
)
.matches;
.spans;
assert_eq!(results.len(), 4);
assert_eq!(results.get(0).unwrap().text, "fe80::2:202:fe4");
assert_eq!(spans.len(), 4);
assert_eq!(spans.get(0).unwrap().text, "fe80::2:202:fe4");
assert_eq!(
results.get(1).unwrap().text,
spans.get(1).unwrap().text,
"2001:67c:670:202:7ba8:5e41:1591:d723"
);
assert_eq!(results.get(2).unwrap().text, "fe80::2:1");
assert_eq!(results.get(3).unwrap().text, "fe80:22:312:fe::1%eth0");
assert_eq!(spans.get(2).unwrap().text, "fe80::2:1");
assert_eq!(spans.get(3).unwrap().text, "fe80:22:312:fe::1%eth0");
}
#[test]
@ -300,7 +300,7 @@ mod tests {
let alphabet = Alphabet("abcd".to_string());
let reverse = false;
let unique_hint = false;
let results = Model::new(
let spans = Model::new(
&lines,
&alphabet,
use_all_patterns,
@ -309,13 +309,13 @@ mod tests {
reverse,
unique_hint,
)
.matches;
.spans;
assert_eq!(results.len(), 2);
assert_eq!(results.get(0).unwrap().pattern, "markdown-url");
assert_eq!(results.get(0).unwrap().text, "https://github.io?foo=bar");
assert_eq!(results.get(1).unwrap().pattern, "markdown-url");
assert_eq!(results.get(1).unwrap().text, "http://cdn.com/img.jpg");
assert_eq!(spans.len(), 2);
assert_eq!(spans.get(0).unwrap().pattern, "markdown-url");
assert_eq!(spans.get(0).unwrap().text, "https://github.io?foo=bar");
assert_eq!(spans.get(1).unwrap().pattern, "markdown-url");
assert_eq!(spans.get(1).unwrap().text, "http://cdn.com/img.jpg");
}
#[test]
@ -328,7 +328,7 @@ mod tests {
let alphabet = Alphabet("abcd".to_string());
let reverse = false;
let unique_hint = false;
let results = Model::new(
let spans = Model::new(
&lines,
&alphabet,
use_all_patterns,
@ -337,20 +337,20 @@ mod tests {
reverse,
unique_hint,
)
.matches;
.spans;
assert_eq!(results.len(), 4);
assert_eq!(spans.len(), 4);
assert_eq!(
results.get(0).unwrap().text,
spans.get(0).unwrap().text,
"https://www.rust-lang.org/tools"
);
assert_eq!(results.get(0).unwrap().pattern, "url");
assert_eq!(results.get(1).unwrap().text, "https://crates.io");
assert_eq!(results.get(1).unwrap().pattern, "url");
assert_eq!(results.get(2).unwrap().text, "https://github.io?foo=bar");
assert_eq!(results.get(2).unwrap().pattern, "url");
assert_eq!(results.get(3).unwrap().text, "ssh://github.io");
assert_eq!(results.get(3).unwrap().pattern, "url");
assert_eq!(spans.get(0).unwrap().pattern, "url");
assert_eq!(spans.get(1).unwrap().text, "https://crates.io");
assert_eq!(spans.get(1).unwrap().pattern, "url");
assert_eq!(spans.get(2).unwrap().text, "https://github.io?foo=bar");
assert_eq!(spans.get(2).unwrap().pattern, "url");
assert_eq!(spans.get(3).unwrap().text, "ssh://github.io");
assert_eq!(spans.get(3).unwrap().pattern, "url");
}
#[test]
@ -364,7 +364,7 @@ mod tests {
let alphabet = Alphabet("abcd".to_string());
let reverse = false;
let unique_hint = false;
let results = Model::new(
let spans = Model::new(
&lines,
&alphabet,
use_all_patterns,
@ -373,17 +373,14 @@ mod tests {
reverse,
unique_hint,
)
.matches;
.spans;
assert_eq!(results.len(), 2);
assert_eq!(results.get(0).unwrap().pattern, "email");
assert_eq!(spans.len(), 2);
assert_eq!(spans.get(0).unwrap().pattern, "email");
assert_eq!(spans.get(0).unwrap().text, "first.last+social@example.com");
assert_eq!(spans.get(1).unwrap().pattern, "email");
assert_eq!(
results.get(0).unwrap().text,
"first.last+social@example.com"
);
assert_eq!(results.get(1).unwrap().pattern, "email");
assert_eq!(
results.get(1).unwrap().text,
spans.get(1).unwrap().text,
"john@server.department.company.com"
);
}
@ -398,7 +395,7 @@ mod tests {
let alphabet = Alphabet("abcd".to_string());
let reverse = false;
let unique_hint = false;
let results = Model::new(
let spans = Model::new(
&lines,
&alphabet,
use_all_patterns,
@ -407,15 +404,15 @@ mod tests {
reverse,
unique_hint,
)
.matches;
.spans;
assert_eq!(results.len(), 3);
assert_eq!(results.get(0).unwrap().pattern, "mem-address");
assert_eq!(results.get(0).unwrap().text, "0xfd70b5695");
assert_eq!(results.get(1).unwrap().pattern, "mem-address");
assert_eq!(results.get(1).unwrap().text, "0x5246ddf");
assert_eq!(results.get(2).unwrap().pattern, "mem-address");
assert_eq!(results.get(2).unwrap().text, "0x973113");
assert_eq!(spans.len(), 3);
assert_eq!(spans.get(0).unwrap().pattern, "mem-address");
assert_eq!(spans.get(0).unwrap().text, "0xfd70b5695");
assert_eq!(spans.get(1).unwrap().pattern, "mem-address");
assert_eq!(spans.get(1).unwrap().text, "0x5246ddf");
assert_eq!(spans.get(2).unwrap().pattern, "mem-address");
assert_eq!(spans.get(2).unwrap().text, "0x973113");
}
#[test]
@ -428,7 +425,7 @@ mod tests {
let alphabet = Alphabet("abcd".to_string());
let reverse = false;
let unique_hint = false;
let results = Model::new(
let spans = Model::new(
&lines,
&alphabet,
use_all_patterns,
@ -437,13 +434,13 @@ mod tests {
reverse,
unique_hint,
)
.matches;
.spans;
assert_eq!(results.len(), 4);
assert_eq!(results.get(0).unwrap().text, "#fd7b56");
assert_eq!(results.get(1).unwrap().text, "#FF00FF");
assert_eq!(results.get(2).unwrap().text, "#00fF05");
assert_eq!(results.get(3).unwrap().text, "#abcd00");
assert_eq!(spans.len(), 4);
assert_eq!(spans.get(0).unwrap().text, "#fd7b56");
assert_eq!(spans.get(1).unwrap().text, "#FF00FF");
assert_eq!(spans.get(2).unwrap().text, "#00fF05");
assert_eq!(spans.get(3).unwrap().text, "#abcd00");
}
#[test]
@ -456,7 +453,7 @@ mod tests {
let alphabet = Alphabet("abcd".to_string());
let reverse = false;
let unique_hint = false;
let results = Model::new(
let spans = Model::new(
&lines,
&alphabet,
use_all_patterns,
@ -465,11 +462,11 @@ mod tests {
reverse,
unique_hint,
)
.matches;
.spans;
assert_eq!(results.len(), 1);
assert_eq!(spans.len(), 1);
assert_eq!(
results.get(0).unwrap().text,
spans.get(0).unwrap().text,
"QmRdbNSxDJBXmssAc9fvTtux4duptMvfSGiGuq6yHAQVKQ"
);
}
@ -484,7 +481,7 @@ mod tests {
let alphabet = Alphabet("abcd".to_string());
let reverse = false;
let unique_hint = false;
let results = Model::new(
let spans = Model::new(
&lines,
&alphabet,
use_all_patterns,
@ -493,9 +490,9 @@ mod tests {
reverse,
unique_hint,
)
.matches;
.spans;
assert_eq!(results.len(), 8);
assert_eq!(spans.len(), 8);
}
#[test]
@ -508,7 +505,7 @@ mod tests {
let alphabet = Alphabet("abcd".to_string());
let reverse = false;
let unique_hint = false;
let results = Model::new(
let spans = Model::new(
&lines,
&alphabet,
use_all_patterns,
@ -517,11 +514,11 @@ mod tests {
reverse,
unique_hint,
)
.matches;
.spans;
assert_eq!(results.len(), 1);
assert_eq!(results.get(0).unwrap().pattern, "diff-a");
assert_eq!(results.get(0).unwrap().text, "src/main.rs");
assert_eq!(spans.len(), 1);
assert_eq!(spans.get(0).unwrap().pattern, "diff-a");
assert_eq!(spans.get(0).unwrap().text, "src/main.rs");
}
#[test]
@ -534,7 +531,7 @@ mod tests {
let alphabet = Alphabet("abcd".to_string());
let reverse = false;
let unique_hint = false;
let results = Model::new(
let spans = Model::new(
&lines,
&alphabet,
use_all_patterns,
@ -543,11 +540,11 @@ mod tests {
reverse,
unique_hint,
)
.matches;
.spans;
assert_eq!(results.len(), 1);
assert_eq!(results.get(0).unwrap().pattern, "diff-b");
assert_eq!(results.get(0).unwrap().text, "src/main.rs");
assert_eq!(spans.len(), 1);
assert_eq!(spans.get(0).unwrap().pattern, "diff-b");
assert_eq!(spans.get(0).unwrap().text, "src/main.rs");
}
#[test]
@ -563,7 +560,7 @@ mod tests {
let alphabet = Alphabet("abcd".to_string());
let reverse = false;
let unique_hint = false;
let results = Model::new(
let spans = Model::new(
&lines,
&alphabet,
use_all_patterns,
@ -572,22 +569,22 @@ mod tests {
reverse,
unique_hint,
)
.matches;
.spans;
assert_eq!(results.len(), 9);
assert_eq!(results.get(0).unwrap().text, "http://foo.bar");
assert_eq!(results.get(1).unwrap().text, "CUSTOM-52463");
assert_eq!(results.get(2).unwrap().text, "ISSUE-123");
assert_eq!(results.get(3).unwrap().text, "/var/fd70b569/9999.log");
assert_eq!(results.get(4).unwrap().text, "52463");
assert_eq!(results.get(5).unwrap().text, "973113");
assert_eq!(spans.len(), 9);
assert_eq!(spans.get(0).unwrap().text, "http://foo.bar");
assert_eq!(spans.get(1).unwrap().text, "CUSTOM-52463");
assert_eq!(spans.get(2).unwrap().text, "ISSUE-123");
assert_eq!(spans.get(3).unwrap().text, "/var/fd70b569/9999.log");
assert_eq!(spans.get(4).unwrap().text, "52463");
assert_eq!(spans.get(5).unwrap().text, "973113");
assert_eq!(
results.get(6).unwrap().text,
spans.get(6).unwrap().text,
"123e4567-e89b-12d3-a456-426655440000"
);
assert_eq!(results.get(7).unwrap().text, "8888");
assert_eq!(spans.get(7).unwrap().text, "8888");
assert_eq!(
results.get(8).unwrap().text,
spans.get(8).unwrap().text,
"https://crates.io/23456/fd70b569"
);
}
@ -605,7 +602,7 @@ mod tests {
let alphabet = Alphabet("abcd".to_string());
let reverse = false;
let unique_hint = false;
let results = Model::new(
let spans = Model::new(
&lines,
&alphabet,
use_all_patterns,
@ -614,12 +611,12 @@ mod tests {
reverse,
unique_hint,
)
.matches;
.spans;
assert_eq!(results.len(), 2);
assert_eq!(results.get(0).unwrap().text, "http://foo.bar");
assert_eq!(spans.len(), 2);
assert_eq!(spans.get(0).unwrap().text, "http://foo.bar");
assert_eq!(
results.get(1).unwrap().text,
spans.get(1).unwrap().text,
"https://crates.io/23456/fd70b569"
);
}

View file

@ -4,22 +4,20 @@ use regex::Regex;
use sequence_trie::SequenceTrie;
use super::alphabet::Alphabet;
use super::matches::Match;
use super::raw_match::RawMatch;
use super::raw_span::RawSpan;
use super::regexes::{NamedPattern, EXCLUDE_PATTERNS, PATTERNS};
use super::span::Span;
/// Holds data for the `Ui`.
pub struct Model<'a> {
// buffer: &'a str,
pub lines: &'a [&'a str],
pub reverse: bool,
pub matches: Vec<Match<'a>>,
pub spans: Vec<Span<'a>>,
pub lookup_trie: SequenceTrie<char, usize>,
}
impl<'a> Model<'a> {
pub fn new(
// buffer: &'a str,
lines: &'a [&'a str],
alphabet: &'a Alphabet,
use_all_patterns: bool,
@ -28,36 +26,34 @@ impl<'a> Model<'a> {
reverse: bool,
unique_hint: bool,
) -> Model<'a> {
// let lines = buffer.split('\n').collect::<Vec<_>>();
let mut raw_matches =
raw_matches(&lines, named_patterns, custom_patterns, use_all_patterns);
let mut raw_spans =
find_raw_spans(&lines, named_patterns, custom_patterns, use_all_patterns);
if reverse {
raw_matches.reverse();
raw_spans.reverse();
}
let mut matches = associate_hints(&raw_matches, alphabet, unique_hint);
let mut spans = associate_hints(&raw_spans, alphabet, unique_hint);
if reverse {
matches.reverse();
spans.reverse();
}
let lookup_trie = build_lookup_trie(&matches);
let lookup_trie = build_lookup_trie(&spans);
Model {
// buffer,
lines,
reverse,
matches,
spans,
lookup_trie,
}
}
}
/// Internal function that searches the model's lines for pattern matches.
/// Returns a vector of `RawMatch`es (text, location, pattern id) without
/// an associated hint. The hint is attached to `Match`, not to `RawMatch`.
/// Returns a vector of `RawSpan` (text, location, pattern id) without
/// an associated hint. The hint is attached to `Span`, not to `RawSpan`.
///
/// # Notes
///
@ -65,12 +61,12 @@ impl<'a> Model<'a> {
///
/// If no named patterns were specified, it will search for all available
/// patterns from the `PATTERNS` catalog.
fn raw_matches<'a>(
fn find_raw_spans<'a>(
lines: &'a [&'a str],
named_patterns: &'a [NamedPattern],
custom_patterns: &'a [String],
use_all_patterns: bool,
) -> Vec<RawMatch<'a>> {
) -> Vec<RawSpan<'a>> {
let exclude_regexes = EXCLUDE_PATTERNS
.iter()
.map(|&(name, pattern)| (name, Regex::new(pattern).unwrap()))
@ -100,7 +96,7 @@ fn raw_matches<'a>(
let all_regexes = [exclude_regexes, custom_regexes, regexes].concat();
let mut raw_matches = Vec::new();
let mut raw_spans = Vec::new();
for (index, line) in lines.iter().enumerate() {
// Chunk is the remainder of the line to be searched for matches.
@ -110,7 +106,7 @@ fn raw_matches<'a>(
// Use all avail regexes to match the chunk and select the match
// occuring the earliest on the chunk. Save its matched text and
// position in a `RawMatch` struct.
// position in a `RawSpan` struct.
loop {
// For each avalable regex, use the `find_iter` iterator to
// get the first non-overlapping match in the chunk, returning
@ -149,7 +145,7 @@ fn raw_matches<'a>(
None => (text, 0),
};
raw_matches.push(RawMatch {
raw_spans.push(RawSpan {
x: offset + reg_match.start() as i32 + substart as i32,
y: index as i32,
pattern: pat_name,
@ -164,54 +160,54 @@ fn raw_matches<'a>(
}
}
raw_matches
raw_spans
}
/// Associate a hint to each `RawMatch`, returning a vector of `Match`es.
/// Associate a hint to each `RawSpan`, returning a vector of `Span`.
///
/// If `unique` is `true`, all duplicate matches will have the same hint.
/// For copying matched text, this seems easier and more natural.
/// If `unique` is `false`, duplicate matches will have their own hint.
/// If `unique` is `true`, all duplicate spans will have the same hint.
/// For copying text spans, this seems easier and more natural.
/// If `unique` is `false`, duplicate spans will have their own hint.
fn associate_hints<'a>(
raw_matches: &[RawMatch<'a>],
raw_spans: &[RawSpan<'a>],
alphabet: &'a Alphabet,
unique: bool,
) -> Vec<Match<'a>> {
let hints = alphabet.make_hints(raw_matches.len());
) -> Vec<Span<'a>> {
let hints = alphabet.make_hints(raw_spans.len());
let mut hints_iter = hints.iter();
let mut result: Vec<Match<'a>> = vec![];
let mut result: Vec<Span<'a>> = vec![];
if unique {
// Map (text, hint)
let mut known: collections::HashMap<&str, &str> = collections::HashMap::new();
for raw_mat in raw_matches {
let hint: &str = known.entry(raw_mat.text).or_insert_with(|| {
for raw_span in raw_spans {
let hint: &str = known.entry(raw_span.text).or_insert_with(|| {
hints_iter
.next()
.expect("We should have as many hints as necessary, even invisible ones.")
});
result.push(Match {
x: raw_mat.x,
y: raw_mat.y,
pattern: raw_mat.pattern,
text: raw_mat.text,
result.push(Span {
x: raw_span.x,
y: raw_span.y,
pattern: raw_span.pattern,
text: raw_span.text,
hint: hint.to_string(),
});
}
} else {
for raw_mat in raw_matches {
for raw_span in raw_spans {
let hint = hints_iter
.next()
.expect("We should have as many hints as necessary, even invisible ones.");
result.push(Match {
x: raw_mat.x,
y: raw_mat.y,
pattern: raw_mat.pattern,
text: raw_mat.text,
result.push(Span {
x: raw_span.x,
y: raw_span.y,
pattern: raw_span.pattern,
text: raw_span.text,
hint: hint.to_string(),
});
}
@ -222,12 +218,12 @@ fn associate_hints<'a>(
/// Builds a `SequenceTrie` that helps determine if a sequence of keys
/// entered by the user corresponds to a match. This kind of lookup
/// directly returns a reference to the corresponding `Match` if any.
fn build_lookup_trie<'a>(matches: &'a [Match<'a>]) -> SequenceTrie<char, usize> {
/// directly returns a reference to the corresponding `Span` if any.
fn build_lookup_trie<'a>(spans: &'a [Span<'a>]) -> SequenceTrie<char, usize> {
let mut trie = SequenceTrie::new();
for (index, mat) in matches.iter().enumerate() {
let hint_chars = mat.hint.chars().collect::<Vec<char>>();
for (index, span) in spans.iter().enumerate() {
let hint_chars = span.hint.chars().collect::<Vec<char>>();
// no need to insert twice the same hint
if trie.get(&hint_chars).is_none() {

View file

@ -1,8 +0,0 @@
/// Internal surrogate for `Match`, before a Hint has been associated.
#[derive(Debug)]
pub(super) struct RawMatch<'a> {
pub x: i32,
pub y: i32,
pub pattern: &'a str,
pub text: &'a str,
}

8
src/textbuf/raw_span.rs Normal file
View file

@ -0,0 +1,8 @@
/// Internal surrogate for `Span`, before a Hint has been associated.
#[derive(Debug)]
pub(super) struct RawSpan<'a> {
pub x: i32,
pub y: i32,
pub pattern: &'a str,
pub text: &'a str,
}

10
src/textbuf/span.rs Normal file
View file

@ -0,0 +1,10 @@
/// Represents some span of text, its location on screen, the pattern that
/// created it, and the associated hint.
#[derive(Debug)]
pub struct Span<'a> {
pub x: i32,
pub y: i32,
pub pattern: &'a str,
pub text: &'a str,
pub hint: String,
}

View file

@ -30,7 +30,7 @@ mod tests {
use super::*;
#[test]
fn match_color() {
fn span_color() {
let text1 = format!(
"{}{}",
color::Fg(parse_color("green").unwrap().as_ref()),
@ -42,15 +42,15 @@ mod tests {
}
#[test]
fn no_match_color() {
fn no_span_color() {
assert!(parse_color("wat").is_err(), "this color should not exist");
}
}
/// Holds color-related data.
///
/// - `focus_*` colors are used to render the currently focused matched text.
/// - `normal_*` colors are used to render other matched text.
/// - `focus_*` colors are used to render the currently focused text span.
/// - `normal_*` colors are used to render other text spans.
/// - `hint_*` colors are used to render the hints.
#[derive(Clap, Debug)]
#[clap(about)] // Needed to avoid this doc comment to be used as overall `about`.
@ -63,22 +63,22 @@ pub struct UiColors {
#[clap(long, default_value = "bright-white", parse(try_from_str = parse_color))]
pub text_bg: Box<dyn color::Color>,
/// Foreground color for matches.
/// Foreground color for spans.
#[clap(long, default_value = "yellow",
parse(try_from_str = parse_color))]
pub match_fg: Box<dyn color::Color>,
pub span_fg: Box<dyn color::Color>,
/// Background color for matches.
/// Background color for spans.
#[clap(long, default_value = "bright-white",
parse(try_from_str = parse_color))]
pub match_bg: Box<dyn color::Color>,
pub span_bg: Box<dyn color::Color>,
/// Foreground color for the focused match.
/// Foreground color for the focused span.
#[clap(long, default_value = "magenta",
parse(try_from_str = parse_color))]
pub focused_fg: Box<dyn color::Color>,
/// Background color for the focused match.
/// Background color for the focused span.
#[clap(long, default_value = "bright-white",
parse(try_from_str = parse_color))]
pub focused_bg: Box<dyn color::Color>,

View file

@ -3,7 +3,7 @@
//!
//! In particular, the `Ui` struct
//!
//! - renders text, matched text and hints from the structured buffer content
//! - renders text, spans and hints from the structured buffer content
//! to the screen,
//! - listens for keypress events,
//! - and returns the user selection in the form of a `Selection` struct.
@ -12,8 +12,8 @@
//!
//! - navigate the buffer (in case it is larger than the number of lines in
//! the terminal)
//! - move the focus from one match to another
//! - select one of the matches
//! - move the focus from one span to another
//! - select one of the available spans
//! - toggle the output destination (tmux buffer or clipboard)
//!

View file

@ -33,7 +33,7 @@ impl<'a> ViewController<'a> {
hint_style: Option<HintStyle>,
) -> ViewController<'a> {
let focus_index = if model.reverse {
model.matches.len() - 1
model.spans.len() - 1
} else {
0
};
@ -57,10 +57,10 @@ impl<'a> ViewController<'a> {
// }}}
// Coordinates {{{1
/// Convert the `Match` text into the coordinates of the wrapped lines.
/// Convert the `Span` text into the coordinates of the wrapped lines.
///
/// Compute the new x offset of the text as the remainder of the line width
/// (e.g. the match could start at offset 120 in a 80-width terminal, the new
/// (e.g. the Span could start at offset 120 in a 80-width terminal, the new
/// offset being 40).
///
/// Compute the new y offset of the text as the initial y offset plus any
@ -76,20 +76,20 @@ impl<'a> ViewController<'a> {
(new_offset_x, new_offset_y)
}
/// Returns screen offset of a given `Match`.
/// Returns screen offset of a given `Span`.
///
/// If multibyte characters occur before the hint (in the "prefix"), then
/// their compouding takes less space on screen when printed: for
/// instance ´ + e = é. Consequently the hint offset has to be adjusted
/// to the left.
fn match_offsets(&self, mat: &textbuf::Match<'a>) -> (usize, usize) {
fn span_offsets(&self, span: &textbuf::Span<'a>) -> (usize, usize) {
let offset_x = {
let line = &self.model.lines[mat.y as usize];
let prefix = &line[0..mat.x as usize];
let line = &self.model.lines[span.y as usize];
let prefix = &line[0..span.x as usize];
let adjust = prefix.len() - prefix.chars().count();
(mat.x as usize) - (adjust)
(span.x as usize) - (adjust)
};
let offset_y = mat.y as usize;
let offset_y = span.y as usize;
(offset_x, offset_y)
}
@ -98,12 +98,12 @@ impl<'a> ViewController<'a> {
// Focus management {{{1
/// Move focus onto the previous hint, returning both the index of the
/// previously focused match, and the index of the newly focused one.
/// previously focused Span, and the index of the newly focused one.
fn prev_focus_index(&mut self) -> (usize, usize) {
let old_index = self.focus_index;
if self.focus_wrap_around {
if self.focus_index == 0 {
self.focus_index = self.model.matches.len() - 1;
self.focus_index = self.model.spans.len() - 1;
} else {
self.focus_index -= 1;
}
@ -115,16 +115,16 @@ impl<'a> ViewController<'a> {
}
/// Move focus onto the next hint, returning both the index of the
/// previously focused match, and the index of the newly focused one.
/// previously focused Span, and the index of the newly focused one.
fn next_focus_index(&mut self) -> (usize, usize) {
let old_index = self.focus_index;
if self.focus_wrap_around {
if self.focus_index == self.model.matches.len() - 1 {
if self.focus_index == self.model.spans.len() - 1 {
self.focus_index = 0;
} else {
self.focus_index += 1;
}
} else if self.focus_index < self.model.matches.len() - 1 {
} else if self.focus_index < self.model.spans.len() - 1 {
self.focus_index += 1;
}
let new_index = self.focus_index;
@ -136,7 +136,7 @@ impl<'a> ViewController<'a> {
/// Render entire model lines on provided writer.
///
/// This renders the basic content on which matches and hints can be rendered.
/// This renders the basic content on which spans and hints can be rendered.
///
/// # Notes
/// - All trailing whitespaces are trimmed, empty lines are skipped.
@ -181,7 +181,7 @@ impl<'a> ViewController<'a> {
.unwrap();
}
/// Render the Match's `text` field on provided writer using the `match_*g` color.
/// Render the Span's `text` field on provided writer using the `span_*g` color.
///
/// If a Mach is "focused", it is then rendered with the `focused_*g` colors.
///
@ -195,14 +195,14 @@ impl<'a> ViewController<'a> {
offset: (usize, usize),
colors: &UiColors,
) {
// To help identify it, the match thas has focus is rendered with a dedicated color.
// To help identify it, the span thas has focus is rendered with a dedicated color.
let (fg_color, bg_color) = if focused {
(&colors.focused_fg, &colors.focused_bg)
} else {
(&colors.match_fg, &colors.match_bg)
(&colors.span_fg, &colors.span_bg)
};
// Render just the Match's text on top of existing content.
// Render just the Span's text on top of existing content.
write!(
stdout,
"{goto}{bg_color}{fg_color}{text}{fg_reset}{bg_reset}",
@ -216,7 +216,7 @@ impl<'a> ViewController<'a> {
.unwrap();
}
/// Render a Match's `hint` field on the provided writer.
/// Render a Span's `hint` field on the provided writer.
///
/// This renders the hint according to some provided style:
/// - just colors
@ -318,12 +318,12 @@ impl<'a> ViewController<'a> {
}
}
/// Convenience function that renders both the matched text and its hint,
/// Convenience function that renders both the text span and its hint,
/// if focused.
fn render_match(&self, stdout: &mut dyn io::Write, mat: &textbuf::Match<'a>, focused: bool) {
let text = mat.text;
fn render_span(&self, stdout: &mut dyn io::Write, span: &textbuf::Span<'a>, focused: bool) {
let text = span.text;
let (offset_x, offset_y) = self.match_offsets(mat);
let (offset_x, offset_y) = self.span_offsets(span);
let (offset_x, offset_y) = self.map_coords_to_wrapped_space(offset_x, offset_y);
ViewController::render_matched_text(
@ -336,16 +336,16 @@ impl<'a> ViewController<'a> {
if !focused {
// If not focused, render the hint (e.g. "eo") as an overlay on
// top of the rendered matched text, aligned at its leading or the
// top of the rendered text span, aligned at its leading or the
// trailing edge.
let extra_offset = match self.hint_alignment {
HintAlignment::Leading => 0,
HintAlignment::Trailing => text.len() - mat.hint.len(),
HintAlignment::Trailing => text.len() - span.hint.len(),
};
ViewController::render_matched_hint(
stdout,
&mat.hint,
&span.hint,
(offset_x + extra_offset, offset_y),
&self.rendering_colors,
&self.hint_style,
@ -357,15 +357,15 @@ impl<'a> ViewController<'a> {
///
/// This renders in 3 phases:
/// - all lines are rendered verbatim
/// - each Match's `text` is rendered as an overlay on top of it
/// - each Match's `hint` text is rendered as a final overlay
/// - each Span's `text` is rendered as an overlay on top of it
/// - each Span's `hint` text is rendered as a final overlay
///
/// Depending on the value of `self.hint_alignment`, the hint can be rendered
/// on the leading edge of the underlying Match's `text`,
/// on the leading edge of the underlying Span's `text`,
/// or on the trailing edge.
///
/// # Note
/// Multibyte characters are taken into account, so that the Match's `text`
/// Multibyte characters are taken into account, so that the Span's `text`
/// and `hint` are rendered in their proper position.
fn full_render(&self, stdout: &mut dyn io::Write) {
// 1. Trim all lines and render non-empty ones.
@ -376,31 +376,31 @@ impl<'a> ViewController<'a> {
&self.rendering_colors,
);
for (index, mat) in self.model.matches.iter().enumerate() {
for (index, span) in self.model.spans.iter().enumerate() {
let focused = index == self.focus_index;
self.render_match(stdout, mat, focused);
self.render_span(stdout, span, focused);
}
stdout.flush().unwrap();
}
/// Render the previous match with its hint, and render the newly focused
/// match without its hint. This is more efficient than a full render.
/// Render the previous span with its hint, and render the newly focused
/// span without its hint. This is more efficient than a full render.
fn diff_render(
&self,
stdout: &mut dyn io::Write,
old_focus_index: usize,
new_focus_index: usize,
) {
// Render the previously focused match as non-focused
let mat = self.model.matches.get(old_focus_index).unwrap();
// Render the previously focused span as non-focused
let span = self.model.spans.get(old_focus_index).unwrap();
let focused = false;
self.render_match(stdout, mat, focused);
self.render_span(stdout, span, focused);
// Render the previously focused match as non-focused
let mat = self.model.matches.get(new_focus_index).unwrap();
// Render the previously focused span as non-focused
let span = self.model.spans.get(new_focus_index).unwrap();
let focused = true;
self.render_match(stdout, mat, focused);
self.render_span(stdout, span, focused);
stdout.flush().unwrap();
}
@ -409,7 +409,7 @@ impl<'a> ViewController<'a> {
// Listening {{{1
/// Listen to keys entered on stdin, moving focus accordingly, or
/// selecting one match.
/// selecting one span.
///
/// # Panics
///
@ -417,7 +417,7 @@ impl<'a> ViewController<'a> {
fn listen(&mut self, reader: &mut dyn io::Read, writer: &mut dyn io::Write) -> Event {
use termion::input::TermRead; // Trait for `reader.keys().next()`.
if self.model.matches.is_empty() {
if self.model.spans.is_empty() {
return Event::Exit;
}
@ -448,7 +448,7 @@ impl<'a> ViewController<'a> {
break;
}
// Move focus to next/prev match.
// Move focus to next/prev span.
event::Key::Up => {
let (old_index, focused_index) = self.prev_focus_index();
self.diff_render(writer, old_index, focused_index);
@ -484,16 +484,16 @@ impl<'a> ViewController<'a> {
// Yank/copy
event::Key::Char(_ch @ 'y') | event::Key::Char(_ch @ '\n') => {
let text = self.model.matches.get(self.focus_index).unwrap().text;
return Event::Match(Selection {
let text = self.model.spans.get(self.focus_index).unwrap().text;
return Event::Select(Selection {
text: text.to_string(),
uppercased: false,
output_destination,
});
}
event::Key::Char(_ch @ 'Y') => {
let text = self.model.matches.get(self.focus_index).unwrap().text;
return Event::Match(Selection {
let text = self.model.spans.get(self.focus_index).unwrap().text;
return Event::Select(Selection {
text: text.to_string(),
uppercased: true,
output_destination,
@ -511,7 +511,7 @@ impl<'a> ViewController<'a> {
// Use a Trie or another data structure to determine
// if the entered key belongs to a longer hint.
// Attempts at finding a match with a corresponding hint.
// Attempts at finding a span with a corresponding hint.
//
// If any of the typed character is caps, the typed hint is
// deemed as uppercased.
@ -535,12 +535,12 @@ impl<'a> ViewController<'a> {
let node = node.unwrap();
if node.is_leaf() {
// The last key of a hint was entered.
let match_index = node.value().expect(
let span_index = node.value().expect(
"By construction, the Lookup Trie should have a value for each leaf.",
);
let mat = self.model.matches.get(*match_index).expect("By construction, the value in a leaf should correspond to an existing hint.");
let text = mat.text.to_string();
return Event::Match(Selection {
let span = self.model.spans.get(*span_index).expect("By construction, the value in a leaf should correspond to an existing hint.");
let text = span.text.to_string();
return Event::Select(Selection {
text,
uppercased,
output_destination,
@ -585,7 +585,7 @@ impl<'a> ViewController<'a> {
let selection = match self.listen(&mut stdin, &mut stdout) {
Event::Exit => None,
Event::Match(selection) => Some(selection),
Event::Select(selection) => Some(selection),
};
write!(stdout, "{}", cursor::Show).unwrap();
@ -623,10 +623,10 @@ fn get_line_offsets(lines: &[&str], term_width: u16) -> Vec<usize> {
/// Returned value after the `Ui` has finished listening to events.
enum Event {
/// Exit with no selected matches,
/// Exit with no selected spans,
Exit,
/// A vector of matched text and whether it was selected with uppercase.
Match(Selection),
/// The selected span of text and whether it was selected with uppercase.
Select(Selection),
}
#[cfg(test)]
@ -650,8 +650,8 @@ path: /usr/local/bin/cargo";
text_bg: Box::new(color::White),
focused_fg: Box::new(color::Red),
focused_bg: Box::new(color::Blue),
match_fg: Box::new(color::Green),
match_bg: Box::new(color::Magenta),
span_fg: Box::new(color::Green),
span_bg: Box::new(color::Magenta),
hint_fg: Box::new(color::Yellow),
hint_bg: Box::new(color::Cyan),
};
@ -688,8 +688,8 @@ path: /usr/local/bin/cargo";
text_bg: Box::new(color::White),
focused_fg: Box::new(color::Red),
focused_bg: Box::new(color::Blue),
match_fg: Box::new(color::Green),
match_bg: Box::new(color::Magenta),
span_fg: Box::new(color::Green),
span_bg: Box::new(color::Magenta),
hint_fg: Box::new(color::Yellow),
hint_bg: Box::new(color::Cyan),
};
@ -722,8 +722,8 @@ path: /usr/local/bin/cargo";
text_bg: Box::new(color::White),
focused_fg: Box::new(color::Red),
focused_bg: Box::new(color::Blue),
match_fg: Box::new(color::Green),
match_bg: Box::new(color::Magenta),
span_fg: Box::new(color::Green),
span_bg: Box::new(color::Magenta),
hint_fg: Box::new(color::Yellow),
hint_bg: Box::new(color::Cyan),
};
@ -735,8 +735,8 @@ path: /usr/local/bin/cargo";
format!(
"{goto}{bg}{fg}{text}{fg_reset}{bg_reset}",
goto = cursor::Goto(4, 2),
fg = color::Fg(colors.match_fg.as_ref()),
bg = color::Bg(colors.match_bg.as_ref()),
fg = color::Fg(colors.span_fg.as_ref()),
bg = color::Bg(colors.span_bg.as_ref()),
fg_reset = color::Fg(color::Reset),
bg_reset = color::Bg(color::Reset),
text = &text,
@ -755,8 +755,8 @@ path: /usr/local/bin/cargo";
text_bg: Box::new(color::White),
focused_fg: Box::new(color::Red),
focused_bg: Box::new(color::Blue),
match_fg: Box::new(color::Green),
match_bg: Box::new(color::Magenta),
span_fg: Box::new(color::Green),
span_bg: Box::new(color::Magenta),
hint_fg: Box::new(color::Yellow),
hint_bg: Box::new(color::Cyan),
};
@ -797,8 +797,8 @@ path: /usr/local/bin/cargo";
text_bg: Box::new(color::White),
focused_fg: Box::new(color::Red),
focused_bg: Box::new(color::Blue),
match_fg: Box::new(color::Green),
match_bg: Box::new(color::Magenta),
span_fg: Box::new(color::Green),
span_bg: Box::new(color::Magenta),
hint_fg: Box::new(color::Yellow),
hint_bg: Box::new(color::Cyan),
};
@ -841,8 +841,8 @@ path: /usr/local/bin/cargo";
text_bg: Box::new(color::White),
focused_fg: Box::new(color::Red),
focused_bg: Box::new(color::Blue),
match_fg: Box::new(color::Green),
match_bg: Box::new(color::Magenta),
span_fg: Box::new(color::Green),
span_bg: Box::new(color::Magenta),
hint_fg: Box::new(color::Yellow),
hint_bg: Box::new(color::Cyan),
};
@ -876,8 +876,8 @@ path: /usr/local/bin/cargo";
}
#[test]
/// Simulates rendering without any match.
fn test_render_full_without_matches() {
/// Simulates rendering without any span.
fn test_render_full_without_available_spans() {
let buffer = "lorem 127.0.0.1 lorem
Barcelona https://en.wikipedia.org/wiki/Barcelona - ";
@ -905,14 +905,14 @@ Barcelona https://en.wikipedia.org/wiki/Barcelona - ";
text_bg: Box::new(color::White),
focused_fg: Box::new(color::Red),
focused_bg: Box::new(color::Blue),
match_fg: Box::new(color::Green),
match_bg: Box::new(color::Magenta),
span_fg: Box::new(color::Green),
span_bg: Box::new(color::Magenta),
hint_fg: Box::new(color::Yellow),
hint_bg: Box::new(color::Cyan),
};
let hint_alignment = HintAlignment::Leading;
// create a Ui without any match
// create a Ui without any span
let ui = ViewController {
model: &mut model,
term_width,
@ -945,15 +945,12 @@ Barcelona https://en.wikipedia.org/wiki/Barcelona - ";
// println!("{:?}", writer);
// println!("{:?}", expected.as_bytes());
// println!("matches: {}", ui.matches.len());
// println!("lines: {}", lines.len());
assert_eq!(writer, expected.as_bytes());
}
#[test]
/// Simulates rendering with matches.
fn test_render_full_with_matches() {
/// Simulates rendering with available spans.
fn test_render_full_with_spans() {
let buffer = "lorem 127.0.0.1 lorem
Barcelona https://en.wikipedia.org/wiki/Barcelona - ";
@ -982,8 +979,8 @@ Barcelona https://en.wikipedia.org/wiki/Barcelona - ";
text_bg: Box::new(color::White),
focused_fg: Box::new(color::Red),
focused_bg: Box::new(color::Blue),
match_fg: Box::new(color::Green),
match_bg: Box::new(color::Magenta),
span_fg: Box::new(color::Green),
span_bg: Box::new(color::Magenta),
hint_fg: Box::new(color::Yellow),
hint_bg: Box::new(color::Cyan),
};
@ -1021,10 +1018,10 @@ Barcelona https://en.wikipedia.org/wiki/Barcelona - ";
let expected_match1_text = {
let goto7_1 = cursor::Goto(7, 1);
format!(
"{goto7_1}{match_bg}{match_fg}127.0.0.1{fg_reset}{bg_reset}",
"{goto7_1}{span_bg}{span_fg}127.0.0.1{fg_reset}{bg_reset}",
goto7_1 = goto7_1,
match_fg = color::Fg(rendering_colors.match_fg.as_ref()),
match_bg = color::Bg(rendering_colors.match_bg.as_ref()),
span_fg = color::Fg(rendering_colors.span_fg.as_ref()),
span_bg = color::Bg(rendering_colors.span_bg.as_ref()),
fg_reset = color::Fg(color::Reset),
bg_reset = color::Bg(color::Reset)
)
@ -1055,7 +1052,7 @@ Barcelona https://en.wikipedia.org/wiki/Barcelona - ";
)
};
// Because reverse is true, this second match is focused,
// Because reverse is true, this second span is focused,
// then the hint should not be rendered.
// let expected_match2_hint = {
@ -1090,7 +1087,7 @@ Barcelona https://en.wikipedia.org/wiki/Barcelona - ";
// .find(|(_idx, (&l, &r))| l != r);
// println!("{:?}", diff_point);
assert_eq!(2, ui.model.matches.len());
assert_eq!(2, ui.model.spans.len());
assert_eq!(writer, expected.as_bytes());
}