fix: avoid nested BufReader and serve tealdeer page without cache

This commit is contained in:
Pavel Timofeev 2026-04-01 20:36:32 -03:00
commit 25866e69d6
4 changed files with 55 additions and 30 deletions

View file

@ -5,12 +5,6 @@
> This page shows tealdeer specific functionality. See tldr tldr for more examples.
`tldr --update`
- List all pages in the cache:
`tldr --list`
- Render a local markdown file as a tldr page:
`tldr --render {{path/to/file.md}}`
@ -27,6 +21,10 @@
`tldr --seed-config`
- Override config file location:
`tldr --config-path <FILE>`
- Open a custom page for a command in `$EDITOR` (creates it if it doesn't exist):
`tldr --edit-page {{command}}`
@ -38,3 +36,7 @@
- Clear the local cache:
`tldr --clear-cache`
- If auto update is configured, disable it for this run:
`tldr --no-auto-update`

View file

@ -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<BufReader<Box<dyn Read>>> {
pub fn reader(&self) -> Result<Box<dyn Read>> {
// 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<dyn Read>
} else {
Box::new(page_file) as Box<dyn Read>
}))
})
}
}

View file

@ -265,6 +265,18 @@ fn try_main(args: Cli, enable_styles: bool) -> Result<ExitCode> {
return Ok(ExitCode::SUCCESS);
}
// The tealdeer page is embedded in the binary, no cache needed
if command == "tealdeer" {
print_page(
Cursor::new(TEALDEER_PAGE.as_bytes()),
args.raw,
enable_styles,
args.pager,
&config,
)?;
return Ok(ExitCode::SUCCESS);
}
if let Some(platforms) = args.platforms {
config.search.platforms = platforms;
if !config.search.platforms.contains(&PlatformType::Common) {
@ -409,27 +421,28 @@ fn try_main(args: Cli, enable_styles: bool) -> Result<ExitCode> {
);
}
let reader: Box<dyn io::Read> = if command == "tealdeer" {
Box::new(Cursor::new(TEALDEER_PAGE.as_bytes()))
} else {
let Some(result) = cache.find_page(&command) else {
if !args.quiet {
print_warning(
enable_styles,
&format!(
"Page `{}` not found in cache.\n\
Try updating with `tldr --update`, or submit a pull request to:\n\
https://github.com/tldr-pages/tldr",
&command
),
);
}
return Ok(ExitCode::FAILURE);
};
Box::new(result.reader()?)
let Some(result) = cache.find_page(&command) else {
if !args.quiet {
print_warning(
enable_styles,
&format!(
"Page `{}` not found in cache.\n\
Try updating with `tldr --update`, or submit a pull request to:\n\
https://github.com/tldr-pages/tldr",
&command
),
);
}
return Ok(ExitCode::FAILURE);
};
print_page(reader, args.raw, enable_styles, args.pager, &config)?;
print_page(
result.reader()?,
args.raw,
enable_styles,
args.pager,
&config,
)?;
}
Ok(ExitCode::SUCCESS)

View file

@ -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() {