mirror of
https://github.com/sharkdp/bat
synced 2024-11-16 21:25:56 +00: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 std::collections::HashSet;
|
||||
use std::env;
|
||||
use style::{OutputComponent, OutputComponents};
|
||||
use style::{OutputComponent, OutputComponents, OutputWrap};
|
||||
|
||||
#[cfg(windows)]
|
||||
use ansi_term;
|
||||
@ -86,6 +86,14 @@ impl App {
|
||||
.default_value("auto")
|
||||
.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::with_name("list-languages")
|
||||
.long("list-languages")
|
||||
@ -141,6 +149,16 @@ impl App {
|
||||
true_color: is_truecolor_terminal(),
|
||||
output_components: self.output_components()?,
|
||||
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") {
|
||||
Some("always") => true,
|
||||
Some("never") => false,
|
||||
@ -197,6 +215,7 @@ impl App {
|
||||
|
||||
pub struct Config<'a> {
|
||||
pub true_color: bool,
|
||||
pub output_wrap: OutputWrap,
|
||||
pub output_components: OutputComponents,
|
||||
pub language: Option<&'a str>,
|
||||
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 assets;
|
||||
mod decorations;
|
||||
mod diff;
|
||||
mod printer;
|
||||
mod style;
|
||||
|
220
src/printer.rs
220
src/printer.rs
@ -1,18 +1,21 @@
|
||||
use ansi_term::Style;
|
||||
use app::Config;
|
||||
use diff::{LineChange, LineChanges};
|
||||
use decorations::{Decoration, GridBorderDecoration, LineChangesDecoration, LineNumberDecoration};
|
||||
use diff::LineChanges;
|
||||
use errors::*;
|
||||
use std::boxed::Box;
|
||||
use std::io::Write;
|
||||
use std::vec::Vec;
|
||||
use style::OutputWrap;
|
||||
use syntect::highlighting;
|
||||
use terminal::as_terminal_escaped;
|
||||
use Colors;
|
||||
|
||||
const PANEL_WIDTH: usize = 7;
|
||||
|
||||
pub struct Printer<'a> {
|
||||
handle: &'a mut Write,
|
||||
colors: Colors,
|
||||
config: &'a Config<'a>,
|
||||
decorations: Vec<Box<Decoration>>,
|
||||
panel_width: usize,
|
||||
pub line_changes: Option<LineChanges>,
|
||||
}
|
||||
|
||||
@ -24,10 +27,43 @@ impl<'a> Printer<'a> {
|
||||
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 {
|
||||
panel_width,
|
||||
handle,
|
||||
colors,
|
||||
config,
|
||||
decorations,
|
||||
line_changes: None,
|
||||
}
|
||||
}
|
||||
@ -43,8 +79,10 @@ impl<'a> Printer<'a> {
|
||||
write!(
|
||||
self.handle,
|
||||
"{}{} ",
|
||||
" ".repeat(PANEL_WIDTH),
|
||||
self.colors.grid.paint("│"),
|
||||
" ".repeat(self.panel_width),
|
||||
self.colors
|
||||
.grid
|
||||
.paint(if self.panel_width > 0 { "│" } else { "" }),
|
||||
)?;
|
||||
}
|
||||
|
||||
@ -75,85 +113,123 @@ impl<'a> Printer<'a> {
|
||||
line_number: usize,
|
||||
regions: &[(highlighting::Style, &str)],
|
||||
) -> Result<()> {
|
||||
let decorations = vec![
|
||||
self.print_line_number(line_number),
|
||||
self.print_git_marker(line_number),
|
||||
self.print_line_border(),
|
||||
Some(as_terminal_escaped(
|
||||
®ions,
|
||||
self.config.true_color,
|
||||
self.config.colored_output,
|
||||
)),
|
||||
];
|
||||
let mut cursor: usize = 0;
|
||||
let mut cursor_max: usize = self.config.term_width;
|
||||
let mut panel_wrap: Option<String> = None;
|
||||
|
||||
// Line decorations.
|
||||
if self.panel_width > 0 {
|
||||
let decorations = self
|
||||
.decorations
|
||||
.iter()
|
||||
.map(|ref d| d.generate(line_number, false, self))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for deco in decorations {
|
||||
write!(self.handle, "{} ", deco.text)?;
|
||||
cursor_max -= deco.width + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Line contents.
|
||||
if self.config.output_wrap == OutputWrap::None {
|
||||
let true_color = self.config.true_color;
|
||||
let colored_output = self.config.colored_output;
|
||||
|
||||
let grid_requested = self.config.output_components.grid();
|
||||
write!(
|
||||
self.handle,
|
||||
"{}",
|
||||
decorations
|
||||
.into_iter()
|
||||
.filter_map(|dec| if grid_requested {
|
||||
Some(dec.unwrap_or_else(|| " ".to_owned()))
|
||||
} else {
|
||||
dec
|
||||
})
|
||||
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(())
|
||||
}
|
||||
|
||||
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<()> {
|
||||
let hline = "─".repeat(self.config.term_width - (PANEL_WIDTH + 1));
|
||||
let hline = format!("{}{}{}", "─".repeat(PANEL_WIDTH), grid_char, hline);
|
||||
|
||||
if self.panel_width == 0 {
|
||||
writeln!(
|
||||
self.handle,
|
||||
"{}",
|
||||
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(())
|
||||
}
|
||||
|
@ -13,6 +13,12 @@ pub enum OutputComponent {
|
||||
Plain,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
|
||||
pub enum OutputWrap {
|
||||
Character,
|
||||
None,
|
||||
}
|
||||
|
||||
impl OutputComponent {
|
||||
pub fn components(&self, interactive_terminal: bool) -> &'static [OutputComponent] {
|
||||
match *self {
|
||||
|
@ -1,5 +1,3 @@
|
||||
use std::fmt::Write;
|
||||
|
||||
use ansi_term::Colour::{Fixed, RGB};
|
||||
use ansi_term::Style;
|
||||
use syntect::highlighting::{self, FontStyle};
|
||||
@ -27,12 +25,11 @@ fn rgb2ansi(r: u8, g: u8, b: u8) -> u8 {
|
||||
}
|
||||
|
||||
pub fn as_terminal_escaped(
|
||||
v: &[(highlighting::Style, &str)],
|
||||
style: highlighting::Style,
|
||||
text: &str,
|
||||
true_color: bool,
|
||||
colored: bool,
|
||||
) -> String {
|
||||
let mut s: String = String::new();
|
||||
for &(ref style, text) in v.iter() {
|
||||
let style = if !colored {
|
||||
Style::default()
|
||||
} else {
|
||||
@ -54,10 +51,7 @@ pub fn as_terminal_escaped(
|
||||
}
|
||||
};
|
||||
|
||||
write!(s, "{}", style.paint(text)).unwrap();
|
||||
}
|
||||
|
||||
s
|
||||
style.paint(text).to_string()
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1,6 +1,6 @@
|
||||
───────┬────────────────────────────────────────────────────────────────────────
|
||||
──┬─────────────────────────────────────────────────────────────────────────────
|
||||
│ File: sample.rs
|
||||
───────┼────────────────────────────────────────────────────────────────────────
|
||||
──┼─────────────────────────────────────────────────────────────────────────────
|
||||
│ struct Rectangle {
|
||||
│ width: u32,
|
||||
│ height: u32,
|
||||
@ -22,4 +22,4 @@
|
||||
+ │ fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||
+ │ (rectangle.width + rectangle.height) * 2
|
||||
+ │ }
|
||||
───────┴────────────────────────────────────────────────────────────────────────
|
||||
──┴─────────────────────────────────────────────────────────────────────────────
|
||||
|
@ -19,4 +19,4 @@
|
||||
+ │ fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||
+ │ (rectangle.width + rectangle.height) * 2
|
||||
+ │ }
|
||||
───────┴────────────────────────────────────────────────────────────────────────
|
||||
──┴─────────────────────────────────────────────────────────────────────────────
|
||||
|
@ -1,6 +1,6 @@
|
||||
───────┬────────────────────────────────────────────────────────────────────────
|
||||
─────┬──────────────────────────────────────────────────────────────────────────
|
||||
│ File: sample.rs
|
||||
───────┼────────────────────────────────────────────────────────────────────────
|
||||
─────┼──────────────────────────────────────────────────────────────────────────
|
||||
1 │ struct Rectangle {
|
||||
2 │ width: u32,
|
||||
3 │ height: u32,
|
||||
@ -22,4 +22,4 @@
|
||||
19 │ fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||
20 │ (rectangle.width + rectangle.height) * 2
|
||||
21 │ }
|
||||
───────┴────────────────────────────────────────────────────────────────────────
|
||||
─────┴──────────────────────────────────────────────────────────────────────────
|
||||
|
@ -1,25 +1,25 @@
|
||||
───────┬────────────────────────────────────────────────────────────────────────
|
||||
│ File: sample.rs
|
||||
───────┼────────────────────────────────────────────────────────────────────────
|
||||
│ struct Rectangle {
|
||||
│ width: u32,
|
||||
│ height: u32,
|
||||
│ }
|
||||
│
|
||||
│ fn main() {
|
||||
│ let rect1 = Rectangle { width: 30, height: 50 };
|
||||
│
|
||||
│ println!(
|
||||
│ "The perimeter of the rectangle is {} pixels.",
|
||||
│ perimeter(&rect1)
|
||||
│ );
|
||||
│ }
|
||||
│
|
||||
│ fn area(rectangle: &Rectangle) -> u32 {
|
||||
│ rectangle.width * rectangle.height
|
||||
│ }
|
||||
│
|
||||
│ fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||
│ (rectangle.width + rectangle.height) * 2
|
||||
│ }
|
||||
───────┴────────────────────────────────────────────────────────────────────────
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
File: sample.rs
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
struct Rectangle {
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let rect1 = Rectangle { width: 30, height: 50 };
|
||||
|
||||
println!(
|
||||
"The perimeter of the rectangle is {} pixels.",
|
||||
perimeter(&rect1)
|
||||
);
|
||||
}
|
||||
|
||||
fn area(rectangle: &Rectangle) -> u32 {
|
||||
rectangle.width * rectangle.height
|
||||
}
|
||||
|
||||
fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||
(rectangle.width + rectangle.height) * 2
|
||||
}
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
|
@ -19,4 +19,4 @@
|
||||
19 │ fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||
20 │ (rectangle.width + rectangle.height) * 2
|
||||
21 │ }
|
||||
───────┴────────────────────────────────────────────────────────────────────────
|
||||
─────┴──────────────────────────────────────────────────────────────────────────
|
||||
|
@ -1,22 +1,22 @@
|
||||
│ struct Rectangle {
|
||||
│ width: u32,
|
||||
│ height: u32,
|
||||
│ }
|
||||
│
|
||||
│ fn main() {
|
||||
│ let rect1 = Rectangle { width: 30, height: 50 };
|
||||
│
|
||||
│ println!(
|
||||
│ "The perimeter of the rectangle is {} pixels.",
|
||||
│ perimeter(&rect1)
|
||||
│ );
|
||||
│ }
|
||||
│
|
||||
│ fn area(rectangle: &Rectangle) -> u32 {
|
||||
│ rectangle.width * rectangle.height
|
||||
│ }
|
||||
│
|
||||
│ fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||
│ (rectangle.width + rectangle.height) * 2
|
||||
│ }
|
||||
───────┴────────────────────────────────────────────────────────────────────────
|
||||
struct Rectangle {
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let rect1 = Rectangle { width: 30, height: 50 };
|
||||
|
||||
println!(
|
||||
"The perimeter of the rectangle is {} pixels.",
|
||||
perimeter(&rect1)
|
||||
);
|
||||
}
|
||||
|
||||
fn area(rectangle: &Rectangle) -> u32 {
|
||||
rectangle.width * rectangle.height
|
||||
}
|
||||
|
||||
fn perimeter(rectangle: &Rectangle) -> u32 {
|
||||
(rectangle.width + rectangle.height) * 2
|
||||
}
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
|
Loading…
Reference in New Issue
Block a user