summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAndrew Gallant <jamslam@gmail.com>2016-09-05 18:22:12 -0400
committerAndrew Gallant <jamslam@gmail.com>2016-09-05 18:22:12 -0400
commit2bda77c414d113b3640b372afffc781a2fe56e6d (patch)
treeb82f58a9aaa65cc33fdac0154062a29e32068bdc /src
parent7a149c20fe9f7c33c6db4e7c2546505c05c7e96f (diff)
Fix deps so that others can build it.
Diffstat (limited to 'src')
-rw-r--r--src/main.rs1
-rw-r--r--src/printer.rs15
-rw-r--r--src/search.rs2
-rw-r--r--src/terminal.rs202
4 files changed, 209 insertions, 11 deletions
diff --git a/src/main.rs b/src/main.rs
index 164918a4..b01633b5 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -64,6 +64,7 @@ mod out;
mod printer;
mod search;
mod sys;
+mod terminal;
mod types;
mod walk;
diff --git a/src/printer.rs b/src/printer.rs
index bcb1f468..e5da39e9 100644
--- a/src/printer.rs
+++ b/src/printer.rs
@@ -7,6 +7,7 @@ use term::{self, Terminal};
use term::color::*;
use term::terminfo::TermInfo;
+use terminal::TerminfoTerminal;
use types::FileTypeDef;
use self::Writer::*;
@@ -265,7 +266,7 @@ impl<W: Send + io::Write> Printer<W> {
}
enum Writer<W> {
- Colored(term::TerminfoTerminal<W>),
+ Colored(TerminfoTerminal<W>),
NoColor(W),
}
@@ -289,14 +290,8 @@ impl<W: Send + io::Write> Writer<W> {
if !color || TERMINFO.is_none() {
return NoColor(wtr);
}
- // Why doesn't TERMINFO.as_ref().unwrap().clone() work?
let info = TERMINFO.clone().unwrap();
- // names: TERMINFO.as_ref().unwrap().names.clone(),
- // bools: TERMINFO.as_ref().unwrap().bools.clone(),
- // numbers: TERMINFO.as_ref().unwrap().numbers.clone(),
- // strings: TERMINFO.as_ref().unwrap().strings.clone(),
- // };
- let tt = term::TerminfoTerminal::new_with_terminfo(wtr, info);
+ let tt = TerminfoTerminal::new_with_terminfo(wtr, info);
if !tt.supports_color() {
debug!("environment doesn't support coloring");
return NoColor(tt.into_inner());
@@ -315,7 +310,7 @@ impl<W: Send + io::Write> Writer<W> {
&mut self,
mut f: F,
) -> term::Result<()>
- where F: FnMut(&mut term::TerminfoTerminal<W>) -> term::Result<()> {
+ where F: FnMut(&mut TerminfoTerminal<W>) -> term::Result<()> {
match *self {
Colored(ref mut w) => f(w),
NoColor(_) => Err(term::Error::NotSupported),
@@ -326,7 +321,7 @@ impl<W: Send + io::Write> Writer<W> {
&self,
mut f: F,
) -> bool
- where F: FnMut(&term::TerminfoTerminal<W>) -> bool {
+ where F: FnMut(&TerminfoTerminal<W>) -> bool {
match *self {
Colored(ref w) => f(w),
NoColor(_) => false,
diff --git a/src/search.rs b/src/search.rs
index 66706225..9739d51f 100644
--- a/src/search.rs
+++ b/src/search.rs
@@ -329,7 +329,7 @@ impl<'a, R: io::Read, W: Send + io::Write> Searcher<'a, R, W> {
self.count_lines(start);
self.add_line(end);
self.printer.matched(
- &self.grep.regex(), &self.path,
+ self.grep.regex(), &self.path,
&self.inp.buf, start, end, self.line_count);
self.last_printed = end;
self.after_context_remaining = self.opts.after_context;
diff --git a/src/terminal.rs b/src/terminal.rs
new file mode 100644
index 00000000..50461e74
--- /dev/null
+++ b/src/terminal.rs
@@ -0,0 +1,202 @@
+/*!
+This module contains an implementation of the `term::Terminal` trait.
+
+The actual implementation is copied almost verbatim from the `term` crate, so
+this code is under the same license (MIT/Apache).
+
+The specific reason why this is copied here is to wrap an Arc<TermInfo> instead
+of a TermInfo. This makes multithreaded sharing much more performant.
+
+N.B. This is temporary until this issue is fixed:
+https://github.com/Stebalien/term/issues/64
+*/
+
+use std::io::{self, Write};
+use std::sync::Arc;
+
+use term::{Attr, Error, Result, Terminal, color};
+use term::terminfo::TermInfo;
+use term::terminfo::parm::{Param, Variables, expand};
+
+/// A Terminal that knows how many colors it supports, with a reference to its
+/// parsed Terminfo database record.
+#[derive(Clone, Debug)]
+pub struct TerminfoTerminal<T> {
+ num_colors: u16,
+ out: T,
+ ti: Arc<TermInfo>,
+}
+
+impl<T: Write + Send> Terminal for TerminfoTerminal<T> {
+ type Output = T;
+ fn fg(&mut self, color: color::Color) -> Result<()> {
+ let color = self.dim_if_necessary(color);
+ if self.num_colors > color {
+ return apply_cap(&self.ti, "setaf", &[Param::Number(color as i32)], &mut self.out);
+ }
+ Err(Error::ColorOutOfRange)
+ }
+
+ fn bg(&mut self, color: color::Color) -> Result<()> {
+ let color = self.dim_if_necessary(color);
+ if self.num_colors > color {
+ return apply_cap(&self.ti, "setab", &[Param::Number(color as i32)], &mut self.out);
+ }
+ Err(Error::ColorOutOfRange)
+ }
+
+ fn attr(&mut self, attr: Attr) -> Result<()> {
+ match attr {
+ Attr::ForegroundColor(c) => self.fg(c),
+ Attr::BackgroundColor(c) => self.bg(c),
+ _ => apply_cap(&self.ti, cap_for_attr(attr), &[], &mut self.out),
+ }
+ }
+
+ fn supports_attr(&self, attr: Attr) -> bool {
+ match attr {
+ Attr::ForegroundColor(_) | Attr::BackgroundColor(_) => self.num_colors > 0,
+ _ => {
+ let cap = cap_for_attr(attr);
+ self.ti.strings.get(cap).is_some()
+ }
+ }
+ }
+
+ fn reset(&mut self) -> Result<()> {
+ reset(&self.ti, &mut self.out)
+ }
+
+ fn supports_reset(&self) -> bool {
+ ["sgr0", "sgr", "op"].iter().any(|&cap| self.ti.strings.get(cap).is_some())
+ }
+
+ fn supports_color(&self) -> bool {
+ self.num_colors > 0 && self.supports_reset()
+ }
+
+ fn cursor_up(&mut self) -> Result<()> {
+ apply_cap(&self.ti, "cuu1", &[], &mut self.out)
+ }
+
+ fn delete_line(&mut self) -> Result<()> {
+ apply_cap(&self.ti, "dl", &[], &mut self.out)
+ }
+
+ fn carriage_return(&mut self) -> Result<()> {
+ apply_cap(&self.ti, "cr", &[], &mut self.out)
+ }
+
+ fn get_ref(&self) -> &T {
+ &self.out
+ }
+
+ fn get_mut(&mut self) -> &mut T {
+ &mut self.out
+ }
+
+ fn into_inner(self) -> T
+ where Self: Sized
+ {
+ self.out
+ }
+}
+
+impl<T: Write + Send> TerminfoTerminal<T> {
+ /// Create a new TerminfoTerminal with the given TermInfo and Write.
+ pub fn new_with_terminfo(out: T, terminfo: Arc<TermInfo>) -> TerminfoTerminal<T> {
+ let nc = if terminfo.strings.contains_key("setaf") &&
+ terminfo.strings.contains_key("setab") {
+ terminfo.numbers.get("colors").map_or(0, |&n| n)
+ } else {
+ 0
+ };
+
+ TerminfoTerminal {
+ out: out,
+ ti: terminfo,
+ num_colors: nc,
+ }
+ }
+
+ /// Create a new TerminfoTerminal for the current environment with the given Write.
+ ///
+ /// Returns `None` when the terminfo cannot be found or parsed.
+ pub fn new(out: T) -> Option<TerminfoTerminal<T>> {
+ TermInfo::from_env().map(move |ti| {
+ TerminfoTerminal::new_with_terminfo(out, Arc::new(ti))
+ }).ok()
+ }
+
+ fn dim_if_necessary(&self, color: color::Color) -> color::Color {
+ if color >= self.num_colors && color >= 8 && color < 16 {
+ color - 8
+ } else {
+ color
+ }
+ }
+}
+
+impl<T: Write> Write for TerminfoTerminal<T> {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.out.write(buf)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ self.out.flush()
+ }
+}
+
+fn cap_for_attr(attr: Attr) -> &'static str {
+ match attr {
+ Attr::Bold => "bold",
+ Attr::Dim => "dim",
+ Attr::Italic(true) => "sitm",
+ Attr::Italic(false) => "ritm",
+ Attr::Underline(true) => "smul",
+ Attr::Underline(false) => "rmul",
+ Attr::Blink => "blink",
+ Attr::Standout(true) => "smso",
+ Attr::Standout(false) => "rmso",
+ Attr::Reverse => "rev",
+ Attr::Secure => "invis",
+ Attr::ForegroundColor(_) => "setaf",
+ Attr::BackgroundColor(_) => "setab",
+ }
+}
+
+fn apply_cap(ti: &TermInfo, cmd: &str, params: &[Param], out: &mut io::Write) -> Result<()> {
+ match ti.strings.get(cmd) {
+ Some(cmd) => {
+ match expand(cmd, params, &mut Variables::new()) {
+ Ok(s) => {
+ try!(out.write_all(&s));
+ Ok(())
+ }
+ Err(e) => Err(e.into()),
+ }
+ }
+ None => Err(Error::NotSupported),
+ }
+}
+
+fn reset(ti: &TermInfo, out: &mut io::Write) -> Result<()> {
+ // are there any terminals that have color/attrs and not sgr0?
+ // Try falling back to sgr, then op
+ let cmd = match [("sgr0", &[] as &[Param]), ("sgr", &[Param::Number(0)]), ("op", &[])]
+ .iter()
+ .filter_map(|&(cap, params)| {
+ ti.strings.get(cap).map(|c| (c, params))
+ })
+ .next() {
+ Some((op, params)) => {
+ match expand(op, params, &mut Variables::new()) {
+ Ok(cmd) => cmd,
+ Err(e) => return Err(e.into()),
+ }
+ }
+ None => return Err(Error::NotSupported),
+ };
+ try!(out.write_all(&cmd));
+ Ok(())
+}