From b19517097ae0a5f9015794030b782ae9fd54535c Mon Sep 17 00:00:00 2001 From: Pavel Timofeev Date: Mon, 13 Apr 2026 18:31:31 -0400 Subject: [PATCH] Add builtin `tldr tealdeer` page (#472) Fixes #218. --- docs/src/usage.txt | 2 ++ pages/tealdeer.md | 42 ++++++++++++++++++++++++++++++++++++++++++ src/cache.rs | 10 +++++----- src/cli.rs | 4 +++- src/main.rs | 29 ++++++++++++++++++++++++----- src/output.rs | 8 +++----- tests/lib.rs | 10 ++++++++++ 7 files changed, 89 insertions(+), 16 deletions(-) create mode 100644 pages/tealdeer.md diff --git a/docs/src/usage.txt b/docs/src/usage.txt index f7fcc46..6a04de7 100644 --- a/docs/src/usage.txt +++ b/docs/src/usage.txt @@ -29,3 +29,5 @@ Options: -h, --help Print help To view the user documentation, please visit https://tealdeer-rs.github.io/tealdeer/. + +To view usage examples, run tldr tldr or tldr tealdeer. diff --git a/pages/tealdeer.md b/pages/tealdeer.md new file mode 100644 index 0000000..948b278 --- /dev/null +++ b/pages/tealdeer.md @@ -0,0 +1,42 @@ +# tldr + +> This is a builtin page that shows information for your installed tealdeer version. +> More information: . + +> This page shows tealdeer specific functionality. See tldr tldr for more examples. + +- Render a local markdown file as a tldr page: + +`tldr --render {{path/to/file.md}}` + +- Show the raw markdown source of a page instead of rendering it: + +`tldr --raw {{command}}` + +- Show file and directory paths used by tealdeer: + +`tldr --show-paths` + +- Create an initial config file: + +`tldr --seed-config` + +- Override config file location: + +`tldr --config-path ` + +- Open a custom page for a command in `$EDITOR` (creates it if it doesn't exist): + +`tldr --edit-page {{command}}` + +- Open a custom patch for a command in `$EDITOR` (appended to the existing page): + +`tldr --edit-patch {{command}}` + +- Clear the local cache: + +`tldr --clear-cache` + +- If auto update is configured, disable it for this run: + +`tldr --no-auto-update` diff --git a/src/cache.rs b/src/cache.rs index b181310..a77036d 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -1,6 +1,6 @@ use std::{ fs::{self, File}, - io::{BufReader, Cursor, ErrorKind, Read}, + io::{Cursor, ErrorKind, Read}, path::{Path, PathBuf}, time::{Duration, SystemTime}, }; @@ -277,12 +277,12 @@ impl PageLookupResult { self } - /// Create a buffered reader that sequentially reads from the page and the + /// Create a reader that sequentially reads from the page and the /// patch, as if they were concatenated. /// /// This will return an error if either the page file or the patch file /// cannot be opened. - pub fn reader(&self) -> Result>> { + pub fn reader(&self) -> Result> { // Open page file let page_file = File::open(&self.page_path) .with_context(|| format!("Could not open page file at {}", self.page_path.display()))?; @@ -302,11 +302,11 @@ impl PageLookupResult { // the page and patch files and that will read them sequentially, // because it avoids the boxing below. However, the performance impact // would first need to be shown to be significant using a benchmark. - Ok(BufReader::new(if let Some(patch_file) = patch_file_opt { + Ok(if let Some(patch_file) = patch_file_opt { Box::new(page_file.chain(&b"\n"[..]).chain(patch_file)) as Box } else { Box::new(page_file) as Box - })) + }) } } diff --git a/src/cli.rs b/src/cli.rs index d461a3e..161d69d 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -18,7 +18,9 @@ use crate::types::{ColorOptions, PlatformType}; {usage-heading} {usage} {all-args}{after-help}", - after_help = "To view the user documentation, please visit https://tealdeer-rs.github.io/tealdeer/.", + after_help = "To view the user documentation, please visit https://tealdeer-rs.github.io/tealdeer/. + +To view usage examples, run tldr tldr or tldr tealdeer.", arg_required_else_help = true, help_expected = true, group = ArgGroup::new("command_or_file").args(&["command", "render"]), diff --git a/src/main.rs b/src/main.rs index 1d1b5fc..5b12613 100644 --- a/src/main.rs +++ b/src/main.rs @@ -68,6 +68,8 @@ const APP_INFO: AppInfo = AppInfo { name: NAME, author: NAME, }; +static TEALDEER_PAGE: &str = + include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/pages/tealdeer.md")); /// Clear the cache fn clear_cache(cache: Cache, quietly: bool) -> Result<()> { @@ -258,8 +260,20 @@ fn try_main(args: Cli, enable_styles: bool) -> Result { // If a local file was passed in, render it and exit if let Some(file) = args.render { - let path = PageLookupResult::with_page(file); - print_page(&path, args.raw, enable_styles, args.pager, &config)?; + let reader = PageLookupResult::with_page(file).reader()?; + print_page(reader, args.raw, enable_styles, args.pager, &config)?; + return Ok(ExitCode::SUCCESS); + } + + // The tealdeer page is embedded in the binary, no cache needed + if command == "tealdeer" { + print_page( + TEALDEER_PAGE.as_bytes(), + args.raw, + enable_styles, + args.pager, + &config, + )?; return Ok(ExitCode::SUCCESS); } @@ -407,7 +421,7 @@ fn try_main(args: Cli, enable_styles: bool) -> Result { ); } - let Some(lookup_result) = cache.find_page(&command) else { + let Some(result) = cache.find_page(&command) else { if !args.quiet { print_warning( enable_styles, @@ -419,11 +433,16 @@ fn try_main(args: Cli, enable_styles: bool) -> Result { ), ); } - return Ok(ExitCode::FAILURE); }; - print_page(&lookup_result, args.raw, enable_styles, args.pager, &config)?; + print_page( + result.reader()?, + args.raw, + enable_styles, + args.pager, + &config, + )?; } Ok(ExitCode::SUCCESS) diff --git a/src/output.rs b/src/output.rs index 927d20e..9305c20 100644 --- a/src/output.rs +++ b/src/output.rs @@ -1,12 +1,11 @@ //! Functions for printing pages to the terminal -use std::io::{self, BufRead, Write}; +use std::io::{self, BufRead, BufReader, Read, Write}; use anyhow::{Context, Result}; use yansi::Paint; use crate::{ - cache::PageLookupResult, config::{Config, StyleConfig}, formatter::{highlight_lines, PageSnippet}, line_iterator::LineIterator, @@ -30,14 +29,13 @@ fn configure_pager(enable_styles: bool) { /// Print page by path pub fn print_page( - lookup_result: &PageLookupResult, + reader: impl Read, enable_markdown: bool, enable_styles: bool, use_pager: bool, config: &Config, ) -> Result<()> { - // Create reader from file(s) - let reader = lookup_result.reader()?; + let reader = BufReader::new(reader); // Configure pager if applicable if use_pager || config.display.use_pager { diff --git a/tests/lib.rs b/tests/lib.rs index cb987db..40cb7e9 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -301,6 +301,16 @@ fn test_missing_cache() { .stderr(contains("Page cache not found. Please run `tldr --update`")); } +#[test] +fn test_tealdeer_page_works_without_cache() { + TestEnv::new() + .command() + .args(["tealdeer"]) + .assert() + .success() + .stdout(contains("for your installed tealdeer version")); +} + #[cfg_attr(feature = "ignore-online-tests", ignore = "online test")] #[test] fn test_update_cache_default_features() {