on master help sign in
Refactor InputDescription API into Input API
commit798b742617fe789647a34611716d60e5ece9ebf8 authorEthan P <eth-p+git@hidden.email> dateSat 16 May 2020, 15:06 (6 years ago) parent11a72ab
5 files changed+137−54
src/bin/bat/app.rs+3−3 src/bin/bat/main.rs−2 src/input.rs+49−36 src/pretty_printer.rs+84−12 src/printer.rs+1−1
src/bin/bat/app.rs+3−3
@@ -257,7 +257,7 @@ impl App {
257257 let files: Option<Vec<&OsStr>> = self.matches.values_of_os("FILE").map(|vs| vs.collect());
258258
259259 if files.is_none() {
260− let input = Input::stdin().with_name(filenames_or_none.next().unwrap_or(None));
260+ let input = Input::stdin().as_file(filenames_or_none.next().unwrap_or(None));
261261 return Ok(vec![input]);
262262 }
263263 let files_or_none: Box<dyn Iterator<Item = _>> = match files {
@@ -269,9 +269,9 @@ impl App {
269269 for (filepath, provided_name) in files_or_none.zip(filenames_or_none) {
270270 if let Some(filepath) = filepath {
271271 if filepath.to_str().unwrap_or_default() == "-" {
272− file_input.push(Input::stdin().with_name(provided_name));
272+ file_input.push(Input::stdin().as_file(provided_name));
273273 } else {
274− file_input.push(Input::ordinary_file(filepath).with_name(provided_name));
274+ file_input.push(Input::ordinary_file(filepath).as_file(provided_name));
275275 }
276276 }
277277 }
src/bin/bat/main.rs−2
@@ -25,7 +25,6 @@ use assets::{assets_from_cache_or_binary, cache_dir, clear_assets, config_dir};
2525use clap::crate_version;
2626use directories::PROJECT_DIRS;
2727
28−use bat::input::InputDescription;
2928use bat::{
3029 assets::HighlightingAssets,
3130 config::Config,
@@ -124,7 +123,6 @@ pub fn list_languages(config: &Config) -> Result<()> {
124123fn theme_preview_file<'a>() -> Input<'a> {
125124 Input::from_reader(Box::new(BufReader::new(THEME_PREVIEW_DATA)))
126125 .with_name(Some("theme.rs".as_ref()))
127− .with_description(Some(InputDescription::new("")))
128126}
129127
130128pub fn list_themes(cfg: &Config) -> Result<()> {
src/input.rs+49−36
@@ -10,39 +10,48 @@ use crate::error::*;
1010/// This tells bat how to refer to the input.
1111#[derive(Clone)]
1212pub struct InputDescription {
13− name: String,
13+ pub(crate) name: String,
14+
15+ /// The input title.
16+ /// This replaces the name if provided.
17+ title: Option<String>,
18+
19+ /// The input kind.
1420 kind: Option<String>,
21+
22+ /// A summary description of the input.
23+ /// Defaults to "{kind} '{name}'"
1524 summary: Option<String>,
1625}
1726
1827impl InputDescription {
1928 /// Creates a description for an input.
20− ///
21− /// The name should describe where the input came from (e.g. "README.md")
2229 pub fn new(name: impl Into<String>) -> Self {
2330 InputDescription {
2431 name: name.into(),
32+ title: None,
2533 kind: None,
2634 summary: None,
2735 }
2836 }
2937
30− /// A description for the type of input (e.g. "File")
31− pub fn with_kind(mut self, kind: Option<impl Into<String>>) -> Self {
32− self.kind = kind.map(|kind| kind.into());
33− self
38+ pub fn set_kind(&mut self, kind: Option<String>) -> () {
39+ self.kind = kind;
3440 }
3541
36− /// A summary description of the input.
37− ///
38− /// Defaults to "{kind} '{name}'"
39− pub fn with_summary(mut self, summary: Option<impl Into<String>>) -> Self {
40− self.summary = summary.map(|summary| summary.into());
41− self
42+ pub fn set_summary(&mut self, summary: Option<String>) -> () {
43+ self.summary = summary;
44+ }
45+
46+ pub fn set_title(&mut self, title: Option<String>) -> () {
47+ self.title = title;
4248 }
4349
44− pub fn name(&self) -> &String {
45− &self.name
50+ pub fn title(&self) -> &String {
51+ match self.title.as_ref() {
52+ Some(ref title) => title,
53+ None => &self.name,
54+ }
4655 }
4756
4857 pub fn kind(&self) -> Option<&String> {
@@ -66,9 +75,7 @@ pub(crate) enum InputKind<'a> {
6675impl<'a> InputKind<'a> {
6776 pub fn description(&self) -> InputDescription {
6877 match self {
69− InputKind::OrdinaryFile(ref path) => {
70− InputDescription::new(path.to_string_lossy()).with_kind(Some("File"))
71− }
78+ InputKind::OrdinaryFile(ref path) => InputDescription::new(path.to_string_lossy()),
7279 InputKind::StdIn => InputDescription::new("STDIN"),
7380 InputKind::CustomReader(_) => InputDescription::new("READER"),
7481 }
@@ -83,7 +90,7 @@ pub(crate) struct InputMetadata {
8390pub struct Input<'a> {
8491 pub(crate) kind: InputKind<'a>,
8592 pub(crate) metadata: InputMetadata,
86− pub(crate) description: Option<InputDescription>,
93+ pub(crate) description: InputDescription,
8794}
8895
8996pub(crate) enum OpenedInputKind {
@@ -101,26 +108,29 @@ pub(crate) struct OpenedInput<'a> {
101108
102109impl<'a> Input<'a> {
103110 pub fn ordinary_file(path: &OsStr) -> Self {
111+ let kind = InputKind::OrdinaryFile(path.to_os_string());
104112 Input {
105− kind: InputKind::OrdinaryFile(path.to_os_string()),
113+ description: kind.description(),
106114 metadata: InputMetadata::default(),
107− description: None,
115+ kind,
108116 }
109117 }
110118
111119 pub fn stdin() -> Self {
120+ let kind = InputKind::StdIn;
112121 Input {
113− kind: InputKind::StdIn,
122+ description: kind.description(),
114123 metadata: InputMetadata::default(),
115− description: None,
124+ kind,
116125 }
117126 }
118127
119128 pub fn from_reader(reader: Box<dyn Read + 'a>) -> Self {
129+ let kind = InputKind::CustomReader(reader);
120130 Input {
121− kind: InputKind::CustomReader(reader),
131+ description: kind.description(),
122132 metadata: InputMetadata::default(),
123− description: None,
133+ kind,
124134 }
125135 }
126136
@@ -133,23 +143,26 @@ impl<'a> Input<'a> {
133143 }
134144
135145 pub fn with_name(mut self, provided_name: Option<&OsStr>) -> Self {
146+ match provided_name {
147+ Some(name) => self.description.name = name.to_string_lossy().to_string(),
148+ None => {}
149+ }
150+
136151 self.metadata.user_provided_name = provided_name.map(|n| n.to_owned());
137152 self
138153 }
139154
140− pub fn with_description(mut self, description: Option<InputDescription>) -> Self {
141− self.description = description;
142− self
155+ pub fn as_file(mut self, provided_name: Option<&OsStr>) -> Self {
156+ self.description.kind = Some("File".to_owned());
157+ self.with_name(provided_name)
143158 }
144159
145− pub fn description(&self) -> InputDescription {
146− if let Some(ref description) = self.description {
147− description.clone()
148− } else if let Some(ref name) = self.metadata.user_provided_name {
149− InputDescription::new(name.to_string_lossy()).with_kind(Some("File"))
150− } else {
151− self.kind.description()
152− }
160+ pub fn description(&self) -> &InputDescription {
161+ &self.description
162+ }
163+
164+ pub fn description_mut(&mut self) -> &mut InputDescription {
165+ &mut self.description
153166 }
154167
155168 pub(crate) fn open<R: BufRead + 'a>(self, stdin: R) -> Result<OpenedInput<'a>> {
src/pretty_printer.rs+84−12
@@ -9,7 +9,7 @@ use crate::{
99 config::{Config, VisibleLines},
1010 controller::Controller,
1111 error::Result,
12− input::Input,
12+ input::Input as BatInput,
1313 line_range::{HighlightedLineRanges, LineRange, LineRanges},
1414 style::{StyleComponent, StyleComponents},
1515 SyntaxMapping, WrappingMode,
@@ -61,10 +61,17 @@ impl<'a> PrettyPrinter<'a> {
6161 self
6262 }
6363
64+ /// Adds multiple inputs which should be pretty-printed
65+ pub fn inputs(&mut self, inputs: impl IntoIterator<Item = Input<'a>>) -> &mut Self {
66+ for input in inputs {
67+ self.inputs.push(input);
68+ }
69+ self
70+ }
71+
6472 /// Add a file which should be pretty-printed
6573 pub fn input_file(&mut self, path: impl AsRef<OsStr>) -> &mut Self {
66− self.inputs.push(Input::ordinary_file(path.as_ref()));
67− self
74+ self.input(Input::from_file(path).kind("File"))
6875 }
6976
7077 /// Add multiple files which should be pretty-printed
@@ -73,22 +80,20 @@ impl<'a> PrettyPrinter<'a> {
7380 I: IntoIterator<Item = P>,
7481 P: AsRef<OsStr>,
7582 {
76− for path in paths {
77− self.inputs.push(Input::ordinary_file(path.as_ref()));
78− }
79− self
83+ self.inputs(paths.into_iter().map(Input::from_file))
8084 }
8185
8286 /// Add STDIN as an input
8387 pub fn input_stdin(&mut self) -> &mut Self {
84− self.inputs.push(Input::stdin());
88+ self.inputs.push(Input::from_stdin());
8589 self
8690 }
8791
8892 /// Add STDIN as an input (with customized name)
93+ #[deprecated]
8994 pub fn input_stdin_with_name(&mut self, name: impl AsRef<OsStr>) -> &mut Self {
9095 self.inputs
91− .push(Input::stdin().with_name(Some(name.as_ref())));
96+ .push(Input::from_stdin().name(name).kind("File"));
9297 self
9398 }
9499
@@ -98,6 +103,8 @@ impl<'a> PrettyPrinter<'a> {
98103 }
99104
100105 /// Add a byte string as an input (with customized name)
106+ #[deprecated]
107+ #[allow(deprecated)]
101108 pub fn input_from_bytes_with_name(
102109 &mut self,
103110 content: &'a [u8],
@@ -108,18 +115,19 @@ impl<'a> PrettyPrinter<'a> {
108115
109116 /// Add a custom reader as an input
110117 pub fn input_from_reader<R: Read + 'a>(&mut self, reader: R) -> &mut Self {
111− self.inputs.push(Input::from_reader(Box::new(reader)));
118+ self.inputs.push(Input::from_reader(reader));
112119 self
113120 }
114121
115122 /// Add a custom reader as an input (with customized name)
123+ #[deprecated]
116124 pub fn input_from_reader_with_name<R: Read + 'a>(
117125 &mut self,
118126 reader: R,
119127 name: impl AsRef<OsStr>,
120128 ) -> &mut Self {
121129 self.inputs
122− .push(Input::from_reader(Box::new(reader)).with_name(Some(name.as_ref())));
130+ .push(Input::from_reader(reader).name(name).kind("File"));
123131 self
124132 }
125133
@@ -292,10 +300,74 @@ impl<'a> PrettyPrinter<'a> {
292300 }
293301 self.config.style_components = StyleComponents::new(&style_components);
294302
303+ // Collect the inputs to print
295304 let mut inputs: Vec<Input> = vec![];
296305 std::mem::swap(&mut inputs, &mut self.inputs);
297306
307+ // Run the controller
298308 let controller = Controller::new(&self.config, &self.assets);
299− controller.run(inputs)
309+ controller.run(inputs.into_iter().map(|i| i.into()).collect())
310+ }
311+}
312+
313+pub struct Input<'a> {
314+ input: BatInput<'a>,
315+}
316+
317+impl<'a> Input<'a> {
318+ /// A new input from a reader.
319+ pub fn from_reader<R: Read + 'a>(reader: R) -> Self {
320+ BatInput::from_reader(Box::new(reader)).into()
321+ }
322+
323+ /// A new input from a file.
324+ pub fn from_file(path: impl AsRef<OsStr>) -> Self {
325+ BatInput::ordinary_file(path.as_ref()).into()
326+ }
327+
328+ /// A new input from bytes.
329+ pub fn from_bytes(bytes: &'a [u8]) -> Self {
330+ Input::from_reader(bytes).into()
331+ }
332+
333+ /// A new input from STDIN.
334+ pub fn from_stdin() -> Self {
335+ BatInput::stdin().into()
336+ }
337+
338+ /// The filename of the input.
339+ /// This affects syntax detection and changes the default header title.
340+ pub fn name(mut self, name: impl AsRef<OsStr>) -> Self {
341+ self.input = self.input.with_name(Some(name.as_ref()));
342+ self
343+ }
344+
345+ /// The description for the type of input (e.g. "File")
346+ /// This defaults to "File" for files, and nothing for other inputs.
347+ pub fn kind(mut self, kind: impl Into<String>) -> Self {
348+ let kind = kind.into();
349+ self.input
350+ .description_mut()
351+ .set_kind(if kind.is_empty() { None } else { Some(kind) });
352+ self
353+ }
354+
355+ /// The title for the input (e.g. "http://example.com/example.txt")
356+ /// This defaults to the file name.
357+ pub fn title(mut self, title: impl Into<String>) -> Self {
358+ self.input.description_mut().set_title(Some(title.into()));
359+ self
360+ }
361+}
362+
363+impl<'a> Into<Input<'a>> for BatInput<'a> {
364+ fn into(self) -> Input<'a> {
365+ Input { input: self }
366+ }
367+}
368+
369+impl<'a> Into<BatInput<'a>> for Input<'a> {
370+ fn into(self) -> BatInput<'a> {
371+ self.input
300372 }
301373}
src/printer.rs+1−1
@@ -292,7 +292,7 @@ impl<'a> Printer for InteractivePrinter<'a> {
292292 .kind()
293293 .map(|kind| format!("{}: ", kind))
294294 .unwrap_or("".into()),
295− self.colors.filename.paint(description.name()),
295+ self.colors.filename.paint(description.title()),
296296 mode
297297 )?;
298298