summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanilo Bargen <mail@dbrgn.ch>2018-09-16 00:42:41 +0200
committerDanilo Bargen <mail@dbrgn.ch>2018-09-16 00:42:41 +0200
commit278a2bbac9ea8434f546df017fc935e1d4013200 (patch)
treed08d2d1b4e25cd373f46bdaf5e41e6d952f76388
parent9e86f2ee73d84a1d992c5d1dcdbf7305c4dd6a1f (diff)
parentf3c80ad744cd7784cdc1645eeb382a382e10f5cc (diff)
Merge pull request #43 from Voultapher/tealdeer
-rw-r--r--Cargo.lock7
-rw-r--r--Cargo.toml1
-rw-r--r--README.md70
-rw-r--r--bash_tealdeer2
-rw-r--r--screenshot-custom.pngbin0 -> 60027 bytes
-rw-r--r--screenshot-default.pngbin0 -> 58268 bytes
-rw-r--r--screenshot.pngbin60230 -> 0 bytes
-rw-r--r--src/config.rs255
-rw-r--r--src/error.rs1
-rw-r--r--src/formatter.rs65
-rw-r--r--src/main.rs85
-rw-r--r--tests/config.toml17
-rw-r--r--tests/inkscape-default.expected (renamed from tests/inkscape.expected)2
-rw-r--r--tests/inkscape-v1.md2
-rw-r--r--tests/inkscape-v2.md2
-rw-r--r--tests/inkscape-with-config.expected28
-rw-r--r--tests/lib.rs59
17 files changed, 540 insertions, 56 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 3f8a7d9..13e8dfd 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -136,7 +136,7 @@ dependencies = [
"semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
- "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -672,6 +672,7 @@ dependencies = [
"tar 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)",
"tempdir 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"walkdir 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"xdg 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -724,7 +725,7 @@ dependencies = [
[[package]]
name = "toml"
-version = "0.4.5"
+version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -937,7 +938,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
"checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963"
"checksum time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "a15375f1df02096fb3317256ce2cee6a1f42fc84ea5ad5fc8c421cfe40c73098"
-"checksum toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7540f4ffc193e0d3c94121edb19b055670d369f77d5804db11ae053a45b6e7e"
+"checksum toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a0263c6c02c4db6c8f7681f9fd35e90de799ebd4cfdeab77a38f4ff6b3d8c0d9"
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
"checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f"
"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
diff --git a/Cargo.toml b/Cargo.toml
index 619d888..f2c142b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -25,6 +25,7 @@ serde = "1.0.21"
serde_derive = "1.0.21"
tar = "0.4.14"
time = "0.1.38"
+toml = "0.4.6"
walkdir = "2.0.1"
xdg = "2.1.0"
diff --git a/README.md b/README.md
index 4c3a527..4e959a7 100644
--- a/README.md
+++ b/README.md
@@ -9,13 +9,14 @@
A very fast implementation of [tldr](https://github.com/tldr-pages/tldr) in
Rust: Simplified, example based and community-driven man pages.
-![screenshot](screenshot.png)
+<img src="screenshot-default.png" alt="Screenshot of tldr command" width="600">
If you pronounce "tldr" in English, it sounds somewhat like "tealdeer". Hence the project name :)
In case you're in a hurry and just want to quickly try tealdeer, you can find static
binaries on the [GitHub releases page](https://github.com/dbrgn/tealdeer/releases/)!
+
## Goals
High level project goals:
@@ -54,6 +55,7 @@ These are the clients I tried but failed to compile or run:
[Go client by anoopengineer](https://github.com/anoopengineer/tldr/),
[PHP client](https://github.com/BrainMaestro/tldr-php).
+
## Usage
tldr [options] <command>
@@ -61,13 +63,15 @@ These are the clients I tried but failed to compile or run:
Options:
- -h --help Show this screen
- -v --version Show version information
- -l --list List all commands in the cache
- -f --render <file> Render a specific markdown file
- -o --os <type> Override the operating system [linux, osx, sunos]
- -u --update Update the local cache
- -c --clear-cache Clear the local cache
+ -h --help Show this screen
+ -v --version Show version information
+ -l --list List all commands in the cache
+ -f --render <file> Render a specific markdown file
+ -o --os <type> Override the operating system [linux, osx, sunos]
+ -u --update Update the local cache
+ -c --clear-cache Clear the local cache
+ --config-path Show config file path
+ --seed-config Create a basic config
Examples:
@@ -116,14 +120,58 @@ To enable the log output, set the `RUST_LOG` env variable:
$ export RUST_LOG=tldr=debug
-
### From AUR (Arch Linux)
If you're an Arch Linux user, you can also install the package from the AUR:
- $ yaourt -S tealdeer
+- [tealdeer](https://aur.archlinux.org/packages/tealdeer/)
+- [tealdeer-git](https://aur.archlinux.org/packages/tealdeer-git/)
+
+
+## Configuration
+
+The tldr command can be customized with a config file called `config.toml`.
+Creating the config file can be done manually or with the help of tldr:
+
+ $ tldr --seed-config
+
+The configuration file path follows OS conventions. It can be queried with the following command:
+
+ $ tldr --config-path
+
+### Style
+
+Using the config file, the style (e.g. colors or underlines) can be customized.
+
+Possible styles:
+
+- `description`: The initial description text
+- `command_name`: The command name as part of the example code
+- `example_text`: The text that describes an example
+- `example_code`: The example itself, except the `command_name` and `example_variable`
+- `example_variable`: The variables in the example
+
+Currently supported attributes:
+
+- `foreground` (color string, see below)
+- `background` (color string, see below)
+- `underline` (`true` or `false`)
+- `bold` (`true` or `false`)
+
+The currently supported colors are:
+
+- `black`
+- `red`
+- `green`
+- `yellow`
+- `blue`
+- `purple`
+- `cyan`
+- `white`
+
+Example customization:
-(Or `tealdeer-git` if you prefer the current development version.)
+<img src="screenshot-custom.png" alt="Screenshot of customized version" width="600">
## Bash Autocompletion
diff --git a/bash_tealdeer b/bash_tealdeer
index 315aee5..05d298e 100644
--- a/bash_tealdeer
+++ b/bash_tealdeer
@@ -6,7 +6,7 @@ _tealdeer()
_init_completion || return
case $prev in
- -h|--help|-v|--version|-l|--list|-u|--update|-c|--clear-cache)
+ -h|--help|-v|--version|-l|--list|-u|--update|-c|--clear-cache|--config-path|--seed-config)
return
;;
-f|--render)
diff --git a/screenshot-custom.png b/screenshot-custom.png
new file mode 100644
index 0000000..ff0c78d
--- /dev/null
+++ b/screenshot-custom.png
Binary files differ
diff --git a/screenshot-default.png b/screenshot-default.png
new file mode 100644
index 0000000..8a73de7
--- /dev/null
+++ b/screenshot-default.png
Binary files differ
diff --git a/screenshot.png b/screenshot.png
deleted file mode 100644
index 2aa51e8..0000000
--- a/screenshot.png
+++ /dev/null
Binary files differ
diff --git a/src/config.rs b/src/config.rs
new file mode 100644
index 0000000..bbfc2d7
--- /dev/null
+++ b/src/config.rs
@@ -0,0 +1,255 @@
+use std::env;
+use std::fs;
+use std::io::{Error as IoError, Read, Write};
+use std::path::PathBuf;
+
+use ansi_term::{Color, Style};
+use toml;
+use xdg::BaseDirectories;
+
+use error::TealdeerError::{self, ConfigError};
+
+pub const CONFIG_FILE_NAME: &'static str = "config.toml";
+
+fn default_underline() -> bool {
+ false
+}
+
+fn default_bold() -> bool {
+ false
+}
+
+#[serde(rename_all = "lowercase")]
+#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
+pub enum RawColor {
+ Black,
+ Red,
+ Green,
+ Yellow,
+ Blue,
+ Purple,
+ Cyan,
+ White,
+}
+
+impl From<RawColor> for Color {
+ fn from(raw_color: RawColor) -> Color {
+ match raw_color {
+ RawColor::Black => Color::Black,
+ RawColor::Red => Color::Red,
+ RawColor::Green => Color::Green,
+ RawColor::Yellow => Color::Yellow,
+ RawColor::Blue => Color::Blue,
+ RawColor::Purple => Color::Purple,
+ RawColor::Cyan => Color::Cyan,
+ RawColor::White => Color::White,
+ }
+ }
+}
+
+#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
+struct RawStyle {
+ pub foreground: Option<RawColor>,
+ pub background: Option<RawColor>,
+ #[serde(default = "default_underline")]
+ pub underline: bool,
+ #[serde(default = "default_bold")]
+ pub bold: bool,
+}
+
+impl Default for RawStyle {
+ fn default() -> RawStyle {
+ RawStyle{
+ foreground: None,
+ background: None,
+ underline: false,
+ bold: false,
+ }
+ }
+} // impl RawStyle
+
+impl From<RawStyle> for Style {
+ fn from(raw_style: RawStyle) -> Style {
+ let mut style = Style::default();
+
+ if let Some(foreground) = raw_style.foreground {
+ style = style.fg(Color::from(foreground));
+ }
+
+ if let Some(background) = raw_style.background {
+ style = style.on(Color::from(background));
+ }
+
+ if raw_style.underline {
+ style = style.underline();
+ }
+
+ if raw_style.bold {
+ style = style.bold();
+ }
+
+ style
+ }
+}
+
+#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
+struct RawStyleConfig {
+ #[serde(default)]
+ pub description: RawStyle,
+ #[serde(default)]
+ pub command_name: RawStyle,
+ #[serde(default)]
+ pub example_text: RawStyle,
+ #[serde(default)]
+ pub example_code: RawStyle,
+ #[serde(default)]
+ pub example_variable: RawStyle,
+}
+
+
+#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
+struct RawConfig {
+ style: RawStyleConfig,
+}
+
+impl RawConfig {
+ fn new() -> RawConfig {
+ let mut raw_config = RawConfig::default();
+
+ // Set default config
+ raw_config.style.example_text.foreground = Some(RawColor::Green);
+ raw_config.style.command_name.foreground = Some(RawColor::Cyan);
+ raw_config.style.example_code.foreground = Some(RawColor::Cyan);
+ raw_config.style.example_variable.foreground = Some(RawColor::Cyan);
+ raw_config.style.example_variable.underline = true;
+
+ raw_config
+ }
+} // impl RawConfig
+
+#[derive(Copy, Clone, Debug, PartialEq)]
+pub struct StyleConfig {
+ pub description: Style,
+ pub command_name: Style,
+ pub example_text: Style,
+ pub example_code: Style,
+ pub example_variable: Style,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq)]
+pub struct Config {
+ pub style: StyleConfig,
+}
+
+impl From<RawConfig> for Config {
+ fn from(raw_config: RawConfig) -> Config {
+ Config{
+ style: StyleConfig{
+ command_name: raw_config.style.command_name.into(),
+ description: raw_config.style.description.into(),
+ example_text: raw_config.style.example_text.into(),
+ example_code: raw_config.style.example_code.into(),
+ example_variable: raw_config.style.example_variable.into(),
+ }
+ }
+ }
+}
+
+fn map_io_err_to_config_err(e: IoError) -> TealdeerError {
+ ConfigError(format!("Io Error: {}", e))
+}
+
+impl Config {
+ pub fn load() -> Result<Config, TealdeerError> {
+ let raw_config = match get_config_path() {
+ Ok(config_file_path) => {
+ let mut config_file = fs::File::open(config_file_path)
+ .map_err(map_io_err_to_config_err)?;
+ let mut contents = String::new();
+ let _rc = config_file.read_to_string(&mut contents)
+ .map_err(map_io_err_to_config_err)?;
+
+ toml::from_str(&contents).map_err(|err| ConfigError(format!("Failed to parse config file: {}", err)))?
+ }
+ Err(ConfigError(_)) => RawConfig::new(),
+ Err(_) => {
+ return Err(ConfigError("Unknown error while looking up config path".into()));
+ }
+ };
+
+ Ok(Config::from(raw_config))
+ }
+} // impl Config
+
+/// Return the path to the config directory.
+pub fn get_config_dir() -> Result<PathBuf, TealdeerError> {
+ // Allow overriding the config directory by setting the
+ // $TEALDEER_CONFIG_DIR env variable.
+ if let Ok(value) = env::var("TEALDEER_CONFIG_DIR") {
+ let path = PathBuf::from(value);
+
+ if path.exists() && path.is_dir() {
+ return Ok(path)
+ } else {
+ return Err(ConfigError(
+ "Path specified by $TEALDEER_CONFIG_DIR \
+ does not exist or is not a directory.".into()
+ ));
+ }
+ };
+
+ // Otherwise, fall back to $XDG_CONFIG_HOME/tealdeer.
+ let xdg_dirs = match BaseDirectories::with_prefix(::NAME) {
+ Ok(dirs) => dirs,
+ Err(_) => return Err(ConfigError("Could not determine XDG base directory.".into())),
+ };
+ Ok(xdg_dirs.get_config_home())
+}
+
+/// Return the path to the config file.
+pub fn get_config_path() -> Result<PathBuf, TealdeerError> {
+ let config_dir = get_config_dir()?;
+ let config_file_path = config_dir.join(CONFIG_FILE_NAME);
+
+ if config_file_path.is_file() {
+ Ok(config_file_path)
+ } else {
+ Err(ConfigError(format!("{} is not a file path", config_file_path.to_str().unwrap())))
+ }
+}
+
+/// Create default config file.
+pub fn make_default_config() -> Result<PathBuf, TealdeerError> {
+ let config_dir = get_config_dir()?;
+ if !config_dir.is_dir() {
+ if let Err(e) = fs::create_dir_all(&config_dir) {
+ return Err(ConfigError(format!("Could not create config directory: {}", e)));
+ }
+ }
+
+ let config_file_path = config_dir.join(CONFIG_FILE_NAME);
+ if config_file_path.is_file() {
+ return Err(ConfigError(format!(
+ "A configuration file already exists at {}, no action was taken.",
+ config_file_path.to_str().unwrap()
+ )));
+ }
+
+ let serialized_config = toml::to_string(&RawConfig::new())
+ .map_err(|err| ConfigError(format!("Failed to serialize default config: {}", err)))?;
+
+ let mut config_file = fs::File::create(&config_file_path)
+ .map_err(map_io_err_to_config_err)?;
+ let _wc = config_file.write(serialized_config.as_bytes())
+ .map_err(map_io_err_to_config_err)?;
+
+ Ok(config_file_path)
+}
+
+#[test]
+fn test_serialize_deserialize() {
+ let raw_config = RawConfig::new();
+ let serialized = toml::to_string(&raw_config).unwrap();
+ let deserialized: RawConfig = toml::from_str(&serialized).unwrap();
+ assert_eq!(raw_config, deserialized);
+}
diff --git a/src/error.rs b/src/error.rs
index f099eb2..8274008 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -3,6 +3,7 @@ use curl::Error as CurlError;
#[derive(Debug)]
pub enum TealdeerError {
CacheError(String),
+ ConfigError(String),
UpdateError(String),
}
diff --git a/src/formatter.rs b/src/formatter.rs
index 4031132..2be62d1 100644
--- a/src/formatter.rs
+++ b/src/formatter.rs
@@ -2,35 +2,64 @@
use std::io::BufRead;
-use ansi_term::{Colour, ANSIStrings};
+use ansi_term::{ANSIString, ANSIStrings};
+use config::Config;
use tokenizer::Tokenizer;
use types::LineType;
-/// Provide formatting for {{ curly braces }} in ExampleCode lines
-fn format_braces(text: &str) -> String {
- let parts = text.split("{{").flat_map(|s| s.split("}}"))
- .enumerate()
- .map(|(i, v)| {
- if i % 2 == 0 {
- Colour::Cyan.paint(v)
- } else {
- Colour::Cyan.underline().paint(v)
- }
- })
- .collect::<Vec<_>>();
+fn highlight_command<'a>(
+ command: &'a str,
+ example_code: &'a str,
+ config: &Config,
+ parts: &mut Vec<ANSIString<'a>>
+) {
+ let mut code_part_end_pos = 0;
+ while let Some(command_start) = example_code[code_part_end_pos..].find(&command) {
+ let code_part = &example_code[code_part_end_pos..code_part_end_pos + command_start];
+ parts.push(config.style.example_code.paint(code_part));
+ parts.push(config.style.command_name.paint(command));
+
+ code_part_end_pos += command_start + command.len();
+ }
+ parts.push(config.style.example_code.paint(&example_code[code_part_end_pos..]));
+}
+
+/// Format and highlight code examples including variables in {{ curly braces }}.
+fn format_code(command: &str, text: &str, config: &Config) -> String {
+ let mut parts = Vec::new();
+ for between_variables in text.split("}}") {
+ if let Some(variable_start) = between_variables.find("{{") {
+ let example_code = &between_variables[..variable_start];
+ let example_variable = &between_variables[variable_start + 2..];
+
+ highlight_command(&command, &example_code, &config, &mut parts);
+ parts.push(config.style.example_variable.paint(example_variable));
+ } else {
+ highlight_command(&command, &between_variables, &config, &mut parts);
+ }
+ }
+
ANSIStrings(&parts).to_string()
}
/// Print a token stream to an ANSI terminal.
-pub fn print_lines<R>(tokenizer: &mut Tokenizer<R>) where R: BufRead {
+pub fn print_lines<R>(tokenizer: &mut Tokenizer<R>, config: &Config) where R: BufRead {
+ let mut command = String::new();
while let Some(token) = tokenizer.next_token() {
match token {
LineType::Empty => println!(""),
- LineType::Title(_) => debug!("Ignoring title"),
- LineType::Description(text) => println!(" {}", text),
- LineType::ExampleText(text) => println!(" {}", Colour::Green.paint(text)),
- LineType::ExampleCode(text) => println!(" {}", &format_braces(&text)),
+ LineType::Title(title) => {
+ debug!("Ignoring title");
+
+ // This is safe as long as the parsed title is only the command,
+ // and tokenizer yields values in order of appearance.
+ command = title;
+ debug!("Detected command name: {}", &command);
+ },
+ LineType::Description(text) => println!(" {}", config.style.description.paint(text)),
+ LineType::ExampleText(text) => println!(" {}", config.style.example_text.paint(text)),
+ LineType::ExampleCode(text) => println!(" {}", &format_code(&command, &text, &config)),
LineType::Other(text) => debug!("Unknown line type: {:?}", text),
}
}
diff --git a/src/main.rs b/src/main.rs
index c40e62f..9ce2d32 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -31,6 +31,7 @@ extern crate tar;
extern crate xdg;
extern crate curl;
extern crate time;
+extern crate toml;
extern crate walkdir;
#[macro_use]
extern crate serde_derive;
@@ -41,17 +42,19 @@ use std::path::{Path, PathBuf};
use std::process;
use docopt::Docopt;
-use ansi_term::Colour;
+use ansi_term::Color;
mod types;
mod tokenizer;
mod formatter;
mod cache;
+mod config;
mod error;
use tokenizer::Tokenizer;
use cache::Cache;
-use error::TealdeerError::{UpdateError, CacheError};
+use config::{get_config_path, make_default_config, Config};
+use error::TealdeerError::{CacheError, ConfigError, UpdateError};
use formatter::print_lines;
use types::OsType;
@@ -72,6 +75,8 @@ Options:
-o --os <type> Override the operating system [linux, osx, sunos]
-u --update Update the local cache
-c --clear-cache Clear the local cache
+ --config-path Show config file path
+ --seed-config Create a basic config
Examples:
@@ -100,6 +105,8 @@ struct Args {
flag_os: Option<OsType>,
flag_update: bool,
flag_clear_cache: bool,
+ flag_config_path: bool,
+ flag_seed_config: bool,
}
/// Print page by path
@@ -110,9 +117,22 @@ fn print_page(path: &Path) -> Result<(), String> {
);
let reader = BufReader::new(file);
+ // Look up config file, if none is found fall back to default config.
+ let config = match Config::load() {
+ Ok(config) => config,
+ Err(ConfigError(msg)) => {
+ eprintln!("Failed to create config: {}", msg);
+ process::exit(1);
+ }
+ Err(_) => {
+ eprintln!("Unknown error while creating config");
+ process::exit(1);
+ }
+ };
+
// Create tokenizer and print output
let mut tokenizer = Tokenizer::new(reader);
- print_lines(&mut tokenizer);
+ print_lines(&mut tokenizer, &config);
Ok(())
}
@@ -122,14 +142,14 @@ fn check_cache(args: &Args, cache: &Cache) {
if !args.flag_update {
match cache.last_update() {
Some(ago) if ago > MAX_CACHE_AGE => {
- println!("{}", Colour::Red.paint(format!(
+ println!("{}", Color::Red.paint(format!(
"Cache wasn't updated in {} days.\n\
- You should probably run `tldr --update` soon.\n",
+ You should probably run `tldr --update` soon.",
MAX_CACHE_AGE / 24 / 3600
)));
},
None => {
- println!("Cache not found. Please run `tldr --update`.");
+ eprintln!("Cache not found. Please run `tldr --update`.");
process::exit(1);
},
_ => {},
@@ -182,7 +202,8 @@ fn main() {
if args.flag_clear_cache {
cache.clear().unwrap_or_else(|e| {
match e {
- UpdateError(msg) | CacheError(msg) => println!("Could not delete cache: {}", msg),
+ CacheError(msg) | ConfigError(msg) | UpdateError(msg) =>
+ eprintln!("Could not delete cache: {}", msg),
};
process::exit(1);
});
@@ -193,7 +214,8 @@ fn main() {
if args.flag_update {
cache.update().unwrap_or_else(|e| {
match e {
- UpdateError(msg) | CacheError(msg) => println!("Could not update cache: {}", msg),
+ CacheError(msg) | ConfigError(msg) | UpdateError(msg) =>
+ eprintln!("Could not update cache: {}", msg),
};
process::exit(1);
});
@@ -204,7 +226,7 @@ fn main() {
if let Some(ref file) = args.flag_render {
let path = PathBuf::from(file);
if let Err(msg) = print_page(&path) {
- println!("{}", msg);
+ eprintln!("{}", msg);
process::exit(1);
} else {
process::exit(0);
@@ -219,7 +241,8 @@ fn main() {
// Get list of pages
let pages = cache.list_pages().unwrap_or_else(|e| {
match e {
- UpdateError(msg) | CacheError(msg) => println!("Could not get list of pages: {}", msg),
+ CacheError(msg) | ConfigError(msg) | UpdateError(msg) =>
+ eprintln!("Could not get list of pages: {}", msg),
}
process::exit(1);
});
@@ -237,7 +260,7 @@ fn main() {
// Search for command in cache
if let Some(path) = cache.find_page(&command) {
if let Err(msg) = print_page(&path) {
- println!("{}", msg);
+ eprintln!("{}", msg);
process::exit(1);
} else {
process::exit(0);
@@ -245,14 +268,50 @@ fn main() {
} else {
println!("Page {} not found in cache", &command);
println!("Try updating with `tldr --update`, or submit a pull request to:");
- println!("https://github.com/tldr-pages/tldr");
+ eprintln!("https://github.com/tldr-pages/tldr");
process::exit(1);
}
}
+ // Show config file and path and exit
+ if args.flag_config_path {
+ match get_config_path() {
+ Ok(config_file_path) => {
+ println!("Config path is: {}", config_file_path.to_str().unwrap());
+ process::exit(0);
+ },
+ Err(ConfigError(msg)) => {
+ eprintln!("Could not look up config_path: {}", msg);
+ process::exit(1);
+ },
+ Err(_) => {
+ eprintln!("Unknown error");
+ process::exit(1);
+ },
+ }
+ }
+
+ // Create a basic config and exit
+ if args.flag_seed_config {
+ match make_default_config() {
+ Ok(config_file_path) => {
+ println!("Successfully created seed config file here: {}", config_file_path.to_str().unwrap());
+ process::exit(0);
+ },
+ Err(ConfigError(msg)) => {
+ eprintln!("Could not create seed config: {}", msg);
+ process::exit(1);
+ },
+ Err(_) => {
+ eprintln!("Unkown error");
+ process::exit(1);
+ },
+ }
+ }
+
// Some flags can be run without a command.
if !(args.flag_update || args.flag_clear_cache) {
- println!("{}", USAGE);
+ eprintln!("{}", USAGE);
process::exit(1);
}
}
diff --git a/tests/config.toml b/tests/config.toml
new file mode 100644
index 0000000..7440a82
--- /dev/null
+++ b/tests/config.toml
@@ -0,0 +1,17 @@
+[style.highlight]
+foreground = "green"
+underline = false
+bold = false
+
+[style.description]
+underline = false
+bold = false
+
+[style.example_text]
+foreground = "black"
+background = "blue"
+underline = false
+
+[style.example_variable]
+underline = true
+bold = false
diff --git a/tests/inkscape.expected b/tests/inkscape-default.expected
index 7aed257..c7061b3 100644
--- a/tests/inkscape.expected
+++ b/tests/inkscape-default.expected
@@ -20,7 +20,7 @@
Export an SVG document to PDF, converting all texts to paths:
- inkscape filename.svg --export-pdf=filename.pdf --export-text-to-path
+ inkscape filename.svg | inkscape | inkscape --export-pdf=inkscape.pdf | inkscape | inkscape --export-text-to-path
Duplicate the object with id="path123", rotate the duplicate 90 degrees, save the file, and quit Inkscape:
diff --git a/tests/inkscape-v1.md b/tests/inkscape-v1.md
index dfa30dc..4071196 100644
--- a/tests/inkscape-v1.md
+++ b/tests/inkscape-v1.md
@@ -21,7 +21,7 @@
- Export an SVG document to PDF, converting all texts to paths:
-`inkscape {{filename.svg}} --export-pdf={{filename.pdf}} --export-text-to-path`
+`inkscape {{filename.svg}} | inkscape | inkscape --export-pdf={{inkscape.pdf}} | inkscape | inkscape --export-text-to-path`
- Duplicate the object with id="path123", rotate the duplicate 90 degrees, save the file, and quit Inkscape:
diff --git a/tests/inkscape-v2.md b/tests/inkscape-v2.md
index 5772c89..3051867 100644
--- a/tests/inkscape-v2.md
+++ b/tests/inkscape-v2.md
@@ -22,7 +22,7 @@ Export a single object, given its ID, into a bitmap:
Export an SVG document to PDF, converting all texts to paths:
- inkscape {{filename.svg}} --export-pdf={{filename.pdf}} --export-text-to-path
+ inkscape {{filename.svg}} | inkscape | inkscape --export-pdf={{inkscape.pdf}} | inkscape | inkscape --export-text-to-path
Duplicate the object with id="path123", rotate the duplicate 90 degrees, save the file, and quit Inkscape:
diff --git a/tests/inkscape-with-config.expected b/tests/inkscape-with-config.expected
new file mode 100644
index 0000000..313e140
--- /dev/null
+++ b/tests/inkscape-with-config.expected
@@ -0,0 +1,28 @@
+
+ An SVG (Scalable Vector Graphics) editing program.
+ Use -z to not open the GUI and only process files in the console.
+
+ Open an SVG file in the Inkscape GUI:
+
+ inkscape filename.svg
+
+ Export an SVG file into a bitmap with the default format (PNG) and the default resolution (90 DPI):
+
+ inkscape filename.svg -e filename.png
+
+ Export an SVG file into a bitmap of 600x400 pixels (aspect ratio distortion may occur):
+
+ inkscape filename.svg -e filename.png -w 600 -h 400
+
+ Export a single object, given its ID, into a bitmap:
+
+ inkscape filename.svg -i id -e object.png
+
+ Export an SVG document to PDF, converting all texts to paths:
+
+ inkscape filename.svg | inkscape | inkscape --export-pdf=inkscape.pdf | inkscape | inkscape --export-text-to-path
+
+ Duplicate the object with id="path123", rotate the duplicate 90 degrees, save the file, and quit Inkscape:
+
+ inkscape filename.svg --select=path123 --verb=EditDuplicate --verb=ObjectRotate90 --verb=FileSave --verb=FileQuit
+
diff --git a/tests/lib.rs b/tests/lib.rs
index 79a12ec..6c3f51b 100644
--- a/tests/lib.rs
+++ b/tests/lib.rs
@@ -11,21 +11,25 @@ use tempdir::TempDir;
struct TestEnv {
pub cache_dir: TempDir,
+ pub config_dir: TempDir,
pub input_dir: TempDir,
}
impl TestEnv {
fn new() -> Self {
- let cache_dir = TempDir::new(".tldr.test.cache").unwrap();
- let input_dir = TempDir::new(".tldr.test.input").unwrap();
- TestEnv { cache_dir, input_dir }
+ TestEnv {
+ cache_dir: TempDir::new(".tldr.test.cache").unwrap(),
+ config_dir: TempDir::new(".tldr.test.config").unwrap(),
+ input_dir: TempDir::new(".tldr.test.input").unwrap(),
+ }
}
/// Return a new [`Assert`](../assert_cli/struct.Assert.html) instance for
/// the main binary with env vars set.
fn assert(&self) -> Assert {
let env = Environment::inherit()
- .insert("TEALDEER_CACHE_DIR", self.cache_dir.path().to_str().unwrap());
+ .insert("TEALDEER_CACHE_DIR", self.cache_dir.path().to_str().unwrap())
+ .insert("TEALDEER_CONFIG_DIR", self.config_dir.path().to_str().unwrap());
Assert::main_binary()
.with_env(env)
}
@@ -37,7 +41,7 @@ fn test_missing_cache() {
.assert()
.with_args(&["sl"])
.fails()
- .stdout()