mirror of
https://github.com/FliegendeWurst/tmux-thumbs.git
synced 2024-11-09 16:00:35 +00:00
Merge pull request #4 from fcsonline/feature/rustfmt
Format rules with rustfmt
This commit is contained in:
commit
06560e3328
1
.rustfmt.toml
Normal file
1
.rustfmt.toml
Normal file
@ -0,0 +1 @@
|
||||
tab_spaces = 2
|
@ -9,6 +9,10 @@ rust:
|
||||
- nightly
|
||||
- stable
|
||||
|
||||
before_script:
|
||||
- rustup component add rustfmt
|
||||
|
||||
script:
|
||||
- cargo fmt --all -- --check
|
||||
- cargo build
|
||||
- cargo test
|
||||
|
@ -26,14 +26,12 @@ const ALPHABETS: [(&'static str, &'static str); 22] = [
|
||||
];
|
||||
|
||||
pub struct Alphabet<'a> {
|
||||
letters: &'a str
|
||||
letters: &'a str,
|
||||
}
|
||||
|
||||
impl<'a> Alphabet<'a> {
|
||||
fn new(letters: &'a str) -> Alphabet {
|
||||
Alphabet{
|
||||
letters: letters
|
||||
}
|
||||
Alphabet { letters: letters }
|
||||
}
|
||||
|
||||
pub fn hints(&self, matches: usize) -> Vec<String> {
|
||||
@ -43,16 +41,28 @@ impl<'a> Alphabet<'a> {
|
||||
let mut expanded: Vec<String> = Vec::new();
|
||||
|
||||
loop {
|
||||
if expansion.len() + expanded.len() >= matches { break; }
|
||||
if expansion.len() == 0 { break; }
|
||||
if expansion.len() + expanded.len() >= matches {
|
||||
break;
|
||||
}
|
||||
if expansion.len() == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
let prefix = expansion.pop().expect("Ouch!");
|
||||
let sub_expansion: Vec<String> = letters.iter().take(matches - expansion.len() - expanded.len()).map(|s| prefix.clone() + s).collect();
|
||||
let sub_expansion: Vec<String> = letters
|
||||
.iter()
|
||||
.take(matches - expansion.len() - expanded.len())
|
||||
.map(|s| prefix.clone() + s)
|
||||
.collect();
|
||||
|
||||
expanded.splice(0..0, sub_expansion);
|
||||
}
|
||||
|
||||
expansion = expansion.iter().take(matches - expanded.len()).map(|s| s.clone()).collect();
|
||||
expansion = expansion
|
||||
.iter()
|
||||
.take(matches - expanded.len())
|
||||
.map(|s| s.clone())
|
||||
.collect();
|
||||
expansion.append(&mut expanded);
|
||||
expansion
|
||||
}
|
||||
@ -61,7 +71,9 @@ impl<'a> Alphabet<'a> {
|
||||
pub fn get_alphabet(alphabet_name: &str) -> Alphabet {
|
||||
let alphabets: HashMap<&str, &str> = ALPHABETS.iter().cloned().collect();
|
||||
|
||||
alphabets.get(alphabet_name).expect(format!("Unknown alphabet: {}", alphabet_name).as_str()); // FIXME
|
||||
alphabets
|
||||
.get(alphabet_name)
|
||||
.expect(format!("Unknown alphabet: {}", alphabet_name).as_str()); // FIXME
|
||||
|
||||
Alphabet::new(alphabets[alphabet_name])
|
||||
}
|
||||
@ -71,28 +83,28 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn simple_matches () {
|
||||
fn simple_matches() {
|
||||
let alphabet = Alphabet::new("abcd");
|
||||
let hints = alphabet.hints(3);
|
||||
assert_eq!(hints, ["a", "b", "c"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn composed_matches () {
|
||||
fn composed_matches() {
|
||||
let alphabet = Alphabet::new("abcd");
|
||||
let hints = alphabet.hints(6);
|
||||
assert_eq!(hints, ["a", "b", "c", "da", "db", "dc"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn composed_matches_multiple () {
|
||||
fn composed_matches_multiple() {
|
||||
let alphabet = Alphabet::new("abcd");
|
||||
let hints = alphabet.hints(8);
|
||||
assert_eq!(hints, ["a", "b", "ca", "cb", "da", "db", "dc", "dd"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn composed_matches_max () {
|
||||
fn composed_matches_max() {
|
||||
let alphabet = Alphabet::new("ab");
|
||||
let hints = alphabet.hints(8);
|
||||
assert_eq!(hints, ["aa", "ab", "ba", "bb"]);
|
||||
|
@ -16,7 +16,9 @@ const COLORS: [(&'static str, Color); 9] = [
|
||||
pub fn get_color(color_name: &str) -> Color {
|
||||
let available_colors: HashMap<&str, Color> = COLORS.iter().cloned().collect();
|
||||
|
||||
available_colors.get(color_name).expect(format!("Unknown color: {}", color_name).as_str()); // FIXME
|
||||
available_colors
|
||||
.get(color_name)
|
||||
.expect(format!("Unknown color: {}", color_name).as_str()); // FIXME
|
||||
|
||||
available_colors[&color_name]
|
||||
}
|
||||
@ -26,7 +28,7 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn match_color () {
|
||||
fn match_color() {
|
||||
assert_eq!(get_color("green"), Color::Green);
|
||||
}
|
||||
}
|
||||
|
155
src/main.rs
155
src/main.rs
@ -1,14 +1,14 @@
|
||||
extern crate rustbox;
|
||||
extern crate clap;
|
||||
extern crate rustbox;
|
||||
|
||||
mod state;
|
||||
mod alphabets;
|
||||
mod colors;
|
||||
mod state;
|
||||
mod view;
|
||||
|
||||
use self::clap::{Arg, App};
|
||||
use std::process::Command;
|
||||
use self::clap::{App, Arg};
|
||||
use clap::crate_version;
|
||||
use std::process::Command;
|
||||
|
||||
fn exec_command(command: String) -> std::process::Output {
|
||||
let args: Vec<_> = command.split(" ").collect();
|
||||
@ -19,66 +19,92 @@ fn exec_command(command: String) -> std::process::Output {
|
||||
.expect("Couldn't run it");
|
||||
}
|
||||
|
||||
fn app_args<'a> () -> clap::ArgMatches<'a> {
|
||||
fn app_args<'a>() -> clap::ArgMatches<'a> {
|
||||
return App::new("tmux-thumbs")
|
||||
.version(crate_version!())
|
||||
.about("A lightning fast version of tmux-fingers, copy/pasting tmux like vimium/vimperator")
|
||||
.arg(Arg::with_name("alphabet")
|
||||
.help("Sets the alphabet")
|
||||
.long("alphabet")
|
||||
.short("a")
|
||||
.default_value("qwerty"))
|
||||
.arg(Arg::with_name("foreground_color")
|
||||
.help("Sets the foregroud color for matches")
|
||||
.long("fg-color")
|
||||
.default_value("green"))
|
||||
.arg(Arg::with_name("background_color")
|
||||
.help("Sets the background color for matches")
|
||||
.long("bg-color")
|
||||
.default_value("black"))
|
||||
.arg(Arg::with_name("hint_foreground_color")
|
||||
.help("Sets the foregroud color for hints")
|
||||
.long("hint-fg-color")
|
||||
.default_value("yellow"))
|
||||
.arg(Arg::with_name("hint_background_color")
|
||||
.help("Sets the background color for hints")
|
||||
.long("hint-bg-color")
|
||||
.default_value("black"))
|
||||
.arg(Arg::with_name("select_foreground_color")
|
||||
.help("Sets the foregroud color for selection")
|
||||
.long("select-fg-color")
|
||||
.default_value("blue"))
|
||||
.arg(Arg::with_name("reverse")
|
||||
.help("Reverse the order for assigned hints")
|
||||
.long("reverse")
|
||||
.short("r"))
|
||||
.arg(Arg::with_name("unique")
|
||||
.help("Don't show duplicated hints for the same match")
|
||||
.long("unique")
|
||||
.short("u"))
|
||||
.arg(Arg::with_name("position")
|
||||
.help("Hint position")
|
||||
.long("position")
|
||||
.default_value("left")
|
||||
.short("p"))
|
||||
.arg(Arg::with_name("tmux_pane")
|
||||
.help("Get this tmux pane as reference pane")
|
||||
.long("tmux-pane")
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("command")
|
||||
.help("Pick command")
|
||||
.long("command")
|
||||
.default_value("tmux set-buffer {}"))
|
||||
.arg(Arg::with_name("upcase_command")
|
||||
.help("Upcase command")
|
||||
.long("upcase-command")
|
||||
.default_value("tmux paste-buffer"))
|
||||
.arg(Arg::with_name("regexp")
|
||||
.help("Use this regexp as extra pattern to match")
|
||||
.long("regexp")
|
||||
.short("x")
|
||||
.takes_value(true)
|
||||
.multiple(true))
|
||||
.arg(
|
||||
Arg::with_name("alphabet")
|
||||
.help("Sets the alphabet")
|
||||
.long("alphabet")
|
||||
.short("a")
|
||||
.default_value("qwerty"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("foreground_color")
|
||||
.help("Sets the foregroud color for matches")
|
||||
.long("fg-color")
|
||||
.default_value("green"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("background_color")
|
||||
.help("Sets the background color for matches")
|
||||
.long("bg-color")
|
||||
.default_value("black"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("hint_foreground_color")
|
||||
.help("Sets the foregroud color for hints")
|
||||
.long("hint-fg-color")
|
||||
.default_value("yellow"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("hint_background_color")
|
||||
.help("Sets the background color for hints")
|
||||
.long("hint-bg-color")
|
||||
.default_value("black"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("select_foreground_color")
|
||||
.help("Sets the foregroud color for selection")
|
||||
.long("select-fg-color")
|
||||
.default_value("blue"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("reverse")
|
||||
.help("Reverse the order for assigned hints")
|
||||
.long("reverse")
|
||||
.short("r"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("unique")
|
||||
.help("Don't show duplicated hints for the same match")
|
||||
.long("unique")
|
||||
.short("u"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("position")
|
||||
.help("Hint position")
|
||||
.long("position")
|
||||
.default_value("left")
|
||||
.short("p"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("tmux_pane")
|
||||
.help("Get this tmux pane as reference pane")
|
||||
.long("tmux-pane")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("command")
|
||||
.help("Pick command")
|
||||
.long("command")
|
||||
.default_value("tmux set-buffer {}"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("upcase_command")
|
||||
.help("Upcase command")
|
||||
.long("upcase-command")
|
||||
.default_value("tmux paste-buffer"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("regexp")
|
||||
.help("Use this regexp as extra pattern to match")
|
||||
.long("regexp")
|
||||
.short("x")
|
||||
.takes_value(true)
|
||||
.multiple(true),
|
||||
)
|
||||
.get_matches();
|
||||
}
|
||||
|
||||
@ -98,7 +124,8 @@ fn main() {
|
||||
let background_color = colors::get_color(args.value_of("background_color").unwrap());
|
||||
let hint_foreground_color = colors::get_color(args.value_of("hint_foreground_color").unwrap());
|
||||
let hint_background_color = colors::get_color(args.value_of("hint_background_color").unwrap());
|
||||
let select_foreground_color = colors::get_color(args.value_of("select_foreground_color").unwrap());
|
||||
let select_foreground_color =
|
||||
colors::get_color(args.value_of("select_foreground_color").unwrap());
|
||||
|
||||
let command = args.value_of("command").unwrap();
|
||||
let upcase_command = args.value_of("upcase_command").unwrap();
|
||||
@ -124,7 +151,7 @@ fn main() {
|
||||
foreground_color,
|
||||
background_color,
|
||||
hint_foreground_color,
|
||||
hint_background_color
|
||||
hint_background_color,
|
||||
);
|
||||
|
||||
viewbox.present()
|
||||
@ -134,7 +161,6 @@ fn main() {
|
||||
exec_command(format!("tmux swap-pane -t {}", pane));
|
||||
};
|
||||
|
||||
|
||||
if let Some((text, paste)) = selected {
|
||||
exec_command(str::replace(command, "{}", text.as_str()));
|
||||
|
||||
@ -142,5 +168,4 @@ fn main() {
|
||||
exec_command(upcase_command.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
105
src/state.rs
105
src/state.rs
@ -1,18 +1,23 @@
|
||||
use std::collections::HashMap;
|
||||
use regex::Regex;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
|
||||
const EXCLUDE_PATTERNS: [(&'static str, &'static str); 1] = [
|
||||
("bash", r"[[:cntrl:]]\[([0-9]{1,2};)?([0-9]{1,2})?m"),
|
||||
];
|
||||
const EXCLUDE_PATTERNS: [(&'static str, &'static str); 1] =
|
||||
[("bash", r"[[:cntrl:]]\[([0-9]{1,2};)?([0-9]{1,2})?m")];
|
||||
|
||||
const PATTERNS: [(&'static str, &'static str); 10] = [
|
||||
("url", r"((https?://|git@|git://|ssh://|ftp://|file:///)[\w?=%/_.:,;~@!#$&()*+-]*)"),
|
||||
(
|
||||
"url",
|
||||
r"((https?://|git@|git://|ssh://|ftp://|file:///)[\w?=%/_.:,;~@!#$&()*+-]*)",
|
||||
),
|
||||
("diff_a", r"--- a/([^ ]+)"),
|
||||
("diff_b", r"\+\+\+ b/([^ ]+)"),
|
||||
("path", r"[^ ]+/[^ [[:cntrl:]]]+"),
|
||||
("color", r"#[0-9a-fA-F]{6}"),
|
||||
("uid", r"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"),
|
||||
(
|
||||
"uid",
|
||||
r"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}",
|
||||
),
|
||||
("sha", r"[0-9a-f]{7,40}"),
|
||||
("ip", r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"),
|
||||
("address", r"0x[0-9a-fA-F]+"),
|
||||
@ -24,12 +29,19 @@ pub struct Match<'a> {
|
||||
pub x: i32,
|
||||
pub y: i32,
|
||||
pub text: &'a str,
|
||||
pub hint: Option<String>
|
||||
pub hint: Option<String>,
|
||||
}
|
||||
|
||||
impl<'a> fmt::Debug for Match<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Match {{ x: {}, y: {}, text: {}, hint: <{}> }}", self.x, self.y, self.text, self.hint.clone().unwrap_or("<undefined>".to_string()))
|
||||
write!(
|
||||
f,
|
||||
"Match {{ x: {}, y: {}, text: {}, hint: <{}> }}",
|
||||
self.x,
|
||||
self.y,
|
||||
self.text,
|
||||
self.hint.clone().unwrap_or("<undefined>".to_string())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,27 +59,31 @@ pub struct State<'a> {
|
||||
|
||||
impl<'a> State<'a> {
|
||||
pub fn new(lines: &'a Vec<&'a str>, alphabet: &'a str, regexp: &'a Vec<&'a str>) -> State<'a> {
|
||||
State{
|
||||
State {
|
||||
lines: lines,
|
||||
alphabet: alphabet,
|
||||
regexp: regexp
|
||||
regexp: regexp,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn matches(&self, reverse: bool, unique: bool) -> Vec<Match<'a>> {
|
||||
let mut matches = Vec::new();
|
||||
|
||||
let exclude_patterns = EXCLUDE_PATTERNS.iter().map(|tuple|
|
||||
(tuple.0, Regex::new(tuple.1).unwrap())
|
||||
).collect::<Vec<_>>();
|
||||
let exclude_patterns = EXCLUDE_PATTERNS
|
||||
.iter()
|
||||
.map(|tuple| (tuple.0, Regex::new(tuple.1).unwrap()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let custom_patterns = self.regexp.iter().map(|regexp|
|
||||
("custom", Regex::new(regexp).expect("Invalid custom regexp"))
|
||||
).collect::<Vec<_>>();
|
||||
let custom_patterns = self
|
||||
.regexp
|
||||
.iter()
|
||||
.map(|regexp| ("custom", Regex::new(regexp).expect("Invalid custom regexp")))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let patterns = PATTERNS.iter().map(|tuple|
|
||||
(tuple.0, Regex::new(tuple.1).unwrap())
|
||||
).collect::<Vec<_>>();
|
||||
let patterns = PATTERNS
|
||||
.iter()
|
||||
.map(|tuple| (tuple.0, Regex::new(tuple.1).unwrap()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let all_patterns = [exclude_patterns, custom_patterns, patterns].concat();
|
||||
|
||||
@ -76,13 +92,16 @@ impl<'a> State<'a> {
|
||||
let mut offset: i32 = 0;
|
||||
|
||||
loop {
|
||||
let submatches = all_patterns.iter().filter_map(|tuple|
|
||||
match tuple.1.find_iter(chunk).nth(0) {
|
||||
let submatches = all_patterns
|
||||
.iter()
|
||||
.filter_map(|tuple| match tuple.1.find_iter(chunk).nth(0) {
|
||||
Some(m) => Some((tuple.0, tuple.1.clone(), m)),
|
||||
None => None
|
||||
}
|
||||
).collect::<Vec<_>>();
|
||||
let first_match_option = submatches.iter().min_by(|x, y| x.2.start().cmp(&y.2.start()));
|
||||
None => None,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let first_match_option = submatches
|
||||
.iter()
|
||||
.min_by(|x, y| x.2.start().cmp(&y.2.start()));
|
||||
|
||||
if let Some(first_match) = first_match_option {
|
||||
let (name, pattern, matching) = first_match;
|
||||
@ -97,17 +116,16 @@ impl<'a> State<'a> {
|
||||
|
||||
// Never hint or broke bash color sequences
|
||||
if *name != "bash" {
|
||||
matches.push(Match{
|
||||
matches.push(Match {
|
||||
x: offset + matching.start() as i32 + substart as i32,
|
||||
y: index as i32,
|
||||
text: subtext,
|
||||
hint: None
|
||||
hint: None,
|
||||
});
|
||||
}
|
||||
|
||||
chunk = chunk.get(matching.end()..).expect("Unknown chunk");
|
||||
offset = offset + matching.end() as i32;
|
||||
|
||||
} else {
|
||||
panic!("No matching?");
|
||||
}
|
||||
@ -164,7 +182,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn match_reverse () {
|
||||
fn match_reverse() {
|
||||
let lines = split("lorem 127.0.0.1 lorem 255.255.255.255 lorem 127.0.0.1 lorem");
|
||||
let custom = [].to_vec();
|
||||
let results = State::new(&lines, "abcd", &custom).matches(false, false);
|
||||
@ -175,7 +193,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn match_unique () {
|
||||
fn match_unique() {
|
||||
let lines = split("lorem 127.0.0.1 lorem 255.255.255.255 lorem 127.0.0.1 lorem");
|
||||
let custom = [].to_vec();
|
||||
let results = State::new(&lines, "abcd", &custom).matches(false, true);
|
||||
@ -186,7 +204,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn match_bash () {
|
||||
fn match_bash() {
|
||||
let lines = split("path: [32m/var/log/nginx.log[m\npath: [32mtest/log/nginx.log[m");
|
||||
let custom = [].to_vec();
|
||||
let results = State::new(&lines, "abcd", &custom).matches(false, false);
|
||||
@ -195,8 +213,9 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn match_paths () {
|
||||
let lines = split("Lorem /tmp/foo/bar lorem\n Lorem /var/log/bootstrap.log lorem ../log/kern.log lorem");
|
||||
fn match_paths() {
|
||||
let lines =
|
||||
split("Lorem /tmp/foo/bar lorem\n Lorem /var/log/bootstrap.log lorem ../log/kern.log lorem");
|
||||
let custom = [].to_vec();
|
||||
let results = State::new(&lines, "abcd", &custom).matches(false, false);
|
||||
|
||||
@ -204,7 +223,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn match_uids () {
|
||||
fn match_uids() {
|
||||
let lines = split("Lorem ipsum 123e4567-e89b-12d3-a456-426655440000 lorem\n Lorem lorem lorem");
|
||||
let custom = [].to_vec();
|
||||
let results = State::new(&lines, "abcd", &custom).matches(false, false);
|
||||
@ -213,7 +232,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn match_shas () {
|
||||
fn match_shas() {
|
||||
let lines = split("Lorem fd70b5695 5246ddf f924213 lorem\n Lorem 973113963b491874ab2e372ee60d4b4cb75f717c lorem");
|
||||
let custom = [].to_vec();
|
||||
let results = State::new(&lines, "abcd", &custom).matches(false, false);
|
||||
@ -222,7 +241,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn match_ips () {
|
||||
fn match_ips() {
|
||||
let lines = split("Lorem ipsum 127.0.0.1 lorem\n Lorem 255.255.10.255 lorem 127.0.0.1 lorem");
|
||||
let custom = [].to_vec();
|
||||
let results = State::new(&lines, "abcd", &custom).matches(false, false);
|
||||
@ -231,7 +250,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn match_urls () {
|
||||
fn match_urls() {
|
||||
let lines = split("Lorem ipsum https://www.rust-lang.org/tools lorem\n Lorem https://crates.io lorem https://github.io lorem ssh://github.io");
|
||||
let custom = [].to_vec();
|
||||
let results = State::new(&lines, "abcd", &custom).matches(false, false);
|
||||
@ -240,7 +259,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn match_addresses () {
|
||||
fn match_addresses() {
|
||||
let lines = split("Lorem 0xfd70b5695 0x5246ddf lorem\n Lorem 0x973113 lorem");
|
||||
let custom = [].to_vec();
|
||||
let results = State::new(&lines, "abcd", &custom).matches(false, false);
|
||||
@ -249,7 +268,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn match_hex_colors () {
|
||||
fn match_hex_colors() {
|
||||
let lines = split("Lorem #fd7b56 lorem #FF00FF\n Lorem #00fF05 lorem #abcd00 lorem #afRR00");
|
||||
let custom = [].to_vec();
|
||||
let results = State::new(&lines, "abcd", &custom).matches(false, false);
|
||||
@ -258,7 +277,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn match_process_port () {
|
||||
fn match_process_port() {
|
||||
let lines = split("Lorem 5695 52463 lorem\n Lorem 973113 lorem 99999 lorem 8888 lorem\n 23456 lorem 5432 lorem 23444");
|
||||
let custom = [].to_vec();
|
||||
let results = State::new(&lines, "abcd", &custom).matches(false, false);
|
||||
@ -267,7 +286,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn match_diff_a () {
|
||||
fn match_diff_a() {
|
||||
let lines = split("Lorem lorem\n--- a/src/main.rs");
|
||||
let custom = [].to_vec();
|
||||
let results = State::new(&lines, "abcd", &custom).matches(false, false);
|
||||
@ -277,7 +296,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn match_diff_b () {
|
||||
fn match_diff_b() {
|
||||
let lines = split("Lorem lorem\n+++ b/src/main.rs");
|
||||
let custom = [].to_vec();
|
||||
let results = State::new(&lines, "abcd", &custom).matches(false, false);
|
||||
@ -287,7 +306,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn priority () {
|
||||
fn priority() {
|
||||
let lines = split("Lorem CUSTOM-52463 lorem ISSUE-123 lorem\nLorem /var/fd70b569/9999.log 52463 lorem\n Lorem 973113 lorem 123e4567-e89b-12d3-a456-426655440000 lorem 8888 lorem\n https://crates.io/23456/fd70b569 lorem");
|
||||
let custom = ["CUSTOM-[0-9]{4,}", "ISSUE-[0-9]{3}"].to_vec();
|
||||
let results = State::new(&lines, "abcd", &custom).matches(false, false);
|
||||
|
139
src/view.rs
139
src/view.rs
@ -1,8 +1,8 @@
|
||||
use super::*;
|
||||
use rustbox::Key;
|
||||
use rustbox::{Color, OutputMode, RustBox};
|
||||
use std::char;
|
||||
use std::default::Default;
|
||||
use rustbox::{Color, RustBox, OutputMode};
|
||||
use rustbox::Key;
|
||||
use super::*;
|
||||
|
||||
pub struct View<'a> {
|
||||
state: &'a mut state::State<'a>,
|
||||
@ -14,12 +14,22 @@ pub struct View<'a> {
|
||||
foreground_color: Color,
|
||||
background_color: Color,
|
||||
hint_background_color: Color,
|
||||
hint_foreground_color: Color
|
||||
hint_foreground_color: Color,
|
||||
}
|
||||
|
||||
impl<'a> View<'a> {
|
||||
pub fn new(state: &'a mut state::State<'a>, reverse: bool, unique: bool, position: &'a str, select_foreground_color: Color, foreground_color: Color, background_color: Color, hint_foreground_color: Color, hint_background_color: Color) -> View<'a> {
|
||||
View{
|
||||
pub fn new(
|
||||
state: &'a mut state::State<'a>,
|
||||
reverse: bool,
|
||||
unique: bool,
|
||||
position: &'a str,
|
||||
select_foreground_color: Color,
|
||||
foreground_color: Color,
|
||||
background_color: Color,
|
||||
hint_foreground_color: Color,
|
||||
hint_background_color: Color,
|
||||
) -> View<'a> {
|
||||
View {
|
||||
state: state,
|
||||
skip: 0,
|
||||
reverse: reverse,
|
||||
@ -29,7 +39,7 @@ impl<'a> View<'a> {
|
||||
foreground_color: foreground_color,
|
||||
background_color: background_color,
|
||||
hint_foreground_color: hint_foreground_color,
|
||||
hint_background_color: hint_background_color
|
||||
hint_background_color: hint_background_color,
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,7 +65,12 @@ impl<'a> View<'a> {
|
||||
|
||||
let mut typed_hint: String = "".to_owned();
|
||||
let matches = self.state.matches(self.reverse, self.unique);
|
||||
let longest_hint = matches.iter().filter_map(|m| m.hint.clone()).max_by(|x, y| x.len().cmp(&y.len())).unwrap().clone();
|
||||
let longest_hint = matches
|
||||
.iter()
|
||||
.filter_map(|m| m.hint.clone())
|
||||
.max_by(|x, y| x.len().cmp(&y.len()))
|
||||
.unwrap()
|
||||
.clone();
|
||||
let mut selected;
|
||||
|
||||
self.skip = if self.reverse { matches.len() - 1 } else { 0 };
|
||||
@ -68,7 +83,14 @@ impl<'a> View<'a> {
|
||||
let clean = line.trim_end_matches(|c: char| c.is_whitespace());
|
||||
|
||||
if clean.len() > 0 {
|
||||
rustbox.print(0, index, rustbox::RB_NORMAL, Color::White, Color::Black, line);
|
||||
rustbox.print(
|
||||
0,
|
||||
index,
|
||||
rustbox::RB_NORMAL,
|
||||
Color::White,
|
||||
Color::Black,
|
||||
line,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,55 +109,78 @@ impl<'a> View<'a> {
|
||||
let extra = prefix.len() - prefix.chars().count();
|
||||
let offset = (mat.x as usize) - extra;
|
||||
|
||||
rustbox.print(offset, mat.y as usize, rustbox::RB_NORMAL, selected_color, self.background_color, mat.text);
|
||||
rustbox.print(
|
||||
offset,
|
||||
mat.y as usize,
|
||||
rustbox::RB_NORMAL,
|
||||
selected_color,
|
||||
self.background_color,
|
||||
mat.text,
|
||||
);
|
||||
|
||||
if let Some(ref hint) = mat.hint {
|
||||
let extra_position = if self.position == "left" { 0 } else { mat.text.len() - mat.hint.clone().unwrap().len() };
|
||||
let extra_position = if self.position == "left" {
|
||||
0
|
||||
} else {
|
||||
mat.text.len() - mat.hint.clone().unwrap().len()
|
||||
};
|
||||
|
||||
rustbox.print(offset + extra_position, mat.y as usize, rustbox::RB_BOLD, self.hint_foreground_color, self.hint_background_color, hint.as_str());
|
||||
rustbox.print(
|
||||
offset + extra_position,
|
||||
mat.y as usize,
|
||||
rustbox::RB_BOLD,
|
||||
self.hint_foreground_color,
|
||||
self.hint_background_color,
|
||||
hint.as_str(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
rustbox.present();
|
||||
|
||||
match rustbox.poll_event(false) {
|
||||
Ok(rustbox::Event::KeyEvent(key)) => {
|
||||
match key {
|
||||
Key::Esc => { break; }
|
||||
Key::Enter => {
|
||||
match matches.iter().enumerate().find(|&h| h.0 == self.skip) {
|
||||
Some(hm) => {
|
||||
return Some((hm.1.text.to_string(), false))
|
||||
}
|
||||
_ => panic!("Match not found?"),
|
||||
}
|
||||
}
|
||||
Key::Up => { self.prev(); }
|
||||
Key::Down => { self.next(matches.len() - 1); }
|
||||
Key::Left => { self.prev(); }
|
||||
Key::Right => { self.next(matches.len() - 1); }
|
||||
Key::Char(ch) => {
|
||||
let key = ch.to_string();
|
||||
let lower_key = key.to_lowercase();
|
||||
|
||||
typed_hint.push_str(lower_key.as_str());
|
||||
|
||||
match matches.iter().find(|mat| mat.hint == Some(typed_hint.clone())) {
|
||||
Some(mat) => {
|
||||
return Some((mat.text.to_string(), key != lower_key))
|
||||
},
|
||||
None => {
|
||||
if typed_hint.len() >= longest_hint.len() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
Ok(rustbox::Event::KeyEvent(key)) => match key {
|
||||
Key::Esc => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Key::Enter => match matches.iter().enumerate().find(|&h| h.0 == self.skip) {
|
||||
Some(hm) => return Some((hm.1.text.to_string(), false)),
|
||||
_ => panic!("Match not found?"),
|
||||
},
|
||||
Key::Up => {
|
||||
self.prev();
|
||||
}
|
||||
Key::Down => {
|
||||
self.next(matches.len() - 1);
|
||||
}
|
||||
Key::Left => {
|
||||
self.prev();
|
||||
}
|
||||
Key::Right => {
|
||||
self.next(matches.len() - 1);
|
||||
}
|
||||
Key::Char(ch) => {
|
||||
let key = ch.to_string();
|
||||
let lower_key = key.to_lowercase();
|
||||
|
||||
typed_hint.push_str(lower_key.as_str());
|
||||
|
||||
match matches
|
||||
.iter()
|
||||
.find(|mat| mat.hint == Some(typed_hint.clone()))
|
||||
{
|
||||
Some(mat) => return Some((mat.text.to_string(), key != lower_key)),
|
||||
None => {
|
||||
if typed_hint.len() >= longest_hint.len() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
Err(e) => panic!("{}", e),
|
||||
_ => { }
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user