Format rules with rustfmt

This commit is contained in:
Ferran Basora 2019-03-17 20:16:55 +00:00
parent c828ff39d7
commit 64f1473551
7 changed files with 279 additions and 171 deletions

1
.rustfmt.toml Normal file
View File

@ -0,0 +1 @@
tab_spaces = 2

View File

@ -9,6 +9,10 @@ rust:
- nightly
- stable
before_script:
- rustup component add rustfmt
script:
- cargo fmt --all -- --check
- cargo build
- cargo test

View File

@ -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])
}

View File

@ -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]
}

View File

@ -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();
@ -23,62 +23,88 @@ 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")
.arg(
Arg::with_name("alphabet")
.help("Sets the alphabet")
.long("alphabet")
.short("a")
.default_value("qwerty"))
.arg(Arg::with_name("foreground_color")
.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")
.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")
.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")
.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")
.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")
.default_value("blue"),
)
.arg(
Arg::with_name("reverse")
.help("Reverse the order for assigned hints")
.long("reverse")
.short("r"))
.arg(Arg::with_name("unique")
.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")
.short("u"),
)
.arg(
Arg::with_name("position")
.help("Hint position")
.long("position")
.default_value("left")
.short("p"))
.arg(Arg::with_name("tmux_pane")
.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")
.takes_value(true),
)
.arg(
Arg::with_name("command")
.help("Pick command")
.long("command")
.default_value("tmux set-buffer {}"))
.arg(Arg::with_name("upcase_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")
.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))
.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());
}
}
}

View File

@ -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())
)
}
}
@ -50,24 +62,28 @@ impl<'a> State<'a> {
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;
@ -101,13 +120,12 @@ impl<'a> State<'a> {
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?");
}
@ -196,7 +214,8 @@ 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");
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);

View File

@ -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,11 +14,21 @@ 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> {
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,
@ -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,43 +109,67 @@ 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))
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::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))
},
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;
@ -132,8 +178,7 @@ impl<'a> View<'a> {
}
}
_ => {}
}
}
},
Err(e) => panic!("{}", e),
_ => {}
}