A very fast implementation of tldr in Rust

Related tags

rust tldr hacktoberfest
Overview

tealdeer

teal deer

Crate CI (Linux/macOS/Windows)
Crates.io GitHub CI

A very fast implementation of tldr in Rust: Simplified, example based and community-driven man pages.

Screenshot of tldr command

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!

Docs (Installing, Usage, Configuration)

User documentation is available at https://dbrgn.github.io/tealdeer/!

The docs are generated using mdbook. They can be edited through the markdown files in the docs/src/ directory.

Goals

High level project goals:

  • Download and cache pages
  • Don't require a network connection for anything besides updating the cache
  • Command line interface similar or equivalent to the NodeJS client
  • Be fast

A tool like tldr should be as frictionless as possible to use. It should be easy to invoke (just tldr tar, not using another subcommand like tldr find tar) and it should show the output as fast as possible.

tealdeer reaches these goals. During a (highly non-scientific) test (see #38 for details), I tested the invocation speed of tldr for a few of the existing clients:

Client Times (ms) Avg of 5 (ms)
Tealdeer 15/11/5/5/11 9.4 (100%)
C client 11/5/12/11/15 10.8 (115%)
Bash client 15/19/22/25/24 21.0 (223%)
Go client by k3mist 98/96/100/95/101 98.8 (1'051%)
Python client 152/148/151/158/140 149.8 (1'594%)
NodeJS client 169/171/170/170/170 170.0 (1'809%)

tealdeer was the winner here, although the C client and the Bash client are in the same speed class. Interpreted languages are clearly much slower to invoke, a delay of 170 milliseconds is definitely noticeable and increases friction for the user.

These are the clients I tried but failed to compile or run: Haskell client, Ruby client, Perl client, Go client by anoopengineer, PHP client.

Development

Creating a debug build with logging enabled:

$ cargo build --features logging

Release build without logging:

$ cargo build --release

To enable the log output, set the RUST_LOG env variable:

$ export RUST_LOG=tldr=debug

To run tests:

$ cargo test

To run lints:

$ rustup component add clippy
$ cargo clean && cargo clippy

MSRV (Minimally Supported Rust Version)

When publishing a Tealdeer release, the Rust version required to build it should be stable for at least a month.

License

Licensed under either of

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Thanks to @SShrike for coming up with the name "tealdeer"!

Issues
  • Feature/improve colour contrast

    Feature/improve colour contrast

    What

    • Change default colour scheme to high contrast using terminal default colour
    • Highlight program name in code examples

    Before: screenshot_20180708_173111 After: screenshot_20180708_173320

    Why

    Right now the only reason I use a painfully slow python version of tldr is because its colour scheme makes quickly glancing at a tldr and seeing what I'm looking for much easier than when looking at the monotone low contrast produced by the current version of tealdeer. The current contrast of most likely dark background to teal is challenging for certain people with colour blindness. I understand that the project is called tealdear and removing the teal colour might make the pun obsolete. If you prefer the old colour scheme, I suggest making it an option. People that want another scheme could do alias tldr=tldr --color=teal.

    Implementation Notes

    I chose to go with string indexing over split and flat_map as I wanted to avoid a performance regression. In a micro benchmark, format_code is faster and more consistent than format_braces whilst doing more work. Yet it is seems to be only a small fraction of the overall time, which means I wouldn't be opposed to rewriting it in a more readable fashion. Pulling the command from the title isn't pretty, the command name is present when called regularly, however when using the option --render we would have to either introduce a new parameter to specify the command, which would increase usage burden and could introduce user errors, or accept different behavior for regular use vs --render which I find particular bad. This solution doesn't change the current interface and behaves the same way in regular use and --render. However I have not tested if all tldr files correctly specify the program title in their title.

    opened by Voultapher 21
  • Upload to crates.io

    Upload to crates.io

    I'd like to put a version of tldr on crates.io that supports an offline cache. The name is already taken though (rilut/rust-tldr#1).

    Therefore I'd go with another name. A few ideas:

    • toolong
    • tldr-rs

    Any other ideas? The binary name could also be different from the crate name I guess.

    cc @SShrike

    opened by dbrgn 20
  • #36 add -p --pager flag to page the output using pager crate

    #36 add -p --pager flag to page the output using pager crate

    I just added the pager crate and a flag (-p --pager) to enable or disable it.

    BTW, I have tested it with Rust 1.28.0 and it works well, maybe you can update.

    I would need help for windows and macOS testers.

    refs #36

    opened by jdvr 18
  • Support custom pages and patches

    Support custom pages and patches

    Feature implementation for issue #98 This is a feature that lets you create custom tldr pages locally. You can set a directory where tealdeer will search for these local pages with the env variable TEALDEER_CUSTOM_PAGES_DIR. If this is not set then it will use the tldr-master/pages.custom

    If you give a custom tldr page the same name as an existing one, then your custom one will be appended to it.

    Example with existing tldr page:
    Example with no existing tldr page:

    I find the value added here is that overtime a person can build their own collection of common use-cases to a particular command that they use semi-frequently. I created this because I would create my own repository of command specific use-cases, and to document personalized scripts for myself.

    Side note: This is my first real open-source contribution, and I'm not super familiar w/ the ins and outs of rust. Please leave suggestions for improvements :smile: .

    Update, Dec 18. Implemented suggested changes from @dbrgn

    • Implemented .page and .patch differences. {}.page files overwrite existing tldr entries. {}.patch appends to existing entries.
    • Now using the config file for custom_pages_dir, default directory is CONFIGDIR/pages
    • ~Also added 2 flags, --patch and --overwrite. These commands create and or open the .page or .patch files in your $EDITOR. I added this because I found it was annoying to constantly switch the the custom page directory. Also this enables people to very quickly make changes to their custom patches/pages~
    Example of a .patch file in work
    Example of a new tldr page with a .page file
    Example of overwriting an existing tldr page using a .page file
    How the config looks now
    opened by dmaahs2017 14
  • --update no longer works behind proxies after switching to reqwest

    --update no longer works behind proxies after switching to reqwest

    It looks like #61 has broken cache updating behind proxies:

    Commit e73261542cc601408596fb404c57d54f8cbc6bf7 (just before switching to reqwest):

    $ git checkout e73261542cc601408596fb404c57d54f8cbc6bf7
    $ cargo build
    $ target/debug/tldr --update
    Successfully updated cache.
    

    Master branch:

    $ git checkout master
    $ cargo build
    $ target/debug/tldr --update
    Could not update cache: HTTP error: https://github.com/tldr-pages/tldr/archive/master.tar.gz: timed out
    
    
    opened by aldanor 13
  • move from curl to reqwest

    move from curl to reqwest

    Fixes #60

    opened by jcgruenhage 9
  • Evaluate using xdg-basedir crate

    Evaluate using xdg-basedir crate

    The xdg-basedir crate could make the $XDG_CACHE lookup (usually ~/.cache) more standards compliant.

    A get_dir function could be conditionally-compiled for unix and non-unix platforms. On unix, the $XDG_CACHE lookup would be used, on Windows a directory in the user profile that doesn't contain a dot would be used.

    opened by dbrgn 8
  • Add --auto-update flag to allow automatically updating the cache

    Add --auto-update flag to allow automatically updating the cache

    When not updating the cache manually one often gets the following message:

    Cache wasn't updated in 30 days.
    You should probably run `tldr --update` soon.
    

    The auto-update flag allows to just alias tldr to tldr -a which will automatically update the cache if it is older than the maximum age.

    opened by rnestler 7
  • Update dependencies

    Update dependencies

    Pretty simple PR, I just went ahead and updated the dependencies.

    AFAIK nothing broke, all the tests passed and using tldr itself worked fine.

    opened by severen 7
  • Refactor formatting code

    Refactor formatting code

    See this discussion.

    This aims to introduce some abstractions where needed and refactor code that has accumulated complexity over time

    opened by niklasmohrin 4
  • Include custom pages directory in --show-paths command

    Include custom pages directory in --show-paths command

    Adds custom pages to output of --show-paths. See issue: #182

    If [directories.custom_page_dir] is not set then it will show the default location as defined by the DirectoriesConfig RawDirectoriesConfig structs image

    opened by dmaahs2017 1
  • Include custom pages and Patches directory in `--show-paths` option

    Include custom pages and Patches directory in `--show-paths` option

    Quote from PR #142

    We should also include the custom pages directory in the new --show-paths option output, but that's probably best done in a separate PR, in order not to hold up this one.

    Acceptance Criteria:

    • Using --show-paths includes the location of the custom_pages directory in the output
    • Tests are created / updated for new and changed code
    enhancement good-first-issue 
    opened by dmaahs2017 0
  • Custom patches should not need to be formatted like a full page

    Custom patches should not need to be formatted like a full page

    Quote from PR #142 discussion:

    Another issue for a new PR: Right now the patches need to be formatted like a full page, including a heading. Otherwise, the first line is interpreted as the heading, and skipped when printing (because the page and the patch are passed to separate tokenizer instances). However, I think that too can be fixed in a separate PR, I don't want to hold up this PR too long.

    Pre-requisites:

    • Issue #180

    Acceptance Criteria:

    • Format of .patch files should be expected to not have a heading
    • Update tests to reflect this change
    enhancement 
    opened by dmaahs2017 3
  • Directly return in case of an empty command

    Directly return in case of an empty command

    Fixes #177. The idea is to panic whenever a LineType::Title is created from an empty/blank string.

    opened by SimplyDanny 2
  • Infinite loop in formatter with certain inputs

    Infinite loop in formatter with certain inputs

    The following input...

    
    Abcd
     `efgh`
    

    ...leads to an infinite loop when printing the page.

    As a testcase, add this to src/formatter.rs (with ntest as a new dev dependency):

    #[cfg(test)]
    mod tests {
        use super::*;
    
        use ntest::timeout;
    
        use crate::config::Config;
    
        #[test]
        #[timeout(1000)]
        fn regression_issueX_first_line_empty() {
            let input = "\nAbcd\n `efgh`";
            let mut tokenizer = Tokenizer::new(input.as_bytes());
            print_lines(&mut tokenizer, &Config::testconfig());
        }
    }
    

    The culprit is the highlight_command function. When using an empty string as command parameter and some example code (like "`efgh`"), it never returns.

    The reason for the bug is this:

    code_part_end_pos += command_start + command.len();
    

    If command length is 0, this will never advance.

    We need to handle or avoid the "empty command" case. (If we decide that it's illegal to call the command this way, panic and documentation should be fine.)

    bug good-first-issue 
    opened by dbrgn 0
  • Fix #167: Create cache directory path if it does not exist

    Fix #167: Create cache directory path if it does not exist

    This PR tries to resolve #167. If TEALDEER_CACHE_DIR is set but does not exist, the complete path is just created as suggested in the issue. The user will be informed about the creation.

    opened by SimplyDanny 0
  • Release with github workflow

    Release with github workflow

    image Issue: #165

    I created a workflow that puts Mac into the release. You don't have to expose the GitHub key.

    Here's how to permanently erase files from the Git History:

    git filter-branch --tree-filter 'rm -rf ./release-build.sh' HEAD
    git filter-branch --prune-empty HEAD
    git push origin --force master
    
    opened by black7375 11
  • `tldr --update` output is displayed by pager

    `tldr --update` output is displayed by pager

    When a pager is configured, e.g. less, the output of tldr --update is displayed in it.

    Info messages should be displayed as typical output, like STDERR, regardless of pager config.

    bug 
    opened by tranzystorek-io 10
  • `tldr --clear-cache` with $TEALDEER_CACHE_DIR requires manual mkdir to rebuild cache

    `tldr --clear-cache` with $TEALDEER_CACHE_DIR requires manual mkdir to rebuild cache

    tldr --clear-cache deletes the $TEALDEER_CACHE_DIR folder but tldr --update is unable to remake the folder.

    ❯ tldr --list | head -n 2
    2to3
    7z
    
    ~
    ❯ tldr --clear-cache
    Successfully deleted cache.
    Could not update cache: Path specified by $TEALDEER_CACHE_DIR does not exist or is not a directory.
    
    ~
    ❯ tldr --list | head -n 2
    Could not update cache: Path specified by $TEALDEER_CACHE_DIR does not exist or is not a directory.
    
    ~
    ❯ tldr --update
    Could not update cache: Path specified by $TEALDEER_CACHE_DIR does not exist or is not a directory.
    
    ~
    ❯ mkdir -p "$TEALDEER_CACHE_DIR"
    
    ~
    ❯ tldr --update
    Successfully updated cache.
    

    Also, error messages in --show-paths:

    ❯ ./target/debug/tldr --show-paths
    Config dir:  /Users/cho-m/.config/tealdeer/ (env variable)
    Config path: /Users/cho-m/.config/tealdeer/config.toml
    Cache dir:   [Error: CacheError: Path specified by $TEALDEER_CACHE_DIR does not exist or is not a directory.]
    Pages dir:   [Error: CacheError: Path specified by $TEALDEER_CACHE_DIR does not exist or is not a directory.]
    Could not update cache: Path specified by $TEALDEER_CACHE_DIR does not exist or is not a directory.
    
    bug good-first-issue 
    opened by cho-m 4
Releases(v1.4.1)
A curated list of replacements for existing software written in Rust

Awesome Alternatives in Rust A curated list of replacements for existing software written in Rust. If you want to contribute, please read CONTRIBUTING

Takayuki Maeda 1.7k Jun 13, 2021
An interactive cheatsheet tool for the command-line

navi An interactive cheatsheet tool for the command-line. navi allows you to browse through cheatsheets (that you may write yourself or download from

Denis Isidoro 9.3k Jun 8, 2021
Fast conversion between linear float and 8-bit sRGB

fast-srgb8 Small crate implementing fast conversion between linear float and 8-bit sRGB. Includes API for performing 4 simultaneous conversions, which

Thom Chiovoloni 8 Jun 13, 2021
A full featured, fast Command Line Argument Parser for Rust

clap Command Line Argument Parser for Rust It is a simple-to-use, efficient, and full-featured library for parsing command line arguments and subcomma

null 6k Jun 13, 2021
fd is a program to find entries in your filesystem. It is a simple, fast and user-friendly alternative to find

fd is a program to find entries in your filesystem. It is a simple, fast and user-friendly alternative to find. While it does not aim to support all of find's powerful functionality, it provides sensible (opinionated) defaults for a majority of use cases.

David Peter 17.5k Jun 10, 2021
Alacritty - A fast, cross-platform, OpenGL terminal emulator

Alacritty is a modern terminal emulator that comes with sensible defaults, but allows for extensive configuration. By integrating with other applications, rather than reimplementing their functionality, it manages to provide a flexible set of features with high performance. The supported platforms currently consist of BSD, Linux, macOS and Windows.

Alacritty 33.1k Jun 13, 2021
🤖 just is a handy way to save and run project-specific commands.

just just is a handy way to save and run project-specific commands. (非官方中文文档,这里,快看过来!) Commands, called recipes, are stored in a file called justfile

Casey Rodarmor 3k Jun 10, 2021
A Text User Interface library for the Rust programming language

Cursive Cursive is a TUI (Text User Interface) library for rust. It uses ncurses by default, but other backends are available. It allows you to build

Alexandre Bury 2.3k Jun 11, 2021
A hackable, minimal, fast TUI file explorer, stealing ideas from nnn and fzf.

xplr A hackable, minimal, fast TUI file explorer, stealing ideas from nnn and fzf. [Quickstart] [Features] [Plugins] [Documentation] [Upgrade Guide] [

Arijit Basu 1.2k Jun 13, 2021
An implementation of Joshua Yanovski's Ghost Cell paper.

A novel safe and zero-cost borrow-checking paradigm from the GhostCell paper. Motivation A number of collections, such as linked-lists, binary-trees,

null 51 Jun 11, 2021
Rust implementation of the termbox library

Rustbox Rustbox is a Rust implementation of termbox. Currently, this is just a wrapper of the C library by nsf, though my plan is to convert it to be

Greg Chapple 438 Jun 14, 2021
Shell scripting that will knock your socks off

atom Shell scripting that will knock your socks off. NOTE: Click the image above for a video demonstration.

adam mcdaniel 238 May 19, 2021
A cat(1) clone with syntax highlighting and Git integration.

A cat(1) clone with syntax highlighting and Git integration. Key Features • How To Use • Installation • Customization • Project goals, alternatives [中

David Peter 27.5k Jun 10, 2021
This is choose, a human-friendly and fast alternative to cut and (sometimes) awk

Choose This is choose, a human-friendly and fast alternative to cut and (sometimes) awk Features terse field selection syntax similar to Python's list

Ryan Geary 643 Jun 10, 2021