mirror of
https://github.com/sharkdp/bat.git
synced 2025-05-17 15:00:51 +02:00
Merge pull request #102 from eth-p/master
Added text wrapping. (Fixes #54)
This commit is contained in:
commit
2eee68599d
21
src/app.rs
21
src/app.rs
@ -4,7 +4,7 @@ use console::Term;
|
|||||||
use errors::*;
|
use errors::*;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::env;
|
use std::env;
|
||||||
use style::{OutputComponent, OutputComponents};
|
use style::{OutputComponent, OutputComponents, OutputWrap};
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use ansi_term;
|
use ansi_term;
|
||||||
@ -86,6 +86,14 @@ impl App {
|
|||||||
.default_value("auto")
|
.default_value("auto")
|
||||||
.help("When to use the pager"),
|
.help("When to use the pager"),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("wrap")
|
||||||
|
.long("wrap")
|
||||||
|
.takes_value(true)
|
||||||
|
.possible_values(&["character", "never"])
|
||||||
|
.default_value("character")
|
||||||
|
.help("When to wrap text"),
|
||||||
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("list-languages")
|
Arg::with_name("list-languages")
|
||||||
.long("list-languages")
|
.long("list-languages")
|
||||||
@ -141,6 +149,16 @@ impl App {
|
|||||||
true_color: is_truecolor_terminal(),
|
true_color: is_truecolor_terminal(),
|
||||||
output_components: self.output_components()?,
|
output_components: self.output_components()?,
|
||||||
language: self.matches.value_of("language"),
|
language: self.matches.value_of("language"),
|
||||||
|
output_wrap: if !self.interactive_output {
|
||||||
|
// We don't have the tty width when piping to another program.
|
||||||
|
// There's no point in wrapping when this is the case.
|
||||||
|
OutputWrap::None
|
||||||
|
} else {
|
||||||
|
match self.matches.value_of("wrap") {
|
||||||
|
Some("character") => OutputWrap::Character,
|
||||||
|
Some("never") | _ => OutputWrap::None,
|
||||||
|
}
|
||||||
|
},
|
||||||
colored_output: match self.matches.value_of("color") {
|
colored_output: match self.matches.value_of("color") {
|
||||||
Some("always") => true,
|
Some("always") => true,
|
||||||
Some("never") => false,
|
Some("never") => false,
|
||||||
@ -197,6 +215,7 @@ impl App {
|
|||||||
|
|
||||||
pub struct Config<'a> {
|
pub struct Config<'a> {
|
||||||
pub true_color: bool,
|
pub true_color: bool,
|
||||||
|
pub output_wrap: OutputWrap,
|
||||||
pub output_components: OutputComponents,
|
pub output_components: OutputComponents,
|
||||||
pub language: Option<&'a str>,
|
pub language: Option<&'a str>,
|
||||||
pub colored_output: bool,
|
pub colored_output: bool,
|
||||||
|
154
src/decorations.rs
Normal file
154
src/decorations.rs
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
use ansi_term::Style;
|
||||||
|
use diff::LineChange;
|
||||||
|
use printer::Printer;
|
||||||
|
use Colors;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct DecorationText {
|
||||||
|
pub width: usize,
|
||||||
|
pub text: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Decoration {
|
||||||
|
fn generate(&self, line_number: usize, continuation: bool, printer: &Printer)
|
||||||
|
-> DecorationText;
|
||||||
|
fn width(&self) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Line number decoration.
|
||||||
|
pub struct LineNumberDecoration {
|
||||||
|
color: Style,
|
||||||
|
cached_wrap: DecorationText,
|
||||||
|
cached_wrap_invalid_at: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LineNumberDecoration {
|
||||||
|
pub fn new(colors: &Colors) -> Self {
|
||||||
|
LineNumberDecoration {
|
||||||
|
color: colors.line_number,
|
||||||
|
cached_wrap_invalid_at: 10000,
|
||||||
|
cached_wrap: DecorationText {
|
||||||
|
text: colors.line_number.paint(" ".repeat(4)).to_string(),
|
||||||
|
width: 4,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Decoration for LineNumberDecoration {
|
||||||
|
fn generate(
|
||||||
|
&self,
|
||||||
|
line_number: usize,
|
||||||
|
continuation: bool,
|
||||||
|
_printer: &Printer,
|
||||||
|
) -> DecorationText {
|
||||||
|
if continuation {
|
||||||
|
if line_number > self.cached_wrap_invalid_at {
|
||||||
|
let new_width = self.cached_wrap.width + 1;
|
||||||
|
return DecorationText {
|
||||||
|
text: self.color.paint(" ".repeat(new_width)).to_string(),
|
||||||
|
width: new_width,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
self.cached_wrap.clone()
|
||||||
|
} else {
|
||||||
|
let plain: String = format!("{:4}", line_number);
|
||||||
|
DecorationText {
|
||||||
|
width: plain.len(),
|
||||||
|
text: self.color.paint(plain).to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn width(&self) -> usize {
|
||||||
|
4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Line changes decoration.
|
||||||
|
pub struct LineChangesDecoration {
|
||||||
|
cached_none: DecorationText,
|
||||||
|
cached_added: DecorationText,
|
||||||
|
cached_removed_above: DecorationText,
|
||||||
|
cached_removed_below: DecorationText,
|
||||||
|
cached_modified: DecorationText,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LineChangesDecoration {
|
||||||
|
#[inline]
|
||||||
|
fn generate_cached(style: Style, text: &str) -> DecorationText {
|
||||||
|
DecorationText {
|
||||||
|
text: style.paint(text).to_string(),
|
||||||
|
width: text.chars().count(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(colors: &Colors) -> Self {
|
||||||
|
LineChangesDecoration {
|
||||||
|
cached_none: Self::generate_cached(Style::default(), " "),
|
||||||
|
cached_added: Self::generate_cached(colors.git_added, "+"),
|
||||||
|
cached_removed_above: Self::generate_cached(colors.git_removed, "‾"),
|
||||||
|
cached_removed_below: Self::generate_cached(colors.git_removed, "_"),
|
||||||
|
cached_modified: Self::generate_cached(colors.git_modified, "~"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Decoration for LineChangesDecoration {
|
||||||
|
fn generate(
|
||||||
|
&self,
|
||||||
|
line_number: usize,
|
||||||
|
continuation: bool,
|
||||||
|
printer: &Printer,
|
||||||
|
) -> DecorationText {
|
||||||
|
if !continuation {
|
||||||
|
if let Some(ref changes) = printer.line_changes {
|
||||||
|
return match changes.get(&(line_number as u32)) {
|
||||||
|
Some(&LineChange::Added) => self.cached_added.clone(),
|
||||||
|
Some(&LineChange::RemovedAbove) => self.cached_removed_above.clone(),
|
||||||
|
Some(&LineChange::RemovedBelow) => self.cached_removed_below.clone(),
|
||||||
|
Some(&LineChange::Modified) => self.cached_modified.clone(),
|
||||||
|
_ => self.cached_none.clone(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.cached_none.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn width(&self) -> usize {
|
||||||
|
self.cached_none.width
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grid border decoration.
|
||||||
|
pub struct GridBorderDecoration {
|
||||||
|
cached: DecorationText,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GridBorderDecoration {
|
||||||
|
pub fn new(colors: &Colors) -> Self {
|
||||||
|
GridBorderDecoration {
|
||||||
|
cached: DecorationText {
|
||||||
|
text: colors.grid.paint("│").to_string(),
|
||||||
|
width: 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Decoration for GridBorderDecoration {
|
||||||
|
fn generate(
|
||||||
|
&self,
|
||||||
|
_line_number: usize,
|
||||||
|
_continuation: bool,
|
||||||
|
_printer: &Printer,
|
||||||
|
) -> DecorationText {
|
||||||
|
self.cached.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn width(&self) -> usize {
|
||||||
|
self.cached.width
|
||||||
|
}
|
||||||
|
}
|
@ -19,6 +19,7 @@ extern crate syntect;
|
|||||||
|
|
||||||
mod app;
|
mod app;
|
||||||
mod assets;
|
mod assets;
|
||||||
|
mod decorations;
|
||||||
mod diff;
|
mod diff;
|
||||||
mod printer;
|
mod printer;
|
||||||
mod style;
|
mod style;
|
||||||
|
234
src/printer.rs
234
src/printer.rs
@ -1,18 +1,21 @@
|
|||||||
use ansi_term::Style;
|
|
||||||
use app::Config;
|
use app::Config;
|
||||||
use diff::{LineChange, LineChanges};
|
use decorations::{Decoration, GridBorderDecoration, LineChangesDecoration, LineNumberDecoration};
|
||||||
|
use diff::LineChanges;
|
||||||
use errors::*;
|
use errors::*;
|
||||||
|
use std::boxed::Box;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
use std::vec::Vec;
|
||||||
|
use style::OutputWrap;
|
||||||
use syntect::highlighting;
|
use syntect::highlighting;
|
||||||
use terminal::as_terminal_escaped;
|
use terminal::as_terminal_escaped;
|
||||||
use Colors;
|
use Colors;
|
||||||
|
|
||||||
const PANEL_WIDTH: usize = 7;
|
|
||||||
|
|
||||||
pub struct Printer<'a> {
|
pub struct Printer<'a> {
|
||||||
handle: &'a mut Write,
|
handle: &'a mut Write,
|
||||||
colors: Colors,
|
colors: Colors,
|
||||||
config: &'a Config<'a>,
|
config: &'a Config<'a>,
|
||||||
|
decorations: Vec<Box<Decoration>>,
|
||||||
|
panel_width: usize,
|
||||||
pub line_changes: Option<LineChanges>,
|
pub line_changes: Option<LineChanges>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,10 +27,43 @@ impl<'a> Printer<'a> {
|
|||||||
Colors::plain()
|
Colors::plain()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Create decorations.
|
||||||
|
let mut decorations: Vec<Box<Decoration>> = Vec::new();
|
||||||
|
|
||||||
|
if config.output_components.numbers() {
|
||||||
|
decorations.push(Box::new(LineNumberDecoration::new(&colors)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.output_components.changes() {
|
||||||
|
decorations.push(Box::new(LineChangesDecoration::new(&colors)));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut panel_width: usize =
|
||||||
|
decorations.len() + decorations.iter().fold(0, |a, x| a + x.width());
|
||||||
|
|
||||||
|
// The grid border decoration isn't added until after the panel_width calculation, since the
|
||||||
|
// print_horizontal_line, print_header, and print_footer functions all assume the panel
|
||||||
|
// width is without the grid border.
|
||||||
|
if config.output_components.grid() && decorations.len() > 0 {
|
||||||
|
decorations.push(Box::new(GridBorderDecoration::new(&colors)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable the panel if the terminal is too small (i.e. can't fit 5 characters with the
|
||||||
|
// panel showing).
|
||||||
|
if config.term_width
|
||||||
|
< (decorations.len() + decorations.iter().fold(0, |a, x| a + x.width())) + 5
|
||||||
|
{
|
||||||
|
decorations.clear();
|
||||||
|
panel_width = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create printer.
|
||||||
Printer {
|
Printer {
|
||||||
|
panel_width,
|
||||||
handle,
|
handle,
|
||||||
colors,
|
colors,
|
||||||
config,
|
config,
|
||||||
|
decorations,
|
||||||
line_changes: None,
|
line_changes: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -43,8 +79,10 @@ impl<'a> Printer<'a> {
|
|||||||
write!(
|
write!(
|
||||||
self.handle,
|
self.handle,
|
||||||
"{}{} ",
|
"{}{} ",
|
||||||
" ".repeat(PANEL_WIDTH),
|
" ".repeat(self.panel_width),
|
||||||
self.colors.grid.paint("│"),
|
self.colors
|
||||||
|
.grid
|
||||||
|
.paint(if self.panel_width > 0 { "│" } else { "" }),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,85 +113,123 @@ impl<'a> Printer<'a> {
|
|||||||
line_number: usize,
|
line_number: usize,
|
||||||
regions: &[(highlighting::Style, &str)],
|
regions: &[(highlighting::Style, &str)],
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let decorations = vec![
|
let mut cursor: usize = 0;
|
||||||
self.print_line_number(line_number),
|
let mut cursor_max: usize = self.config.term_width;
|
||||||
self.print_git_marker(line_number),
|
let mut panel_wrap: Option<String> = None;
|
||||||
self.print_line_border(),
|
|
||||||
Some(as_terminal_escaped(
|
|
||||||
®ions,
|
|
||||||
self.config.true_color,
|
|
||||||
self.config.colored_output,
|
|
||||||
)),
|
|
||||||
];
|
|
||||||
|
|
||||||
let grid_requested = self.config.output_components.grid();
|
// Line decorations.
|
||||||
write!(
|
if self.panel_width > 0 {
|
||||||
self.handle,
|
let decorations = self
|
||||||
"{}",
|
.decorations
|
||||||
decorations
|
.iter()
|
||||||
.into_iter()
|
.map(|ref d| d.generate(line_number, false, self))
|
||||||
.filter_map(|dec| if grid_requested {
|
.collect::<Vec<_>>();
|
||||||
Some(dec.unwrap_or_else(|| " ".to_owned()))
|
|
||||||
} else {
|
for deco in decorations {
|
||||||
dec
|
write!(self.handle, "{} ", deco.text)?;
|
||||||
})
|
cursor_max -= deco.width + 1;
|
||||||
.collect::<Vec<_>>()
|
}
|
||||||
.join(" ")
|
}
|
||||||
)?;
|
|
||||||
|
// Line contents.
|
||||||
|
if self.config.output_wrap == OutputWrap::None {
|
||||||
|
let true_color = self.config.true_color;
|
||||||
|
let colored_output = self.config.colored_output;
|
||||||
|
|
||||||
|
write!(
|
||||||
|
self.handle,
|
||||||
|
"{}",
|
||||||
|
regions
|
||||||
|
.iter()
|
||||||
|
.map(|&(style, text)| as_terminal_escaped(
|
||||||
|
style,
|
||||||
|
text,
|
||||||
|
true_color,
|
||||||
|
colored_output,
|
||||||
|
))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("")
|
||||||
|
)?;
|
||||||
|
} else {
|
||||||
|
for &(style, text) in regions.iter() {
|
||||||
|
let text = text.trim_right_matches(|c| c == '\r' || c == '\n');
|
||||||
|
let mut chars = text.chars();
|
||||||
|
let mut remaining = text.chars().count();
|
||||||
|
|
||||||
|
while remaining > 0 {
|
||||||
|
let available = cursor_max - cursor;
|
||||||
|
|
||||||
|
// It fits.
|
||||||
|
if remaining <= available {
|
||||||
|
let text = chars.by_ref().take(remaining).collect::<String>();
|
||||||
|
cursor += remaining;
|
||||||
|
|
||||||
|
write!(
|
||||||
|
self.handle,
|
||||||
|
"{}",
|
||||||
|
as_terminal_escaped(
|
||||||
|
style,
|
||||||
|
&*text,
|
||||||
|
self.config.true_color,
|
||||||
|
self.config.colored_output,
|
||||||
|
)
|
||||||
|
)?;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate wrap padding if not already generated.
|
||||||
|
if panel_wrap.is_none() {
|
||||||
|
panel_wrap = if self.panel_width > 0 {
|
||||||
|
Some(format!(
|
||||||
|
"{} ",
|
||||||
|
self.decorations
|
||||||
|
.iter()
|
||||||
|
.map(|ref d| d.generate(line_number, true, self).text)
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(" ")
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Some("".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// It wraps.
|
||||||
|
let text = chars.by_ref().take(available).collect::<String>();
|
||||||
|
cursor = 0;
|
||||||
|
remaining -= available;
|
||||||
|
|
||||||
|
write!(
|
||||||
|
self.handle,
|
||||||
|
"{}\n{}",
|
||||||
|
as_terminal_escaped(
|
||||||
|
style,
|
||||||
|
&*text,
|
||||||
|
self.config.true_color,
|
||||||
|
self.config.colored_output,
|
||||||
|
),
|
||||||
|
panel_wrap.clone().unwrap()
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(self.handle, "\n")?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_line_number(&self, line_number: usize) -> Option<String> {
|
|
||||||
if self.config.output_components.numbers() {
|
|
||||||
Some(
|
|
||||||
self.colors
|
|
||||||
.line_number
|
|
||||||
.paint(format!("{:4}", line_number))
|
|
||||||
.to_string(),
|
|
||||||
)
|
|
||||||
} else if self.config.output_components.grid() {
|
|
||||||
Some(" ".to_owned())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn print_git_marker(&self, line_number: usize) -> Option<String> {
|
|
||||||
if self.config.output_components.changes() {
|
|
||||||
Some(
|
|
||||||
if let Some(ref changes) = self.line_changes {
|
|
||||||
match changes.get(&(line_number as u32)) {
|
|
||||||
Some(&LineChange::Added) => self.colors.git_added.paint("+"),
|
|
||||||
Some(&LineChange::RemovedAbove) => self.colors.git_removed.paint("‾"),
|
|
||||||
Some(&LineChange::RemovedBelow) => self.colors.git_removed.paint("_"),
|
|
||||||
Some(&LineChange::Modified) => self.colors.git_modified.paint("~"),
|
|
||||||
_ => Style::default().paint(" "),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Style::default().paint(" ")
|
|
||||||
}.to_string(),
|
|
||||||
)
|
|
||||||
} else if self.config.output_components.grid() {
|
|
||||||
Some(" ".to_owned())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn print_line_border(&self) -> Option<String> {
|
|
||||||
if self.config.output_components.grid() {
|
|
||||||
Some(self.colors.grid.paint("│").to_string())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn print_horizontal_line(&mut self, grid_char: char) -> Result<()> {
|
fn print_horizontal_line(&mut self, grid_char: char) -> Result<()> {
|
||||||
let hline = "─".repeat(self.config.term_width - (PANEL_WIDTH + 1));
|
if self.panel_width == 0 {
|
||||||
let hline = format!("{}{}{}", "─".repeat(PANEL_WIDTH), grid_char, hline);
|
writeln!(
|
||||||
|
self.handle,
|
||||||
writeln!(self.handle, "{}", self.colors.grid.paint(hline))?;
|
"{}",
|
||||||
|
self.colors.grid.paint("─".repeat(self.config.term_width))
|
||||||
|
)?;
|
||||||
|
} else {
|
||||||
|
let hline = "─".repeat(self.config.term_width - (self.panel_width + 1));
|
||||||
|
let hline = format!("{}{}{}", "─".repeat(self.panel_width), grid_char, hline);
|
||||||
|
writeln!(self.handle, "{}", self.colors.grid.paint(hline))?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,12 @@ pub enum OutputComponent {
|
|||||||
Plain,
|
Plain,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
|
||||||
|
pub enum OutputWrap {
|
||||||
|
Character,
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
impl OutputComponent {
|
impl OutputComponent {
|
||||||
pub fn components(&self, interactive_terminal: bool) -> &'static [OutputComponent] {
|
pub fn components(&self, interactive_terminal: bool) -> &'static [OutputComponent] {
|
||||||
match *self {
|
match *self {
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
use std::fmt::Write;
|
|
||||||
|
|
||||||
use ansi_term::Colour::{Fixed, RGB};
|
use ansi_term::Colour::{Fixed, RGB};
|
||||||
use ansi_term::Style;
|
use ansi_term::Style;
|
||||||
use syntect::highlighting::{self, FontStyle};
|
use syntect::highlighting::{self, FontStyle};
|
||||||
@ -27,37 +25,33 @@ fn rgb2ansi(r: u8, g: u8, b: u8) -> u8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_terminal_escaped(
|
pub fn as_terminal_escaped(
|
||||||
v: &[(highlighting::Style, &str)],
|
style: highlighting::Style,
|
||||||
|
text: &str,
|
||||||
true_color: bool,
|
true_color: bool,
|
||||||
colored: bool,
|
colored: bool,
|
||||||
) -> String {
|
) -> String {
|
||||||
let mut s: String = String::new();
|
let style = if !colored {
|
||||||
for &(ref style, text) in v.iter() {
|
Style::default()
|
||||||
let style = if !colored {
|
} else {
|
||||||
Style::default()
|
let color = if true_color {
|
||||||
|
RGB(style.foreground.r, style.foreground.g, style.foreground.b)
|
||||||
} else {
|
} else {
|
||||||
let color = if true_color {
|
let ansi = rgb2ansi(style.foreground.r, style.foreground.g, style.foreground.b);
|
||||||
RGB(style.foreground.r, style.foreground.g, style.foreground.b)
|
Fixed(ansi)
|
||||||
} else {
|
|
||||||
let ansi = rgb2ansi(style.foreground.r, style.foreground.g, style.foreground.b);
|
|
||||||
Fixed(ansi)
|
|
||||||
};
|
|
||||||
|
|
||||||
if style.font_style.contains(FontStyle::BOLD) {
|
|
||||||
color.bold()
|
|
||||||
} else if style.font_style.contains(FontStyle::UNDERLINE) {
|
|
||||||
color.underline()
|
|
||||||
} else if style.font_style.contains(FontStyle::ITALIC) {
|
|
||||||
color.italic()
|
|
||||||
} else {
|
|
||||||
color.normal()
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
write!(s, "{}", style.paint(text)).unwrap();
|
if style.font_style.contains(FontStyle::BOLD) {
|
||||||
}
|
color.bold()
|
||||||
|
} else if style.font_style.contains(FontStyle::UNDERLINE) {
|
||||||
|
color.underline()
|
||||||
|
} else if style.font_style.contains(FontStyle::ITALIC) {
|
||||||
|
color.italic()
|
||||||
|
} else {
|
||||||
|
color.normal()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
s
|
style.paint(text).to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1,25 +1,25 @@
|
|||||||
───────┬────────────────────────────────────────────────────────────────────────
|
──┬─────────────────────────────────────────────────────────────────────────────
|
||||||
│ File: sample.rs
|
│ File: sample.rs
|
||||||
───────┼────────────────────────────────────────────────────────────────────────
|
──┼─────────────────────────────────────────────────────────────────────────────
|
||||||
│ struct Rectangle {
|
│ struct Rectangle {
|
||||||
│ width: u32,
|
│ width: u32,
|
||||||
│ height: u32,
|
│ height: u32,
|
||||||
│ }
|
│ }
|
||||||
│
|
│
|
||||||
_ │ fn main() {
|
_ │ fn main() {
|
||||||
│ let rect1 = Rectangle { width: 30, height: 50 };
|
│ let rect1 = Rectangle { width: 30, height: 50 };
|
||||||
│
|
│
|
||||||
│ println!(
|
│ println!(
|
||||||
~ │ "The perimeter of the rectangle is {} pixels.",
|
~ │ "The perimeter of the rectangle is {} pixels.",
|
||||||
~ │ perimeter(&rect1)
|
~ │ perimeter(&rect1)
|
||||||
│ );
|
│ );
|
||||||
│ }
|
│ }
|
||||||
│
|
│
|
||||||
│ fn area(rectangle: &Rectangle) -> u32 {
|
│ fn area(rectangle: &Rectangle) -> u32 {
|
||||||
│ rectangle.width * rectangle.height
|
│ rectangle.width * rectangle.height
|
||||||
│ }
|
│ }
|
||||||
+ │
|
+ │
|
||||||
+ │ fn perimeter(rectangle: &Rectangle) -> u32 {
|
+ │ fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||||
+ │ (rectangle.width + rectangle.height) * 2
|
+ │ (rectangle.width + rectangle.height) * 2
|
||||||
+ │ }
|
+ │ }
|
||||||
───────┴────────────────────────────────────────────────────────────────────────
|
──┴─────────────────────────────────────────────────────────────────────────────
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
│ struct Rectangle {
|
│ struct Rectangle {
|
||||||
│ width: u32,
|
│ width: u32,
|
||||||
│ height: u32,
|
│ height: u32,
|
||||||
│ }
|
│ }
|
||||||
│
|
│
|
||||||
_ │ fn main() {
|
_ │ fn main() {
|
||||||
│ let rect1 = Rectangle { width: 30, height: 50 };
|
│ let rect1 = Rectangle { width: 30, height: 50 };
|
||||||
│
|
│
|
||||||
│ println!(
|
│ println!(
|
||||||
~ │ "The perimeter of the rectangle is {} pixels.",
|
~ │ "The perimeter of the rectangle is {} pixels.",
|
||||||
~ │ perimeter(&rect1)
|
~ │ perimeter(&rect1)
|
||||||
│ );
|
│ );
|
||||||
│ }
|
│ }
|
||||||
│
|
│
|
||||||
│ fn area(rectangle: &Rectangle) -> u32 {
|
│ fn area(rectangle: &Rectangle) -> u32 {
|
||||||
│ rectangle.width * rectangle.height
|
│ rectangle.width * rectangle.height
|
||||||
│ }
|
│ }
|
||||||
+ │
|
+ │
|
||||||
+ │ fn perimeter(rectangle: &Rectangle) -> u32 {
|
+ │ fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||||
+ │ (rectangle.width + rectangle.height) * 2
|
+ │ (rectangle.width + rectangle.height) * 2
|
||||||
+ │ }
|
+ │ }
|
||||||
───────┴────────────────────────────────────────────────────────────────────────
|
──┴─────────────────────────────────────────────────────────────────────────────
|
||||||
|
@ -1,25 +1,25 @@
|
|||||||
───────┬────────────────────────────────────────────────────────────────────────
|
─────┬──────────────────────────────────────────────────────────────────────────
|
||||||
│ File: sample.rs
|
│ File: sample.rs
|
||||||
───────┼────────────────────────────────────────────────────────────────────────
|
─────┼──────────────────────────────────────────────────────────────────────────
|
||||||
1 │ struct Rectangle {
|
1 │ struct Rectangle {
|
||||||
2 │ width: u32,
|
2 │ width: u32,
|
||||||
3 │ height: u32,
|
3 │ height: u32,
|
||||||
4 │ }
|
4 │ }
|
||||||
5 │
|
5 │
|
||||||
6 │ fn main() {
|
6 │ fn main() {
|
||||||
7 │ let rect1 = Rectangle { width: 30, height: 50 };
|
7 │ let rect1 = Rectangle { width: 30, height: 50 };
|
||||||
8 │
|
8 │
|
||||||
9 │ println!(
|
9 │ println!(
|
||||||
10 │ "The perimeter of the rectangle is {} pixels.",
|
10 │ "The perimeter of the rectangle is {} pixels.",
|
||||||
11 │ perimeter(&rect1)
|
11 │ perimeter(&rect1)
|
||||||
12 │ );
|
12 │ );
|
||||||
13 │ }
|
13 │ }
|
||||||
14 │
|
14 │
|
||||||
15 │ fn area(rectangle: &Rectangle) -> u32 {
|
15 │ fn area(rectangle: &Rectangle) -> u32 {
|
||||||
16 │ rectangle.width * rectangle.height
|
16 │ rectangle.width * rectangle.height
|
||||||
17 │ }
|
17 │ }
|
||||||
18 │
|
18 │
|
||||||
19 │ fn perimeter(rectangle: &Rectangle) -> u32 {
|
19 │ fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||||
20 │ (rectangle.width + rectangle.height) * 2
|
20 │ (rectangle.width + rectangle.height) * 2
|
||||||
21 │ }
|
21 │ }
|
||||||
───────┴────────────────────────────────────────────────────────────────────────
|
─────┴──────────────────────────────────────────────────────────────────────────
|
||||||
|
@ -1,25 +1,25 @@
|
|||||||
───────┬────────────────────────────────────────────────────────────────────────
|
────────────────────────────────────────────────────────────────────────────────
|
||||||
│ File: sample.rs
|
File: sample.rs
|
||||||
───────┼────────────────────────────────────────────────────────────────────────
|
────────────────────────────────────────────────────────────────────────────────
|
||||||
│ struct Rectangle {
|
struct Rectangle {
|
||||||
│ width: u32,
|
width: u32,
|
||||||
│ height: u32,
|
height: u32,
|
||||||
│ }
|
}
|
||||||
│
|
|
||||||
│ fn main() {
|
fn main() {
|
||||||
│ let rect1 = Rectangle { width: 30, height: 50 };
|
let rect1 = Rectangle { width: 30, height: 50 };
|
||||||
│
|
|
||||||
│ println!(
|
println!(
|
||||||
│ "The perimeter of the rectangle is {} pixels.",
|
"The perimeter of the rectangle is {} pixels.",
|
||||||
│ perimeter(&rect1)
|
perimeter(&rect1)
|
||||||
│ );
|
);
|
||||||
│ }
|
}
|
||||||
│
|
|
||||||
│ fn area(rectangle: &Rectangle) -> u32 {
|
fn area(rectangle: &Rectangle) -> u32 {
|
||||||
│ rectangle.width * rectangle.height
|
rectangle.width * rectangle.height
|
||||||
│ }
|
}
|
||||||
│
|
|
||||||
│ fn perimeter(rectangle: &Rectangle) -> u32 {
|
fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||||
│ (rectangle.width + rectangle.height) * 2
|
(rectangle.width + rectangle.height) * 2
|
||||||
│ }
|
}
|
||||||
───────┴────────────────────────────────────────────────────────────────────────
|
────────────────────────────────────────────────────────────────────────────────
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
1 │ struct Rectangle {
|
1 │ struct Rectangle {
|
||||||
2 │ width: u32,
|
2 │ width: u32,
|
||||||
3 │ height: u32,
|
3 │ height: u32,
|
||||||
4 │ }
|
4 │ }
|
||||||
5 │
|
5 │
|
||||||
6 │ fn main() {
|
6 │ fn main() {
|
||||||
7 │ let rect1 = Rectangle { width: 30, height: 50 };
|
7 │ let rect1 = Rectangle { width: 30, height: 50 };
|
||||||
8 │
|
8 │
|
||||||
9 │ println!(
|
9 │ println!(
|
||||||
10 │ "The perimeter of the rectangle is {} pixels.",
|
10 │ "The perimeter of the rectangle is {} pixels.",
|
||||||
11 │ perimeter(&rect1)
|
11 │ perimeter(&rect1)
|
||||||
12 │ );
|
12 │ );
|
||||||
13 │ }
|
13 │ }
|
||||||
14 │
|
14 │
|
||||||
15 │ fn area(rectangle: &Rectangle) -> u32 {
|
15 │ fn area(rectangle: &Rectangle) -> u32 {
|
||||||
16 │ rectangle.width * rectangle.height
|
16 │ rectangle.width * rectangle.height
|
||||||
17 │ }
|
17 │ }
|
||||||
18 │
|
18 │
|
||||||
19 │ fn perimeter(rectangle: &Rectangle) -> u32 {
|
19 │ fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||||
20 │ (rectangle.width + rectangle.height) * 2
|
20 │ (rectangle.width + rectangle.height) * 2
|
||||||
21 │ }
|
21 │ }
|
||||||
───────┴────────────────────────────────────────────────────────────────────────
|
─────┴──────────────────────────────────────────────────────────────────────────
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
│ struct Rectangle {
|
struct Rectangle {
|
||||||
│ width: u32,
|
width: u32,
|
||||||
│ height: u32,
|
height: u32,
|
||||||
│ }
|
}
|
||||||
│
|
|
||||||
│ fn main() {
|
fn main() {
|
||||||
│ let rect1 = Rectangle { width: 30, height: 50 };
|
let rect1 = Rectangle { width: 30, height: 50 };
|
||||||
│
|
|
||||||
│ println!(
|
println!(
|
||||||
│ "The perimeter of the rectangle is {} pixels.",
|
"The perimeter of the rectangle is {} pixels.",
|
||||||
│ perimeter(&rect1)
|
perimeter(&rect1)
|
||||||
│ );
|
);
|
||||||
│ }
|
}
|
||||||
│
|
|
||||||
│ fn area(rectangle: &Rectangle) -> u32 {
|
fn area(rectangle: &Rectangle) -> u32 {
|
||||||
│ rectangle.width * rectangle.height
|
rectangle.width * rectangle.height
|
||||||
│ }
|
}
|
||||||
│
|
|
||||||
│ fn perimeter(rectangle: &Rectangle) -> u32 {
|
fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||||
│ (rectangle.width + rectangle.height) * 2
|
(rectangle.width + rectangle.height) * 2
|
||||||
│ }
|
}
|
||||||
───────┴────────────────────────────────────────────────────────────────────────
|
────────────────────────────────────────────────────────────────────────────────
|
||||||
|
Loading…
Reference in New Issue
Block a user