Compare commits
No commits in common. "main" and "gh-pages" have entirely different histories.
|
|
@ -1,12 +0,0 @@
|
||||||
root = true
|
|
||||||
|
|
||||||
[*]
|
|
||||||
end_of_line = lf
|
|
||||||
charset = utf-8
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
insert_final_newline = true
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 4
|
|
||||||
|
|
||||||
[*.yml]
|
|
||||||
indent_size = 2
|
|
||||||
4
.gitattributes
vendored
|
|
@ -1,4 +0,0 @@
|
||||||
* text=auto
|
|
||||||
|
|
||||||
*.md eol=lf
|
|
||||||
*.expected eol=lf
|
|
||||||
6
.github/dependabot.yml
vendored
|
|
@ -1,6 +0,0 @@
|
||||||
version: 2
|
|
||||||
updates:
|
|
||||||
- package-ecosystem: "github-actions"
|
|
||||||
directory: "/"
|
|
||||||
schedule:
|
|
||||||
interval: "monthly"
|
|
||||||
93
.github/workflows/ci.yml
vendored
|
|
@ -1,93 +0,0 @@
|
||||||
name: CI
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
- "v*.x"
|
|
||||||
pull_request:
|
|
||||||
schedule:
|
|
||||||
- cron: '30 3 * * 2'
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test:
|
|
||||||
name: run tests
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
platform: [ubuntu-latest, macos-latest, windows-latest]
|
|
||||||
toolchain: [stable, 1.87.0] # MSRV
|
|
||||||
include:
|
|
||||||
- platform: windows-latest
|
|
||||||
exe_suffix: .exe
|
|
||||||
runs-on: ${{ matrix.platform }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v7
|
|
||||||
- uses: dtolnay/rust-toolchain@master
|
|
||||||
with:
|
|
||||||
toolchain: ${{ matrix.toolchain }}
|
|
||||||
- run: mkdir artifacts
|
|
||||||
- name: Build with default features
|
|
||||||
run: |
|
|
||||||
cargo build
|
|
||||||
cp target/debug/tldr${{ matrix.exe_suffix}} artifacts/tldr-default${{ matrix.exe_suffix}}
|
|
||||||
- name: Build with logging and Rustls with webpki roots
|
|
||||||
run: |
|
|
||||||
cargo build --features logging,rustls-with-webpki-roots --no-default-features
|
|
||||||
cp target/debug/tldr${{ matrix.exe_suffix}} artifacts/tldr-logging-rustls-webpki${{ matrix.exe_suffix}}
|
|
||||||
- name: Build with native TLS backend
|
|
||||||
run: |
|
|
||||||
# expects runners have the proper Native SSL library
|
|
||||||
cargo build --features native-tls --no-default-features
|
|
||||||
cp target/debug/tldr${{ matrix.exe_suffix}} artifacts/tldr-native-tls${{ matrix.exe_suffix}}
|
|
||||||
- uses: actions/upload-artifact@v7
|
|
||||||
with:
|
|
||||||
name: tldr-debug-build-${{ matrix.platform }}-rust-${{ matrix.toolchain }}
|
|
||||||
path: artifacts/
|
|
||||||
- name: Run tests
|
|
||||||
run: cargo test -- --test-threads 1
|
|
||||||
|
|
||||||
clippy:
|
|
||||||
name: run clippy lints
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v7
|
|
||||||
- uses: dtolnay/rust-toolchain@master
|
|
||||||
with:
|
|
||||||
toolchain: stable
|
|
||||||
components: clippy
|
|
||||||
- name: run clippy lints
|
|
||||||
run: cargo clippy --all-targets --features logging
|
|
||||||
|
|
||||||
fmt:
|
|
||||||
name: run rustfmt
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v7
|
|
||||||
- uses: dtolnay/rust-toolchain@master
|
|
||||||
with:
|
|
||||||
toolchain: stable
|
|
||||||
components: rustfmt
|
|
||||||
- name: run rustfmt
|
|
||||||
run: cargo fmt --all -- --check
|
|
||||||
|
|
||||||
docs:
|
|
||||||
name: build docs
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v7
|
|
||||||
- name: Setup mdBook
|
|
||||||
uses: peaceiris/actions-mdbook@v2
|
|
||||||
with:
|
|
||||||
mdbook-version: '0.4.4'
|
|
||||||
- name: Setup toolchain
|
|
||||||
uses: dtolnay/rust-toolchain@master
|
|
||||||
with:
|
|
||||||
toolchain: stable
|
|
||||||
- name: Build
|
|
||||||
run: cargo build
|
|
||||||
- name: Ensure that docs can be built
|
|
||||||
run: cd docs && mdbook build
|
|
||||||
- name: Generate usage string
|
|
||||||
run: cargo run -- --help > docs/src/usage-actual.txt
|
|
||||||
- name: Ensure that usage string is up to date
|
|
||||||
run: diff docs/src/usage{,-actual}.txt
|
|
||||||
25
.github/workflows/gh-pages.yml
vendored
|
|
@ -1,25 +0,0 @@
|
||||||
name: GitHub Pages
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- "v[1-9]*" # push events matching `v` followed by anything larger than 0, e.g. v1.0, v20.15.10
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
deploy:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v7
|
|
||||||
|
|
||||||
- name: Setup mdBook
|
|
||||||
uses: peaceiris/actions-mdbook@v2
|
|
||||||
with:
|
|
||||||
mdbook-version: '0.4.4'
|
|
||||||
|
|
||||||
- run: cd docs && mdbook build
|
|
||||||
|
|
||||||
- name: Deploy
|
|
||||||
uses: peaceiris/actions-gh-pages@v4
|
|
||||||
with:
|
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
publish_dir: ./docs/book
|
|
||||||
160
.github/workflows/release.yml
vendored
|
|
@ -1,160 +0,0 @@
|
||||||
name: Release
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- "v*" # push events to matching v*, i.e. v1.0, v20.15.10
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
create-release:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v7
|
|
||||||
- name: Create release for tag
|
|
||||||
if: startsWith(github.ref, 'refs/tags/')
|
|
||||||
run: |
|
|
||||||
source ./scripts/upload-asset.sh
|
|
||||||
# Create: <token> <repo> <tag>
|
|
||||||
create_release ${{ secrets.GITHUB_TOKEN }} ${{ github.repository }} ${GITHUB_REF#refs/*/} "Tealdeer version ${GITHUB_REF#refs/*/v}.\n\nFor the full changelog, see https://github.com/tealdeer-rs/tealdeer/blob/main/CHANGELOG.md.\n\nBinaries were generated automatically in CI, and are therefore unsigned. For a fully trusted release, please build from source."
|
|
||||||
|
|
||||||
upload-completions:
|
|
||||||
needs:
|
|
||||||
- create-release
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
target: ["bash", "fish", "zsh"]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v7
|
|
||||||
- name: Upload completion
|
|
||||||
if: startsWith(github.ref, 'refs/tags/')
|
|
||||||
run: |
|
|
||||||
source ./scripts/upload-asset.sh
|
|
||||||
# Upload: <token> <repo> <tag> <file> <name>
|
|
||||||
upload_release_file ${{ secrets.GITHUB_TOKEN }} ${{ github.repository }} ${GITHUB_REF#refs/*/} completion/${{ matrix.target }}_tealdeer completions_${{ matrix.target }}
|
|
||||||
|
|
||||||
upload-license:
|
|
||||||
needs:
|
|
||||||
- create-release
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
target: ["MIT", "APACHE"]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v7
|
|
||||||
- name: Upload license
|
|
||||||
if: startsWith(github.ref, 'refs/tags/')
|
|
||||||
run: |
|
|
||||||
source ./scripts/upload-asset.sh
|
|
||||||
# Upload: <token> <repo> <tag> <file> <name>
|
|
||||||
upload_release_file ${{ secrets.GITHUB_TOKEN }} ${{ github.repository }} ${GITHUB_REF#refs/*/} LICENSE-${{ matrix.target }} LICENSE-${{ matrix.target }}.txt
|
|
||||||
|
|
||||||
build-linux:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- arch: "x86_64"
|
|
||||||
libc: "musl"
|
|
||||||
- arch: "aarch64"
|
|
||||||
libc: "musl"
|
|
||||||
- arch: "i686"
|
|
||||||
libc: "musl"
|
|
||||||
- arch: "armv7"
|
|
||||||
libc: "musleabihf"
|
|
||||||
- arch: "arm"
|
|
||||||
libc: "musleabi"
|
|
||||||
- arch: "arm"
|
|
||||||
libc: "musleabihf"
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v7
|
|
||||||
- name: Pull Docker image
|
|
||||||
run: docker pull messense/rust-musl-cross:${{ matrix.arch }}-${{ matrix.libc }}
|
|
||||||
- name: Build in Docker
|
|
||||||
run: docker run --rm -i -v "$(pwd)":/home/rust/src messense/rust-musl-cross:${{ matrix.arch }}-${{ matrix.libc }} cargo build --release
|
|
||||||
- name: Strip binary
|
|
||||||
run: docker run --rm -i -v "$(pwd)":/home/rust/src messense/rust-musl-cross:${{ matrix.arch }}-${{ matrix.libc }} musl-strip -s /home/rust/src/target/${{ matrix.arch }}-unknown-linux-${{ matrix.libc }}/release/tldr
|
|
||||||
- uses: actions/upload-artifact@v7
|
|
||||||
with:
|
|
||||||
name: "tealdeer-linux-${{ matrix.arch }}-${{ matrix.libc }}"
|
|
||||||
path: "target/${{ matrix.arch }}-unknown-linux-${{ matrix.libc }}/release/tldr"
|
|
||||||
|
|
||||||
build-macos:
|
|
||||||
runs-on: macos-latest
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- arch: "x86_64"
|
|
||||||
- arch: "aarch64"
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v7
|
|
||||||
- name: Setup toolchain
|
|
||||||
uses: dtolnay/rust-toolchain@master
|
|
||||||
with:
|
|
||||||
toolchain: stable
|
|
||||||
targets: "${{ matrix.arch }}-apple-darwin"
|
|
||||||
- name: Build
|
|
||||||
run: cargo build --release --target ${{ matrix.arch }}-apple-darwin
|
|
||||||
- uses: actions/upload-artifact@v7
|
|
||||||
with:
|
|
||||||
name: "tealdeer-macos-${{ matrix.arch }}"
|
|
||||||
path: "target/${{ matrix.arch }}-apple-darwin/release/tldr"
|
|
||||||
|
|
||||||
build-windows:
|
|
||||||
runs-on: windows-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v7
|
|
||||||
- name: Setup toolchain
|
|
||||||
uses: dtolnay/rust-toolchain@master
|
|
||||||
with:
|
|
||||||
toolchain: stable
|
|
||||||
- name: Build
|
|
||||||
run: cargo build --release --target x86_64-pc-windows-msvc
|
|
||||||
- uses: actions/upload-artifact@v7
|
|
||||||
with:
|
|
||||||
name: "tealdeer-windows-x86_64-msvc"
|
|
||||||
path: "target/x86_64-pc-windows-msvc/release/tldr.exe"
|
|
||||||
|
|
||||||
upload-release:
|
|
||||||
needs:
|
|
||||||
- create-release
|
|
||||||
- build-linux
|
|
||||||
- build-macos
|
|
||||||
- build-windows
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
target:
|
|
||||||
- linux-x86_64-musl
|
|
||||||
- linux-aarch64-musl
|
|
||||||
- linux-i686-musl
|
|
||||||
- linux-armv7-musleabihf
|
|
||||||
- linux-arm-musleabi
|
|
||||||
- linux-arm-musleabihf
|
|
||||||
- macos-x86_64
|
|
||||||
- macos-aarch64
|
|
||||||
- windows-x86_64-msvc
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v7
|
|
||||||
- uses: actions/download-artifact@v8
|
|
||||||
- name: Upload binary
|
|
||||||
if: startsWith(github.ref, 'refs/tags/')
|
|
||||||
run: |
|
|
||||||
source ./scripts/upload-asset.sh
|
|
||||||
|
|
||||||
# Move/rename file
|
|
||||||
mkdir out && cd out
|
|
||||||
if [[ "${{ matrix.target }}" == *windows* ]]; then
|
|
||||||
src="../tealdeer-${{ matrix.target }}/tldr.exe"
|
|
||||||
filename="tealdeer-${{ matrix.target }}.exe"
|
|
||||||
else
|
|
||||||
src="../tealdeer-${{ matrix.target }}/tldr"
|
|
||||||
filename="tealdeer-${{ matrix.target }}"
|
|
||||||
fi
|
|
||||||
cp $src $filename
|
|
||||||
|
|
||||||
# Create checksum
|
|
||||||
sha256sum "$filename" > "$filename.sha256"
|
|
||||||
|
|
||||||
# Upload: <token> <repo> <tag> <file> <name>
|
|
||||||
upload_release_file ${{ secrets.GITHUB_TOKEN }} ${{ github.repository }} ${GITHUB_REF#refs/*/} $filename $filename
|
|
||||||
upload_release_file ${{ secrets.GITHUB_TOKEN }} ${{ github.repository }} ${GITHUB_REF#refs/*/} $filename.sha256 $filename.sha256
|
|
||||||
5
.gitignore
vendored
|
|
@ -1,5 +0,0 @@
|
||||||
target
|
|
||||||
*.swp
|
|
||||||
*.tar.gz
|
|
||||||
tldr-master/
|
|
||||||
dist-*/
|
|
||||||
1
.nojekyll
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
This file makes sure that Github Pages doesn't process mdBook's output.
|
||||||
222
404.html
Normal file
|
|
@ -0,0 +1,222 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html lang="en" class="sidebar-visible no-js light">
|
||||||
|
<head>
|
||||||
|
<!-- Book generated using mdBook -->
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title></title>
|
||||||
|
|
||||||
|
|
||||||
|
<base href="/">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Custom HTML head -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||||
|
<meta name="description" content="">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="theme-color" content="#ffffff" />
|
||||||
|
|
||||||
|
|
||||||
|
<link rel="icon" href="favicon.svg">
|
||||||
|
|
||||||
|
|
||||||
|
<link rel="shortcut icon" href="favicon.png">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="css/variables.css">
|
||||||
|
<link rel="stylesheet" href="css/general.css">
|
||||||
|
<link rel="stylesheet" href="css/chrome.css">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="css/print.css" media="print">
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Fonts -->
|
||||||
|
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="fonts/fonts.css">
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Highlight.js Stylesheets -->
|
||||||
|
<link rel="stylesheet" href="highlight.css">
|
||||||
|
<link rel="stylesheet" href="tomorrow-night.css">
|
||||||
|
<link rel="stylesheet" href="ayu-highlight.css">
|
||||||
|
|
||||||
|
<!-- Custom theme stylesheets -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- Provide site root to javascript -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var path_to_root = "";
|
||||||
|
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
try {
|
||||||
|
var theme = localStorage.getItem('mdbook-theme');
|
||||||
|
var sidebar = localStorage.getItem('mdbook-sidebar');
|
||||||
|
|
||||||
|
if (theme.startsWith('"') && theme.endsWith('"')) {
|
||||||
|
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
||||||
|
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
||||||
|
}
|
||||||
|
} catch (e) { }
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Set the theme before any content is loaded, prevents flash -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var theme;
|
||||||
|
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||||||
|
if (theme === null || theme === undefined) { theme = default_theme; }
|
||||||
|
var html = document.querySelector('html');
|
||||||
|
html.classList.remove('no-js')
|
||||||
|
html.classList.remove('light')
|
||||||
|
html.classList.add(theme);
|
||||||
|
html.classList.add('js');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Hide / unhide sidebar before it is displayed -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var html = document.querySelector('html');
|
||||||
|
var sidebar = 'hidden';
|
||||||
|
if (document.body.clientWidth >= 1080) {
|
||||||
|
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
||||||
|
sidebar = sidebar || 'visible';
|
||||||
|
}
|
||||||
|
html.classList.remove('sidebar-visible');
|
||||||
|
html.classList.add("sidebar-" + sidebar);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||||
|
<div class="sidebar-scrollbox">
|
||||||
|
<ol class="chapter"><li class="chapter-item expanded affix "><a href="intro.html">Introduction</a></li><li class="chapter-item expanded "><a href="installing.html"><strong aria-hidden="true">1.</strong> Installing</a></li><li class="chapter-item expanded "><a href="usage.html"><strong aria-hidden="true">2.</strong> Usage</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="usage_custom_pages.html"><strong aria-hidden="true">2.1.</strong> Custom Pages and Patches</a></li></ol></li><li class="chapter-item expanded "><a href="config.html"><strong aria-hidden="true">3.</strong> Configuration</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="config_display.html"><strong aria-hidden="true">3.1.</strong> Section: [display]</a></li><li class="chapter-item expanded "><a href="config_style.html"><strong aria-hidden="true">3.2.</strong> Section: [style]</a></li><li class="chapter-item expanded "><a href="config_search.html"><strong aria-hidden="true">3.3.</strong> Section: [search]</a></li><li class="chapter-item expanded "><a href="config_updates.html"><strong aria-hidden="true">3.4.</strong> Section: [updates]</a></li><li class="chapter-item expanded "><a href="config_directories.html"><strong aria-hidden="true">3.5.</strong> Section: [directories]</a></li></ol></li><li class="chapter-item expanded "><a href="tips_and_tricks.html"><strong aria-hidden="true">4.</strong> Tips and Tricks</a></li></ol>
|
||||||
|
</div>
|
||||||
|
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div id="page-wrapper" class="page-wrapper">
|
||||||
|
|
||||||
|
<div class="page">
|
||||||
|
|
||||||
|
<div id="menu-bar-hover-placeholder"></div>
|
||||||
|
<div id="menu-bar" class="menu-bar sticky bordered">
|
||||||
|
<div class="left-buttons">
|
||||||
|
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
||||||
|
<i class="fa fa-bars"></i>
|
||||||
|
</button>
|
||||||
|
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
||||||
|
<i class="fa fa-paint-brush"></i>
|
||||||
|
</button>
|
||||||
|
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
||||||
|
<i class="fa fa-search"></i>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1 class="menu-title">Tealdeer User Manual</h1>
|
||||||
|
|
||||||
|
<div class="right-buttons">
|
||||||
|
|
||||||
|
<a href="print.html" title="Print this book" aria-label="Print this book">
|
||||||
|
<i id="print-button" class="fa fa-print"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="search-wrapper" class="hidden">
|
||||||
|
<form id="searchbar-outer" class="searchbar-outer">
|
||||||
|
<input type="search" name="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||||||
|
</form>
|
||||||
|
<div id="searchresults-outer" class="searchresults-outer hidden">
|
||||||
|
<div id="searchresults-header" class="searchresults-header"></div>
|
||||||
|
<ul id="searchresults">
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
||||||
|
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
||||||
|
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
||||||
|
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div id="content" class="content">
|
||||||
|
<main>
|
||||||
|
<h1><a class="header" href="#document-not-found-404" id="document-not-found-404">Document not found (404)</a></h1>
|
||||||
|
<p>This URL is invalid, sorry. Please use the navigation bar or search to continue.</p>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||||
|
<!-- Mobile navigation buttons -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div style="clear: both"></div>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
window.playground_copyable = true;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="searcher.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="highlight.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="book.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
||||||
|
<!-- Custom JS scripts -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
724
CHANGELOG.md
|
|
@ -1,724 +0,0 @@
|
||||||
# Changelog
|
|
||||||
|
|
||||||
This project follows semantic versioning.
|
|
||||||
|
|
||||||
Possible log types:
|
|
||||||
|
|
||||||
- `[added]` for new features.
|
|
||||||
- `[changed]` for changes in existing functionality.
|
|
||||||
- `[deprecated]` for once-stable features removed in upcoming releases.
|
|
||||||
- `[removed]` for deprecated features removed in this release.
|
|
||||||
- `[fixed]` for any bug fixes.
|
|
||||||
- `[security]` to invite users to upgrade in case of vulnerabilities.
|
|
||||||
- `[docs]` for documentation changes.
|
|
||||||
- `[chore]` for maintenance work.
|
|
||||||
|
|
||||||
### [v1.5.1][v1.5.1], [v1.6.2][v1.6.2], [v1.7.3][v1.7.3] (2026-01-25)
|
|
||||||
|
|
||||||
Today I am releasing three patch updates for outdated versions of tealdeer.
|
|
||||||
They are minimal patches for Linux distributions that ship old versions of
|
|
||||||
tealdeer which recently broke due to an upstream change. If you can choose
|
|
||||||
freely which version of tealdeer to use, I recommend using the latest version of
|
|
||||||
tealdeer, 1.8.1. For more details, see the "Notes to package maintainers"
|
|
||||||
section below.
|
|
||||||
|
|
||||||
All three updates contain only a single change compared to their respective
|
|
||||||
previous versions which changes the `ARCHIVE_URL` constant used for updating the
|
|
||||||
page cache. The reason for this change is that the upstream tldr-pages
|
|
||||||
repository shut down the domain that clients were previously required to use.
|
|
||||||
|
|
||||||
Note that this issue is already fixed in tealdeer 1.8.0 where we introduced a
|
|
||||||
config file option for changing the URL used at runtime. The versions 1.8.0 and
|
|
||||||
1.8.1 also use the new domain of the tldr-pages archive by default, so no action
|
|
||||||
is needed for users of those versions.
|
|
||||||
|
|
||||||
#### Changes
|
|
||||||
|
|
||||||
- [fixed] Update `ARCHIVE_URL`
|
|
||||||
|
|
||||||
#### Notes to package maintainers
|
|
||||||
|
|
||||||
I have _not_ updated the lockfile for any of these releases, so the locked
|
|
||||||
dependency versions are still the same as they were for the previous release in
|
|
||||||
the respective v1.x series. Updating the lockfile for tealdeer 1.5.0 to remove
|
|
||||||
any `cargo audit` warnings while also maintaining compatibility with Rust 1.54
|
|
||||||
also brings larger changes through transitive dependencies, which contradicts my
|
|
||||||
plan to make this update easy to plug into existing build pipelines.
|
|
||||||
|
|
||||||
If you want to build / distribute tealdeer v1.5.1, v1.6.2, or v1.7.3, please use
|
|
||||||
an up to date Rust toolchain to permit updates to newer versions of (transitive)
|
|
||||||
dependencies. Do not use the lockfile, instead update to the newest available
|
|
||||||
dependency versions.
|
|
||||||
|
|
||||||
For the same reason, there are no artifacts attached to the GitHub releases of
|
|
||||||
these versions.
|
|
||||||
|
|
||||||
### [v1.8.1][v1.8.1] (2025-11-11)
|
|
||||||
|
|
||||||
This patch release tweaks the enabled features for ureq, the library we use to
|
|
||||||
perform HTTP requests when updating the cache. In particular, support for socks
|
|
||||||
proxies is now enabled.
|
|
||||||
|
|
||||||
#### Changes:
|
|
||||||
|
|
||||||
- [added] Enable ureq's socks-proxy feature ([#451])
|
|
||||||
|
|
||||||
### [v1.8.0][v1.8.0] (2025-10-03)
|
|
||||||
|
|
||||||
One year and one day have passed since tealdeer version 1.7.0 was released, so
|
|
||||||
it's time for an update! Tealdeer 1.8 comes with a complete rewrite of the page
|
|
||||||
cache and contains many long awaited improvements around it.
|
|
||||||
|
|
||||||
Firstly, tealdeer now supports language-specific downloads. This means that only
|
|
||||||
the pages matching the configured languages are downloaded when updating the
|
|
||||||
cache. The languages used for searching pages can be configured separately to
|
|
||||||
the ones used for updating, so it is possible to download pages in languages
|
|
||||||
that are not usually queried.
|
|
||||||
|
|
||||||
Next to configuring which languages are used for searching, it is now also
|
|
||||||
possible to specify which platforms are used in the config file. Importantly,
|
|
||||||
the default behavior for page search has changed so that all platforms are
|
|
||||||
searched if no page is found for the platform that tealdeer is running on. To
|
|
||||||
restore the behavior of tealdeer 1.7, users should set
|
|
||||||
```toml
|
|
||||||
[search]
|
|
||||||
platforms = ["current", "common"]
|
|
||||||
```
|
|
||||||
in their config file.
|
|
||||||
|
|
||||||
Coming back to updating, the default build configuration of tealdeer now
|
|
||||||
includes multiple TLS backends. This means that tealdeer does not have to be
|
|
||||||
rebuilt to try out a different TLS backend. The used backend can be chosen in
|
|
||||||
the config file. By default, tealdeer comes with support for rustls using webpki
|
|
||||||
certificates or system certificates. Native TLS is supported, but not enabled by
|
|
||||||
default to avoid build troubles with OpenSSL and musl.
|
|
||||||
|
|
||||||
For details, please refer to the [user documentation].
|
|
||||||
|
|
||||||
#### Changes:
|
|
||||||
|
|
||||||
- [added] Resolve paths in config `[directories]` relative to the config directory ([#306])
|
|
||||||
- [added] Add `common` platform to CLI ([#401])
|
|
||||||
- [added] Add configuration option for `archive_source` ([#337])
|
|
||||||
- [added] Allows configuring TLS backend ([#386])
|
|
||||||
- [added] Add args: `--edit-page` and `--edit-patch` ([#388])
|
|
||||||
- [added] Add an option to specify a custom config file to be used ([#422])
|
|
||||||
- [added] Upload binaries from build step as artifact ([#423])
|
|
||||||
- [added] Add `search.languages` and `updates.download_languages` settings ([#430])
|
|
||||||
- [added] Add `search.platforms` config option and search all platforms by default ([#435])
|
|
||||||
- [added] Add `display.show_title` option to display command titles in output ([#439])
|
|
||||||
- [chore] Various test improvements ([#399])
|
|
||||||
- [chore] Add tests for osx/macos alias ([#407])
|
|
||||||
- [chore] Move most of `main` to `try_main` ([#400])
|
|
||||||
- [chore] Only create a single temporary directory in integration tests ([#411])
|
|
||||||
- [chore] Replace reqwest with ureq ([#417])
|
|
||||||
- [chore] Introduce Language struct ([#425])
|
|
||||||
- [chore] Cache rewrite ([#416])
|
|
||||||
- [chore] Allow references in `Config` ([#429])
|
|
||||||
- [docs] Highlight code examples in user docs ([#440])
|
|
||||||
- [removed] Remove native-tls from default feature set ([#436])
|
|
||||||
|
|
||||||
#### Contributors to this version:
|
|
||||||
|
|
||||||
- [Christoph Loy][@beatbrot]
|
|
||||||
- [Erick Guan][@erickguan]
|
|
||||||
- [@MHS-0][@MHS-0]
|
|
||||||
- [Matěj Kafka][@MatejKafka]
|
|
||||||
- [Nachiket Kanore][@nachiketkanore]
|
|
||||||
- [Niklas Mohrin][@niklasmohrin]
|
|
||||||
- [Predrag Minic][@mipedja]
|
|
||||||
- [@hex1c][@hex1c]
|
|
||||||
- [lyj][@lengyijun]
|
|
||||||
|
|
||||||
Thanks!
|
|
||||||
|
|
||||||
#### Notes to package maintainers
|
|
||||||
|
|
||||||
1. The MSRV has been bumped to 1.85.
|
|
||||||
2. Consider whether you want to include the `native-tls` feature in your build
|
|
||||||
of tealdeer. The feature is disabled for the binaries in the GitHub release
|
|
||||||
because we target musl, but it might work out of the box for your
|
|
||||||
distribution.
|
|
||||||
3. We have added the `ignore-online-tests` feature to automatically mark all
|
|
||||||
tests that require an internet connection as skipped, so you can use this
|
|
||||||
feature instead of maintaining a list of these tests yourself.
|
|
||||||
|
|
||||||
### [v1.7.2][v1.7.2] (2025-03-18)
|
|
||||||
|
|
||||||
This patch release updates the `zip` dependency to mitigate a potential security
|
|
||||||
vulnerability. A successful attack against tealdeer users would require
|
|
||||||
manipulation of the tldr pages archive downloaded during an update. As the
|
|
||||||
archive is downloaded from a trusted source (the tldr-pages organization), it
|
|
||||||
seems very unlikely that running a version of tealdeer prior to 1.7.2 poses a
|
|
||||||
security risk. Nevertheless, it cannot hurt to rule out any chance of an attack
|
|
||||||
by updating tealdeer to version 1.7.2.
|
|
||||||
|
|
||||||
For more details, please see https://github.com/advisories/GHSA-94vh-gphv-8pm8.
|
|
||||||
|
|
||||||
- [security] Require `zip >= 2.3.0`
|
|
||||||
- [chore] Run CI on backport branches and on dispatch
|
|
||||||
|
|
||||||
### [v1.7.1][v1.7.1] (2024-11-14)
|
|
||||||
|
|
||||||
This patch release updates the `yansi` dependency to version 1, so that the
|
|
||||||
previous versions of `yansi` can be removed from the package sets of Linux
|
|
||||||
distributions. This change should not impact the behavior of tealdeer.
|
|
||||||
|
|
||||||
#### Changes:
|
|
||||||
|
|
||||||
- [chore] Upgrade yansi: 0.5.1 -> 1.0.1 ([#389])
|
|
||||||
|
|
||||||
#### Contributors to this version:
|
|
||||||
|
|
||||||
- [Blair Noctis][@nc7s]
|
|
||||||
|
|
||||||
Thanks!
|
|
||||||
|
|
||||||
### [v1.7.0][v1.7.0] (2024-10-02)
|
|
||||||
|
|
||||||
It's been 24 months since the last release, time for tealdeer 1.7.0! Thanks to
|
|
||||||
16 individual contributors, a few nice changes and features are included in
|
|
||||||
this release.
|
|
||||||
|
|
||||||
One change is that you can **query multiple platforms at once**. For example:
|
|
||||||
|
|
||||||
tldr --platform openbsd --platform linux df
|
|
||||||
|
|
||||||
This will show the `df` page for OpenBSD (if available), followed by Linux (if
|
|
||||||
available), with fallback to the current platform on which tealdeer runs.
|
|
||||||
|
|
||||||
What's that `openbsd` thing up there? Yes, there's now **support for the BSD
|
|
||||||
platforms `freebsd`, `netbsd` and `openbsd`**.
|
|
||||||
|
|
||||||
And since we're already talking about platform support: Our **binary releases
|
|
||||||
now include builds for ARM64 (aka `aarch64`) on macOS (Apple Silicon, M1/M2/M3)
|
|
||||||
and Linux**. _(Keep in mind that binary releases are generated in CI and are
|
|
||||||
unsigned. For a trusted build, please compile from source.)_
|
|
||||||
|
|
||||||
There's also a breaking change for the folks using [custom pages and
|
|
||||||
patches](https://tealdeer-rs.github.io/tealdeer/usage_custom_pages.html): These
|
|
||||||
files now use a `.md` extension. Old files will continue to work, but will
|
|
||||||
result a deprecation warning being printed when used.
|
|
||||||
|
|
||||||
On a personal note, this will be the last release from me
|
|
||||||
([Danilo](https://github.com/dbrgn/)) as primary maintainer of tealdeer. For
|
|
||||||
details, see [#376](https://github.com/tealdeer-rs/tealdeer/issues/376).
|
|
||||||
|
|
||||||
#### Changes:
|
|
||||||
|
|
||||||
- [added] Allow querying multiple platforms ([#300])
|
|
||||||
- [added] Add BSD platform support ([#354])
|
|
||||||
- [added] Allow building with native-tls in addition to rustls ([#303])
|
|
||||||
- [changed] Change custom page files to use a `.md` file extension ([#322])
|
|
||||||
- [changed] Update to clap v4 for doing command line parsing ([#298])
|
|
||||||
- [changed] Performance optimization in LineIterator ([#314])
|
|
||||||
- [changed] Performance optimizations by tweaking Cargo flags ([#355])
|
|
||||||
- [changed] Include completions in published crate ([#333])
|
|
||||||
- [changed] Minimal supported Rust version is now 1.75 ([#298])
|
|
||||||
- [fixed] Fix bash/zsh/fish completions when cache is empty ([#327], [#331])
|
|
||||||
- [docs] Publish docs only when tagging a release ([#362])
|
|
||||||
- [docs] List Scoop and Debian packages ([#305], [#315])
|
|
||||||
- [docs] Add "Tips and Tricks" chapter to user manual ([#342])
|
|
||||||
- [docs] Various docs improvements ([#293])
|
|
||||||
- [chore] Improvements to CI workflows ([#324])
|
|
||||||
- [chore] Update Cargo.toml license field following SPDX 2.1 ([#336])
|
|
||||||
- [chore] Dependency updates
|
|
||||||
|
|
||||||
#### Contributors to this version:
|
|
||||||
|
|
||||||
- [Adam Henley][@adamazing]
|
|
||||||
- [Andrea Frigido][@frisoft]
|
|
||||||
- [Blair Noctis][@nc7s]
|
|
||||||
- [Danilo Bargen][@dbrgn]
|
|
||||||
- [Felix Yan][@felixonmars]
|
|
||||||
- [Iliia Maleki][@iliya-malecki]
|
|
||||||
- [JJ Style][@jj-style]
|
|
||||||
- [K.B.Dharun Krishna][@kbdharun]
|
|
||||||
- [Linus Walker][@Walker-00]
|
|
||||||
- [Mohit Raj][@agrmohit]
|
|
||||||
- [Nicolai Fröhlich][@nifr]
|
|
||||||
- [Niklas Mohrin][@niklasmohrin]
|
|
||||||
- [@qknogxxb][@qknogxxb]
|
|
||||||
- [@tveness][@tveness]
|
|
||||||
- [Y.D.X.][@YDX-2147483647]
|
|
||||||
- [Zacchary Dempsey-Plante][@zedseven]
|
|
||||||
|
|
||||||
Thanks!
|
|
||||||
|
|
||||||
|
|
||||||
### [v1.6.1][v1.6.1] (2022-10-24)
|
|
||||||
|
|
||||||
#### Changes:
|
|
||||||
|
|
||||||
- [fixed] Fix path source for custom pages dir ([#297])
|
|
||||||
- [chore] Update dependendencies ([#299])
|
|
||||||
|
|
||||||
#### Contributors to this version:
|
|
||||||
|
|
||||||
- [Cyrus Yip][@CyrusYip]
|
|
||||||
- [Danilo Bargen][@dbrgn]
|
|
||||||
|
|
||||||
Thanks!
|
|
||||||
|
|
||||||
|
|
||||||
### [v1.6.0][v1.6.0] (2022-10-02)
|
|
||||||
|
|
||||||
It's been 9 months since the last release already! This is not a huge update
|
|
||||||
feature-wise, but it still contains a few nice new improvements and a few
|
|
||||||
bugfixes, contributed by 11 different people. The most important new feature is
|
|
||||||
probably the option to override the cache directory through the config file.
|
|
||||||
The `TEALDEER_CACHE_DIR` env variable is now deprecated.
|
|
||||||
|
|
||||||
A note to packagers: Shell completions have been moved to the `completion/`
|
|
||||||
subdirectory! Packaging scripts might need to be updated.
|
|
||||||
|
|
||||||
#### Changes:
|
|
||||||
|
|
||||||
- [added] Allow overriding cache directory through config ([#276])
|
|
||||||
- [added] Add `--no-auto-update` CLI flag ([#257])
|
|
||||||
- [added] Show note about auto-updates when cache is missing ([#254])
|
|
||||||
- [added] Add support for android platform ([#274])
|
|
||||||
- [added] Add custom pages to list output ([#285])
|
|
||||||
- [fixed] Cache: Return error if HTTP client cannot be created ([#247])
|
|
||||||
- [fixed] Handle cache download errors ([#253])
|
|
||||||
- [fixed] Do not page output of `tldr --update` ([#231])
|
|
||||||
- [fixed] Create macOS release builds with bundled root certificates ([#272])
|
|
||||||
- [fixed] Clean up and fix shell completions ([#262])
|
|
||||||
- [deprecated] The `TEALDEER_CACHE_DIR` env variable is now deprecated ([#276])
|
|
||||||
- [removed] The `--config-path` command was removed, use `--show-paths` instead ([#290])
|
|
||||||
- [removed] The `-o/--os` command was removed, use `-p/--platform` instead ([#290])
|
|
||||||
- [removed] The `-m/--markdown` command was removed, use `-r/--raw` instead ([#290])
|
|
||||||
- [chore] Move shell completion scripts to their own directory ([#259])
|
|
||||||
- [chore] Update dependencies ([#271], [#287], [#291])
|
|
||||||
- [chore] Use anyhow for error handling ([#249])
|
|
||||||
- [chore] Switch to Rust 2021 edition ([#284])
|
|
||||||
|
|
||||||
#### Contributors to this version:
|
|
||||||
|
|
||||||
- [@bagohart][@bagohart]
|
|
||||||
- [@cyqsimon][@cyqsimon]
|
|
||||||
- [Danilo Bargen][@dbrgn]
|
|
||||||
- [Danny Mösch][@SimplyDanny]
|
|
||||||
- [Evan Lloyd New-Schmidt][@newsch]
|
|
||||||
- [Hans Gaiser][@hgaiser]
|
|
||||||
- [Kian-Meng Ang][@kianmeng]
|
|
||||||
- [Marcin Puc][@tranzystorek-io]
|
|
||||||
- [Niklas Mohrin][@niklasmohrin]
|
|
||||||
- [Olav de Haas][@Olavhaasie]
|
|
||||||
- [Simon Perdrisat][@gagarine]
|
|
||||||
|
|
||||||
Thanks!
|
|
||||||
|
|
||||||
|
|
||||||
### [v1.5.0][v1.5.0] (2021-12-31)
|
|
||||||
|
|
||||||
This is quite a big release with many new features. In the 15 months since the
|
|
||||||
last release, 59 pull requests from 16 different contributors were merged!
|
|
||||||
|
|
||||||
The highlights:
|
|
||||||
|
|
||||||
- **Custom pages and patches**: You can now create your own local-only tldr
|
|
||||||
pages. But not just that, you can also extend existing upstream pages with
|
|
||||||
your own examples. For more details, see
|
|
||||||
[the docs](https://tealdeer-rs.github.io/tealdeer/usage_custom_pages.html).
|
|
||||||
- **Change argument parsing from docopt to clap**: We replaced docopt.rs as
|
|
||||||
argument parsing library with clap v3, resulting in almost 1 MiB smaller
|
|
||||||
binaries and a 22% speed increase when rendering a tldr page.
|
|
||||||
- **Multi-language support**: You can now override the language with `-L/--language`.
|
|
||||||
- **A new `--show-paths` command**: By running `tldr --show-paths`, you can list
|
|
||||||
the currently used config dir, cache dir, upstream pages dir and custom pages dir.
|
|
||||||
- **Compliance with the tldr client spec v1.5**: We renamed `-o/--os` to
|
|
||||||
`-p/--platform` and implemented transparent lowercasing of the page names.
|
|
||||||
- **Docs**: The README based documentation has reached its limits. There are
|
|
||||||
now new mdbook based docs over at
|
|
||||||
[tealdeer-rs.github.io/tealdeer/](https://tealdeer-rs.github.io/tealdeer/), we hope these
|
|
||||||
make using tealdeer easier. Of course, documentation improvements are
|
|
||||||
welcome! Also, if you're confused about how to use a certain feature, feel
|
|
||||||
free to open an issue, this way we can improve the docs.
|
|
||||||
|
|
||||||
Note that the MSRV (Minimal Supported Rust Version) of the project
|
|
||||||
[changed][i190]:
|
|
||||||
|
|
||||||
> When publishing a tealdeer release, the Rust version required to build it
|
|
||||||
> should be stable for at least a month.
|
|
||||||
|
|
||||||
#### Changes:
|
|
||||||
|
|
||||||
- [added] Support custom pages and patches ([#142][i142])
|
|
||||||
- [added] Multi-language support ([#125][i125], [#161][i161])
|
|
||||||
- [added] Add support for ANSI code and RGB colors ([#148][i148])
|
|
||||||
- [added] Implement new `--show-paths` command ([#162][i162])
|
|
||||||
- [added] Support for italic text styling ([#197][i197])
|
|
||||||
- [added] Allow SunOS platform override ([#176][i176])
|
|
||||||
- [added] Automatically lowercase page names before lookup ([#227][i227])
|
|
||||||
- [added] Add "macos" alias for "osx" ([#215][i215])
|
|
||||||
- [fixed] Consider only standalone command names for styling ([#157][i157])
|
|
||||||
- [fixed] Fixed and improved zsh completions ([#168][i168])
|
|
||||||
- [fixed] Create cache directory path if it does not exist ([#174][i174])
|
|
||||||
- [fixed] Use default style if user-defined style is missing ([#210][i210])
|
|
||||||
- [changed] Switch from docopt to clap for argument parsing ([#108][i108])
|
|
||||||
- [changed] Switch from OpenSSL to Rustls ([#187][i187])
|
|
||||||
- [changed] Performance improvements ([#187][i187])
|
|
||||||
- [changed] Send all progress logging messages to stderr ([#171][i171])
|
|
||||||
- [changed] Rename `-o/--os` to `-p/--platform` ([#217][i217])
|
|
||||||
- [changed] Rename `-m/--markdown` to `-r/--raw` ([#108][i108])
|
|
||||||
- [deprecated] The `--config-path` command is deprecated, use `--show-paths` instead ([#162][i162])
|
|
||||||
- [deprecated] The `-o/--os` command is deprecated, use `-p/--platform` instead ([#217][i217])
|
|
||||||
- [deprecated] The `-m/--markdown` command is deprecated, use `-r/--raw` instead ([#108][i108])
|
|
||||||
- [docs] New docs at [tealdeer-rs.github.io/tealdeer/](https://tealdeer-rs.github.io/tealdeer/)
|
|
||||||
- [docs] Add comparative benchmarks with hyperfine ([#163][i163], [README](https://github.com/tealdeer-rs/tealdeer#goals))
|
|
||||||
- [chore] Download tldr pages archive from their website, not from GitHub ([#213][i213])
|
|
||||||
- [chore] Bump MSRV to 1.54 and change MSRV policy ([#190][i190])
|
|
||||||
- [chore] The `master` branch was renamed to `main`
|
|
||||||
- [chore] All release binaries are now generated in CI. Binaries for macOS and Windows are also provided. ([#240][i240])
|
|
||||||
- [chore] Update all dependencies
|
|
||||||
|
|
||||||
#### Contributors to this version:
|
|
||||||
|
|
||||||
- [@bl-ue][@bl-ue]
|
|
||||||
- [Cameron Tod][@cam8001]
|
|
||||||
- [Dalton][@dmaahs2017]
|
|
||||||
- [Danilo Bargen][@dbrgn]
|
|
||||||
- [Danny Mösch][@SimplyDanny]
|
|
||||||
- [Marcin Puc][@tranzystorek-io]
|
|
||||||
- [Michael Cho][@cho-m]
|
|
||||||
- [MS_Y][@black7375]
|
|
||||||
- [Niklas Mohrin][@niklasmohrin]
|
|
||||||
- [Rithvik Vibhu][@rithvikvibhu]
|
|
||||||
- [rnd][@0ndorio]
|
|
||||||
- [Sondre Nilsen][@sondr3]
|
|
||||||
- [Tomás Farías Santana][@tomasfarias]
|
|
||||||
- [Tsvetomir Bonev][@invakid404]
|
|
||||||
- [@tveness][@tveness]
|
|
||||||
- [ギャラ][@laxect]
|
|
||||||
|
|
||||||
Thanks!
|
|
||||||
|
|
||||||
Last but not least, [Niklas Mohrin][@niklasmohrin] has joined the project as
|
|
||||||
co-maintainer. Thank you for your help!
|
|
||||||
|
|
||||||
|
|
||||||
### [v1.4.1][v1.4.1] (2020-09-04)
|
|
||||||
|
|
||||||
- [fixed] Syntax error in zsh completion file ([#138][i138])
|
|
||||||
|
|
||||||
#### Contributors to this version:
|
|
||||||
|
|
||||||
- [Danilo Bargen][@dbrgn]
|
|
||||||
- [Bruno A. Muciño][@mucinoab]
|
|
||||||
- [Francesco][@BachoSeven]
|
|
||||||
|
|
||||||
Thanks!
|
|
||||||
|
|
||||||
|
|
||||||
### [v1.4.0][v1.4.0] (2020-09-03)
|
|
||||||
|
|
||||||
- [added] Configurable automatic cache updates ([#115][i115])
|
|
||||||
- [added] Improved color detection and support for `--color` argument and
|
|
||||||
`NO_COLOR` env variable ([#111][i111])
|
|
||||||
- [changed] Make `--list` option comply with official spec ([#112][i112])
|
|
||||||
- [changed] Move cache age warning to stderr ([#113][i113])
|
|
||||||
|
|
||||||
#### Contributors to this version:
|
|
||||||
|
|
||||||
- [Atul Bhosale][@Atul9]
|
|
||||||
- [Danilo Bargen][@dbrgn]
|
|
||||||
- [Danny Mösch][@SimplyDanny]
|
|
||||||
- [Ilaï Deutel][@ilai-deutel]
|
|
||||||
- [Kornel][@kornelski]
|
|
||||||
- [@LovecraftianHorror][@LovecraftianHorror]
|
|
||||||
- [@michaeldel][@michaeldel]
|
|
||||||
- [Niklas Mohrin][@niklasmohrin]
|
|
||||||
|
|
||||||
Thanks!
|
|
||||||
|
|
||||||
|
|
||||||
### [v1.3.0][v1.3.0] (2020-02-28)
|
|
||||||
|
|
||||||
- [added] New config option for compact output mode ([#89][i89])
|
|
||||||
- [added] New -m/--markdown parameter for raw rendering ([#95][i95])
|
|
||||||
- [added] Provide zsh autocompletion ([#86][i86])
|
|
||||||
- [changed] Require at least Rust 1.39 to build (previous: 1.32)
|
|
||||||
- [changed] Switch to GitHub actions, CI testing now covers Windows as well ([#99][i99])
|
|
||||||
- [changed] Tweak the "outdated cache" warning message ([#97][i97])
|
|
||||||
- [changed] General maintenance: Upgrade dependencies, fix linter warnings
|
|
||||||
- [fixed] Fix Fish autocompletion on macOS ([#87][i87])
|
|
||||||
- [fixed] Fix compilation on Windows by disabling pager ([#99][i99])
|
|
||||||
|
|
||||||
#### Contributors to this version:
|
|
||||||
|
|
||||||
- [Bruno Heridet][@Delapouite]
|
|
||||||
- [Danilo Bargen][@dbrgn]
|
|
||||||
- [Hugo Locurcio][@Calinou]
|
|
||||||
- [Isak Johansson][@Plommonsorbet]
|
|
||||||
- [James Doyle][@james2doyle]
|
|
||||||
- [Jesús Trinidad Díaz Ramírez][@jesdazrez]
|
|
||||||
- [@korrat][@korrat]
|
|
||||||
- [Marc-André Renaud][@ma-renaud]
|
|
||||||
|
|
||||||
Thanks!
|
|
||||||
|
|
||||||
|
|
||||||
### [v1.2.0][v1.2.0] (2019-08-10)
|
|
||||||
|
|
||||||
- [added] Add Windows support ([#77][i77])
|
|
||||||
- [added] Add support for spaces in commands ([#75][i75])
|
|
||||||
- [added] Add support for Fish-based autocompletion ([#71][i71])
|
|
||||||
- [added] Add pager support ([#44][i44])
|
|
||||||
- [added] Print detected OS with `-v` / `--version` ([#57][i57])
|
|
||||||
- [changed] OS detection: Treat BSDs as "osx" ([#58][i58])
|
|
||||||
- [changed] Move from curl to reqwest ([#61][i61])
|
|
||||||
- [changed] Move to Rust 2018, require Rust 1.32 ([#69][i69] / [#84][i84])
|
|
||||||
- [fixed] Add (back) support for proxies ([#68][i68])
|
|
||||||
|
|
||||||
#### Contributors to this version:
|
|
||||||
|
|
||||||
- [Bar Hatsor][@Bassets]
|
|
||||||
- [Danilo Bargen][@dbrgn]
|
|
||||||
- [Gabriel Martinez][@mystal]
|
|
||||||
- [Ivan Smirnov][@aldanor]
|
|
||||||
- [Jan Christian Grünhage][@jcgruenhage]
|
|
||||||
- [Jonathan Dahan][@jedahan]
|
|
||||||
- [Juan D. Vega][@jdvr]
|
|
||||||
- [Natalie Pendragon][@natpen]
|
|
||||||
- [Raphael Das Gupta][@das-g]
|
|
||||||
|
|
||||||
Thanks!
|
|
||||||
|
|
||||||
|
|
||||||
### [v1.1.0][v1.1.0] (2018-10-22)
|
|
||||||
|
|
||||||
- [added] Configuration file support ([#43][i43])
|
|
||||||
- [added] Allow configuration of colors/style ([#43][i43])
|
|
||||||
- [added] New `--quiet` / `-q` option to suppress most non-error messages ([#48][i48])
|
|
||||||
- [changed] Require at least Rust 1.28 to build (previous: 1.19)
|
|
||||||
- [fixed] Fix building on systems with openssl 1.1.1 ([#47][i47])
|
|
||||||
|
|
||||||
#### Contributors to this version:
|
|
||||||
|
|
||||||
- [Danilo Bargen][@dbrgn]
|
|
||||||
- [@equal-l2][@equal-l2]
|
|
||||||
- [Jonathan Dahan][@jedahan]
|
|
||||||
- [Lukas Bergdoll][@Voultapher]
|
|
||||||
|
|
||||||
Thanks!
|
|
||||||
|
|
||||||
|
|
||||||
### [v1.0.0][v1.0.0] (2018-02-11)
|
|
||||||
|
|
||||||
- [added] Include bash completions ([#34][i34])
|
|
||||||
- [changed] Update all dependencies
|
|
||||||
- [changed] Require at least Rust 1.19 to build (previous: 1.9)
|
|
||||||
- [changed] Improved unit/integration testing
|
|
||||||
|
|
||||||
|
|
||||||
### v0.4.0 (2016-11-25)
|
|
||||||
|
|
||||||
- [added] Support for new page format
|
|
||||||
- [changed] Update all dependencies
|
|
||||||
|
|
||||||
|
|
||||||
### v0.3.0 (2016-08-01)
|
|
||||||
|
|
||||||
- [changed] Update curl dependency
|
|
||||||
|
|
||||||
|
|
||||||
### v0.2.0 (2016-04-16)
|
|
||||||
|
|
||||||
- First crates.io release
|
|
||||||
|
|
||||||
[user documentation]: https://tealdeer-rs.github.io/tealdeer/
|
|
||||||
|
|
||||||
[@0ndorio]: https://github.com/0ndorio
|
|
||||||
[@adamazing]: https://github.com/adamazing
|
|
||||||
[@agrmohit]: https://github.com/agrmohit
|
|
||||||
[@aldanor]: https://github.com/aldanor
|
|
||||||
[@Atul9]: https://github.com/Atul9
|
|
||||||
[@BachoSeven]: https://github.com/BachoSeven
|
|
||||||
[@bagohart]: https://github.com/bagohart
|
|
||||||
[@Bassets]: https://github.com/Bassets
|
|
||||||
[@black7375]: https://github.com/black7375
|
|
||||||
[@bl-ue]: https://github.com/bl-ue
|
|
||||||
[@Calinou]: https://github.com/Calinou
|
|
||||||
[@cam8001]: https://github.com/cam8001
|
|
||||||
[@cho-m]: https://github.com/cho-m
|
|
||||||
[@cyqsimon]: https://github.com/cyqsimon
|
|
||||||
[@CyrusYip]: https://github.com/CyrusYip
|
|
||||||
[@das-g]: https://github.com/das-g
|
|
||||||
[@dbrgn]: https://github.com/dbrgn
|
|
||||||
[@Delapouite]: https://github.com/Delapouite
|
|
||||||
[@dmaahs2017]: https://github.com/dmaahs2017
|
|
||||||
[@equal-l2]: https://github.com/equal-l2
|
|
||||||
[@felixonmars]: https://github.com/felixonmars
|
|
||||||
[@frisoft]: https://github.com/frisoft
|
|
||||||
[@gagarine]: https://github.com/gagarine
|
|
||||||
[@hgaiser]: https://github.com/hgaiser
|
|
||||||
[@ilai-deutel]: https://github.com/ilai-deutel
|
|
||||||
[@iliya-malecki]: https://github.com/iliya-malecki
|
|
||||||
[@invakid404]: https://github.com/invakid404
|
|
||||||
[@james2doyle]: https://github.com/james2doyle
|
|
||||||
[@jcgruenhage]: https://github.com/jcgruenhage
|
|
||||||
[@jdvr]: https://github.com/jdvr
|
|
||||||
[@jedahan]: https://github.com/jedahan
|
|
||||||
[@jesdazrez]: https://github.com/jesdazrez
|
|
||||||
[@jj-style]: https://github.com/jj-style
|
|
||||||
[@kbdharun]: https://github.com/kbdharun
|
|
||||||
[@kianmeng]: https://github.com/kianmeng
|
|
||||||
[@kornelski]: https://github.com/kornelski
|
|
||||||
[@korrat]: https://github.com/korrat
|
|
||||||
[@laxect]: https://github.com/laxect
|
|
||||||
[@LovecraftianHorror]: https://github.com/LovecraftianHorror
|
|
||||||
[@ma-renaud]: https://github.com/ma-renaud
|
|
||||||
[@michaeldel]: https://github.com/michaeldel
|
|
||||||
[@mucinoab]: https://github.com/mucinoab
|
|
||||||
[@mystal]: https://github.com/mystal
|
|
||||||
[@natpen]: https://github.com/natpen
|
|
||||||
[@nc7s]: https://github.com/nc7s
|
|
||||||
[@newsch]: https://github.com/newsch
|
|
||||||
[@nifr]: https://github.com/nifr
|
|
||||||
[@niklasmohrin]: https://github.com/niklasmohrin
|
|
||||||
[@Olavhaasie]: https://github.com/Olavhaasie
|
|
||||||
[@Plommonsorbet]: https://github.com/Plommonsorbet
|
|
||||||
[@qknogxxb]: https://github.com/qknogxxb
|
|
||||||
[@rithvikvibhu]: https://github.com/rithvikvibhu
|
|
||||||
[@SimplyDanny]: https://github.com/SimplyDanny
|
|
||||||
[@sondr3]: https://github.com/sondr3
|
|
||||||
[@tomasfarias]: https://github.com/tomasfarias
|
|
||||||
[@tranzystorek-io]: https://github.com/tranzystorek-io
|
|
||||||
[@tveness]: https://github.com/tveness
|
|
||||||
[@Voultapher]: https://github.com/Voultapher
|
|
||||||
[@Walker-00]: https://github.com/Walker-00
|
|
||||||
[@YDX-2147483647]: https://github.com/YDX-2147483647
|
|
||||||
[@zedseven]: https://github.com/zedseven
|
|
||||||
[@beatbrot]: https://github.com/beatbrot
|
|
||||||
[@erickguan]: https://github.com/erickguan
|
|
||||||
[@MHS-0]: https://github.com/MHS-0
|
|
||||||
[@MatejKafka]: https://github.com/MatejKafka
|
|
||||||
[@nachiketkanore]: https://github.com/nachiketkanore
|
|
||||||
[@mipedja]: https://github.com/mipedja
|
|
||||||
[@hex1c]: https://github.com/hex1c
|
|
||||||
[@lengyijun]: https://github.com/lengyijun
|
|
||||||
|
|
||||||
[v1.0.0]: https://github.com/tealdeer-rs/tealdeer/compare/v0.4.0...v1.0.0
|
|
||||||
[v1.1.0]: https://github.com/tealdeer-rs/tealdeer/compare/v1.0.0...v1.1.0
|
|
||||||
[v1.2.0]: https://github.com/tealdeer-rs/tealdeer/compare/v1.1.0...v1.2.0
|
|
||||||
[v1.3.0]: https://github.com/tealdeer-rs/tealdeer/compare/v1.2.0...v1.3.0
|
|
||||||
[v1.4.0]: https://github.com/tealdeer-rs/tealdeer/compare/v1.3.0...v1.4.0
|
|
||||||
[v1.4.1]: https://github.com/tealdeer-rs/tealdeer/compare/v1.4.0...v1.4.1
|
|
||||||
[v1.5.0]: https://github.com/tealdeer-rs/tealdeer/compare/v1.4.1...v1.5.0
|
|
||||||
[v1.5.1]: https://github.com/tealdeer-rs/tealdeer/compare/v1.5.0...v1.5.1
|
|
||||||
[v1.6.0]: https://github.com/tealdeer-rs/tealdeer/compare/v1.5.0...v1.6.0
|
|
||||||
[v1.6.1]: https://github.com/tealdeer-rs/tealdeer/compare/v1.6.0...v1.6.1
|
|
||||||
[v1.6.2]: https://github.com/tealdeer-rs/tealdeer/compare/v1.6.1...v1.6.2
|
|
||||||
[v1.7.0]: https://github.com/tealdeer-rs/tealdeer/compare/v1.6.1...v1.7.0
|
|
||||||
[v1.7.1]: https://github.com/tealdeer-rs/tealdeer/compare/v1.7.0...v1.7.1
|
|
||||||
[v1.7.2]: https://github.com/tealdeer-rs/tealdeer/compare/v1.7.1...v1.7.2
|
|
||||||
[v1.7.3]: https://github.com/tealdeer-rs/tealdeer/compare/v1.7.2...v1.7.3
|
|
||||||
[v1.8.0]: https://github.com/tealdeer-rs/tealdeer/compare/v1.7.2...v1.8.0
|
|
||||||
[v1.8.1]: https://github.com/tealdeer-rs/tealdeer/compare/v1.8.0...v1.8.1
|
|
||||||
|
|
||||||
[i34]: https://github.com/tealdeer-rs/tealdeer/issues/34
|
|
||||||
[i43]: https://github.com/tealdeer-rs/tealdeer/issues/43
|
|
||||||
[i44]: https://github.com/tealdeer-rs/tealdeer/issues/44
|
|
||||||
[i47]: https://github.com/tealdeer-rs/tealdeer/issues/47
|
|
||||||
[i48]: https://github.com/tealdeer-rs/tealdeer/issues/48
|
|
||||||
[i57]: https://github.com/tealdeer-rs/tealdeer/issues/57
|
|
||||||
[i58]: https://github.com/tealdeer-rs/tealdeer/issues/58
|
|
||||||
[i61]: https://github.com/tealdeer-rs/tealdeer/issues/61
|
|
||||||
[i68]: https://github.com/tealdeer-rs/tealdeer/issues/68
|
|
||||||
[i69]: https://github.com/tealdeer-rs/tealdeer/issues/69
|
|
||||||
[i71]: https://github.com/tealdeer-rs/tealdeer/issues/71
|
|
||||||
[i75]: https://github.com/tealdeer-rs/tealdeer/issues/75
|
|
||||||
[i77]: https://github.com/tealdeer-rs/tealdeer/issues/77
|
|
||||||
[i84]: https://github.com/tealdeer-rs/tealdeer/issues/84
|
|
||||||
[i86]: https://github.com/tealdeer-rs/tealdeer/issues/86
|
|
||||||
[i87]: https://github.com/tealdeer-rs/tealdeer/issues/87
|
|
||||||
[i89]: https://github.com/tealdeer-rs/tealdeer/issues/89
|
|
||||||
[i95]: https://github.com/tealdeer-rs/tealdeer/issues/95
|
|
||||||
[i97]: https://github.com/tealdeer-rs/tealdeer/issues/97
|
|
||||||
[i99]: https://github.com/tealdeer-rs/tealdeer/issues/99
|
|
||||||
[i108]: https://github.com/tealdeer-rs/tealdeer/pull/108
|
|
||||||
[i111]: https://github.com/tealdeer-rs/tealdeer/issues/111
|
|
||||||
[i112]: https://github.com/tealdeer-rs/tealdeer/issues/112
|
|
||||||
[i113]: https://github.com/tealdeer-rs/tealdeer/issues/113
|
|
||||||
[i115]: https://github.com/tealdeer-rs/tealdeer/issues/115
|
|
||||||
[i125]: https://github.com/tealdeer-rs/tealdeer/pull/125
|
|
||||||
[i138]: https://github.com/tealdeer-rs/tealdeer/issues/138
|
|
||||||
[i142]: https://github.com/tealdeer-rs/tealdeer/pull/142
|
|
||||||
[i148]: https://github.com/tealdeer-rs/tealdeer/pull/148
|
|
||||||
[i157]: https://github.com/tealdeer-rs/tealdeer/pull/157
|
|
||||||
[i161]: https://github.com/tealdeer-rs/tealdeer/pull/161
|
|
||||||
[i162]: https://github.com/tealdeer-rs/tealdeer/pull/162
|
|
||||||
[i163]: https://github.com/tealdeer-rs/tealdeer/pull/163
|
|
||||||
[i168]: https://github.com/tealdeer-rs/tealdeer/pull/168
|
|
||||||
[i171]: https://github.com/tealdeer-rs/tealdeer/pull/171
|
|
||||||
[i174]: https://github.com/tealdeer-rs/tealdeer/pull/174
|
|
||||||
[i176]: https://github.com/tealdeer-rs/tealdeer/pull/176
|
|
||||||
[i187]: https://github.com/tealdeer-rs/tealdeer/pull/187
|
|
||||||
[i190]: https://github.com/tealdeer-rs/tealdeer/issues/190
|
|
||||||
[i197]: https://github.com/tealdeer-rs/tealdeer/pull/197
|
|
||||||
[i210]: https://github.com/tealdeer-rs/tealdeer/pull/210
|
|
||||||
[i213]: https://github.com/tealdeer-rs/tealdeer/pull/213
|
|
||||||
[i215]: https://github.com/tealdeer-rs/tealdeer/pull/215
|
|
||||||
[i217]: https://github.com/tealdeer-rs/tealdeer/pull/217
|
|
||||||
[i227]: https://github.com/tealdeer-rs/tealdeer/pull/227
|
|
||||||
[#231]: https://github.com/tealdeer-rs/tealdeer/pull/231
|
|
||||||
[i240]: https://github.com/tealdeer-rs/tealdeer/pull/240
|
|
||||||
[#247]: https://github.com/tealdeer-rs/tealdeer/pull/247
|
|
||||||
[#249]: https://github.com/tealdeer-rs/tealdeer/pull/249
|
|
||||||
[#253]: https://github.com/tealdeer-rs/tealdeer/pull/253
|
|
||||||
[#254]: https://github.com/tealdeer-rs/tealdeer/pull/254
|
|
||||||
[#257]: https://github.com/tealdeer-rs/tealdeer/pull/257
|
|
||||||
[#259]: https://github.com/tealdeer-rs/tealdeer/pull/259
|
|
||||||
[#262]: https://github.com/tealdeer-rs/tealdeer/pull/262
|
|
||||||
[#271]: https://github.com/tealdeer-rs/tealdeer/pull/271
|
|
||||||
[#272]: https://github.com/tealdeer-rs/tealdeer/pull/272
|
|
||||||
[#274]: https://github.com/tealdeer-rs/tealdeer/pull/274
|
|
||||||
[#276]: https://github.com/tealdeer-rs/tealdeer/pull/276
|
|
||||||
[#284]: https://github.com/tealdeer-rs/tealdeer/pull/284
|
|
||||||
[#285]: https://github.com/tealdeer-rs/tealdeer/pull/285
|
|
||||||
[#287]: https://github.com/tealdeer-rs/tealdeer/pull/287
|
|
||||||
[#290]: https://github.com/tealdeer-rs/tealdeer/pull/290
|
|
||||||
[#291]: https://github.com/tealdeer-rs/tealdeer/pull/291
|
|
||||||
[#293]: https://github.com/tealdeer-rs/tealdeer/pull/293
|
|
||||||
[#297]: https://github.com/tealdeer-rs/tealdeer/pull/297
|
|
||||||
[#298]: https://github.com/tealdeer-rs/tealdeer/pull/298
|
|
||||||
[#299]: https://github.com/tealdeer-rs/tealdeer/pull/299
|
|
||||||
[#300]: https://github.com/tealdeer-rs/tealdeer/pull/300
|
|
||||||
[#303]: https://github.com/tealdeer-rs/tealdeer/pull/303
|
|
||||||
[#305]: https://github.com/tealdeer-rs/tealdeer/pull/305
|
|
||||||
[#306]: https://github.com/tealdeer-rs/tealdeer/pull/306
|
|
||||||
[#314]: https://github.com/tealdeer-rs/tealdeer/pull/314
|
|
||||||
[#315]: https://github.com/tealdeer-rs/tealdeer/pull/315
|
|
||||||
[#322]: https://github.com/tealdeer-rs/tealdeer/pull/322
|
|
||||||
[#324]: https://github.com/tealdeer-rs/tealdeer/pull/324
|
|
||||||
[#327]: https://github.com/tealdeer-rs/tealdeer/pull/327
|
|
||||||
[#331]: https://github.com/tealdeer-rs/tealdeer/pull/331
|
|
||||||
[#333]: https://github.com/tealdeer-rs/tealdeer/pull/333
|
|
||||||
[#336]: https://github.com/tealdeer-rs/tealdeer/pull/336
|
|
||||||
[#337]: https://github.com/tealdeer-rs/tealdeer/pull/337
|
|
||||||
[#342]: https://github.com/tealdeer-rs/tealdeer/pull/342
|
|
||||||
[#354]: https://github.com/tealdeer-rs/tealdeer/pull/354
|
|
||||||
[#355]: https://github.com/tealdeer-rs/tealdeer/pull/355
|
|
||||||
[#362]: https://github.com/tealdeer-rs/tealdeer/pull/362
|
|
||||||
[#386]: https://github.com/tealdeer-rs/tealdeer/pull/386
|
|
||||||
[#388]: https://github.com/tealdeer-rs/tealdeer/pull/388
|
|
||||||
[#389]: https://github.com/tealdeer-rs/tealdeer/pull/389
|
|
||||||
[#399]: https://github.com/tealdeer-rs/tealdeer/pull/399
|
|
||||||
[#400]: https://github.com/tealdeer-rs/tealdeer/pull/400
|
|
||||||
[#401]: https://github.com/tealdeer-rs/tealdeer/pull/401
|
|
||||||
[#407]: https://github.com/tealdeer-rs/tealdeer/pull/407
|
|
||||||
[#411]: https://github.com/tealdeer-rs/tealdeer/pull/411
|
|
||||||
[#416]: https://github.com/tealdeer-rs/tealdeer/pull/416
|
|
||||||
[#417]: https://github.com/tealdeer-rs/tealdeer/pull/417
|
|
||||||
[#422]: https://github.com/tealdeer-rs/tealdeer/pull/422
|
|
||||||
[#423]: https://github.com/tealdeer-rs/tealdeer/pull/423
|
|
||||||
[#425]: https://github.com/tealdeer-rs/tealdeer/pull/425
|
|
||||||
[#426]: https://github.com/tealdeer-rs/tealdeer/pull/426
|
|
||||||
[#429]: https://github.com/tealdeer-rs/tealdeer/pull/429
|
|
||||||
[#430]: https://github.com/tealdeer-rs/tealdeer/pull/430
|
|
||||||
[#435]: https://github.com/tealdeer-rs/tealdeer/pull/435
|
|
||||||
[#436]: https://github.com/tealdeer-rs/tealdeer/pull/436
|
|
||||||
[#439]: https://github.com/tealdeer-rs/tealdeer/pull/439
|
|
||||||
[#440]: https://github.com/tealdeer-rs/tealdeer/pull/440
|
|
||||||
[#451]: https://github.com/tealdeer-rs/tealdeer/pull/451
|
|
||||||
1671
Cargo.lock
generated
61
Cargo.toml
|
|
@ -1,61 +0,0 @@
|
||||||
[package]
|
|
||||||
authors = [
|
|
||||||
"Danilo Bargen <mail@dbrgn.ch>",
|
|
||||||
"Niklas Mohrin <dev@niklasmohrin.de>",
|
|
||||||
]
|
|
||||||
description = "Fetch and show tldr help pages for many CLI commands. Full featured offline client with caching support."
|
|
||||||
homepage = "https://github.com/tealdeer-rs/tealdeer/"
|
|
||||||
license = "MIT OR Apache-2.0"
|
|
||||||
name = "tealdeer"
|
|
||||||
readme = "README.md"
|
|
||||||
repository = "https://github.com/tealdeer-rs/tealdeer/"
|
|
||||||
documentation = "https://tealdeer-rs.github.io/tealdeer/"
|
|
||||||
version = "1.8.1"
|
|
||||||
include = ["/src/**/*", "/tests/**/*", "/Cargo.toml", "/README.md", "/LICENSE-*", "/screenshot.png", "completion/*"]
|
|
||||||
rust-version = "1.87" # MSRV
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[[bin]]
|
|
||||||
name = "tldr"
|
|
||||||
path = "src/main.rs"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
anyhow = "1"
|
|
||||||
clap = { version = "4", features = ["std", "derive", "help", "usage", "cargo", "error-context", "color", "wrap_help"], default-features = false }
|
|
||||||
env_logger = { version = "0.11", optional = true }
|
|
||||||
etcetera = "0.11.0"
|
|
||||||
log = "0.4"
|
|
||||||
serde = "1.0.21"
|
|
||||||
serde_derive = "1.0.21"
|
|
||||||
ureq = { version = "3.0.8", default-features = false, features = ["gzip", "socks-proxy"] }
|
|
||||||
toml = "0.8.19"
|
|
||||||
yansi = "1"
|
|
||||||
zip = { version = "5.1.1", default-features = false, features = ["deflate"] }
|
|
||||||
|
|
||||||
[target.'cfg(not(windows))'.dependencies]
|
|
||||||
pager = "0.16"
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
assert_cmd = "2.0.1"
|
|
||||||
escargot = "0.5"
|
|
||||||
predicates = "3.1.2"
|
|
||||||
tempfile = "3.1.0"
|
|
||||||
filetime = "0.2.10"
|
|
||||||
|
|
||||||
[features]
|
|
||||||
# native-tls is not enabled by default, because it is difficult to build for musl
|
|
||||||
default = ["rustls-with-webpki-roots", "rustls-with-native-roots"]
|
|
||||||
logging = ["env_logger"]
|
|
||||||
|
|
||||||
# At least one of variants for `ureq` HTTP client must be selected.
|
|
||||||
native-tls = ["ureq/native-tls", "ureq/platform-verifier"]
|
|
||||||
rustls-with-webpki-roots = ["ureq/rustls"] # ureq uses WebPKI roots by default
|
|
||||||
rustls-with-native-roots = ["ureq/rustls", "ureq/platform-verifier"]
|
|
||||||
|
|
||||||
ignore-online-tests = []
|
|
||||||
|
|
||||||
[profile.release]
|
|
||||||
strip = true
|
|
||||||
opt-level = 3
|
|
||||||
lto = true
|
|
||||||
codegen-units = 1
|
|
||||||
4
FontAwesome/css/font-awesome.css
vendored
Normal file
BIN
FontAwesome/fonts/FontAwesome.ttf
Normal file
BIN
FontAwesome/fonts/fontawesome-webfont.eot
Normal file
2671
FontAwesome/fonts/fontawesome-webfont.svg
Normal file
|
After Width: | Height: | Size: 434 KiB |
BIN
FontAwesome/fonts/fontawesome-webfont.ttf
Normal file
BIN
FontAwesome/fonts/fontawesome-webfont.woff
Normal file
BIN
FontAwesome/fonts/fontawesome-webfont.woff2
Normal file
176
LICENSE-APACHE
|
|
@ -1,176 +0,0 @@
|
||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
19
LICENSE-MIT
|
|
@ -1,19 +0,0 @@
|
||||||
Copyright (C) 2015-2021 Danilo Bargen and contributors
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
||||||
this software and associated documentation files (the "Software"), to deal in
|
|
||||||
the Software without restriction, including without limitation the rights to
|
|
||||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
||||||
of the Software, and to permit persons to whom the Software is furnished to do
|
|
||||||
so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
141
README.md
|
|
@ -1,141 +0,0 @@
|
||||||
# tealdeer
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|Crate|CI (Linux/macOS/Windows)|
|
|
||||||
|:---:|:---:|
|
|
||||||
|[![Crates.io][crates-io-badge]][crates-io]|[![GitHub CI][github-actions-badge]][github-actions]|
|
|
||||||
|
|
||||||
A very fast implementation of [tldr](https://github.com/tldr-pages/tldr) in
|
|
||||||
Rust: Simplified, example based and community-driven man pages.
|
|
||||||
|
|
||||||
<img src="docs/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/tealdeer-rs/tealdeer/releases/)!
|
|
||||||
|
|
||||||
|
|
||||||
## Docs (Installing, Usage, Configuration)
|
|
||||||
|
|
||||||
User documentation is available at <https://tealdeer-rs.github.io/tealdeer/>!
|
|
||||||
|
|
||||||
The docs are generated using [mdbook](https://rust-lang.github.io/mdBook/index.html).
|
|
||||||
They can be edited through the markdown files in the `docs/src/` directory.
|
|
||||||
|
|
||||||
|
|
||||||
## Goals
|
|
||||||
|
|
||||||
High level project goals:
|
|
||||||
|
|
||||||
- [x] Download and cache pages
|
|
||||||
- [x] Don't require a network connection for anything besides updating the cache
|
|
||||||
- [x] Command line interface similar or equivalent to the [NodeJS client][node-gh]
|
|
||||||
- [x] Comply with the [tldr client specification][client-spec]
|
|
||||||
- [x] Advanced highlighting and configuration
|
|
||||||
- [x] Be fast
|
|
||||||
|
|
||||||
A tool like `tldr` should be as frictionless as possible to use and show the
|
|
||||||
output as fast as possible.
|
|
||||||
|
|
||||||
We think that `tealdeer` reaches these goals. We put together a (more or less)
|
|
||||||
reproducible benchmark that compiles a handful of clients from source and
|
|
||||||
measures the execution times on a cold disk cache. The benchmarking is run in a
|
|
||||||
Docker container using sharkdp's [`hyperfine`][hyperfine-gh]
|
|
||||||
([Dockerfile][benchmark-dockerfile]).
|
|
||||||
|
|
||||||
| Client (50 runs, 17.10.2021) | Programming Language | Mean in ms | Deviation in ms | Comments |
|
|
||||||
| :---: | :---: | :---: | :---: | :---: |
|
|
||||||
| [`outfieldr`][outfieldr-gh] | Zig | 9.1 | 0.5 | no user configuration |
|
|
||||||
| `tealdeer` | Rust | 13.2 | 0.5 | |
|
|
||||||
| [`fast-tldr`][fast-tldr-gh] | Haskell | 17.0 | 0.6 | no example highlighting |
|
|
||||||
| [`tldr-hs`][hs-gh] | Haskell | 25.1 | 0.5 | no example highlighting |
|
|
||||||
| [`tldr-bash`][bash-gh] | Bash | 30.0 | 0.8 | |
|
|
||||||
| [`tldr-python-client`][python-gh] | Python | 87.0 | 2.4 | |
|
|
||||||
| [`tldr-node-client`][node-gh] | JavaScript / NodeJS | 407.1 | 12.9 | |
|
|
||||||
|
|
||||||
As you can see, `tealdeer` is one of the fastest of the tested clients.
|
|
||||||
However, we strive for useful features and code quality over raw performance,
|
|
||||||
even if that means that we don't come out on top in this friendly competition.
|
|
||||||
That said, we are still optimizing the code, for example when the `outfieldr`
|
|
||||||
developers [suggested to switch][outfieldr-comment-tls] to a native TLS
|
|
||||||
implementation instead of the native libraries.
|
|
||||||
|
|
||||||
## 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
|
|
||||||
|
|
||||||
|
|
||||||
### AI Policy
|
|
||||||
|
|
||||||
Using AI is generally discouraged. However, if it is used as part of a contribution, the contributor MUST:
|
|
||||||
|
|
||||||
1. Clearly mark what parts (if any) of a contribution were created with the help of AI tools. This includes issue and pull request comments.
|
|
||||||
2. Check all output of AI tools before sharing it with others in the tealdeer project.
|
|
||||||
3. Not post slop, spam, or low quality contributions. This includes pull request descriptions and comments with excessive text and markdown flair.
|
|
||||||
4. Leave small or easy tasks to new contributors who want to learn without the use of AI. This is to maintain the presence of the `good-first-issue` tag.
|
|
||||||
5. Be respectful of everyone's time: *maintainers and other contributors will be reviewing your PRs.*
|
|
||||||
|
|
||||||
|
|
||||||
## 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
|
|
||||||
|
|
||||||
* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||||
* MIT license ([LICENSE-MIT](LICENSE-MIT) or
|
|
||||||
http://opensource.org/licenses/MIT) at your option.
|
|
||||||
|
|
||||||
|
|
||||||
### 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 @severen for coming up with the name "tealdeer"!
|
|
||||||
|
|
||||||
|
|
||||||
[node-gh]: https://github.com/tldr-pages/tldr-node-client
|
|
||||||
[hs-gh]: https://github.com/psibi/tldr-hs
|
|
||||||
[fast-tldr-gh]: https://github.com/gutjuri/fast-tldr
|
|
||||||
[bash-gh]: https://4e4.win/tldr
|
|
||||||
[outfieldr-gh]: https://gitlab.com/ve-nt/outfieldr
|
|
||||||
[python-gh]: https://github.com/tldr-pages/tldr-python-client
|
|
||||||
|
|
||||||
[benchmark-dockerfile]: https://github.com/tealdeer-rs/tealdeer/blob/main/benchmarks/Dockerfile
|
|
||||||
[client-spec]: https://github.com/tldr-pages/tldr/blob/main/CLIENT-SPECIFICATION.md
|
|
||||||
[hyperfine-gh]: https://github.com/sharkdp/hyperfine
|
|
||||||
[outfieldr-comment-tls]: https://github.com/tealdeer-rs/tealdeer/issues/129#issuecomment-833596765
|
|
||||||
|
|
||||||
<!-- Badges -->
|
|
||||||
[github-actions]: https://github.com/tealdeer-rs/tealdeer/actions?query=branch%3Amain
|
|
||||||
[github-actions-badge]: https://github.com/tealdeer-rs/tealdeer/actions/workflows/ci.yml/badge.svg?branch=main
|
|
||||||
[crates-io]: https://crates.io/crates/tealdeer
|
|
||||||
[crates-io-badge]: https://img.shields.io/crates/v/tealdeer.svg
|
|
||||||
35
RELEASING.md
|
|
@ -1,35 +0,0 @@
|
||||||
# Releasing
|
|
||||||
|
|
||||||
Run linting:
|
|
||||||
|
|
||||||
$ cargo clean && cargo clippy
|
|
||||||
|
|
||||||
Set variables:
|
|
||||||
|
|
||||||
$ export VERSION=X.Y.Z
|
|
||||||
$ export GPG_KEY=20EE002D778AE197EF7D0D2CB993FF98A90C9AB1
|
|
||||||
|
|
||||||
Update version numbers:
|
|
||||||
|
|
||||||
$ vim Cargo.toml
|
|
||||||
$ cargo update -p tealdeer
|
|
||||||
|
|
||||||
Update docs:
|
|
||||||
|
|
||||||
$ cargo run -- --help > docs/src/usage.txt
|
|
||||||
|
|
||||||
Update changelog:
|
|
||||||
|
|
||||||
$ vim CHANGELOG.md
|
|
||||||
|
|
||||||
Commit & tag:
|
|
||||||
|
|
||||||
$ git commit -S${GPG_KEY} -m "Release v${VERSION}"
|
|
||||||
$ git tag -s -u ${GPG_KEY} v${VERSION} -m "Version ${VERSION}"
|
|
||||||
|
|
||||||
Publish:
|
|
||||||
|
|
||||||
$ cargo publish
|
|
||||||
$ git push && git push --tags
|
|
||||||
|
|
||||||
Then publish the release on GitHub.
|
|
||||||
79
ayu-highlight.css
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
Based off of the Ayu theme
|
||||||
|
Original by Dempfi (https://github.com/dempfi/ayu)
|
||||||
|
*/
|
||||||
|
|
||||||
|
.hljs {
|
||||||
|
display: block;
|
||||||
|
overflow-x: auto;
|
||||||
|
background: #191f26;
|
||||||
|
color: #e6e1cf;
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-comment,
|
||||||
|
.hljs-quote {
|
||||||
|
color: #5c6773;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-variable,
|
||||||
|
.hljs-template-variable,
|
||||||
|
.hljs-attribute,
|
||||||
|
.hljs-attr,
|
||||||
|
.hljs-regexp,
|
||||||
|
.hljs-link,
|
||||||
|
.hljs-selector-id,
|
||||||
|
.hljs-selector-class {
|
||||||
|
color: #ff7733;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-number,
|
||||||
|
.hljs-meta,
|
||||||
|
.hljs-builtin-name,
|
||||||
|
.hljs-literal,
|
||||||
|
.hljs-type,
|
||||||
|
.hljs-params {
|
||||||
|
color: #ffee99;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-string,
|
||||||
|
.hljs-bullet {
|
||||||
|
color: #b8cc52;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-title,
|
||||||
|
.hljs-built_in,
|
||||||
|
.hljs-section {
|
||||||
|
color: #ffb454;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-keyword,
|
||||||
|
.hljs-selector-tag,
|
||||||
|
.hljs-symbol {
|
||||||
|
color: #ff7733;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-name {
|
||||||
|
color: #36a3d9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-tag {
|
||||||
|
color: #00568d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-emphasis {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-strong {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-addition {
|
||||||
|
color: #91b362;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-deletion {
|
||||||
|
color: #d96c75;
|
||||||
|
}
|
||||||
|
|
@ -1,139 +0,0 @@
|
||||||
# Benchmark Dockerfile for tealdeer
|
|
||||||
#
|
|
||||||
# To run the benchmarks, execute
|
|
||||||
#
|
|
||||||
# docker build --pull -t tldr-benchmark .
|
|
||||||
# docker run --privileged --rm -it tldr-benchmark
|
|
||||||
#
|
|
||||||
# as root in the directory of this Dockerfile. This will build the compared
|
|
||||||
# clients and benchmark them with `hyperfine` at the end.
|
|
||||||
#
|
|
||||||
# The `--privileged` flag is needed to drop the disk caches before every run. If
|
|
||||||
# you want to test with hot caches or don't want to use this flag, you will have
|
|
||||||
# to remove the `--prepare` line from the `hyperfine` command at the end of this
|
|
||||||
# file and rebuild the image.
|
|
||||||
|
|
||||||
################################################################################
|
|
||||||
|
|
||||||
FROM rust AS tealdeer-builder
|
|
||||||
|
|
||||||
WORKDIR /build
|
|
||||||
RUN git clone https://github.com/tealdeer-rs/tealdeer.git \
|
|
||||||
&& cd tealdeer \
|
|
||||||
&& cargo build --release \
|
|
||||||
&& mkdir /build-outputs \
|
|
||||||
&& cp target/release/tldr /build-outputs/tealdeer
|
|
||||||
|
|
||||||
################################################################################
|
|
||||||
|
|
||||||
FROM ubuntu:latest AS tldr-c-builder
|
|
||||||
|
|
||||||
WORKDIR /build
|
|
||||||
RUN apt-get update && apt-get install -y build-essential git && rm -rf /var/lib/apt/lists/*
|
|
||||||
RUN git clone https://github.com/tldr-pages/tldr-c-client.git \
|
|
||||||
&& cd tldr-c-client \
|
|
||||||
&& DEBIAN_FRONTEND=noninteractive ./deps.sh \
|
|
||||||
&& make \
|
|
||||||
&& mkdir /build-outputs /deps \
|
|
||||||
&& cp tldr /build-outputs/tldr-c \
|
|
||||||
&& cp deps.sh /deps/tldr-c-deps.sh
|
|
||||||
|
|
||||||
################################################################################
|
|
||||||
|
|
||||||
FROM haskell AS haskell-builder
|
|
||||||
|
|
||||||
WORKDIR /build
|
|
||||||
|
|
||||||
RUN git clone https://github.com/psibi/tldr-hs.git \
|
|
||||||
&& cd tldr-hs \
|
|
||||||
&& stack build --install-ghc
|
|
||||||
|
|
||||||
RUN git clone https://github.com/gutjuri/fast-tldr \
|
|
||||||
&& cd fast-tldr \
|
|
||||||
&& stack build --install-ghc
|
|
||||||
|
|
||||||
RUN mkdir /build-outputs \
|
|
||||||
&& find tldr-hs/.stack-work/dist -type f -iname tldr -exec mv '{}' /build-outputs/tldr-hs \; \
|
|
||||||
&& find fast-tldr/.stack-work/dist -type f -iname tldr -exec mv '{}' /build-outputs/fast-tldr \;
|
|
||||||
|
|
||||||
################################################################################
|
|
||||||
|
|
||||||
FROM node:slim AS node-builder
|
|
||||||
|
|
||||||
WORKDIR /build-outputs
|
|
||||||
RUN npm install tldr \
|
|
||||||
&& cp $(which node) . \
|
|
||||||
&& echo './node -- ./node_modules/.bin/tldr "$@"' > tldr-node \
|
|
||||||
&& chmod +x tldr-node
|
|
||||||
|
|
||||||
################################################################################
|
|
||||||
|
|
||||||
FROM euantorano/zig:0.8.0 AS zig-builder
|
|
||||||
|
|
||||||
WORKDIR /build
|
|
||||||
RUN apk add git \
|
|
||||||
&& git clone https://gitlab.com/ve-nt/outfieldr.git \
|
|
||||||
&& cd outfieldr \
|
|
||||||
&& git submodule init \
|
|
||||||
&& git submodule update \
|
|
||||||
&& zig build -Drelease-safe \
|
|
||||||
&& mkdir /build-outputs \
|
|
||||||
&& cp bin/tldr /build-outputs/outfieldr
|
|
||||||
|
|
||||||
################################################################################
|
|
||||||
|
|
||||||
FROM ubuntu:latest AS benchmark
|
|
||||||
|
|
||||||
ENV LANG="en_US.UTF-8"
|
|
||||||
|
|
||||||
WORKDIR /deps
|
|
||||||
RUN apt-get update && apt-get install -y wget unzip python3 python3-venv && rm -rf /var/lib/apt/lists/*
|
|
||||||
COPY --from=tldr-c-builder /deps/* ./
|
|
||||||
RUN for file in *; do DEBIAN_FRONTEND=noninteractive sh $file; done
|
|
||||||
|
|
||||||
WORKDIR /clients
|
|
||||||
COPY --from=tealdeer-builder /build-outputs/* ./
|
|
||||||
COPY --from=tldr-c-builder /build-outputs/* ./
|
|
||||||
COPY --from=haskell-builder /build-outputs/* ./
|
|
||||||
RUN wget -qO tldr-bash https://4e4.win/tldr && chmod +x tldr-bash
|
|
||||||
COPY --from=node-builder /build-outputs/node /build-outputs/tldr-node ./
|
|
||||||
COPY --from=node-builder /build-outputs/node_modules/ ./node_modules/
|
|
||||||
COPY --from=zig-builder /build-outputs/* ./
|
|
||||||
|
|
||||||
# python is really hard to isolate in a package, using pyinstaller didn't really work either, so for now we just use it like this
|
|
||||||
RUN python3 -m venv tldr-python \
|
|
||||||
&& cd tldr-python \
|
|
||||||
&& bash -c 'source bin/activate; pip install wheel; pip install tldr; deactivate' \
|
|
||||||
&& cd .. \
|
|
||||||
&& echo '#!/bin/bash' > tldr-python.bash \
|
|
||||||
&& echo 'source tldr-python/bin/activate; tldr $@' >> tldr-python.bash \
|
|
||||||
&& chmod +x tldr-python.bash
|
|
||||||
|
|
||||||
# Update all the individual caches
|
|
||||||
RUN bash -c 'mkdir -p /caches/{tealdeer,tldr-c,tldr-hs,fast-tldr,tldr-bash,tldr-node,tldr-python,outfieldr/.local/share}' \
|
|
||||||
&& TEALDEER_CACHE_DIR=/caches/tealdeer ./tealdeer -u \
|
|
||||||
&& TLDR_CACHE_DIR=/caches/tldr-c ./tldr-c -u \
|
|
||||||
&& XDG_DATA_HOME=/caches/tldr-hs ./tldr-hs -u \
|
|
||||||
&& XDG_DATA_HOME=/caches/fast-tldr ./fast-tldr -u \
|
|
||||||
&& XDG_DATA_HOME=/caches/tldr-bash ./tldr-bash -u \
|
|
||||||
&& HOME=/caches/tldr-node ./tldr-node -u \
|
|
||||||
&& HOME=/caches/tldr-python ./tldr-python.bash -u \
|
|
||||||
&& HOME=/caches/outfieldr ./outfieldr -u
|
|
||||||
|
|
||||||
WORKDIR /tools
|
|
||||||
RUN wget -q https://github.com/sharkdp/hyperfine/releases/download/v1.11.0/hyperfine_1.11.0_amd64.deb && dpkg -i hyperfine_1.11.0_amd64.deb
|
|
||||||
|
|
||||||
ENV PAGE="tar"
|
|
||||||
WORKDIR /clients
|
|
||||||
CMD hyperfine \
|
|
||||||
--warmup 10 \
|
|
||||||
--runs 50 \
|
|
||||||
--prepare 'sync; echo 3 | tee /proc/sys/vm/drop_caches' \
|
|
||||||
"TEALDEER_CACHE_DIR=/caches/tealdeer ./tealdeer $PAGE" \
|
|
||||||
"TLDR_CACHE_DIR=/caches/tldr-c ./tldr-c $PAGE" \
|
|
||||||
"XDG_DATA_HOME=/caches/tldr-hs ./tldr-hs $PAGE" \
|
|
||||||
"XDG_DATA_HOME=/caches/fast-tldr ./fast-tldr $PAGE" \
|
|
||||||
"XDG_DATA_HOME=/caches/tldr-bash TLDR_LESS=0 ./tldr-bash $PAGE" \
|
|
||||||
"HOME=/caches/tldr-python ./tldr-python.bash $PAGE" \
|
|
||||||
"HOME=/caches/outfieldr ./outfieldr $PAGE" \
|
|
||||||
"HOME=/caches/tldr-node ./tldr-node $PAGE"
|
|
||||||
660
book.js
Normal file
|
|
@ -0,0 +1,660 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Fix back button cache problem
|
||||||
|
window.onunload = function () { };
|
||||||
|
|
||||||
|
// Global variable, shared between modules
|
||||||
|
function playground_text(playground) {
|
||||||
|
let code_block = playground.querySelector("code");
|
||||||
|
|
||||||
|
if (window.ace && code_block.classList.contains("editable")) {
|
||||||
|
let editor = window.ace.edit(code_block);
|
||||||
|
return editor.getValue();
|
||||||
|
} else {
|
||||||
|
return code_block.textContent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(function codeSnippets() {
|
||||||
|
function fetch_with_timeout(url, options, timeout = 6000) {
|
||||||
|
return Promise.race([
|
||||||
|
fetch(url, options),
|
||||||
|
new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout))
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
var playgrounds = Array.from(document.querySelectorAll(".playground"));
|
||||||
|
if (playgrounds.length > 0) {
|
||||||
|
fetch_with_timeout("https://play.rust-lang.org/meta/crates", {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': "application/json",
|
||||||
|
},
|
||||||
|
method: 'POST',
|
||||||
|
mode: 'cors',
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(response => {
|
||||||
|
// get list of crates available in the rust playground
|
||||||
|
let playground_crates = response.crates.map(item => item["id"]);
|
||||||
|
playgrounds.forEach(block => handle_crate_list_update(block, playground_crates));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function handle_crate_list_update(playground_block, playground_crates) {
|
||||||
|
// update the play buttons after receiving the response
|
||||||
|
update_play_button(playground_block, playground_crates);
|
||||||
|
|
||||||
|
// and install on change listener to dynamically update ACE editors
|
||||||
|
if (window.ace) {
|
||||||
|
let code_block = playground_block.querySelector("code");
|
||||||
|
if (code_block.classList.contains("editable")) {
|
||||||
|
let editor = window.ace.edit(code_block);
|
||||||
|
editor.addEventListener("change", function (e) {
|
||||||
|
update_play_button(playground_block, playground_crates);
|
||||||
|
});
|
||||||
|
// add Ctrl-Enter command to execute rust code
|
||||||
|
editor.commands.addCommand({
|
||||||
|
name: "run",
|
||||||
|
bindKey: {
|
||||||
|
win: "Ctrl-Enter",
|
||||||
|
mac: "Ctrl-Enter"
|
||||||
|
},
|
||||||
|
exec: _editor => run_rust_code(playground_block)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// updates the visibility of play button based on `no_run` class and
|
||||||
|
// used crates vs ones available on http://play.rust-lang.org
|
||||||
|
function update_play_button(pre_block, playground_crates) {
|
||||||
|
var play_button = pre_block.querySelector(".play-button");
|
||||||
|
|
||||||
|
// skip if code is `no_run`
|
||||||
|
if (pre_block.querySelector('code').classList.contains("no_run")) {
|
||||||
|
play_button.classList.add("hidden");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get list of `extern crate`'s from snippet
|
||||||
|
var txt = playground_text(pre_block);
|
||||||
|
var re = /extern\s+crate\s+([a-zA-Z_0-9]+)\s*;/g;
|
||||||
|
var snippet_crates = [];
|
||||||
|
var item;
|
||||||
|
while (item = re.exec(txt)) {
|
||||||
|
snippet_crates.push(item[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if all used crates are available on play.rust-lang.org
|
||||||
|
var all_available = snippet_crates.every(function (elem) {
|
||||||
|
return playground_crates.indexOf(elem) > -1;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (all_available) {
|
||||||
|
play_button.classList.remove("hidden");
|
||||||
|
} else {
|
||||||
|
play_button.classList.add("hidden");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function run_rust_code(code_block) {
|
||||||
|
var result_block = code_block.querySelector(".result");
|
||||||
|
if (!result_block) {
|
||||||
|
result_block = document.createElement('code');
|
||||||
|
result_block.className = 'result hljs language-bash';
|
||||||
|
|
||||||
|
code_block.append(result_block);
|
||||||
|
}
|
||||||
|
|
||||||
|
let text = playground_text(code_block);
|
||||||
|
let classes = code_block.querySelector('code').classList;
|
||||||
|
let has_2018 = classes.contains("edition2018");
|
||||||
|
let edition = has_2018 ? "2018" : "2015";
|
||||||
|
|
||||||
|
var params = {
|
||||||
|
version: "stable",
|
||||||
|
optimize: "0",
|
||||||
|
code: text,
|
||||||
|
edition: edition
|
||||||
|
};
|
||||||
|
|
||||||
|
if (text.indexOf("#![feature") !== -1) {
|
||||||
|
params.version = "nightly";
|
||||||
|
}
|
||||||
|
|
||||||
|
result_block.innerText = "Running...";
|
||||||
|
|
||||||
|
fetch_with_timeout("https://play.rust-lang.org/evaluate.json", {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': "application/json",
|
||||||
|
},
|
||||||
|
method: 'POST',
|
||||||
|
mode: 'cors',
|
||||||
|
body: JSON.stringify(params)
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(response => result_block.innerText = response.result)
|
||||||
|
.catch(error => result_block.innerText = "Playground Communication: " + error.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Syntax highlighting Configuration
|
||||||
|
hljs.configure({
|
||||||
|
tabReplace: ' ', // 4 spaces
|
||||||
|
languages: [], // Languages used for auto-detection
|
||||||
|
});
|
||||||
|
|
||||||
|
let code_nodes = Array
|
||||||
|
.from(document.querySelectorAll('code'))
|
||||||
|
// Don't highlight `inline code` blocks in headers.
|
||||||
|
.filter(function (node) {return !node.parentElement.classList.contains("header"); });
|
||||||
|
|
||||||
|
if (window.ace) {
|
||||||
|
// language-rust class needs to be removed for editable
|
||||||
|
// blocks or highlightjs will capture events
|
||||||
|
Array
|
||||||
|
.from(document.querySelectorAll('code.editable'))
|
||||||
|
.forEach(function (block) { block.classList.remove('language-rust'); });
|
||||||
|
|
||||||
|
Array
|
||||||
|
.from(document.querySelectorAll('code:not(.editable)'))
|
||||||
|
.forEach(function (block) { hljs.highlightBlock(block); });
|
||||||
|
} else {
|
||||||
|
code_nodes.forEach(function (block) { hljs.highlightBlock(block); });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adding the hljs class gives code blocks the color css
|
||||||
|
// even if highlighting doesn't apply
|
||||||
|
code_nodes.forEach(function (block) { block.classList.add('hljs'); });
|
||||||
|
|
||||||
|
Array.from(document.querySelectorAll("code.language-rust")).forEach(function (block) {
|
||||||
|
|
||||||
|
var lines = Array.from(block.querySelectorAll('.boring'));
|
||||||
|
// If no lines were hidden, return
|
||||||
|
if (!lines.length) { return; }
|
||||||
|
block.classList.add("hide-boring");
|
||||||
|
|
||||||
|
var buttons = document.createElement('div');
|
||||||
|
buttons.className = 'buttons';
|
||||||
|
buttons.innerHTML = "<button class=\"fa fa-eye\" title=\"Show hidden lines\" aria-label=\"Show hidden lines\"></button>";
|
||||||
|
|
||||||
|
// add expand button
|
||||||
|
var pre_block = block.parentNode;
|
||||||
|
pre_block.insertBefore(buttons, pre_block.firstChild);
|
||||||
|
|
||||||
|
pre_block.querySelector('.buttons').addEventListener('click', function (e) {
|
||||||
|
if (e.target.classList.contains('fa-eye')) {
|
||||||
|
e.target.classList.remove('fa-eye');
|
||||||
|
e.target.classList.add('fa-eye-slash');
|
||||||
|
e.target.title = 'Hide lines';
|
||||||
|
e.target.setAttribute('aria-label', e.target.title);
|
||||||
|
|
||||||
|
block.classList.remove('hide-boring');
|
||||||
|
} else if (e.target.classList.contains('fa-eye-slash')) {
|
||||||
|
e.target.classList.remove('fa-eye-slash');
|
||||||
|
e.target.classList.add('fa-eye');
|
||||||
|
e.target.title = 'Show hidden lines';
|
||||||
|
e.target.setAttribute('aria-label', e.target.title);
|
||||||
|
|
||||||
|
block.classList.add('hide-boring');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (window.playground_copyable) {
|
||||||
|
Array.from(document.querySelectorAll('pre code')).forEach(function (block) {
|
||||||
|
var pre_block = block.parentNode;
|
||||||
|
if (!pre_block.classList.contains('playground')) {
|
||||||
|
var buttons = pre_block.querySelector(".buttons");
|
||||||
|
if (!buttons) {
|
||||||
|
buttons = document.createElement('div');
|
||||||
|
buttons.className = 'buttons';
|
||||||
|
pre_block.insertBefore(buttons, pre_block.firstChild);
|
||||||
|
}
|
||||||
|
|
||||||
|
var clipButton = document.createElement('button');
|
||||||
|
clipButton.className = 'fa fa-copy clip-button';
|
||||||
|
clipButton.title = 'Copy to clipboard';
|
||||||
|
clipButton.setAttribute('aria-label', clipButton.title);
|
||||||
|
clipButton.innerHTML = '<i class=\"tooltiptext\"></i>';
|
||||||
|
|
||||||
|
buttons.insertBefore(clipButton, buttons.firstChild);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process playground code blocks
|
||||||
|
Array.from(document.querySelectorAll(".playground")).forEach(function (pre_block) {
|
||||||
|
// Add play button
|
||||||
|
var buttons = pre_block.querySelector(".buttons");
|
||||||
|
if (!buttons) {
|
||||||
|
buttons = document.createElement('div');
|
||||||
|
buttons.className = 'buttons';
|
||||||
|
pre_block.insertBefore(buttons, pre_block.firstChild);
|
||||||
|
}
|
||||||
|
|
||||||
|
var runCodeButton = document.createElement('button');
|
||||||
|
runCodeButton.className = 'fa fa-play play-button';
|
||||||
|
runCodeButton.hidden = true;
|
||||||
|
runCodeButton.title = 'Run this code';
|
||||||
|
runCodeButton.setAttribute('aria-label', runCodeButton.title);
|
||||||
|
|
||||||
|
buttons.insertBefore(runCodeButton, buttons.firstChild);
|
||||||
|
runCodeButton.addEventListener('click', function (e) {
|
||||||
|
run_rust_code(pre_block);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (window.playground_copyable) {
|
||||||
|
var copyCodeClipboardButton = document.createElement('button');
|
||||||
|
copyCodeClipboardButton.className = 'fa fa-copy clip-button';
|
||||||
|
copyCodeClipboardButton.innerHTML = '<i class="tooltiptext"></i>';
|
||||||
|
copyCodeClipboardButton.title = 'Copy to clipboard';
|
||||||
|
copyCodeClipboardButton.setAttribute('aria-label', copyCodeClipboardButton.title);
|
||||||
|
|
||||||
|
buttons.insertBefore(copyCodeClipboardButton, buttons.firstChild);
|
||||||
|
}
|
||||||
|
|
||||||
|
let code_block = pre_block.querySelector("code");
|
||||||
|
if (window.ace && code_block.classList.contains("editable")) {
|
||||||
|
var undoChangesButton = document.createElement('button');
|
||||||
|
undoChangesButton.className = 'fa fa-history reset-button';
|
||||||
|
undoChangesButton.title = 'Undo changes';
|
||||||
|
undoChangesButton.setAttribute('aria-label', undoChangesButton.title);
|
||||||
|
|
||||||
|
buttons.insertBefore(undoChangesButton, buttons.firstChild);
|
||||||
|
|
||||||
|
undoChangesButton.addEventListener('click', function () {
|
||||||
|
let editor = window.ace.edit(code_block);
|
||||||
|
editor.setValue(editor.originalCode);
|
||||||
|
editor.clearSelection();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
|
||||||
|
(function themes() {
|
||||||
|
var html = document.querySelector('html');
|
||||||
|
var themeToggleButton = document.getElementById('theme-toggle');
|
||||||
|
var themePopup = document.getElementById('theme-list');
|
||||||
|
var themeColorMetaTag = document.querySelector('meta[name="theme-color"]');
|
||||||
|
var stylesheets = {
|
||||||
|
ayuHighlight: document.querySelector("[href$='ayu-highlight.css']"),
|
||||||
|
tomorrowNight: document.querySelector("[href$='tomorrow-night.css']"),
|
||||||
|
highlight: document.querySelector("[href$='highlight.css']"),
|
||||||
|
};
|
||||||
|
|
||||||
|
function showThemes() {
|
||||||
|
themePopup.style.display = 'block';
|
||||||
|
themeToggleButton.setAttribute('aria-expanded', true);
|
||||||
|
themePopup.querySelector("button#" + get_theme()).focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideThemes() {
|
||||||
|
themePopup.style.display = 'none';
|
||||||
|
themeToggleButton.setAttribute('aria-expanded', false);
|
||||||
|
themeToggleButton.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_theme() {
|
||||||
|
var theme;
|
||||||
|
try { theme = localStorage.getItem('mdbook-theme'); } catch (e) { }
|
||||||
|
if (theme === null || theme === undefined) {
|
||||||
|
return default_theme;
|
||||||
|
} else {
|
||||||
|
return theme;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_theme(theme, store = true) {
|
||||||
|
let ace_theme;
|
||||||
|
|
||||||
|
if (theme == 'coal' || theme == 'navy') {
|
||||||
|
stylesheets.ayuHighlight.disabled = true;
|
||||||
|
stylesheets.tomorrowNight.disabled = false;
|
||||||
|
stylesheets.highlight.disabled = true;
|
||||||
|
|
||||||
|
ace_theme = "ace/theme/tomorrow_night";
|
||||||
|
} else if (theme == 'ayu') {
|
||||||
|
stylesheets.ayuHighlight.disabled = false;
|
||||||
|
stylesheets.tomorrowNight.disabled = true;
|
||||||
|
stylesheets.highlight.disabled = true;
|
||||||
|
ace_theme = "ace/theme/tomorrow_night";
|
||||||
|
} else {
|
||||||
|
stylesheets.ayuHighlight.disabled = true;
|
||||||
|
stylesheets.tomorrowNight.disabled = true;
|
||||||
|
stylesheets.highlight.disabled = false;
|
||||||
|
ace_theme = "ace/theme/dawn";
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(function () {
|
||||||
|
themeColorMetaTag.content = getComputedStyle(document.body).backgroundColor;
|
||||||
|
}, 1);
|
||||||
|
|
||||||
|
if (window.ace && window.editors) {
|
||||||
|
window.editors.forEach(function (editor) {
|
||||||
|
editor.setTheme(ace_theme);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var previousTheme = get_theme();
|
||||||
|
|
||||||
|
if (store) {
|
||||||
|
try { localStorage.setItem('mdbook-theme', theme); } catch (e) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
html.classList.remove(previousTheme);
|
||||||
|
html.classList.add(theme);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set theme
|
||||||
|
var theme = get_theme();
|
||||||
|
|
||||||
|
set_theme(theme, false);
|
||||||
|
|
||||||
|
themeToggleButton.addEventListener('click', function () {
|
||||||
|
if (themePopup.style.display === 'block') {
|
||||||
|
hideThemes();
|
||||||
|
} else {
|
||||||
|
showThemes();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
themePopup.addEventListener('click', function (e) {
|
||||||
|
var theme = e.target.id || e.target.parentElement.id;
|
||||||
|
set_theme(theme);
|
||||||
|
});
|
||||||
|
|
||||||
|
themePopup.addEventListener('focusout', function(e) {
|
||||||
|
// e.relatedTarget is null in Safari and Firefox on macOS (see workaround below)
|
||||||
|
if (!!e.relatedTarget && !themeToggleButton.contains(e.relatedTarget) && !themePopup.contains(e.relatedTarget)) {
|
||||||
|
hideThemes();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Should not be needed, but it works around an issue on macOS & iOS: https://github.com/rust-lang/mdBook/issues/628
|
||||||
|
document.addEventListener('click', function(e) {
|
||||||
|
if (themePopup.style.display === 'block' && !themeToggleButton.contains(e.target) && !themePopup.contains(e.target)) {
|
||||||
|
hideThemes();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('keydown', function (e) {
|
||||||
|
if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { return; }
|
||||||
|
if (!themePopup.contains(e.target)) { return; }
|
||||||
|
|
||||||
|
switch (e.key) {
|
||||||
|
case 'Escape':
|
||||||
|
e.preventDefault();
|
||||||
|
hideThemes();
|
||||||
|
break;
|
||||||
|
case 'ArrowUp':
|
||||||
|
e.preventDefault();
|
||||||
|
var li = document.activeElement.parentElement;
|
||||||
|
if (li && li.previousElementSibling) {
|
||||||
|
li.previousElementSibling.querySelector('button').focus();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'ArrowDown':
|
||||||
|
e.preventDefault();
|
||||||
|
var li = document.activeElement.parentElement;
|
||||||
|
if (li && li.nextElementSibling) {
|
||||||
|
li.nextElementSibling.querySelector('button').focus();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'Home':
|
||||||
|
e.preventDefault();
|
||||||
|
themePopup.querySelector('li:first-child button').focus();
|
||||||
|
break;
|
||||||
|
case 'End':
|
||||||
|
e.preventDefault();
|
||||||
|
themePopup.querySelector('li:last-child button').focus();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
|
||||||
|
(function sidebar() {
|
||||||
|
var html = document.querySelector("html");
|
||||||
|
var sidebar = document.getElementById("sidebar");
|
||||||
|
var sidebarLinks = document.querySelectorAll('#sidebar a');
|
||||||
|
var sidebarToggleButton = document.getElementById("sidebar-toggle");
|
||||||
|
var sidebarResizeHandle = document.getElementById("sidebar-resize-handle");
|
||||||
|
var firstContact = null;
|
||||||
|
|
||||||
|
function showSidebar() {
|
||||||
|
html.classList.remove('sidebar-hidden')
|
||||||
|
html.classList.add('sidebar-visible');
|
||||||
|
Array.from(sidebarLinks).forEach(function (link) {
|
||||||
|
link.setAttribute('tabIndex', 0);
|
||||||
|
});
|
||||||
|
sidebarToggleButton.setAttribute('aria-expanded', true);
|
||||||
|
sidebar.setAttribute('aria-hidden', false);
|
||||||
|
try { localStorage.setItem('mdbook-sidebar', 'visible'); } catch (e) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var sidebarAnchorToggles = document.querySelectorAll('#sidebar a.toggle');
|
||||||
|
|
||||||
|
function toggleSection(ev) {
|
||||||
|
ev.currentTarget.parentElement.classList.toggle('expanded');
|
||||||
|
}
|
||||||
|
|
||||||
|
Array.from(sidebarAnchorToggles).forEach(function (el) {
|
||||||
|
el.addEventListener('click', toggleSection);
|
||||||
|
});
|
||||||
|
|
||||||
|
function hideSidebar() {
|
||||||
|
html.classList.remove('sidebar-visible')
|
||||||
|
html.classList.add('sidebar-hidden');
|
||||||
|
Array.from(sidebarLinks).forEach(function (link) {
|
||||||
|
link.setAttribute('tabIndex', -1);
|
||||||
|
});
|
||||||
|
sidebarToggleButton.setAttribute('aria-expanded', false);
|
||||||
|
sidebar.setAttribute('aria-hidden', true);
|
||||||
|
try { localStorage.setItem('mdbook-sidebar', 'hidden'); } catch (e) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle sidebar
|
||||||
|
sidebarToggleButton.addEventListener('click', function sidebarToggle() {
|
||||||
|
if (html.classList.contains("sidebar-hidden")) {
|
||||||
|
var current_width = parseInt(
|
||||||
|
document.documentElement.style.getPropertyValue('--sidebar-width'), 10);
|
||||||
|
if (current_width < 150) {
|
||||||
|
document.documentElement.style.setProperty('--sidebar-width', '150px');
|
||||||
|
}
|
||||||
|
showSidebar();
|
||||||
|
} else if (html.classList.contains("sidebar-visible")) {
|
||||||
|
hideSidebar();
|
||||||
|
} else {
|
||||||
|
if (getComputedStyle(sidebar)['transform'] === 'none') {
|
||||||
|
hideSidebar();
|
||||||
|
} else {
|
||||||
|
showSidebar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
sidebarResizeHandle.addEventListener('mousedown', initResize, false);
|
||||||
|
|
||||||
|
function initResize(e) {
|
||||||
|
window.addEventListener('mousemove', resize, false);
|
||||||
|
window.addEventListener('mouseup', stopResize, false);
|
||||||
|
html.classList.add('sidebar-resizing');
|
||||||
|
}
|
||||||
|
function resize(e) {
|
||||||
|
var pos = (e.clientX - sidebar.offsetLeft);
|
||||||
|
if (pos < 20) {
|
||||||
|
hideSidebar();
|
||||||
|
} else {
|
||||||
|
if (html.classList.contains("sidebar-hidden")) {
|
||||||
|
showSidebar();
|
||||||
|
}
|
||||||
|
pos = Math.min(pos, window.innerWidth - 100);
|
||||||
|
document.documentElement.style.setProperty('--sidebar-width', pos + 'px');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//on mouseup remove windows functions mousemove & mouseup
|
||||||
|
function stopResize(e) {
|
||||||
|
html.classList.remove('sidebar-resizing');
|
||||||
|
window.removeEventListener('mousemove', resize, false);
|
||||||
|
window.removeEventListener('mouseup', stopResize, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('touchstart', function (e) {
|
||||||
|
firstContact = {
|
||||||
|
x: e.touches[0].clientX,
|
||||||
|
time: Date.now()
|
||||||
|
};
|
||||||
|
}, { passive: true });
|
||||||
|
|
||||||
|
document.addEventListener('touchmove', function (e) {
|
||||||
|
if (!firstContact)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var curX = e.touches[0].clientX;
|
||||||
|
var xDiff = curX - firstContact.x,
|
||||||
|
tDiff = Date.now() - firstContact.time;
|
||||||
|
|
||||||
|
if (tDiff < 250 && Math.abs(xDiff) >= 150) {
|
||||||
|
if (xDiff >= 0 && firstContact.x < Math.min(document.body.clientWidth * 0.25, 300))
|
||||||
|
showSidebar();
|
||||||
|
else if (xDiff < 0 && curX < 300)
|
||||||
|
hideSidebar();
|
||||||
|
|
||||||
|
firstContact = null;
|
||||||
|
}
|
||||||
|
}, { passive: true });
|
||||||
|
|
||||||
|
// Scroll sidebar to current active section
|
||||||
|
var activeSection = document.getElementById("sidebar").querySelector(".active");
|
||||||
|
if (activeSection) {
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
|
||||||
|
activeSection.scrollIntoView({ block: 'center' });
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
(function chapterNavigation() {
|
||||||
|
document.addEventListener('keydown', function (e) {
|
||||||
|
if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { return; }
|
||||||
|
if (window.search && window.search.hasFocus()) { return; }
|
||||||
|
|
||||||
|
switch (e.key) {
|
||||||
|
case 'ArrowRight':
|
||||||
|
e.preventDefault();
|
||||||
|
var nextButton = document.querySelector('.nav-chapters.next');
|
||||||
|
if (nextButton) {
|
||||||
|
window.location.href = nextButton.href;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'ArrowLeft':
|
||||||
|
e.preventDefault();
|
||||||
|
var previousButton = document.querySelector('.nav-chapters.previous');
|
||||||
|
if (previousButton) {
|
||||||
|
window.location.href = previousButton.href;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
|
||||||
|
(function clipboard() {
|
||||||
|
var clipButtons = document.querySelectorAll('.clip-button');
|
||||||
|
|
||||||
|
function hideTooltip(elem) {
|
||||||
|
elem.firstChild.innerText = "";
|
||||||
|
elem.className = 'fa fa-copy clip-button';
|
||||||
|
}
|
||||||
|
|
||||||
|
function showTooltip(elem, msg) {
|
||||||
|
elem.firstChild.innerText = msg;
|
||||||
|
elem.className = 'fa fa-copy tooltipped';
|
||||||
|
}
|
||||||
|
|
||||||
|
var clipboardSnippets = new ClipboardJS('.clip-button', {
|
||||||
|
text: function (trigger) {
|
||||||
|
hideTooltip(trigger);
|
||||||
|
let playground = trigger.closest("pre");
|
||||||
|
return playground_text(playground);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Array.from(clipButtons).forEach(function (clipButton) {
|
||||||
|
clipButton.addEventListener('mouseout', function (e) {
|
||||||
|
hideTooltip(e.currentTarget);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
clipboardSnippets.on('success', function (e) {
|
||||||
|
e.clearSelection();
|
||||||
|
showTooltip(e.trigger, "Copied!");
|
||||||
|
});
|
||||||
|
|
||||||
|
clipboardSnippets.on('error', function (e) {
|
||||||
|
showTooltip(e.trigger, "Clipboard error!");
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
|
||||||
|
(function scrollToTop () {
|
||||||
|
var menuTitle = document.querySelector('.menu-title');
|
||||||
|
|
||||||
|
menuTitle.addEventListener('click', function () {
|
||||||
|
document.scrollingElement.scrollTo({ top: 0, behavior: 'smooth' });
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
|
||||||
|
(function controllMenu() {
|
||||||
|
var menu = document.getElementById('menu-bar');
|
||||||
|
|
||||||
|
(function controllPosition() {
|
||||||
|
var scrollTop = document.scrollingElement.scrollTop;
|
||||||
|
var prevScrollTop = scrollTop;
|
||||||
|
var minMenuY = -menu.clientHeight - 50;
|
||||||
|
// When the script loads, the page can be at any scroll (e.g. if you reforesh it).
|
||||||
|
menu.style.top = scrollTop + 'px';
|
||||||
|
// Same as parseInt(menu.style.top.slice(0, -2), but faster
|
||||||
|
var topCache = menu.style.top.slice(0, -2);
|
||||||
|
menu.classList.remove('sticky');
|
||||||
|
var stickyCache = false; // Same as menu.classList.contains('sticky'), but faster
|
||||||
|
document.addEventListener('scroll', function () {
|
||||||
|
scrollTop = Math.max(document.scrollingElement.scrollTop, 0);
|
||||||
|
// `null` means that it doesn't need to be updated
|
||||||
|
var nextSticky = null;
|
||||||
|
var nextTop = null;
|
||||||
|
var scrollDown = scrollTop > prevScrollTop;
|
||||||
|
var menuPosAbsoluteY = topCache - scrollTop;
|
||||||
|
if (scrollDown) {
|
||||||
|
nextSticky = false;
|
||||||
|
if (menuPosAbsoluteY > 0) {
|
||||||
|
nextTop = prevScrollTop;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (menuPosAbsoluteY > 0) {
|
||||||
|
nextSticky = true;
|
||||||
|
} else if (menuPosAbsoluteY < minMenuY) {
|
||||||
|
nextTop = prevScrollTop + minMenuY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nextSticky === true && stickyCache === false) {
|
||||||
|
menu.classList.add('sticky');
|
||||||
|
stickyCache = true;
|
||||||
|
} else if (nextSticky === false && stickyCache === true) {
|
||||||
|
menu.classList.remove('sticky');
|
||||||
|
stickyCache = false;
|
||||||
|
}
|
||||||
|
if (nextTop !== null) {
|
||||||
|
menu.style.top = nextTop + 'px';
|
||||||
|
topCache = nextTop;
|
||||||
|
}
|
||||||
|
prevScrollTop = scrollTop;
|
||||||
|
}, { passive: true });
|
||||||
|
})();
|
||||||
|
(function controllBorder() {
|
||||||
|
menu.classList.remove('bordered');
|
||||||
|
document.addEventListener('scroll', function () {
|
||||||
|
if (menu.offsetTop === 0) {
|
||||||
|
menu.classList.remove('bordered');
|
||||||
|
} else {
|
||||||
|
menu.classList.add('bordered');
|
||||||
|
}
|
||||||
|
}, { passive: true });
|
||||||
|
})();
|
||||||
|
})();
|
||||||
7
clipboard.min.js
vendored
Normal file
|
|
@ -1,35 +0,0 @@
|
||||||
# tealdeer bash completion
|
|
||||||
|
|
||||||
_tealdeer()
|
|
||||||
{
|
|
||||||
local cur prev words cword
|
|
||||||
_init_completion || return
|
|
||||||
|
|
||||||
case $prev in
|
|
||||||
-h|--help|-v|--version|-l|--list|-u|--update|--no-auto-update|-c|--clear-cache|--pager|-r|--raw|--show-paths|--seed-config|-q|--quiet)
|
|
||||||
return
|
|
||||||
;;
|
|
||||||
-f|--render)
|
|
||||||
_filedir
|
|
||||||
return
|
|
||||||
;;
|
|
||||||
-p|--platform)
|
|
||||||
COMPREPLY=( $(compgen -W 'linux macos sunos windows android freebsd netbsd openbsd' -- "${cur}") )
|
|
||||||
return
|
|
||||||
;;
|
|
||||||
--color)
|
|
||||||
COMPREPLY=( $(compgen -W 'always auto never' -- "${cur}") )
|
|
||||||
return
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
if [[ $cur == -* ]]; then
|
|
||||||
COMPREPLY=( $( compgen -W '$( _parse_help "$1" )' -- "$cur" ) )
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
if tldrlist=$(tldr -l 2>/dev/null); then
|
|
||||||
COMPREPLY=( $(compgen -W '$( echo "$tldrlist" | tr -d , )' -- "${cur}") )
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
complete -F _tealdeer tldr
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
#
|
|
||||||
# Completions for the tealdeer implementation of tldr
|
|
||||||
# https://github.com/tealdeer-rs/tealdeer/
|
|
||||||
#
|
|
||||||
|
|
||||||
complete -c tldr -s h -l help -d 'Print the help message.' -f
|
|
||||||
complete -c tldr -s v -l version -d 'Show version information.' -f
|
|
||||||
complete -c tldr -s l -l list -d 'List all commands in the cache.' -f
|
|
||||||
complete -c tldr -s f -l render -d 'Render a specific markdown file.' -r
|
|
||||||
complete -c tldr -s p -l platform -d 'Override the operating system.' -xa 'linux macos sunos windows android freebsd netbsd openbsd'
|
|
||||||
complete -c tldr -s L -l language -d 'Override the language' -x
|
|
||||||
complete -c tldr -s u -l update -d 'Update the local cache.' -f
|
|
||||||
complete -c tldr -l no-auto-update -d 'If auto update is configured, disable it for this run.' -f
|
|
||||||
complete -c tldr -s c -l clear-cache -d 'Clear the local cache.' -f
|
|
||||||
complete -c tldr -l pager -d 'Use a pager to page output.' -f
|
|
||||||
complete -c tldr -s r -l raw -d 'Display the raw markdown instead of rendering it.' -f
|
|
||||||
complete -c tldr -s q -l quiet -d 'Suppress informational messages.' -f
|
|
||||||
complete -c tldr -l show-paths -d 'Show file and directory paths used by tealdeer.' -f
|
|
||||||
complete -c tldr -l seed-config -d 'Create a basic config.' -f
|
|
||||||
complete -c tldr -l color -d 'Controls when to use color.' -xa 'always auto never'
|
|
||||||
|
|
||||||
function __tealdeer_entries
|
|
||||||
if set entries (tldr --list 2>/dev/null)
|
|
||||||
string replace -a -i -r "\,\s" "\n" $entries
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
complete -f -c tldr -a '(__tealdeer_entries)'
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
#compdef tldr
|
|
||||||
|
|
||||||
_applications() {
|
|
||||||
local -a commands
|
|
||||||
if commands=(${(uonzf)"$(tldr --list 2>/dev/null)"//:/\\:}); then
|
|
||||||
_describe -t commands 'command' commands
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
_tealdeer() {
|
|
||||||
local I="-h --help -v --version"
|
|
||||||
integer ret=1
|
|
||||||
local -a args
|
|
||||||
|
|
||||||
args+=(
|
|
||||||
"($I -l --list)"{-l,--list}"[List all commands in the cache]"
|
|
||||||
"($I -f --render)"{-f,--render}"[Render a specific markdown file]:file:_files"
|
|
||||||
"($I -p --platform)"{-p,--platform}'[Override the operating system]:platform:((
|
|
||||||
linux
|
|
||||||
macos
|
|
||||||
sunos
|
|
||||||
windows
|
|
||||||
android
|
|
||||||
freebsd
|
|
||||||
netbsd
|
|
||||||
openbsd
|
|
||||||
))'
|
|
||||||
"($I -L --language)"{-L,--language}"[Override the language settings]:lang"
|
|
||||||
"($I -u --update)"{-u,--update}"[Update the local cache]"
|
|
||||||
"($I)--no-auto-update[If auto update is configured, disable it for this run]"
|
|
||||||
"($I -c --clear-cache)"{-c,--clear-cache}"[Clear the local cache]"
|
|
||||||
"($I)--pager[Use a pager to page output]"
|
|
||||||
"($I -r --raw)"{-r,--raw}"[Display the raw markdown instead of rendering it]"
|
|
||||||
"($I -q --quiet)"{-q,--quiet}"[Suppress informational messages]"
|
|
||||||
"($I)--show-paths[Show file and directory paths used by tealdeer]"
|
|
||||||
"($I)--seed-config[Create a basic config]"
|
|
||||||
"($I)--color[Controls when to use color]:when:((
|
|
||||||
always
|
|
||||||
auto
|
|
||||||
never
|
|
||||||
))"
|
|
||||||
'(- *)'{-h,--help}'[Display help]'
|
|
||||||
'(- *)'{-v,--version}'[Show version information]'
|
|
||||||
'1: :_applications'
|
|
||||||
)
|
|
||||||
|
|
||||||
_arguments $args[@] && ret=0
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
_tealdeer
|
|
||||||
278
config.html
Normal file
|
|
@ -0,0 +1,278 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html lang="en" class="sidebar-visible no-js light">
|
||||||
|
<head>
|
||||||
|
<!-- Book generated using mdBook -->
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Configuration - Tealdeer User Manual</title>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Custom HTML head -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||||
|
<meta name="description" content="">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="theme-color" content="#ffffff" />
|
||||||
|
|
||||||
|
|
||||||
|
<link rel="icon" href="favicon.svg">
|
||||||
|
|
||||||
|
|
||||||
|
<link rel="shortcut icon" href="favicon.png">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="css/variables.css">
|
||||||
|
<link rel="stylesheet" href="css/general.css">
|
||||||
|
<link rel="stylesheet" href="css/chrome.css">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="css/print.css" media="print">
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Fonts -->
|
||||||
|
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="fonts/fonts.css">
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Highlight.js Stylesheets -->
|
||||||
|
<link rel="stylesheet" href="highlight.css">
|
||||||
|
<link rel="stylesheet" href="tomorrow-night.css">
|
||||||
|
<link rel="stylesheet" href="ayu-highlight.css">
|
||||||
|
|
||||||
|
<!-- Custom theme stylesheets -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- Provide site root to javascript -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var path_to_root = "";
|
||||||
|
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
try {
|
||||||
|
var theme = localStorage.getItem('mdbook-theme');
|
||||||
|
var sidebar = localStorage.getItem('mdbook-sidebar');
|
||||||
|
|
||||||
|
if (theme.startsWith('"') && theme.endsWith('"')) {
|
||||||
|
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
||||||
|
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
||||||
|
}
|
||||||
|
} catch (e) { }
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Set the theme before any content is loaded, prevents flash -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var theme;
|
||||||
|
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||||||
|
if (theme === null || theme === undefined) { theme = default_theme; }
|
||||||
|
var html = document.querySelector('html');
|
||||||
|
html.classList.remove('no-js')
|
||||||
|
html.classList.remove('light')
|
||||||
|
html.classList.add(theme);
|
||||||
|
html.classList.add('js');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Hide / unhide sidebar before it is displayed -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var html = document.querySelector('html');
|
||||||
|
var sidebar = 'hidden';
|
||||||
|
if (document.body.clientWidth >= 1080) {
|
||||||
|
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
||||||
|
sidebar = sidebar || 'visible';
|
||||||
|
}
|
||||||
|
html.classList.remove('sidebar-visible');
|
||||||
|
html.classList.add("sidebar-" + sidebar);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||||
|
<div class="sidebar-scrollbox">
|
||||||
|
<ol class="chapter"><li class="chapter-item expanded affix "><a href="intro.html">Introduction</a></li><li class="chapter-item expanded "><a href="installing.html"><strong aria-hidden="true">1.</strong> Installing</a></li><li class="chapter-item expanded "><a href="usage.html"><strong aria-hidden="true">2.</strong> Usage</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="usage_custom_pages.html"><strong aria-hidden="true">2.1.</strong> Custom Pages and Patches</a></li></ol></li><li class="chapter-item expanded "><a href="config.html" class="active"><strong aria-hidden="true">3.</strong> Configuration</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="config_display.html"><strong aria-hidden="true">3.1.</strong> Section: [display]</a></li><li class="chapter-item expanded "><a href="config_style.html"><strong aria-hidden="true">3.2.</strong> Section: [style]</a></li><li class="chapter-item expanded "><a href="config_search.html"><strong aria-hidden="true">3.3.</strong> Section: [search]</a></li><li class="chapter-item expanded "><a href="config_updates.html"><strong aria-hidden="true">3.4.</strong> Section: [updates]</a></li><li class="chapter-item expanded "><a href="config_directories.html"><strong aria-hidden="true">3.5.</strong> Section: [directories]</a></li></ol></li><li class="chapter-item expanded "><a href="tips_and_tricks.html"><strong aria-hidden="true">4.</strong> Tips and Tricks</a></li></ol>
|
||||||
|
</div>
|
||||||
|
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div id="page-wrapper" class="page-wrapper">
|
||||||
|
|
||||||
|
<div class="page">
|
||||||
|
|
||||||
|
<div id="menu-bar-hover-placeholder"></div>
|
||||||
|
<div id="menu-bar" class="menu-bar sticky bordered">
|
||||||
|
<div class="left-buttons">
|
||||||
|
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
||||||
|
<i class="fa fa-bars"></i>
|
||||||
|
</button>
|
||||||
|
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
||||||
|
<i class="fa fa-paint-brush"></i>
|
||||||
|
</button>
|
||||||
|
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
||||||
|
<i class="fa fa-search"></i>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1 class="menu-title">Tealdeer User Manual</h1>
|
||||||
|
|
||||||
|
<div class="right-buttons">
|
||||||
|
|
||||||
|
<a href="print.html" title="Print this book" aria-label="Print this book">
|
||||||
|
<i id="print-button" class="fa fa-print"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="search-wrapper" class="hidden">
|
||||||
|
<form id="searchbar-outer" class="searchbar-outer">
|
||||||
|
<input type="search" name="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||||||
|
</form>
|
||||||
|
<div id="searchresults-outer" class="searchresults-outer hidden">
|
||||||
|
<div id="searchresults-header" class="searchresults-header"></div>
|
||||||
|
<ul id="searchresults">
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
||||||
|
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
||||||
|
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
||||||
|
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div id="content" class="content">
|
||||||
|
<main>
|
||||||
|
<h1><a class="header" href="#configuration" id="configuration">Configuration</a></h1>
|
||||||
|
<p>Tealdeer can be customized with a config file in <a href="https://toml.io/">TOML
|
||||||
|
format</a> called <code>config.toml</code>.</p>
|
||||||
|
<h2><a class="header" href="#configfile-path" id="configfile-path">Configfile Path</a></h2>
|
||||||
|
<p>The configuration file path follows OS conventions (e.g.
|
||||||
|
<code>$XDG_CONFIG_HOME/tealdeer/config.toml</code> on Linux). The paths can be queried
|
||||||
|
with the following command:</p>
|
||||||
|
<pre><code class="language-shell">$ tldr --show-paths
|
||||||
|
</code></pre>
|
||||||
|
<p>Creating the config file can be done manually or with the help of <code>tldr</code>:</p>
|
||||||
|
<pre><code class="language-shell">$ tldr --seed-config
|
||||||
|
</code></pre>
|
||||||
|
<p>On Linux, this will usually be <code>~/.config/tealdeer/config.toml</code>.</p>
|
||||||
|
<h2><a class="header" href="#config-example" id="config-example">Config Example</a></h2>
|
||||||
|
<p>Here's an example configuration file. Note that this example does not contain
|
||||||
|
all possible config options. For details on the things that can be configured,
|
||||||
|
please refer to the subsections of this documentation page
|
||||||
|
(<a href="config_display.html">display</a>, <a href="config_style.html">style</a>, <a href="config_search.html">search</a>,
|
||||||
|
<a href="config_updates.html">updates</a> or <a href="config_directories.html">directories</a>).</p>
|
||||||
|
<pre><code class="language-toml">[display]
|
||||||
|
compact = false
|
||||||
|
use_pager = true
|
||||||
|
show_title = false
|
||||||
|
|
||||||
|
[style.command_name]
|
||||||
|
foreground = "red"
|
||||||
|
|
||||||
|
[style.example_text]
|
||||||
|
foreground = "green"
|
||||||
|
|
||||||
|
[style.example_code]
|
||||||
|
foreground = "blue"
|
||||||
|
|
||||||
|
[style.example_variable]
|
||||||
|
foreground = "blue"
|
||||||
|
underline = true
|
||||||
|
|
||||||
|
[updates]
|
||||||
|
auto_update = true
|
||||||
|
</code></pre>
|
||||||
|
<h2><a class="header" href="#override-config-directory" id="override-config-directory">Override Config Directory</a></h2>
|
||||||
|
<p>The directory where the configuration file resides may be overwritten by the
|
||||||
|
environment variable <code>TEALDEER_CONFIG_DIR</code>. Remember to use an absolute path.
|
||||||
|
Variable expansion will not be performed on the path.</p>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||||
|
<!-- Mobile navigation buttons -->
|
||||||
|
|
||||||
|
<a rel="prev" href="usage_custom_pages.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||||
|
<i class="fa fa-angle-left"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a rel="next" href="config_display.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||||
|
<i class="fa fa-angle-right"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
<div style="clear: both"></div>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||||
|
|
||||||
|
<a rel="prev" href="usage_custom_pages.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||||
|
<i class="fa fa-angle-left"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a rel="next" href="config_display.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||||
|
<i class="fa fa-angle-right"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
window.playground_copyable = true;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="searcher.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="highlight.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="book.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
||||||
|
<!-- Custom JS scripts -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
253
config_directories.html
Normal file
|
|
@ -0,0 +1,253 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html lang="en" class="sidebar-visible no-js light">
|
||||||
|
<head>
|
||||||
|
<!-- Book generated using mdBook -->
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Section: [directories] - Tealdeer User Manual</title>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Custom HTML head -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||||
|
<meta name="description" content="">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="theme-color" content="#ffffff" />
|
||||||
|
|
||||||
|
|
||||||
|
<link rel="icon" href="favicon.svg">
|
||||||
|
|
||||||
|
|
||||||
|
<link rel="shortcut icon" href="favicon.png">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="css/variables.css">
|
||||||
|
<link rel="stylesheet" href="css/general.css">
|
||||||
|
<link rel="stylesheet" href="css/chrome.css">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="css/print.css" media="print">
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Fonts -->
|
||||||
|
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="fonts/fonts.css">
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Highlight.js Stylesheets -->
|
||||||
|
<link rel="stylesheet" href="highlight.css">
|
||||||
|
<link rel="stylesheet" href="tomorrow-night.css">
|
||||||
|
<link rel="stylesheet" href="ayu-highlight.css">
|
||||||
|
|
||||||
|
<!-- Custom theme stylesheets -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- Provide site root to javascript -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var path_to_root = "";
|
||||||
|
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
try {
|
||||||
|
var theme = localStorage.getItem('mdbook-theme');
|
||||||
|
var sidebar = localStorage.getItem('mdbook-sidebar');
|
||||||
|
|
||||||
|
if (theme.startsWith('"') && theme.endsWith('"')) {
|
||||||
|
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
||||||
|
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
||||||
|
}
|
||||||
|
} catch (e) { }
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Set the theme before any content is loaded, prevents flash -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var theme;
|
||||||
|
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||||||
|
if (theme === null || theme === undefined) { theme = default_theme; }
|
||||||
|
var html = document.querySelector('html');
|
||||||
|
html.classList.remove('no-js')
|
||||||
|
html.classList.remove('light')
|
||||||
|
html.classList.add(theme);
|
||||||
|
html.classList.add('js');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Hide / unhide sidebar before it is displayed -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var html = document.querySelector('html');
|
||||||
|
var sidebar = 'hidden';
|
||||||
|
if (document.body.clientWidth >= 1080) {
|
||||||
|
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
||||||
|
sidebar = sidebar || 'visible';
|
||||||
|
}
|
||||||
|
html.classList.remove('sidebar-visible');
|
||||||
|
html.classList.add("sidebar-" + sidebar);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||||
|
<div class="sidebar-scrollbox">
|
||||||
|
<ol class="chapter"><li class="chapter-item expanded affix "><a href="intro.html">Introduction</a></li><li class="chapter-item expanded "><a href="installing.html"><strong aria-hidden="true">1.</strong> Installing</a></li><li class="chapter-item expanded "><a href="usage.html"><strong aria-hidden="true">2.</strong> Usage</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="usage_custom_pages.html"><strong aria-hidden="true">2.1.</strong> Custom Pages and Patches</a></li></ol></li><li class="chapter-item expanded "><a href="config.html"><strong aria-hidden="true">3.</strong> Configuration</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="config_display.html"><strong aria-hidden="true">3.1.</strong> Section: [display]</a></li><li class="chapter-item expanded "><a href="config_style.html"><strong aria-hidden="true">3.2.</strong> Section: [style]</a></li><li class="chapter-item expanded "><a href="config_search.html"><strong aria-hidden="true">3.3.</strong> Section: [search]</a></li><li class="chapter-item expanded "><a href="config_updates.html"><strong aria-hidden="true">3.4.</strong> Section: [updates]</a></li><li class="chapter-item expanded "><a href="config_directories.html" class="active"><strong aria-hidden="true">3.5.</strong> Section: [directories]</a></li></ol></li><li class="chapter-item expanded "><a href="tips_and_tricks.html"><strong aria-hidden="true">4.</strong> Tips and Tricks</a></li></ol>
|
||||||
|
</div>
|
||||||
|
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div id="page-wrapper" class="page-wrapper">
|
||||||
|
|
||||||
|
<div class="page">
|
||||||
|
|
||||||
|
<div id="menu-bar-hover-placeholder"></div>
|
||||||
|
<div id="menu-bar" class="menu-bar sticky bordered">
|
||||||
|
<div class="left-buttons">
|
||||||
|
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
||||||
|
<i class="fa fa-bars"></i>
|
||||||
|
</button>
|
||||||
|
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
||||||
|
<i class="fa fa-paint-brush"></i>
|
||||||
|
</button>
|
||||||
|
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
||||||
|
<i class="fa fa-search"></i>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1 class="menu-title">Tealdeer User Manual</h1>
|
||||||
|
|
||||||
|
<div class="right-buttons">
|
||||||
|
|
||||||
|
<a href="print.html" title="Print this book" aria-label="Print this book">
|
||||||
|
<i id="print-button" class="fa fa-print"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="search-wrapper" class="hidden">
|
||||||
|
<form id="searchbar-outer" class="searchbar-outer">
|
||||||
|
<input type="search" name="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||||||
|
</form>
|
||||||
|
<div id="searchresults-outer" class="searchresults-outer hidden">
|
||||||
|
<div id="searchresults-header" class="searchresults-header"></div>
|
||||||
|
<ul id="searchresults">
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
||||||
|
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
||||||
|
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
||||||
|
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div id="content" class="content">
|
||||||
|
<main>
|
||||||
|
<h1><a class="header" href="#section-directories" id="section-directories">Section: [directories]</a></h1>
|
||||||
|
<p>This section allows overriding some directory paths.</p>
|
||||||
|
<h2><a class="header" href="#cache_dir" id="cache_dir"><code>cache_dir</code></a></h2>
|
||||||
|
<p>Override the cache directory. Remember to use an absolute path. Variable
|
||||||
|
expansion will not be performed on the path. If the directory does not yet
|
||||||
|
exist, it will be created.</p>
|
||||||
|
<pre><code class="language-toml">[directories]
|
||||||
|
cache_dir = "/home/myuser/.tealdeer-cache/"
|
||||||
|
</code></pre>
|
||||||
|
<p>If no <code>cache_dir</code> is specified, tealdeer will fall back to a location that
|
||||||
|
follows OS conventions. On Linux, it will usually be at <code>~/.cache/tealdeer/</code>.
|
||||||
|
Use <code>tldr --show-paths</code> to show the path that is being used.</p>
|
||||||
|
<h2><a class="header" href="#custom_pages_dir" id="custom_pages_dir"><code>custom_pages_dir</code></a></h2>
|
||||||
|
<p>Set the directory to be used to look up <a href="usage_custom_pages.html">custom
|
||||||
|
pages</a>. Remember to use an absolute path. Variable
|
||||||
|
expansion will not be performed on the path.</p>
|
||||||
|
<pre><code class="language-toml">[directories]
|
||||||
|
custom_pages_dir = "/home/myuser/custom-tldr-pages/"
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||||
|
<!-- Mobile navigation buttons -->
|
||||||
|
|
||||||
|
<a rel="prev" href="config_updates.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||||
|
<i class="fa fa-angle-left"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a rel="next" href="tips_and_tricks.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||||
|
<i class="fa fa-angle-right"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
<div style="clear: both"></div>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||||
|
|
||||||
|
<a rel="prev" href="config_updates.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||||
|
<i class="fa fa-angle-left"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a rel="next" href="tips_and_tricks.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||||
|
<i class="fa fa-angle-right"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
window.playground_copyable = true;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="searcher.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="highlight.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="book.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
||||||
|
<!-- Custom JS scripts -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
257
config_display.html
Normal file
|
|
@ -0,0 +1,257 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html lang="en" class="sidebar-visible no-js light">
|
||||||
|
<head>
|
||||||
|
<!-- Book generated using mdBook -->
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Section: [display] - Tealdeer User Manual</title>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Custom HTML head -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||||
|
<meta name="description" content="">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="theme-color" content="#ffffff" />
|
||||||
|
|
||||||
|
|
||||||
|
<link rel="icon" href="favicon.svg">
|
||||||
|
|
||||||
|
|
||||||
|
<link rel="shortcut icon" href="favicon.png">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="css/variables.css">
|
||||||
|
<link rel="stylesheet" href="css/general.css">
|
||||||
|
<link rel="stylesheet" href="css/chrome.css">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="css/print.css" media="print">
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Fonts -->
|
||||||
|
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="fonts/fonts.css">
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Highlight.js Stylesheets -->
|
||||||
|
<link rel="stylesheet" href="highlight.css">
|
||||||
|
<link rel="stylesheet" href="tomorrow-night.css">
|
||||||
|
<link rel="stylesheet" href="ayu-highlight.css">
|
||||||
|
|
||||||
|
<!-- Custom theme stylesheets -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- Provide site root to javascript -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var path_to_root = "";
|
||||||
|
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
try {
|
||||||
|
var theme = localStorage.getItem('mdbook-theme');
|
||||||
|
var sidebar = localStorage.getItem('mdbook-sidebar');
|
||||||
|
|
||||||
|
if (theme.startsWith('"') && theme.endsWith('"')) {
|
||||||
|
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
||||||
|
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
||||||
|
}
|
||||||
|
} catch (e) { }
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Set the theme before any content is loaded, prevents flash -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var theme;
|
||||||
|
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||||||
|
if (theme === null || theme === undefined) { theme = default_theme; }
|
||||||
|
var html = document.querySelector('html');
|
||||||
|
html.classList.remove('no-js')
|
||||||
|
html.classList.remove('light')
|
||||||
|
html.classList.add(theme);
|
||||||
|
html.classList.add('js');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Hide / unhide sidebar before it is displayed -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var html = document.querySelector('html');
|
||||||
|
var sidebar = 'hidden';
|
||||||
|
if (document.body.clientWidth >= 1080) {
|
||||||
|
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
||||||
|
sidebar = sidebar || 'visible';
|
||||||
|
}
|
||||||
|
html.classList.remove('sidebar-visible');
|
||||||
|
html.classList.add("sidebar-" + sidebar);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||||
|
<div class="sidebar-scrollbox">
|
||||||
|
<ol class="chapter"><li class="chapter-item expanded affix "><a href="intro.html">Introduction</a></li><li class="chapter-item expanded "><a href="installing.html"><strong aria-hidden="true">1.</strong> Installing</a></li><li class="chapter-item expanded "><a href="usage.html"><strong aria-hidden="true">2.</strong> Usage</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="usage_custom_pages.html"><strong aria-hidden="true">2.1.</strong> Custom Pages and Patches</a></li></ol></li><li class="chapter-item expanded "><a href="config.html"><strong aria-hidden="true">3.</strong> Configuration</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="config_display.html" class="active"><strong aria-hidden="true">3.1.</strong> Section: [display]</a></li><li class="chapter-item expanded "><a href="config_style.html"><strong aria-hidden="true">3.2.</strong> Section: [style]</a></li><li class="chapter-item expanded "><a href="config_search.html"><strong aria-hidden="true">3.3.</strong> Section: [search]</a></li><li class="chapter-item expanded "><a href="config_updates.html"><strong aria-hidden="true">3.4.</strong> Section: [updates]</a></li><li class="chapter-item expanded "><a href="config_directories.html"><strong aria-hidden="true">3.5.</strong> Section: [directories]</a></li></ol></li><li class="chapter-item expanded "><a href="tips_and_tricks.html"><strong aria-hidden="true">4.</strong> Tips and Tricks</a></li></ol>
|
||||||
|
</div>
|
||||||
|
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div id="page-wrapper" class="page-wrapper">
|
||||||
|
|
||||||
|
<div class="page">
|
||||||
|
|
||||||
|
<div id="menu-bar-hover-placeholder"></div>
|
||||||
|
<div id="menu-bar" class="menu-bar sticky bordered">
|
||||||
|
<div class="left-buttons">
|
||||||
|
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
||||||
|
<i class="fa fa-bars"></i>
|
||||||
|
</button>
|
||||||
|
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
||||||
|
<i class="fa fa-paint-brush"></i>
|
||||||
|
</button>
|
||||||
|
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
||||||
|
<i class="fa fa-search"></i>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1 class="menu-title">Tealdeer User Manual</h1>
|
||||||
|
|
||||||
|
<div class="right-buttons">
|
||||||
|
|
||||||
|
<a href="print.html" title="Print this book" aria-label="Print this book">
|
||||||
|
<i id="print-button" class="fa fa-print"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="search-wrapper" class="hidden">
|
||||||
|
<form id="searchbar-outer" class="searchbar-outer">
|
||||||
|
<input type="search" name="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||||||
|
</form>
|
||||||
|
<div id="searchresults-outer" class="searchresults-outer hidden">
|
||||||
|
<div id="searchresults-header" class="searchresults-header"></div>
|
||||||
|
<ul id="searchresults">
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
||||||
|
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
||||||
|
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
||||||
|
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div id="content" class="content">
|
||||||
|
<main>
|
||||||
|
<h1><a class="header" href="#section-display" id="section-display">Section: [display]</a></h1>
|
||||||
|
<p>In the <code>display</code> section you can configure the output format.</p>
|
||||||
|
<h2><a class="header" href="#use_pager" id="use_pager"><code>use_pager</code></a></h2>
|
||||||
|
<p>Specifies whether the pager should be used by default or not (default <code>false</code>).</p>
|
||||||
|
<pre><code class="language-toml">[display]
|
||||||
|
use_pager = true
|
||||||
|
</code></pre>
|
||||||
|
<p>When enabled, <code>less -R</code> is used as pager. To override the pager command used,
|
||||||
|
set the <code>PAGER</code> environment variable.</p>
|
||||||
|
<p>NOTE: This feature is not available on Windows.</p>
|
||||||
|
<h2><a class="header" href="#compact" id="compact"><code>compact</code></a></h2>
|
||||||
|
<p>Set this to enforce more compact output, where empty lines are stripped out
|
||||||
|
(default <code>false</code>).</p>
|
||||||
|
<pre><code class="language-toml">[display]
|
||||||
|
compact = true
|
||||||
|
</code></pre>
|
||||||
|
<h2><a class="header" href="#show_title" id="show_title"><code>show_title</code></a></h2>
|
||||||
|
<p>Display the command name at the top of the page output (default <code>false</code>).</p>
|
||||||
|
<pre><code class="language-toml">[display]
|
||||||
|
show_title = true
|
||||||
|
</code></pre>
|
||||||
|
<p>When enabled, the command name will be displayed at the top of the output,
|
||||||
|
styled with the <code>command_name</code> style configuration.</p>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||||
|
<!-- Mobile navigation buttons -->
|
||||||
|
|
||||||
|
<a rel="prev" href="config.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||||
|
<i class="fa fa-angle-left"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a rel="next" href="config_style.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||||
|
<i class="fa fa-angle-right"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
<div style="clear: both"></div>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||||
|
|
||||||
|
<a rel="prev" href="config.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||||
|
<i class="fa fa-angle-left"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a rel="next" href="config_style.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||||
|
<i class="fa fa-angle-right"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
window.playground_copyable = true;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="searcher.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="highlight.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="book.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
||||||
|
<!-- Custom JS scripts -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
259
config_search.html
Normal file
|
|
@ -0,0 +1,259 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html lang="en" class="sidebar-visible no-js light">
|
||||||
|
<head>
|
||||||
|
<!-- Book generated using mdBook -->
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Section: [search] - Tealdeer User Manual</title>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Custom HTML head -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||||
|
<meta name="description" content="">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="theme-color" content="#ffffff" />
|
||||||
|
|
||||||
|
|
||||||
|
<link rel="icon" href="favicon.svg">
|
||||||
|
|
||||||
|
|
||||||
|
<link rel="shortcut icon" href="favicon.png">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="css/variables.css">
|
||||||
|
<link rel="stylesheet" href="css/general.css">
|
||||||
|
<link rel="stylesheet" href="css/chrome.css">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="css/print.css" media="print">
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Fonts -->
|
||||||
|
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="fonts/fonts.css">
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Highlight.js Stylesheets -->
|
||||||
|
<link rel="stylesheet" href="highlight.css">
|
||||||
|
<link rel="stylesheet" href="tomorrow-night.css">
|
||||||
|
<link rel="stylesheet" href="ayu-highlight.css">
|
||||||
|
|
||||||
|
<!-- Custom theme stylesheets -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- Provide site root to javascript -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var path_to_root = "";
|
||||||
|
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
try {
|
||||||
|
var theme = localStorage.getItem('mdbook-theme');
|
||||||
|
var sidebar = localStorage.getItem('mdbook-sidebar');
|
||||||
|
|
||||||
|
if (theme.startsWith('"') && theme.endsWith('"')) {
|
||||||
|
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
||||||
|
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
||||||
|
}
|
||||||
|
} catch (e) { }
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Set the theme before any content is loaded, prevents flash -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var theme;
|
||||||
|
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||||||
|
if (theme === null || theme === undefined) { theme = default_theme; }
|
||||||
|
var html = document.querySelector('html');
|
||||||
|
html.classList.remove('no-js')
|
||||||
|
html.classList.remove('light')
|
||||||
|
html.classList.add(theme);
|
||||||
|
html.classList.add('js');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Hide / unhide sidebar before it is displayed -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var html = document.querySelector('html');
|
||||||
|
var sidebar = 'hidden';
|
||||||
|
if (document.body.clientWidth >= 1080) {
|
||||||
|
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
||||||
|
sidebar = sidebar || 'visible';
|
||||||
|
}
|
||||||
|
html.classList.remove('sidebar-visible');
|
||||||
|
html.classList.add("sidebar-" + sidebar);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||||
|
<div class="sidebar-scrollbox">
|
||||||
|
<ol class="chapter"><li class="chapter-item expanded affix "><a href="intro.html">Introduction</a></li><li class="chapter-item expanded "><a href="installing.html"><strong aria-hidden="true">1.</strong> Installing</a></li><li class="chapter-item expanded "><a href="usage.html"><strong aria-hidden="true">2.</strong> Usage</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="usage_custom_pages.html"><strong aria-hidden="true">2.1.</strong> Custom Pages and Patches</a></li></ol></li><li class="chapter-item expanded "><a href="config.html"><strong aria-hidden="true">3.</strong> Configuration</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="config_display.html"><strong aria-hidden="true">3.1.</strong> Section: [display]</a></li><li class="chapter-item expanded "><a href="config_style.html"><strong aria-hidden="true">3.2.</strong> Section: [style]</a></li><li class="chapter-item expanded "><a href="config_search.html" class="active"><strong aria-hidden="true">3.3.</strong> Section: [search]</a></li><li class="chapter-item expanded "><a href="config_updates.html"><strong aria-hidden="true">3.4.</strong> Section: [updates]</a></li><li class="chapter-item expanded "><a href="config_directories.html"><strong aria-hidden="true">3.5.</strong> Section: [directories]</a></li></ol></li><li class="chapter-item expanded "><a href="tips_and_tricks.html"><strong aria-hidden="true">4.</strong> Tips and Tricks</a></li></ol>
|
||||||
|
</div>
|
||||||
|
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div id="page-wrapper" class="page-wrapper">
|
||||||
|
|
||||||
|
<div class="page">
|
||||||
|
|
||||||
|
<div id="menu-bar-hover-placeholder"></div>
|
||||||
|
<div id="menu-bar" class="menu-bar sticky bordered">
|
||||||
|
<div class="left-buttons">
|
||||||
|
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
||||||
|
<i class="fa fa-bars"></i>
|
||||||
|
</button>
|
||||||
|
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
||||||
|
<i class="fa fa-paint-brush"></i>
|
||||||
|
</button>
|
||||||
|
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
||||||
|
<i class="fa fa-search"></i>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1 class="menu-title">Tealdeer User Manual</h1>
|
||||||
|
|
||||||
|
<div class="right-buttons">
|
||||||
|
|
||||||
|
<a href="print.html" title="Print this book" aria-label="Print this book">
|
||||||
|
<i id="print-button" class="fa fa-print"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="search-wrapper" class="hidden">
|
||||||
|
<form id="searchbar-outer" class="searchbar-outer">
|
||||||
|
<input type="search" name="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||||||
|
</form>
|
||||||
|
<div id="searchresults-outer" class="searchresults-outer hidden">
|
||||||
|
<div id="searchresults-header" class="searchresults-header"></div>
|
||||||
|
<ul id="searchresults">
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
||||||
|
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
||||||
|
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
||||||
|
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div id="content" class="content">
|
||||||
|
<main>
|
||||||
|
<h1><a class="header" href="#section-search" id="section-search">Section: [search]</a></h1>
|
||||||
|
<p>This config section is used to configure the page search in the cache.
|
||||||
|
The settings apply to <code>tldr <page></code> and <code>tldr --list</code>.</p>
|
||||||
|
<h2><a class="header" href="#languages" id="languages"><code>languages</code></a></h2>
|
||||||
|
<p>The list of languages that should be considered when searching.
|
||||||
|
If unspecified, the list of languages will be inferred from the <code>LANG</code> and <code>LANGUAGE</code> environment variables.
|
||||||
|
Either way, the language used can be overwritten using the <code>--language</code> command line flag.</p>
|
||||||
|
<pre><code class="language-toml">[search]
|
||||||
|
# Show pages in German if available, otherwise show in English
|
||||||
|
languages = ["de", "en"]
|
||||||
|
</code></pre>
|
||||||
|
<h2><a class="header" href="#platforms" id="platforms"><code>platforms</code></a></h2>
|
||||||
|
<p>The list of platforms that should be considered when searching.
|
||||||
|
In addition to the platforms listed in the help text of the <code>--platform</code> flag, there are two special platforms available:</p>
|
||||||
|
<ul>
|
||||||
|
<li><code>"current"</code>: equals the platform that tealdeer was compiled for</li>
|
||||||
|
<li><code>"all"</code>: adds all remaining platforms to the list</li>
|
||||||
|
</ul>
|
||||||
|
<p>Tealdeer searches the platforms in order of appearance in this list.
|
||||||
|
The default list of platforms is <code>["current", "common", "all"]</code>.
|
||||||
|
The list of platforms can be overwritten using the <code>--platform</code> command line flag.</p>
|
||||||
|
<pre><code class="language-toml">[search]
|
||||||
|
# Search for linux and common, and then search windows before trying the remaining platforms
|
||||||
|
platforms = ["linux", "common", "windows", "all"]
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||||
|
<!-- Mobile navigation buttons -->
|
||||||
|
|
||||||
|
<a rel="prev" href="config_style.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||||
|
<i class="fa fa-angle-left"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a rel="next" href="config_updates.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||||
|
<i class="fa fa-angle-right"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
<div style="clear: both"></div>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||||
|
|
||||||
|
<a rel="prev" href="config_style.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||||
|
<i class="fa fa-angle-left"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a rel="next" href="config_updates.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||||
|
<i class="fa fa-angle-right"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
window.playground_copyable = true;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="searcher.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="highlight.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="book.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
||||||
|
<!-- Custom JS scripts -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
274
config_style.html
Normal file
|
|
@ -0,0 +1,274 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html lang="en" class="sidebar-visible no-js light">
|
||||||
|
<head>
|
||||||
|
<!-- Book generated using mdBook -->
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Section: [style] - Tealdeer User Manual</title>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Custom HTML head -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||||
|
<meta name="description" content="">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="theme-color" content="#ffffff" />
|
||||||
|
|
||||||
|
|
||||||
|
<link rel="icon" href="favicon.svg">
|
||||||
|
|
||||||
|
|
||||||
|
<link rel="shortcut icon" href="favicon.png">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="css/variables.css">
|
||||||
|
<link rel="stylesheet" href="css/general.css">
|
||||||
|
<link rel="stylesheet" href="css/chrome.css">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="css/print.css" media="print">
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Fonts -->
|
||||||
|
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="fonts/fonts.css">
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Highlight.js Stylesheets -->
|
||||||
|
<link rel="stylesheet" href="highlight.css">
|
||||||
|
<link rel="stylesheet" href="tomorrow-night.css">
|
||||||
|
<link rel="stylesheet" href="ayu-highlight.css">
|
||||||
|
|
||||||
|
<!-- Custom theme stylesheets -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- Provide site root to javascript -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var path_to_root = "";
|
||||||
|
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
try {
|
||||||
|
var theme = localStorage.getItem('mdbook-theme');
|
||||||
|
var sidebar = localStorage.getItem('mdbook-sidebar');
|
||||||
|
|
||||||
|
if (theme.startsWith('"') && theme.endsWith('"')) {
|
||||||
|
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
||||||
|
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
||||||
|
}
|
||||||
|
} catch (e) { }
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Set the theme before any content is loaded, prevents flash -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var theme;
|
||||||
|
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||||||
|
if (theme === null || theme === undefined) { theme = default_theme; }
|
||||||
|
var html = document.querySelector('html');
|
||||||
|
html.classList.remove('no-js')
|
||||||
|
html.classList.remove('light')
|
||||||
|
html.classList.add(theme);
|
||||||
|
html.classList.add('js');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Hide / unhide sidebar before it is displayed -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var html = document.querySelector('html');
|
||||||
|
var sidebar = 'hidden';
|
||||||
|
if (document.body.clientWidth >= 1080) {
|
||||||
|
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
||||||
|
sidebar = sidebar || 'visible';
|
||||||
|
}
|
||||||
|
html.classList.remove('sidebar-visible');
|
||||||
|
html.classList.add("sidebar-" + sidebar);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||||
|
<div class="sidebar-scrollbox">
|
||||||
|
<ol class="chapter"><li class="chapter-item expanded affix "><a href="intro.html">Introduction</a></li><li class="chapter-item expanded "><a href="installing.html"><strong aria-hidden="true">1.</strong> Installing</a></li><li class="chapter-item expanded "><a href="usage.html"><strong aria-hidden="true">2.</strong> Usage</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="usage_custom_pages.html"><strong aria-hidden="true">2.1.</strong> Custom Pages and Patches</a></li></ol></li><li class="chapter-item expanded "><a href="config.html"><strong aria-hidden="true">3.</strong> Configuration</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="config_display.html"><strong aria-hidden="true">3.1.</strong> Section: [display]</a></li><li class="chapter-item expanded "><a href="config_style.html" class="active"><strong aria-hidden="true">3.2.</strong> Section: [style]</a></li><li class="chapter-item expanded "><a href="config_search.html"><strong aria-hidden="true">3.3.</strong> Section: [search]</a></li><li class="chapter-item expanded "><a href="config_updates.html"><strong aria-hidden="true">3.4.</strong> Section: [updates]</a></li><li class="chapter-item expanded "><a href="config_directories.html"><strong aria-hidden="true">3.5.</strong> Section: [directories]</a></li></ol></li><li class="chapter-item expanded "><a href="tips_and_tricks.html"><strong aria-hidden="true">4.</strong> Tips and Tricks</a></li></ol>
|
||||||
|
</div>
|
||||||
|
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div id="page-wrapper" class="page-wrapper">
|
||||||
|
|
||||||
|
<div class="page">
|
||||||
|
|
||||||
|
<div id="menu-bar-hover-placeholder"></div>
|
||||||
|
<div id="menu-bar" class="menu-bar sticky bordered">
|
||||||
|
<div class="left-buttons">
|
||||||
|
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
||||||
|
<i class="fa fa-bars"></i>
|
||||||
|
</button>
|
||||||
|
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
||||||
|
<i class="fa fa-paint-brush"></i>
|
||||||
|
</button>
|
||||||
|
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
||||||
|
<i class="fa fa-search"></i>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1 class="menu-title">Tealdeer User Manual</h1>
|
||||||
|
|
||||||
|
<div class="right-buttons">
|
||||||
|
|
||||||
|
<a href="print.html" title="Print this book" aria-label="Print this book">
|
||||||
|
<i id="print-button" class="fa fa-print"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="search-wrapper" class="hidden">
|
||||||
|
<form id="searchbar-outer" class="searchbar-outer">
|
||||||
|
<input type="search" name="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||||||
|
</form>
|
||||||
|
<div id="searchresults-outer" class="searchresults-outer hidden">
|
||||||
|
<div id="searchresults-header" class="searchresults-header"></div>
|
||||||
|
<ul id="searchresults">
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
||||||
|
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
||||||
|
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
||||||
|
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div id="content" class="content">
|
||||||
|
<main>
|
||||||
|
<h1><a class="header" href="#section-style" id="section-style">Section: [style]</a></h1>
|
||||||
|
<p>Using the config file, the style (e.g. colors or underlines) can be customized.</p>
|
||||||
|
<img src="screenshot-custom.png" alt="Screenshot of customized version" width="600">
|
||||||
|
<h2><a class="header" href="#style-targets" id="style-targets">Style Targets</a></h2>
|
||||||
|
<ul>
|
||||||
|
<li><code>description</code>: The initial description text</li>
|
||||||
|
<li><code>command_name</code>: The command name as part of the example code</li>
|
||||||
|
<li><code>example_text</code>: The text that describes an example</li>
|
||||||
|
<li><code>example_code</code>: The example itself (except the <code>command_name</code> and <code>example_variable</code>)</li>
|
||||||
|
<li><code>example_variable</code>: The variables in the example</li>
|
||||||
|
</ul>
|
||||||
|
<h2><a class="header" href="#attributes" id="attributes">Attributes</a></h2>
|
||||||
|
<ul>
|
||||||
|
<li><code>foreground</code> (color string, ANSI code, or RGB, see below)</li>
|
||||||
|
<li><code>background</code> (color string, ANSI code, or RGB, see below)</li>
|
||||||
|
<li><code>underline</code> (<code>true</code> or <code>false</code>)</li>
|
||||||
|
<li><code>bold</code> (<code>true</code> or <code>false</code>)</li>
|
||||||
|
<li><code>italic</code> (<code>true</code> or <code>false</code>)</li>
|
||||||
|
</ul>
|
||||||
|
<p>Colors can be specified in one of three ways:</p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<p>Color string (<code>black</code>, <code>red</code>, <code>green</code>, <code>yellow</code>, <code>blue</code>, <code>magenta</code>, <code>cyan</code>, <code>white</code>):</p>
|
||||||
|
<p>Example:</p>
|
||||||
|
<pre><code class="language-toml">foreground = "green"
|
||||||
|
</code></pre>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p>256 color ANSI code (<em>tealdeer v1.5.0+</em>)</p>
|
||||||
|
<p>Example:</p>
|
||||||
|
<pre><code class="language-toml">foreground = { ansi = 4 }
|
||||||
|
</code></pre>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p>24-bit RGB color (<em>tealdeer v1.5.0+</em>)</p>
|
||||||
|
<p>Example:</p>
|
||||||
|
<pre><code class="language-toml">background = { rgb = { r = 255, g = 255, b = 255 } }
|
||||||
|
</code></pre>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||||
|
<!-- Mobile navigation buttons -->
|
||||||
|
|
||||||
|
<a rel="prev" href="config_display.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||||
|
<i class="fa fa-angle-left"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a rel="next" href="config_search.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||||
|
<i class="fa fa-angle-right"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
<div style="clear: both"></div>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||||
|
|
||||||
|
<a rel="prev" href="config_display.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||||
|
<i class="fa fa-angle-left"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a rel="next" href="config_search.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||||
|
<i class="fa fa-angle-right"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
window.playground_copyable = true;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="searcher.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="highlight.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="book.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
||||||
|
<!-- Custom JS scripts -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
290
config_updates.html
Normal file
|
|
@ -0,0 +1,290 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html lang="en" class="sidebar-visible no-js light">
|
||||||
|
<head>
|
||||||
|
<!-- Book generated using mdBook -->
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Section: [updates] - Tealdeer User Manual</title>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Custom HTML head -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||||
|
<meta name="description" content="">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="theme-color" content="#ffffff" />
|
||||||
|
|
||||||
|
|
||||||
|
<link rel="icon" href="favicon.svg">
|
||||||
|
|
||||||
|
|
||||||
|
<link rel="shortcut icon" href="favicon.png">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="css/variables.css">
|
||||||
|
<link rel="stylesheet" href="css/general.css">
|
||||||
|
<link rel="stylesheet" href="css/chrome.css">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="css/print.css" media="print">
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Fonts -->
|
||||||
|
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="fonts/fonts.css">
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Highlight.js Stylesheets -->
|
||||||
|
<link rel="stylesheet" href="highlight.css">
|
||||||
|
<link rel="stylesheet" href="tomorrow-night.css">
|
||||||
|
<link rel="stylesheet" href="ayu-highlight.css">
|
||||||
|
|
||||||
|
<!-- Custom theme stylesheets -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- Provide site root to javascript -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var path_to_root = "";
|
||||||
|
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
try {
|
||||||
|
var theme = localStorage.getItem('mdbook-theme');
|
||||||
|
var sidebar = localStorage.getItem('mdbook-sidebar');
|
||||||
|
|
||||||
|
if (theme.startsWith('"') && theme.endsWith('"')) {
|
||||||
|
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
||||||
|
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
||||||
|
}
|
||||||
|
} catch (e) { }
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Set the theme before any content is loaded, prevents flash -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var theme;
|
||||||
|
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||||||
|
if (theme === null || theme === undefined) { theme = default_theme; }
|
||||||
|
var html = document.querySelector('html');
|
||||||
|
html.classList.remove('no-js')
|
||||||
|
html.classList.remove('light')
|
||||||
|
html.classList.add(theme);
|
||||||
|
html.classList.add('js');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Hide / unhide sidebar before it is displayed -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var html = document.querySelector('html');
|
||||||
|
var sidebar = 'hidden';
|
||||||
|
if (document.body.clientWidth >= 1080) {
|
||||||
|
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
||||||
|
sidebar = sidebar || 'visible';
|
||||||
|
}
|
||||||
|
html.classList.remove('sidebar-visible');
|
||||||
|
html.classList.add("sidebar-" + sidebar);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||||
|
<div class="sidebar-scrollbox">
|
||||||
|
<ol class="chapter"><li class="chapter-item expanded affix "><a href="intro.html">Introduction</a></li><li class="chapter-item expanded "><a href="installing.html"><strong aria-hidden="true">1.</strong> Installing</a></li><li class="chapter-item expanded "><a href="usage.html"><strong aria-hidden="true">2.</strong> Usage</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="usage_custom_pages.html"><strong aria-hidden="true">2.1.</strong> Custom Pages and Patches</a></li></ol></li><li class="chapter-item expanded "><a href="config.html"><strong aria-hidden="true">3.</strong> Configuration</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="config_display.html"><strong aria-hidden="true">3.1.</strong> Section: [display]</a></li><li class="chapter-item expanded "><a href="config_style.html"><strong aria-hidden="true">3.2.</strong> Section: [style]</a></li><li class="chapter-item expanded "><a href="config_search.html"><strong aria-hidden="true">3.3.</strong> Section: [search]</a></li><li class="chapter-item expanded "><a href="config_updates.html" class="active"><strong aria-hidden="true">3.4.</strong> Section: [updates]</a></li><li class="chapter-item expanded "><a href="config_directories.html"><strong aria-hidden="true">3.5.</strong> Section: [directories]</a></li></ol></li><li class="chapter-item expanded "><a href="tips_and_tricks.html"><strong aria-hidden="true">4.</strong> Tips and Tricks</a></li></ol>
|
||||||
|
</div>
|
||||||
|
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div id="page-wrapper" class="page-wrapper">
|
||||||
|
|
||||||
|
<div class="page">
|
||||||
|
|
||||||
|
<div id="menu-bar-hover-placeholder"></div>
|
||||||
|
<div id="menu-bar" class="menu-bar sticky bordered">
|
||||||
|
<div class="left-buttons">
|
||||||
|
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
||||||
|
<i class="fa fa-bars"></i>
|
||||||
|
</button>
|
||||||
|
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
||||||
|
<i class="fa fa-paint-brush"></i>
|
||||||
|
</button>
|
||||||
|
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
||||||
|
<i class="fa fa-search"></i>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1 class="menu-title">Tealdeer User Manual</h1>
|
||||||
|
|
||||||
|
<div class="right-buttons">
|
||||||
|
|
||||||
|
<a href="print.html" title="Print this book" aria-label="Print this book">
|
||||||
|
<i id="print-button" class="fa fa-print"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="search-wrapper" class="hidden">
|
||||||
|
<form id="searchbar-outer" class="searchbar-outer">
|
||||||
|
<input type="search" name="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||||||
|
</form>
|
||||||
|
<div id="searchresults-outer" class="searchresults-outer hidden">
|
||||||
|
<div id="searchresults-header" class="searchresults-header"></div>
|
||||||
|
<ul id="searchresults">
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
||||||
|
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
||||||
|
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
||||||
|
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div id="content" class="content">
|
||||||
|
<main>
|
||||||
|
<h1><a class="header" href="#section-updates" id="section-updates">Section: [updates]</a></h1>
|
||||||
|
<p>This config section contains settings related to updating the tealdeer cache.</p>
|
||||||
|
<h2><a class="header" href="#automatic-updates" id="automatic-updates">Automatic updates</a></h2>
|
||||||
|
<p>Tealdeer can refresh the cache automatically when it is outdated. This
|
||||||
|
behavior can be configured in the <code>updates</code> section and is disabled by
|
||||||
|
default.</p>
|
||||||
|
<h3><a class="header" href="#auto_update" id="auto_update"><code>auto_update</code></a></h3>
|
||||||
|
<p>Specifies whether the auto-update feature should be enabled (defaults to
|
||||||
|
<code>false</code>).</p>
|
||||||
|
<pre><code class="language-toml">[updates]
|
||||||
|
auto_update = true
|
||||||
|
</code></pre>
|
||||||
|
<h3><a class="header" href="#auto_update_interval_hours" id="auto_update_interval_hours"><code>auto_update_interval_hours</code></a></h3>
|
||||||
|
<p>Duration, since the last cache update, after which the cache will be
|
||||||
|
refreshed (defaults to 720 hours). This parameter is ignored if <code>auto_update</code>
|
||||||
|
is set to <code>false</code>.</p>
|
||||||
|
<pre><code class="language-toml">[updates]
|
||||||
|
auto_update = true
|
||||||
|
auto_update_interval_hours = 24
|
||||||
|
</code></pre>
|
||||||
|
<h2><a class="header" href="#download-configuration" id="download-configuration">Download configuration</a></h2>
|
||||||
|
<h3><a class="header" href="#download_languages" id="download_languages"><code>download_languages</code></a></h3>
|
||||||
|
<p>The list of languages which should be downloaded when updating.
|
||||||
|
If unspecified, the languages listed in the <code>search.languages</code> setting are used.
|
||||||
|
Thus, this setting is the most useful to instruct tealdeer to download pages in additional languages that are not searched by default.
|
||||||
|
Either way, the language used can be overwritten using the <code>--language</code> command line flag.</p>
|
||||||
|
<pre><code class="language-toml">[search]
|
||||||
|
languages = ["de", "en"]
|
||||||
|
|
||||||
|
[updates]
|
||||||
|
# sometimes I like to read the Italian description
|
||||||
|
download_languages = ["de", "en", "it"]
|
||||||
|
</code></pre>
|
||||||
|
<h3><a class="header" href="#archive_source" id="archive_source"><code>archive_source</code></a></h3>
|
||||||
|
<p>URL for the location of the tldr pages archive. By default the pages are
|
||||||
|
fetched from the latest <code>tldr-pages/tldr</code> GitHub release.</p>
|
||||||
|
<pre><code class="language-toml">[updates]
|
||||||
|
archive_source = "https://my-company.example.com/tldr/"
|
||||||
|
</code></pre>
|
||||||
|
<h3><a class="header" href="#tls_backend" id="tls_backend"><code>tls_backend</code></a></h3>
|
||||||
|
<p>Specifies which TLS backend to use. Try changing this setting if you encounter certificate errors.</p>
|
||||||
|
<p>Available options:</p>
|
||||||
|
<ul>
|
||||||
|
<li><code>rustls-with-native-roots</code> - <a href="https://github.com/rustls/rustls">Rustls</a> (a TLS library in Rust) with native roots</li>
|
||||||
|
<li><code>rustls-with-webpki-roots</code> - Rustls with <a href="https://github.com/rustls/webpki">WebPKI</a> roots</li>
|
||||||
|
<li><code>native-tls</code> - Native TLS
|
||||||
|
<ul>
|
||||||
|
<li>SChannel on Windows</li>
|
||||||
|
<li>Secure Transport on macOS</li>
|
||||||
|
<li>OpenSSL on other platforms</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<pre><code class="language-toml">[updates]
|
||||||
|
tls_backend = "native-tls"
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||||
|
<!-- Mobile navigation buttons -->
|
||||||
|
|
||||||
|
<a rel="prev" href="config_search.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||||
|
<i class="fa fa-angle-left"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a rel="next" href="config_directories.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||||
|
<i class="fa fa-angle-right"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
<div style="clear: both"></div>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||||
|
|
||||||
|
<a rel="prev" href="config_search.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||||
|
<i class="fa fa-angle-left"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a rel="next" href="config_directories.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||||
|
<i class="fa fa-angle-right"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
window.playground_copyable = true;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="searcher.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="highlight.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="book.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
||||||
|
<!-- Custom JS scripts -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
495
css/chrome.css
Normal file
|
|
@ -0,0 +1,495 @@
|
||||||
|
/* CSS for UI elements (a.k.a. chrome) */
|
||||||
|
|
||||||
|
@import 'variables.css';
|
||||||
|
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
background: var(--bg);
|
||||||
|
}
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background: var(--scrollbar);
|
||||||
|
}
|
||||||
|
html {
|
||||||
|
scrollbar-color: var(--scrollbar) var(--bg);
|
||||||
|
}
|
||||||
|
#searchresults a,
|
||||||
|
.content a:link,
|
||||||
|
a:visited,
|
||||||
|
a > .hljs {
|
||||||
|
color: var(--links);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Menu Bar */
|
||||||
|
|
||||||
|
#menu-bar,
|
||||||
|
#menu-bar-hover-placeholder {
|
||||||
|
z-index: 101;
|
||||||
|
margin: auto calc(0px - var(--page-padding));
|
||||||
|
}
|
||||||
|
#menu-bar {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
background-color: var(--bg);
|
||||||
|
border-bottom-color: var(--bg);
|
||||||
|
border-bottom-width: 1px;
|
||||||
|
border-bottom-style: solid;
|
||||||
|
}
|
||||||
|
#menu-bar.sticky,
|
||||||
|
.js #menu-bar-hover-placeholder:hover + #menu-bar,
|
||||||
|
.js #menu-bar:hover,
|
||||||
|
.js.sidebar-visible #menu-bar {
|
||||||
|
position: -webkit-sticky;
|
||||||
|
position: sticky;
|
||||||
|
top: 0 !important;
|
||||||
|
}
|
||||||
|
#menu-bar-hover-placeholder {
|
||||||
|
position: sticky;
|
||||||
|
position: -webkit-sticky;
|
||||||
|
top: 0;
|
||||||
|
height: var(--menu-bar-height);
|
||||||
|
}
|
||||||
|
#menu-bar.bordered {
|
||||||
|
border-bottom-color: var(--table-border-color);
|
||||||
|
}
|
||||||
|
#menu-bar i, #menu-bar .icon-button {
|
||||||
|
position: relative;
|
||||||
|
padding: 0 8px;
|
||||||
|
z-index: 10;
|
||||||
|
line-height: var(--menu-bar-height);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: color 0.5s;
|
||||||
|
}
|
||||||
|
@media only screen and (max-width: 420px) {
|
||||||
|
#menu-bar i, #menu-bar .icon-button {
|
||||||
|
padding: 0 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-button {
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
padding: 0;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
.icon-button i {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-buttons {
|
||||||
|
margin: 0 15px;
|
||||||
|
}
|
||||||
|
.right-buttons a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left-buttons {
|
||||||
|
display: flex;
|
||||||
|
margin: 0 5px;
|
||||||
|
}
|
||||||
|
.no-js .left-buttons {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-title {
|
||||||
|
display: inline-block;
|
||||||
|
font-weight: 200;
|
||||||
|
font-size: 2rem;
|
||||||
|
line-height: var(--menu-bar-height);
|
||||||
|
text-align: center;
|
||||||
|
margin: 0;
|
||||||
|
flex: 1;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
.js .menu-title {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-bar,
|
||||||
|
.menu-bar:visited,
|
||||||
|
.nav-chapters,
|
||||||
|
.nav-chapters:visited,
|
||||||
|
.mobile-nav-chapters,
|
||||||
|
.mobile-nav-chapters:visited,
|
||||||
|
.menu-bar .icon-button,
|
||||||
|
.menu-bar a i {
|
||||||
|
color: var(--icons);
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-bar i:hover,
|
||||||
|
.menu-bar .icon-button:hover,
|
||||||
|
.nav-chapters:hover,
|
||||||
|
.mobile-nav-chapters i:hover {
|
||||||
|
color: var(--icons-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Nav Icons */
|
||||||
|
|
||||||
|
.nav-chapters {
|
||||||
|
font-size: 2.5em;
|
||||||
|
text-align: center;
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
margin: 0;
|
||||||
|
max-width: 150px;
|
||||||
|
min-width: 90px;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
transition: color 0.5s, background-color 0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-chapters:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
background-color: var(--theme-hover);
|
||||||
|
transition: background-color 0.15s, color 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-wrapper {
|
||||||
|
margin-top: 50px;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-nav-chapters {
|
||||||
|
font-size: 2.5em;
|
||||||
|
text-align: center;
|
||||||
|
text-decoration: none;
|
||||||
|
width: 90px;
|
||||||
|
border-radius: 5px;
|
||||||
|
background-color: var(--sidebar-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.previous {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.next {
|
||||||
|
float: right;
|
||||||
|
right: var(--page-padding);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 1080px) {
|
||||||
|
.nav-wide-wrapper { display: none; }
|
||||||
|
.nav-wrapper { display: block; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 1380px) {
|
||||||
|
.sidebar-visible .nav-wide-wrapper { display: none; }
|
||||||
|
.sidebar-visible .nav-wrapper { display: block; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Inline code */
|
||||||
|
|
||||||
|
:not(pre) > .hljs {
|
||||||
|
display: inline;
|
||||||
|
padding: 0.1em 0.3em;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:not(pre):not(a) > .hljs {
|
||||||
|
color: var(--inline-code-color);
|
||||||
|
overflow-x: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover > .hljs {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
pre > .buttons {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 100;
|
||||||
|
right: 5px;
|
||||||
|
top: 5px;
|
||||||
|
|
||||||
|
color: var(--sidebar-fg);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
pre > .buttons :hover {
|
||||||
|
color: var(--sidebar-active);
|
||||||
|
}
|
||||||
|
pre > .buttons i {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
pre > .buttons button {
|
||||||
|
color: inherit;
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
cursor: inherit;
|
||||||
|
}
|
||||||
|
pre > .result {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search */
|
||||||
|
|
||||||
|
#searchresults a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
mark {
|
||||||
|
border-radius: 2px;
|
||||||
|
padding: 0 3px 1px 3px;
|
||||||
|
margin: 0 -3px -1px -3px;
|
||||||
|
background-color: var(--search-mark-bg);
|
||||||
|
transition: background-color 300ms linear;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
mark.fade-out {
|
||||||
|
background-color: rgba(0,0,0,0) !important;
|
||||||
|
cursor: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.searchbar-outer {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
max-width: var(--content-max-width);
|
||||||
|
}
|
||||||
|
|
||||||
|
#searchbar {
|
||||||
|
width: 100%;
|
||||||
|
margin: 5px auto 0px auto;
|
||||||
|
padding: 10px 16px;
|
||||||
|
transition: box-shadow 300ms ease-in-out;
|
||||||
|
border: 1px solid var(--searchbar-border-color);
|
||||||
|
border-radius: 3px;
|
||||||
|
background-color: var(--searchbar-bg);
|
||||||
|
color: var(--searchbar-fg);
|
||||||
|
}
|
||||||
|
#searchbar:focus,
|
||||||
|
#searchbar.active {
|
||||||
|
box-shadow: 0 0 3px var(--searchbar-shadow-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.searchresults-header {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 1em;
|
||||||
|
padding: 18px 0 0 5px;
|
||||||
|
color: var(--searchresults-header-fg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.searchresults-outer {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
max-width: var(--content-max-width);
|
||||||
|
border-bottom: 1px dashed var(--searchresults-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
ul#searchresults {
|
||||||
|
list-style: none;
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
ul#searchresults li {
|
||||||
|
margin: 10px 0px;
|
||||||
|
padding: 2px;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
ul#searchresults li.focus {
|
||||||
|
background-color: var(--searchresults-li-bg);
|
||||||
|
}
|
||||||
|
ul#searchresults span.teaser {
|
||||||
|
display: block;
|
||||||
|
clear: both;
|
||||||
|
margin: 5px 0 0 20px;
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
ul#searchresults span.teaser em {
|
||||||
|
font-weight: bold;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sidebar */
|
||||||
|
|
||||||
|
.sidebar {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: var(--sidebar-width);
|
||||||
|
font-size: 0.875em;
|
||||||
|
box-sizing: border-box;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
overscroll-behavior-y: contain;
|
||||||
|
background-color: var(--sidebar-bg);
|
||||||
|
color: var(--sidebar-fg);
|
||||||
|
}
|
||||||
|
.sidebar-resizing {
|
||||||
|
-moz-user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
.js:not(.sidebar-resizing) .sidebar {
|
||||||
|
transition: transform 0.3s; /* Animation: slide away */
|
||||||
|
}
|
||||||
|
.sidebar code {
|
||||||
|
line-height: 2em;
|
||||||
|
}
|
||||||
|
.sidebar .sidebar-scrollbox {
|
||||||
|
overflow-y: auto;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
padding: 10px 10px;
|
||||||
|
}
|
||||||
|
.sidebar .sidebar-resize-handle {
|
||||||
|
position: absolute;
|
||||||
|
cursor: col-resize;
|
||||||
|
width: 0;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
.js .sidebar .sidebar-resize-handle {
|
||||||
|
cursor: col-resize;
|
||||||
|
width: 5px;
|
||||||
|
}
|
||||||
|
.sidebar-hidden .sidebar {
|
||||||
|
transform: translateX(calc(0px - var(--sidebar-width)));
|
||||||
|
}
|
||||||
|
.sidebar::-webkit-scrollbar {
|
||||||
|
background: var(--sidebar-bg);
|
||||||
|
}
|
||||||
|
.sidebar::-webkit-scrollbar-thumb {
|
||||||
|
background: var(--scrollbar);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-visible .page-wrapper {
|
||||||
|
transform: translateX(var(--sidebar-width));
|
||||||
|
}
|
||||||
|
@media only screen and (min-width: 620px) {
|
||||||
|
.sidebar-visible .page-wrapper {
|
||||||
|
transform: none;
|
||||||
|
margin-left: var(--sidebar-width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.chapter {
|
||||||
|
list-style: none outside none;
|
||||||
|
padding-left: 0;
|
||||||
|
line-height: 2.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chapter ol {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chapter li {
|
||||||
|
display: flex;
|
||||||
|
color: var(--sidebar-non-existant);
|
||||||
|
}
|
||||||
|
.chapter li a {
|
||||||
|
display: block;
|
||||||
|
padding: 0;
|
||||||
|
text-decoration: none;
|
||||||
|
color: var(--sidebar-fg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chapter li a:hover {
|
||||||
|
color: var(--sidebar-active);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chapter li a.active {
|
||||||
|
color: var(--sidebar-active);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chapter li > a.toggle {
|
||||||
|
cursor: pointer;
|
||||||
|
display: block;
|
||||||
|
margin-left: auto;
|
||||||
|
padding: 0 10px;
|
||||||
|
user-select: none;
|
||||||
|
opacity: 0.68;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chapter li > a.toggle div {
|
||||||
|
transition: transform 0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* collapse the section */
|
||||||
|
.chapter li:not(.expanded) + li > ol {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chapter li.chapter-item {
|
||||||
|
line-height: 1.5em;
|
||||||
|
margin-top: 0.6em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chapter li.expanded > a.toggle div {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.spacer {
|
||||||
|
width: 100%;
|
||||||
|
height: 3px;
|
||||||
|
margin: 5px 0px;
|
||||||
|
}
|
||||||
|
.chapter .spacer {
|
||||||
|
background-color: var(--sidebar-spacer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (-moz-touch-enabled: 1), (pointer: coarse) {
|
||||||
|
.chapter li a { padding: 5px 0; }
|
||||||
|
.spacer { margin: 10px 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.section {
|
||||||
|
list-style: none outside none;
|
||||||
|
padding-left: 20px;
|
||||||
|
line-height: 1.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Theme Menu Popup */
|
||||||
|
|
||||||
|
.theme-popup {
|
||||||
|
position: absolute;
|
||||||
|
left: 10px;
|
||||||
|
top: var(--menu-bar-height);
|
||||||
|
z-index: 1000;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 0.7em;
|
||||||
|
color: var(--fg);
|
||||||
|
background: var(--theme-popup-bg);
|
||||||
|
border: 1px solid var(--theme-popup-border);
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
list-style: none;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.theme-popup .default {
|
||||||
|
color: var(--icons);
|
||||||
|
}
|
||||||
|
.theme-popup .theme {
|
||||||
|
width: 100%;
|
||||||
|
border: 0;
|
||||||
|
margin: 0;
|
||||||
|
padding: 2px 10px;
|
||||||
|
line-height: 25px;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-align: left;
|
||||||
|
cursor: pointer;
|
||||||
|
color: inherit;
|
||||||
|
background: inherit;
|
||||||
|
font-size: inherit;
|
||||||
|
}
|
||||||
|
.theme-popup .theme:hover {
|
||||||
|
background-color: var(--theme-hover);
|
||||||
|
}
|
||||||
|
.theme-popup .theme:hover:first-child,
|
||||||
|
.theme-popup .theme:hover:last-child {
|
||||||
|
border-top-left-radius: inherit;
|
||||||
|
border-top-right-radius: inherit;
|
||||||
|
}
|
||||||
174
css/general.css
Normal file
|
|
@ -0,0 +1,174 @@
|
||||||
|
/* Base styles and content styles */
|
||||||
|
|
||||||
|
@import 'variables.css';
|
||||||
|
|
||||||
|
:root {
|
||||||
|
/* Browser default font-size is 16px, this way 1 rem = 10px */
|
||||||
|
font-size: 62.5%;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
font-family: "Open Sans", sans-serif;
|
||||||
|
color: var(--fg);
|
||||||
|
background-color: var(--bg);
|
||||||
|
text-size-adjust: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1.6rem;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
font-family: "Source Code Pro", Consolas, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", monospace, monospace !important;
|
||||||
|
font-size: 0.875em; /* please adjust the ace font size accordingly in editor.js */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Don't change font size in headers. */
|
||||||
|
h1 code, h2 code, h3 code, h4 code, h5 code, h6 code {
|
||||||
|
font-size: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left { float: left; }
|
||||||
|
.right { float: right; }
|
||||||
|
.boring { opacity: 0.6; }
|
||||||
|
.hide-boring .boring { display: none; }
|
||||||
|
.hidden { display: none !important; }
|
||||||
|
|
||||||
|
h2, h3 { margin-top: 2.5em; }
|
||||||
|
h4, h5 { margin-top: 2em; }
|
||||||
|
|
||||||
|
.header + .header h3,
|
||||||
|
.header + .header h4,
|
||||||
|
.header + .header h5 {
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 a.header:target::before,
|
||||||
|
h2 a.header:target::before,
|
||||||
|
h3 a.header:target::before,
|
||||||
|
h4 a.header:target::before {
|
||||||
|
display: inline-block;
|
||||||
|
content: "»";
|
||||||
|
margin-left: -30px;
|
||||||
|
width: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 a.header:target,
|
||||||
|
h2 a.header:target,
|
||||||
|
h3 a.header:target,
|
||||||
|
h4 a.header:target {
|
||||||
|
scroll-margin-top: calc(var(--menu-bar-height) + 0.5em);
|
||||||
|
}
|
||||||
|
|
||||||
|
.page {
|
||||||
|
outline: 0;
|
||||||
|
padding: 0 var(--page-padding);
|
||||||
|
margin-top: calc(0px - var(--menu-bar-height)); /* Compensate for the #menu-bar-hover-placeholder */
|
||||||
|
}
|
||||||
|
.page-wrapper {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.js:not(.sidebar-resizing) .page-wrapper {
|
||||||
|
transition: margin-left 0.3s ease, transform 0.3s ease; /* Animation: slide away */
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 0 15px;
|
||||||
|
padding-bottom: 50px;
|
||||||
|
}
|
||||||
|
.content main {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
max-width: var(--content-max-width);
|
||||||
|
}
|
||||||
|
.content p { line-height: 1.45em; }
|
||||||
|
.content ol { line-height: 1.45em; }
|
||||||
|
.content ul { line-height: 1.45em; }
|
||||||
|
.content a { text-decoration: none; }
|
||||||
|
.content a:hover { text-decoration: underline; }
|
||||||
|
.content img { max-width: 100%; }
|
||||||
|
.content .header:link,
|
||||||
|
.content .header:visited {
|
||||||
|
color: var(--fg);
|
||||||
|
}
|
||||||
|
.content .header:link,
|
||||||
|
.content .header:visited:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
margin: 0 auto;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
table td {
|
||||||
|
padding: 3px 20px;
|
||||||
|
border: 1px var(--table-border-color) solid;
|
||||||
|
}
|
||||||
|
table thead {
|
||||||
|
background: var(--table-header-bg);
|
||||||
|
}
|
||||||
|
table thead td {
|
||||||
|
font-weight: 700;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
table thead th {
|
||||||
|
padding: 3px 20px;
|
||||||
|
}
|
||||||
|
table thead tr {
|
||||||
|
border: 1px var(--table-header-bg) solid;
|
||||||
|
}
|
||||||
|
/* Alternate background colors for rows */
|
||||||
|
table tbody tr:nth-child(2n) {
|
||||||
|
background: var(--table-alternate-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
margin: 20px 0;
|
||||||
|
padding: 0 20px;
|
||||||
|
color: var(--fg);
|
||||||
|
background-color: var(--quote-bg);
|
||||||
|
border-top: .1em solid var(--quote-border);
|
||||||
|
border-bottom: .1em solid var(--quote-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
:not(.footnote-definition) + .footnote-definition,
|
||||||
|
.footnote-definition + :not(.footnote-definition) {
|
||||||
|
margin-top: 2em;
|
||||||
|
}
|
||||||
|
.footnote-definition {
|
||||||
|
font-size: 0.9em;
|
||||||
|
margin: 0.5em 0;
|
||||||
|
}
|
||||||
|
.footnote-definition p {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltiptext {
|
||||||
|
position: absolute;
|
||||||
|
visibility: hidden;
|
||||||
|
color: #fff;
|
||||||
|
background-color: #333;
|
||||||
|
transform: translateX(-50%); /* Center by moving tooltip 50% of its width left */
|
||||||
|
left: -8px; /* Half of the width of the icon */
|
||||||
|
top: -35px;
|
||||||
|
font-size: 0.8em;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 5px 8px;
|
||||||
|
margin: 5px;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
.tooltipped .tooltiptext {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chapter li.part-title {
|
||||||
|
color: var(--sidebar-fg);
|
||||||
|
margin: 5px 0px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
54
css/print.css
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
|
||||||
|
#sidebar,
|
||||||
|
#menu-bar,
|
||||||
|
.nav-chapters,
|
||||||
|
.mobile-nav-chapters {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#page-wrapper.page-wrapper {
|
||||||
|
transform: none;
|
||||||
|
margin-left: 0px;
|
||||||
|
overflow-y: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
#content {
|
||||||
|
max-width: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page {
|
||||||
|
overflow-y: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
background-color: #666666;
|
||||||
|
border-radius: 5px;
|
||||||
|
|
||||||
|
/* Force background to be printed in Chrome */
|
||||||
|
-webkit-print-color-adjust: exact;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre > .buttons {
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
a, a:visited, a:active, a:hover {
|
||||||
|
color: #4183c4;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
page-break-inside: avoid;
|
||||||
|
page-break-after: avoid;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre, code {
|
||||||
|
page-break-inside: avoid;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
253
css/variables.css
Normal file
|
|
@ -0,0 +1,253 @@
|
||||||
|
|
||||||
|
/* Globals */
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--sidebar-width: 300px;
|
||||||
|
--page-padding: 15px;
|
||||||
|
--content-max-width: 750px;
|
||||||
|
--menu-bar-height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Themes */
|
||||||
|
|
||||||
|
.ayu {
|
||||||
|
--bg: hsl(210, 25%, 8%);
|
||||||
|
--fg: #c5c5c5;
|
||||||
|
|
||||||
|
--sidebar-bg: #14191f;
|
||||||
|
--sidebar-fg: #c8c9db;
|
||||||
|
--sidebar-non-existant: #5c6773;
|
||||||
|
--sidebar-active: #ffb454;
|
||||||
|
--sidebar-spacer: #2d334f;
|
||||||
|
|
||||||
|
--scrollbar: var(--sidebar-fg);
|
||||||
|
|
||||||
|
--icons: #737480;
|
||||||
|
--icons-hover: #b7b9cc;
|
||||||
|
|
||||||
|
--links: #0096cf;
|
||||||
|
|
||||||
|
--inline-code-color: #ffb454;
|
||||||
|
|
||||||
|
--theme-popup-bg: #14191f;
|
||||||
|
--theme-popup-border: #5c6773;
|
||||||
|
--theme-hover: #191f26;
|
||||||
|
|
||||||
|
--quote-bg: hsl(226, 15%, 17%);
|
||||||
|
--quote-border: hsl(226, 15%, 22%);
|
||||||
|
|
||||||
|
--table-border-color: hsl(210, 25%, 13%);
|
||||||
|
--table-header-bg: hsl(210, 25%, 28%);
|
||||||
|
--table-alternate-bg: hsl(210, 25%, 11%);
|
||||||
|
|
||||||
|
--searchbar-border-color: #848484;
|
||||||
|
--searchbar-bg: #424242;
|
||||||
|
--searchbar-fg: #fff;
|
||||||
|
--searchbar-shadow-color: #d4c89f;
|
||||||
|
--searchresults-header-fg: #666;
|
||||||
|
--searchresults-border-color: #888;
|
||||||
|
--searchresults-li-bg: #252932;
|
||||||
|
--search-mark-bg: #e3b171;
|
||||||
|
}
|
||||||
|
|
||||||
|
.coal {
|
||||||
|
--bg: hsl(200, 7%, 8%);
|
||||||
|
--fg: #98a3ad;
|
||||||
|
|
||||||
|
--sidebar-bg: #292c2f;
|
||||||
|
--sidebar-fg: #a1adb8;
|
||||||
|
--sidebar-non-existant: #505254;
|
||||||
|
--sidebar-active: #3473ad;
|
||||||
|
--sidebar-spacer: #393939;
|
||||||
|
|
||||||
|
--scrollbar: var(--sidebar-fg);
|
||||||
|
|
||||||
|
--icons: #43484d;
|
||||||
|
--icons-hover: #b3c0cc;
|
||||||
|
|
||||||
|
--links: #2b79a2;
|
||||||
|
|
||||||
|
--inline-code-color: #c5c8c6;;
|
||||||
|
|
||||||
|
--theme-popup-bg: #141617;
|
||||||
|
--theme-popup-border: #43484d;
|
||||||
|
--theme-hover: #1f2124;
|
||||||
|
|
||||||
|
--quote-bg: hsl(234, 21%, 18%);
|
||||||
|
--quote-border: hsl(234, 21%, 23%);
|
||||||
|
|
||||||
|
--table-border-color: hsl(200, 7%, 13%);
|
||||||
|
--table-header-bg: hsl(200, 7%, 28%);
|
||||||
|
--table-alternate-bg: hsl(200, 7%, 11%);
|
||||||
|
|
||||||
|
--searchbar-border-color: #aaa;
|
||||||
|
--searchbar-bg: #b7b7b7;
|
||||||
|
--searchbar-fg: #000;
|
||||||
|
--searchbar-shadow-color: #aaa;
|
||||||
|
--searchresults-header-fg: #666;
|
||||||
|
--searchresults-border-color: #98a3ad;
|
||||||
|
--searchresults-li-bg: #2b2b2f;
|
||||||
|
--search-mark-bg: #355c7d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.light {
|
||||||
|
--bg: hsl(0, 0%, 100%);
|
||||||
|
--fg: #333333;
|
||||||
|
|
||||||
|
--sidebar-bg: #fafafa;
|
||||||
|
--sidebar-fg: #364149;
|
||||||
|
--sidebar-non-existant: #aaaaaa;
|
||||||
|
--sidebar-active: #008cff;
|
||||||
|
--sidebar-spacer: #f4f4f4;
|
||||||
|
|
||||||
|
--scrollbar: #cccccc;
|
||||||
|
|
||||||
|
--icons: #cccccc;
|
||||||
|
--icons-hover: #333333;
|
||||||
|
|
||||||
|
--links: #4183c4;
|
||||||
|
|
||||||
|
--inline-code-color: #6e6b5e;
|
||||||
|
|
||||||
|
--theme-popup-bg: #fafafa;
|
||||||
|
--theme-popup-border: #cccccc;
|
||||||
|
--theme-hover: #e6e6e6;
|
||||||
|
|
||||||
|
--quote-bg: hsl(197, 37%, 96%);
|
||||||
|
--quote-border: hsl(197, 37%, 91%);
|
||||||
|
|
||||||
|
--table-border-color: hsl(0, 0%, 95%);
|
||||||
|
--table-header-bg: hsl(0, 0%, 80%);
|
||||||
|
--table-alternate-bg: hsl(0, 0%, 97%);
|
||||||
|
|
||||||
|
--searchbar-border-color: #aaa;
|
||||||
|
--searchbar-bg: #fafafa;
|
||||||
|
--searchbar-fg: #000;
|
||||||
|
--searchbar-shadow-color: #aaa;
|
||||||
|
--searchresults-header-fg: #666;
|
||||||
|
--searchresults-border-color: #888;
|
||||||
|
--searchresults-li-bg: #e4f2fe;
|
||||||
|
--search-mark-bg: #a2cff5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navy {
|
||||||
|
--bg: hsl(226, 23%, 11%);
|
||||||
|
--fg: #bcbdd0;
|
||||||
|
|
||||||
|
--sidebar-bg: #282d3f;
|
||||||
|
--sidebar-fg: #c8c9db;
|
||||||
|
--sidebar-non-existant: #505274;
|
||||||
|
--sidebar-active: #2b79a2;
|
||||||
|
--sidebar-spacer: #2d334f;
|
||||||
|
|
||||||
|
--scrollbar: var(--sidebar-fg);
|
||||||
|
|
||||||
|
--icons: #737480;
|
||||||
|
--icons-hover: #b7b9cc;
|
||||||
|
|
||||||
|
--links: #2b79a2;
|
||||||
|
|
||||||
|
--inline-code-color: #c5c8c6;;
|
||||||
|
|
||||||
|
--theme-popup-bg: #161923;
|
||||||
|
--theme-popup-border: #737480;
|
||||||
|
--theme-hover: #282e40;
|
||||||
|
|
||||||
|
--quote-bg: hsl(226, 15%, 17%);
|
||||||
|
--quote-border: hsl(226, 15%, 22%);
|
||||||
|
|
||||||
|
--table-border-color: hsl(226, 23%, 16%);
|
||||||
|
--table-header-bg: hsl(226, 23%, 31%);
|
||||||
|
--table-alternate-bg: hsl(226, 23%, 14%);
|
||||||
|
|
||||||
|
--searchbar-border-color: #aaa;
|
||||||
|
--searchbar-bg: #aeaec6;
|
||||||
|
--searchbar-fg: #000;
|
||||||
|
--searchbar-shadow-color: #aaa;
|
||||||
|
--searchresults-header-fg: #5f5f71;
|
||||||
|
--searchresults-border-color: #5c5c68;
|
||||||
|
--searchresults-li-bg: #242430;
|
||||||
|
--search-mark-bg: #a2cff5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rust {
|
||||||
|
--bg: hsl(60, 9%, 87%);
|
||||||
|
--fg: #262625;
|
||||||
|
|
||||||
|
--sidebar-bg: #3b2e2a;
|
||||||
|
--sidebar-fg: #c8c9db;
|
||||||
|
--sidebar-non-existant: #505254;
|
||||||
|
--sidebar-active: #e69f67;
|
||||||
|
--sidebar-spacer: #45373a;
|
||||||
|
|
||||||
|
--scrollbar: var(--sidebar-fg);
|
||||||
|
|
||||||
|
--icons: #737480;
|
||||||
|
--icons-hover: #262625;
|
||||||
|
|
||||||
|
--links: #2b79a2;
|
||||||
|
|
||||||
|
--inline-code-color: #6e6b5e;
|
||||||
|
|
||||||
|
--theme-popup-bg: #e1e1db;
|
||||||
|
--theme-popup-border: #b38f6b;
|
||||||
|
--theme-hover: #99908a;
|
||||||
|
|
||||||
|
--quote-bg: hsl(60, 5%, 75%);
|
||||||
|
--quote-border: hsl(60, 5%, 70%);
|
||||||
|
|
||||||
|
--table-border-color: hsl(60, 9%, 82%);
|
||||||
|
--table-header-bg: #b3a497;
|
||||||
|
--table-alternate-bg: hsl(60, 9%, 84%);
|
||||||
|
|
||||||
|
--searchbar-border-color: #aaa;
|
||||||
|
--searchbar-bg: #fafafa;
|
||||||
|
--searchbar-fg: #000;
|
||||||
|
--searchbar-shadow-color: #aaa;
|
||||||
|
--searchresults-header-fg: #666;
|
||||||
|
--searchresults-border-color: #888;
|
||||||
|
--searchresults-li-bg: #dec2a2;
|
||||||
|
--search-mark-bg: #e69f67;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
.light.no-js {
|
||||||
|
--bg: hsl(200, 7%, 8%);
|
||||||
|
--fg: #98a3ad;
|
||||||
|
|
||||||
|
--sidebar-bg: #292c2f;
|
||||||
|
--sidebar-fg: #a1adb8;
|
||||||
|
--sidebar-non-existant: #505254;
|
||||||
|
--sidebar-active: #3473ad;
|
||||||
|
--sidebar-spacer: #393939;
|
||||||
|
|
||||||
|
--scrollbar: var(--sidebar-fg);
|
||||||
|
|
||||||
|
--icons: #43484d;
|
||||||
|
--icons-hover: #b3c0cc;
|
||||||
|
|
||||||
|
--links: #2b79a2;
|
||||||
|
|
||||||
|
--inline-code-color: #c5c8c6;;
|
||||||
|
|
||||||
|
--theme-popup-bg: #141617;
|
||||||
|
--theme-popup-border: #43484d;
|
||||||
|
--theme-hover: #1f2124;
|
||||||
|
|
||||||
|
--quote-bg: hsl(234, 21%, 18%);
|
||||||
|
--quote-border: hsl(234, 21%, 23%);
|
||||||
|
|
||||||
|
--table-border-color: hsl(200, 7%, 13%);
|
||||||
|
--table-header-bg: hsl(200, 7%, 28%);
|
||||||
|
--table-alternate-bg: hsl(200, 7%, 11%);
|
||||||
|
|
||||||
|
--searchbar-border-color: #aaa;
|
||||||
|
--searchbar-bg: #b7b7b7;
|
||||||
|
--searchbar-fg: #000;
|
||||||
|
--searchbar-shadow-color: #aaa;
|
||||||
|
--searchresults-header-fg: #666;
|
||||||
|
--searchresults-border-color: #98a3ad;
|
||||||
|
--searchresults-li-bg: #2b2b2f;
|
||||||
|
--search-mark-bg: #355c7d;
|
||||||
|
}
|
||||||
|
}
|
||||||
1
docs/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
||||||
book
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
# Tealdeer Docs
|
|
||||||
|
|
||||||
To build the docs, install [mdbook](https://github.com/rust-lang/mdBook).
|
|
||||||
|
|
||||||
You can build the HTML with `mdbook build`.
|
|
||||||
|
|
||||||
To serve the docs on `localhost:3000` and watch for changes, use `mdbook
|
|
||||||
serve`.
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
[book]
|
|
||||||
authors = ["Danilo Bargen"]
|
|
||||||
language = "en"
|
|
||||||
multilingual = false
|
|
||||||
src = "src"
|
|
||||||
title = "Tealdeer User Manual"
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
# Summary
|
|
||||||
|
|
||||||
[Introduction](./intro.md)
|
|
||||||
|
|
||||||
- [Installing](./installing.md)
|
|
||||||
- [Usage](./usage.md)
|
|
||||||
- [Custom Pages and Patches](./usage_custom_pages.md)
|
|
||||||
- [Configuration](./config.md)
|
|
||||||
- [Section: \[display\]](./config_display.md)
|
|
||||||
- [Section: \[style\]](./config_style.md)
|
|
||||||
- [Section: \[search\]](./config_search.md)
|
|
||||||
- [Section: \[updates\]](./config_updates.md)
|
|
||||||
- [Section: \[directories\]](./config_directories.md)
|
|
||||||
- [Tips and Tricks](./tips_and_tricks.md)
|
|
||||||
|
|
@ -1,59 +0,0 @@
|
||||||
# Configuration
|
|
||||||
|
|
||||||
Tealdeer can be customized with a config file in [TOML
|
|
||||||
format](https://toml.io/) called `config.toml`.
|
|
||||||
|
|
||||||
## Configfile Path
|
|
||||||
|
|
||||||
The configuration file path follows OS conventions (e.g.
|
|
||||||
`$XDG_CONFIG_HOME/tealdeer/config.toml` on Linux). The paths can be queried
|
|
||||||
with the following command:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ tldr --show-paths
|
|
||||||
```
|
|
||||||
|
|
||||||
Creating the config file can be done manually or with the help of `tldr`:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ tldr --seed-config
|
|
||||||
```
|
|
||||||
|
|
||||||
On Linux, this will usually be `~/.config/tealdeer/config.toml`.
|
|
||||||
|
|
||||||
## Config Example
|
|
||||||
|
|
||||||
Here's an example configuration file. Note that this example does not contain
|
|
||||||
all possible config options. For details on the things that can be configured,
|
|
||||||
please refer to the subsections of this documentation page
|
|
||||||
([display](config_display.html), [style](config_style.html), [search](config_search.html),
|
|
||||||
[updates](config_updates.html) or [directories](config_directories.html)).
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[display]
|
|
||||||
compact = false
|
|
||||||
use_pager = true
|
|
||||||
show_title = false
|
|
||||||
|
|
||||||
[style.command_name]
|
|
||||||
foreground = "red"
|
|
||||||
|
|
||||||
[style.example_text]
|
|
||||||
foreground = "green"
|
|
||||||
|
|
||||||
[style.example_code]
|
|
||||||
foreground = "blue"
|
|
||||||
|
|
||||||
[style.example_variable]
|
|
||||||
foreground = "blue"
|
|
||||||
underline = true
|
|
||||||
|
|
||||||
[updates]
|
|
||||||
auto_update = true
|
|
||||||
```
|
|
||||||
|
|
||||||
## Override Config Directory
|
|
||||||
|
|
||||||
The directory where the configuration file resides may be overwritten by the
|
|
||||||
environment variable `TEALDEER_CONFIG_DIR`. Remember to use an absolute path.
|
|
||||||
Variable expansion will not be performed on the path.
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
# Section: \[directories\]
|
|
||||||
|
|
||||||
This section allows overriding some directory paths.
|
|
||||||
|
|
||||||
## `cache_dir`
|
|
||||||
|
|
||||||
Override the cache directory. Remember to use an absolute path. Variable
|
|
||||||
expansion will not be performed on the path. If the directory does not yet
|
|
||||||
exist, it will be created.
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[directories]
|
|
||||||
cache_dir = "/home/myuser/.tealdeer-cache/"
|
|
||||||
```
|
|
||||||
|
|
||||||
If no `cache_dir` is specified, tealdeer will fall back to a location that
|
|
||||||
follows OS conventions. On Linux, it will usually be at `~/.cache/tealdeer/`.
|
|
||||||
Use `tldr --show-paths` to show the path that is being used.
|
|
||||||
|
|
||||||
## `custom_pages_dir`
|
|
||||||
|
|
||||||
Set the directory to be used to look up [custom
|
|
||||||
pages](usage_custom_pages.html). Remember to use an absolute path. Variable
|
|
||||||
expansion will not be performed on the path.
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[directories]
|
|
||||||
custom_pages_dir = "/home/myuser/custom-tldr-pages/"
|
|
||||||
```
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
# Section: \[display\]
|
|
||||||
|
|
||||||
In the `display` section you can configure the output format.
|
|
||||||
|
|
||||||
## `use_pager`
|
|
||||||
|
|
||||||
Specifies whether the pager should be used by default or not (default `false`).
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[display]
|
|
||||||
use_pager = true
|
|
||||||
```
|
|
||||||
|
|
||||||
When enabled, `less -R` is used as pager. To override the pager command used,
|
|
||||||
set the `PAGER` environment variable.
|
|
||||||
|
|
||||||
NOTE: This feature is not available on Windows.
|
|
||||||
|
|
||||||
## `compact`
|
|
||||||
|
|
||||||
Set this to enforce more compact output, where empty lines are stripped out
|
|
||||||
(default `false`).
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[display]
|
|
||||||
compact = true
|
|
||||||
```
|
|
||||||
|
|
||||||
## `show_title`
|
|
||||||
|
|
||||||
Display the command name at the top of the page output (default `false`).
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[display]
|
|
||||||
show_title = true
|
|
||||||
```
|
|
||||||
|
|
||||||
When enabled, the command name will be displayed at the top of the output,
|
|
||||||
styled with the `command_name` style configuration.
|
|
||||||
|
|
||||||
## `indent`
|
|
||||||
|
|
||||||
Controls the indentation of the output via two sub-keys.
|
|
||||||
|
|
||||||
### `indent.base`
|
|
||||||
|
|
||||||
Specifies the number of spaces used to indent descriptions, example text, and titles (default `2`).
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[display.indent]
|
|
||||||
base = 2
|
|
||||||
```
|
|
||||||
|
|
||||||
### `indent.command`
|
|
||||||
|
|
||||||
Specifies the number of spaces used to indent example code lines (default `6`).
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[display.indent]
|
|
||||||
command = 6
|
|
||||||
```
|
|
||||||
|
|
||||||
You can also configure both subkeys in a single line like this:
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[display]
|
|
||||||
indent = {
|
|
||||||
base = 2,
|
|
||||||
command = 6,
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
# Section: \[search\]
|
|
||||||
|
|
||||||
This config section is used to configure the page search in the cache.
|
|
||||||
The settings apply to `tldr <page>` and `tldr --list`.
|
|
||||||
|
|
||||||
## `languages`
|
|
||||||
|
|
||||||
The list of languages that should be considered when searching.
|
|
||||||
If unspecified, the list of languages will be inferred from the `LANG` and `LANGUAGE` environment variables.
|
|
||||||
Either way, the language used can be overwritten using the `--language` command line flag.
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[search]
|
|
||||||
# Show pages in German if available, otherwise show in English
|
|
||||||
languages = ["de", "en"]
|
|
||||||
```
|
|
||||||
|
|
||||||
## `platforms`
|
|
||||||
|
|
||||||
The list of platforms that should be considered when searching.
|
|
||||||
In addition to the platforms listed in the help text of the `--platform` flag, there are two special platforms available:
|
|
||||||
- `"current"`: equals the platform that tealdeer was compiled for
|
|
||||||
- `"all"`: adds all remaining platforms to the list
|
|
||||||
|
|
||||||
Tealdeer searches the platforms in order of appearance in this list.
|
|
||||||
The default list of platforms is `["current", "common", "all"]`.
|
|
||||||
The list of platforms can be overwritten using the `--platform` command line flag.
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[search]
|
|
||||||
# Search for linux and common, and then search windows before trying the remaining platforms
|
|
||||||
platforms = ["linux", "common", "windows", "all"]
|
|
||||||
```
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
# Section: \[style\]
|
|
||||||
|
|
||||||
Using the config file, the style (e.g. colors or underlines) can be customized.
|
|
||||||
|
|
||||||
<img src="screenshot-custom.png" alt="Screenshot of customized version" width="600">
|
|
||||||
|
|
||||||
## Style Targets
|
|
||||||
|
|
||||||
- `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
|
|
||||||
|
|
||||||
## Attributes
|
|
||||||
|
|
||||||
- `foreground` (color string, ANSI code, or RGB, see below)
|
|
||||||
- `background` (color string, ANSI code, or RGB, see below)
|
|
||||||
- `underline` (`true` or `false`)
|
|
||||||
- `bold` (`true` or `false`)
|
|
||||||
- `italic` (`true` or `false`)
|
|
||||||
|
|
||||||
Colors can be specified in one of three ways:
|
|
||||||
|
|
||||||
- Color string (`black`, `red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, `white`):
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```toml
|
|
||||||
foreground = "green"
|
|
||||||
```
|
|
||||||
|
|
||||||
- 256 color ANSI code (*tealdeer v1.5.0+*)
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```toml
|
|
||||||
foreground = { ansi = 4 }
|
|
||||||
```
|
|
||||||
|
|
||||||
- 24-bit RGB color (*tealdeer v1.5.0+*)
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```toml
|
|
||||||
background = { rgb = { r = 255, g = 255, b = 255 } }
|
|
||||||
```
|
|
||||||
|
|
@ -1,91 +0,0 @@
|
||||||
# Section: \[updates\]
|
|
||||||
|
|
||||||
This config section contains settings related to updating the tealdeer cache.
|
|
||||||
|
|
||||||
## Automatic updates
|
|
||||||
|
|
||||||
Tealdeer can refresh the cache automatically when it is outdated. This
|
|
||||||
behavior can be configured in the `updates` section and is disabled by
|
|
||||||
default.
|
|
||||||
|
|
||||||
### `auto_update`
|
|
||||||
|
|
||||||
Specifies whether the auto-update feature should be enabled (defaults to
|
|
||||||
`false`).
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[updates]
|
|
||||||
auto_update = true
|
|
||||||
```
|
|
||||||
|
|
||||||
### `auto_update_interval_hours`
|
|
||||||
|
|
||||||
Duration, since the last cache update, after which the cache will be
|
|
||||||
refreshed (defaults to 720 hours). This parameter is ignored if `auto_update`
|
|
||||||
is set to `false`.
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[updates]
|
|
||||||
auto_update = true
|
|
||||||
auto_update_interval_hours = 24
|
|
||||||
```
|
|
||||||
|
|
||||||
### `warn_cache_age`
|
|
||||||
|
|
||||||
Controls when a warning is printed if the cache has not been updated in a while.
|
|
||||||
By default, the warning is shown once the cache is older than 30 days. Set this
|
|
||||||
to `"never"` to silence the warning. This is useful if, for some reason, the
|
|
||||||
modification time does not reflect its actual age.
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[updates]
|
|
||||||
warn_cache_age = "never"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Download configuration
|
|
||||||
|
|
||||||
### `download_languages`
|
|
||||||
|
|
||||||
The list of languages which should be downloaded when updating.
|
|
||||||
If unspecified, the languages listed in the `search.languages` setting are used.
|
|
||||||
Thus, this setting is the most useful to instruct tealdeer to download pages in additional languages that are not searched by default.
|
|
||||||
Either way, the language used can be overwritten using the `--language` command line flag.
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[search]
|
|
||||||
languages = ["de", "en"]
|
|
||||||
|
|
||||||
[updates]
|
|
||||||
# sometimes I like to read the Italian description
|
|
||||||
download_languages = ["de", "en", "it"]
|
|
||||||
```
|
|
||||||
|
|
||||||
### `archive_source`
|
|
||||||
|
|
||||||
URL for the location of the tldr pages archive. By default the pages are
|
|
||||||
fetched from the latest `tldr-pages/tldr` GitHub release.
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[updates]
|
|
||||||
archive_source = "https://my-company.example.com/tldr/"
|
|
||||||
```
|
|
||||||
|
|
||||||
### `tls_backend`
|
|
||||||
|
|
||||||
Specifies which TLS backend to use. Try changing this setting if you encounter certificate errors.
|
|
||||||
|
|
||||||
Available options:
|
|
||||||
- `rustls-with-native-roots` - [Rustls][rustls] (a TLS library in Rust) with native roots
|
|
||||||
- `rustls-with-webpki-roots` - Rustls with [WebPKI][rustls-webpki] roots
|
|
||||||
- `native-tls` - Native TLS
|
|
||||||
- SChannel on Windows
|
|
||||||
- Secure Transport on macOS
|
|
||||||
- OpenSSL on other platforms
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[updates]
|
|
||||||
tls_backend = "native-tls"
|
|
||||||
```
|
|
||||||
|
|
||||||
[rustls]: https://github.com/rustls/rustls
|
|
||||||
[rustls-webpki]: https://github.com/rustls/webpki
|
|
||||||
|
Before Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 409 KiB |
|
|
@ -1,74 +0,0 @@
|
||||||
# Installing
|
|
||||||
|
|
||||||
There are a few different ways to install tealdeer:
|
|
||||||
|
|
||||||
- Through [package managers](#package-managers)
|
|
||||||
- Through [static binaries](#static-binaries-linux)
|
|
||||||
- Through [cargo install](#through-cargo-install)
|
|
||||||
- By [building from source](#build-from-source)
|
|
||||||
|
|
||||||
Additionally, when not using system packages, you can [manually install
|
|
||||||
autocompletions](#autocompletion).
|
|
||||||
|
|
||||||
## Package Managers
|
|
||||||
|
|
||||||
Tealdeer has been added to a few package managers:
|
|
||||||
|
|
||||||
- Arch Linux: [`tealdeer`](https://archlinux.org/packages/extra/x86_64/tealdeer/)
|
|
||||||
- Debian: [`tealdeer`](https://tracker.debian.org/tealdeer)
|
|
||||||
- Fedora: [`tealdeer`](https://src.fedoraproject.org/rpms/rust-tealdeer)
|
|
||||||
- FreeBSD: [`sysutils/tealdeer`](https://www.freshports.org/sysutils/tealdeer/)
|
|
||||||
- Funtoo: [`app-misc/tealdeer`](https://github.com/funtoo/core-kit/tree/1.4-release/app-misc/tealdeer)
|
|
||||||
- Homebrew: [`tealdeer`](https://formulae.brew.sh/formula/tealdeer)
|
|
||||||
- MacPorts: [`tealdeer`](https://ports.macports.org/port/tealdeer/)
|
|
||||||
- NetBSD: [`sysutils/tealdeer`](https://pkgsrc.se/sysutils/tealdeer)
|
|
||||||
- Nix: [`tealdeer`](https://search.nixos.org/packages?query=tealdeer)
|
|
||||||
- openSUSE: [`tealdeer`](https://software.opensuse.org/package/tealdeer?search_term=tealdeer)
|
|
||||||
- Scoop: [`tealdeer`](https://github.com/ScoopInstaller/Main/blob/master/bucket/tealdeer.json)
|
|
||||||
- Solus: [`tealdeer`](https://packages.getsol.us/shannon/t/tealdeer/)
|
|
||||||
- Void Linux: [`tealdeer`](https://github.com/void-linux/void-packages/tree/master/srcpkgs/tealdeer)
|
|
||||||
|
|
||||||
## Static Binaries (Linux)
|
|
||||||
|
|
||||||
Static binary builds (currently for Linux only) are available on the
|
|
||||||
[GitHub releases page](https://github.com/tealdeer-rs/tealdeer/releases).
|
|
||||||
Simply download the binary for your platform and run it!
|
|
||||||
|
|
||||||
## Through `cargo install`
|
|
||||||
|
|
||||||
Build and install the tool via cargo...
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ cargo install tealdeer
|
|
||||||
```
|
|
||||||
|
|
||||||
## Build From Source
|
|
||||||
|
|
||||||
Release build:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ cargo build --release
|
|
||||||
```
|
|
||||||
|
|
||||||
Release build with native TLS support:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ cargo build --release --features native-tls
|
|
||||||
```
|
|
||||||
|
|
||||||
Debug build with logging support:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ cargo build --features logging
|
|
||||||
```
|
|
||||||
|
|
||||||
(To enable logging at runtime, export the `RUST_LOG=tldr=debug` env variable.)
|
|
||||||
|
|
||||||
## Autocompletion
|
|
||||||
|
|
||||||
Shell completion scripts are located in the folder `completion`.
|
|
||||||
Just copy them to their designated location:
|
|
||||||
|
|
||||||
- *Bash*: `cp completion/bash_tealdeer /usr/share/bash-completion/completions/tldr`
|
|
||||||
- *Fish*: `cp completion/fish_tealdeer ~/.config/fish/completions/tldr.fish`
|
|
||||||
- *Zsh*: `cp completion/zsh_tealdeer /usr/share/zsh/site-functions/_tldr`
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
# Tealdeer: Introduction
|
|
||||||
|
|
||||||
Tealdeer is a very fast implementation of
|
|
||||||
[tldr](https://github.com/tldr-pages/tldr) in Rust: Simplified, example based
|
|
||||||
and community-driven man pages.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
This documentation shows how to install, use and configure tealdeer.
|
|
||||||
|
|
||||||
## Links
|
|
||||||
|
|
||||||
- [GitHub Project Page](https://github.com/tealdeer-rs/tealdeer)
|
|
||||||
- [TLDR Pages Project](https://tldr.sh/)
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
# Tips and Tricks
|
|
||||||
|
|
||||||
This page features some example use cases of Tealdeer.
|
|
||||||
|
|
||||||
## Showing a random page on shell start
|
|
||||||
|
|
||||||
To display a randomly selected page, you can invoke `tldr` twice: One time to
|
|
||||||
select a page and a second time to display this page. To randomly select a page,
|
|
||||||
we use `shuf` from the GNU coreutils:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
tldr --quiet $(tldr --quiet --list | shuf -n1)
|
|
||||||
```
|
|
||||||
|
|
||||||
You can also add the above command to your `.bashrc` (or similar shell
|
|
||||||
configuration file) to display a random page every time you start a new shell
|
|
||||||
session.
|
|
||||||
|
|
||||||
## Displaying all pages with their summary
|
|
||||||
|
|
||||||
If you want to extend the output of `tldr --list` with the first line summary of
|
|
||||||
each page, you can run the following Python script:
|
|
||||||
|
|
||||||
```python
|
|
||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
commands = subprocess.run(
|
|
||||||
["tldr", "--quiet", "--list"],
|
|
||||||
capture_output=True,
|
|
||||||
encoding="utf-8",
|
|
||||||
).stdout.splitlines()
|
|
||||||
|
|
||||||
for command in commands:
|
|
||||||
output = subprocess.run(
|
|
||||||
["tldr", "--quiet", command],
|
|
||||||
capture_output=True,
|
|
||||||
encoding="utf-8",
|
|
||||||
).stdout
|
|
||||||
description = output.lstrip().split("\n\n")[0]
|
|
||||||
description = " ".join(description.split())
|
|
||||||
print(f"{command} => {description}")
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that there are a lot of pages and the script will run Tealdeer once for
|
|
||||||
every page, so the script may take a couple of seconds to finish.
|
|
||||||
|
|
||||||
## Extending this chapter
|
|
||||||
|
|
||||||
If you have an interesting setup with Tealdeer, feel free to share your
|
|
||||||
configuration on [our Github repository](https://github.com/tealdeer-rs/tealdeer).
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
# Usage
|
|
||||||
|
|
||||||
Tealdeer is straightforward to use, through the binary named `tldr`.
|
|
||||||
|
|
||||||
You can view the available options using `tldr --help`:
|
|
||||||
|
|
||||||
<!-- Note: To update the file below, run `cargo run -- --help > docs/src/usage.txt`. -->
|
|
||||||
```
|
|
||||||
{{#include usage.txt}}
|
|
||||||
```
|
|
||||||
|
|
@ -1,58 +0,0 @@
|
||||||
# Custom Pages and Patches
|
|
||||||
|
|
||||||
> ⚠️ **Breaking change in version 1.7.0:** The file name extension for custom
|
|
||||||
> pages and patches was changed:
|
|
||||||
>
|
|
||||||
> - `<name>.page` → `<name>.page.md`
|
|
||||||
> - `<name>.patch` → `<name>.patch.md`
|
|
||||||
>
|
|
||||||
> If you have custom pages or patches, you need to rename them.
|
|
||||||
|
|
||||||
Tealdeer allows creating new custom pages, overriding existing pages as well as
|
|
||||||
extending existing pages.
|
|
||||||
|
|
||||||
The directory, where these custom pages and patches can be placed, follows OS
|
|
||||||
conventions. On Linux for instance, the default location is
|
|
||||||
`~/.local/share/tealdeer/pages/`. To print the path used on your system, simply
|
|
||||||
run `tldr --show-paths`.
|
|
||||||
|
|
||||||
The custom pages directory can be [overridden by the config
|
|
||||||
file](config_directories.html).
|
|
||||||
|
|
||||||
## Custom Pages
|
|
||||||
|
|
||||||
To document internal command line tools, or if you want to replace an existing
|
|
||||||
tldr page with one that's better suited for you, place a file with the name
|
|
||||||
`<command>.page.md` in the custom pages directory. When calling `tldr <command>`,
|
|
||||||
your custom page will be shown instead of the upstream version in the cache.
|
|
||||||
|
|
||||||
Path:
|
|
||||||
|
|
||||||
```plain
|
|
||||||
$CUSTOM_PAGES_DIR/<command>.page.md
|
|
||||||
```
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```plain
|
|
||||||
~/.local/share/tealdeer/pages/ufw.page.md
|
|
||||||
```
|
|
||||||
|
|
||||||
## Custom Patches
|
|
||||||
|
|
||||||
Sometimes you don't want to fully replace an existing upstream page, but just
|
|
||||||
want to extend it with your own examples that you frequently need. In this
|
|
||||||
case, use a file called `<command>.patch.md`, it will be appended to existing
|
|
||||||
pages.
|
|
||||||
|
|
||||||
Path:
|
|
||||||
|
|
||||||
```plain
|
|
||||||
$CUSTOM_PAGES_DIR/<command>.patch.md
|
|
||||||
```
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```plain
|
|
||||||
~/.local/share/tealdeer/pages/ufw.patch.md
|
|
||||||
```
|
|
||||||
10
elasticlunr.min.js
vendored
Normal file
BIN
favicon.png
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
22
favicon.svg
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 199.7 184.2">
|
||||||
|
<style>
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
svg { fill: white; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<path d="M189.5,36.8c0.2,2.8,0,5.1-0.6,6.8L153,162c-0.6,2.1-2,3.7-4.2,5c-2.2,1.2-4.4,1.9-6.7,1.9H31.4c-9.6,0-15.3-2.8-17.3-8.4
|
||||||
|
c-0.8-2.2-0.8-3.9,0.1-5.2c0.9-1.2,2.4-1.8,4.6-1.8H123c7.4,0,12.6-1.4,15.4-4.1s5.7-8.9,8.6-18.4l32.9-108.6
|
||||||
|
c1.8-5.9,1-11.1-2.2-15.6S169.9,0,164,0H72.7c-1,0-3.1,0.4-6.1,1.1l0.1-0.4C64.5,0.2,62.6,0,61,0.1s-3,0.5-4.3,1.4
|
||||||
|
c-1.3,0.9-2.4,1.8-3.2,2.8S52,6.5,51.2,8.1c-0.8,1.6-1.4,3-1.9,4.3s-1.1,2.7-1.8,4.2c-0.7,1.5-1.3,2.7-2,3.7c-0.5,0.6-1.2,1.5-2,2.5
|
||||||
|
s-1.6,2-2.2,2.8s-0.9,1.5-1.1,2.2c-0.2,0.7-0.1,1.8,0.2,3.2c0.3,1.4,0.4,2.4,0.4,3.1c-0.3,3-1.4,6.9-3.3,11.6
|
||||||
|
c-1.9,4.7-3.6,8.1-5.1,10.1c-0.3,0.4-1.2,1.3-2.6,2.7c-1.4,1.4-2.3,2.6-2.6,3.7c-0.3,0.4-0.3,1.5-0.1,3.4c0.3,1.8,0.4,3.1,0.3,3.8
|
||||||
|
c-0.3,2.7-1.3,6.3-3,10.8c-1.7,4.5-3.4,8.2-5,11c-0.2,0.5-0.9,1.4-2,2.8c-1.1,1.4-1.8,2.5-2,3.4c-0.2,0.6-0.1,1.8,0.1,3.4
|
||||||
|
c0.2,1.6,0.2,2.8-0.1,3.6c-0.6,3-1.8,6.7-3.6,11c-1.8,4.3-3.6,7.9-5.4,11c-0.5,0.8-1.1,1.7-2,2.8c-0.8,1.1-1.5,2-2,2.8
|
||||||
|
s-0.8,1.6-1,2.5c-0.1,0.5,0,1.3,0.4,2.3c0.3,1.1,0.4,1.9,0.4,2.6c-0.1,1.1-0.2,2.6-0.5,4.4c-0.2,1.8-0.4,2.9-0.4,3.2
|
||||||
|
c-1.8,4.8-1.7,9.9,0.2,15.2c2.2,6.2,6.2,11.5,11.9,15.8c5.7,4.3,11.7,6.4,17.8,6.4h110.7c5.2,0,10.1-1.7,14.7-5.2s7.7-7.8,9.2-12.9
|
||||||
|
l33-108.6c1.8-5.8,1-10.9-2.2-15.5C194.9,39.7,192.6,38,189.5,36.8z M59.6,122.8L73.8,80c0,0,7,0,10.8,0s28.8-1.7,25.4,17.5
|
||||||
|
c-3.4,19.2-18.8,25.2-36.8,25.4S59.6,122.8,59.6,122.8z M78.6,116.8c4.7-0.1,18.9-2.9,22.1-17.1S89.2,86.3,89.2,86.3l-8.9,0
|
||||||
|
l-10.2,30.5C70.2,116.9,74,116.9,78.6,116.8z M75.3,68.7L89,26.2h9.8l0.8,34l23.6-34h9.9l-13.6,42.5h-7.1l12.5-35.4l-24.5,35.4h-6.8
|
||||||
|
l-0.8-35L82,68.7H75.3z"/>
|
||||||
|
</svg>
|
||||||
|
<!-- Original image Copyright Dave Gandy — CC BY 4.0 License -->
|
||||||
|
After Width: | Height: | Size: 1.8 KiB |
202
fonts/OPEN-SANS-LICENSE.txt
Normal file
|
|
@ -0,0 +1,202 @@
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
93
fonts/SOURCE-CODE-PRO-LICENSE.txt
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries.
|
||||||
|
|
||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
This license is copied below, and is also available with a FAQ at:
|
||||||
|
http://scripts.sil.org/OFL
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||||
|
development of collaborative font projects, to support the font creation
|
||||||
|
efforts of academic and linguistic communities, and to provide a free and
|
||||||
|
open framework in which fonts may be shared and improved in partnership
|
||||||
|
with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves. The
|
||||||
|
fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply
|
||||||
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as
|
||||||
|
distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting -- in part or in whole -- any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to a
|
||||||
|
new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical
|
||||||
|
writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,
|
||||||
|
in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the corresponding
|
||||||
|
Copyright Holder. This restriction only applies to the primary font name as
|
||||||
|
presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole,
|
||||||
|
must be distributed entirely under this license, and must not be
|
||||||
|
distributed under any other license. The requirement for fonts to
|
||||||
|
remain under this license does not apply to any document created
|
||||||
|
using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||||
100
fonts/fonts.css
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
/* Open Sans is licensed under the Apache License, Version 2.0. See http://www.apache.org/licenses/LICENSE-2.0 */
|
||||||
|
/* Source Code Pro is under the Open Font License. See https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL */
|
||||||
|
|
||||||
|
/* open-sans-300 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Open Sans';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
src: local('Open Sans Light'), local('OpenSans-Light'),
|
||||||
|
url('open-sans-v17-all-charsets-300.woff2') format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open-sans-300italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Open Sans';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 300;
|
||||||
|
src: local('Open Sans Light Italic'), local('OpenSans-LightItalic'),
|
||||||
|
url('open-sans-v17-all-charsets-300italic.woff2') format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open-sans-regular - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Open Sans';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
src: local('Open Sans Regular'), local('OpenSans-Regular'),
|
||||||
|
url('open-sans-v17-all-charsets-regular.woff2') format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open-sans-italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Open Sans';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 400;
|
||||||
|
src: local('Open Sans Italic'), local('OpenSans-Italic'),
|
||||||
|
url('open-sans-v17-all-charsets-italic.woff2') format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open-sans-600 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Open Sans';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
src: local('Open Sans SemiBold'), local('OpenSans-SemiBold'),
|
||||||
|
url('open-sans-v17-all-charsets-600.woff2') format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open-sans-600italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Open Sans';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 600;
|
||||||
|
src: local('Open Sans SemiBold Italic'), local('OpenSans-SemiBoldItalic'),
|
||||||
|
url('open-sans-v17-all-charsets-600italic.woff2') format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open-sans-700 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Open Sans';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
src: local('Open Sans Bold'), local('OpenSans-Bold'),
|
||||||
|
url('open-sans-v17-all-charsets-700.woff2') format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open-sans-700italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Open Sans';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 700;
|
||||||
|
src: local('Open Sans Bold Italic'), local('OpenSans-BoldItalic'),
|
||||||
|
url('open-sans-v17-all-charsets-700italic.woff2') format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open-sans-800 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Open Sans';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 800;
|
||||||
|
src: local('Open Sans ExtraBold'), local('OpenSans-ExtraBold'),
|
||||||
|
url('open-sans-v17-all-charsets-800.woff2') format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open-sans-800italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Open Sans';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 800;
|
||||||
|
src: local('Open Sans ExtraBold Italic'), local('OpenSans-ExtraBoldItalic'),
|
||||||
|
url('open-sans-v17-all-charsets-800italic.woff2') format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* source-code-pro-500 - latin_vietnamese_latin-ext_greek_cyrillic-ext_cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Source Code Pro';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
src: url('source-code-pro-v11-all-charsets-500.woff2') format('woff2');
|
||||||
|
}
|
||||||
BIN
fonts/open-sans-v17-all-charsets-300.woff2
Normal file
BIN
fonts/open-sans-v17-all-charsets-300italic.woff2
Normal file
BIN
fonts/open-sans-v17-all-charsets-600.woff2
Normal file
BIN
fonts/open-sans-v17-all-charsets-600italic.woff2
Normal file
BIN
fonts/open-sans-v17-all-charsets-700.woff2
Normal file
BIN
fonts/open-sans-v17-all-charsets-700italic.woff2
Normal file
BIN
fonts/open-sans-v17-all-charsets-800.woff2
Normal file
BIN
fonts/open-sans-v17-all-charsets-800italic.woff2
Normal file
BIN
fonts/open-sans-v17-all-charsets-italic.woff2
Normal file
BIN
fonts/open-sans-v17-all-charsets-regular.woff2
Normal file
BIN
fonts/source-code-pro-v11-all-charsets-500.woff2
Normal file
79
highlight.css
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
/* Base16 Atelier Dune Light - Theme */
|
||||||
|
/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/dune) */
|
||||||
|
/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
|
||||||
|
|
||||||
|
/* Atelier-Dune Comment */
|
||||||
|
.hljs-comment,
|
||||||
|
.hljs-quote {
|
||||||
|
color: #AAA;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Atelier-Dune Red */
|
||||||
|
.hljs-variable,
|
||||||
|
.hljs-template-variable,
|
||||||
|
.hljs-attribute,
|
||||||
|
.hljs-tag,
|
||||||
|
.hljs-name,
|
||||||
|
.hljs-regexp,
|
||||||
|
.hljs-link,
|
||||||
|
.hljs-name,
|
||||||
|
.hljs-selector-id,
|
||||||
|
.hljs-selector-class {
|
||||||
|
color: #d73737;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Atelier-Dune Orange */
|
||||||
|
.hljs-number,
|
||||||
|
.hljs-meta,
|
||||||
|
.hljs-built_in,
|
||||||
|
.hljs-builtin-name,
|
||||||
|
.hljs-literal,
|
||||||
|
.hljs-type,
|
||||||
|
.hljs-params {
|
||||||
|
color: #b65611;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Atelier-Dune Green */
|
||||||
|
.hljs-string,
|
||||||
|
.hljs-symbol,
|
||||||
|
.hljs-bullet {
|
||||||
|
color: #60ac39;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Atelier-Dune Blue */
|
||||||
|
.hljs-title,
|
||||||
|
.hljs-section {
|
||||||
|
color: #6684e1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Atelier-Dune Purple */
|
||||||
|
.hljs-keyword,
|
||||||
|
.hljs-selector-tag {
|
||||||
|
color: #b854d4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs {
|
||||||
|
display: block;
|
||||||
|
overflow-x: auto;
|
||||||
|
background: #f1f1f1;
|
||||||
|
color: #6e6b5e;
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-emphasis {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-strong {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-addition {
|
||||||
|
color: #22863a;
|
||||||
|
background-color: #f0fff4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-deletion {
|
||||||
|
color: #b31d28;
|
||||||
|
background-color: #ffeef0;
|
||||||
|
}
|
||||||
6
highlight.js
Normal file
237
index.html
Normal file
|
|
@ -0,0 +1,237 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html lang="en" class="sidebar-visible no-js light">
|
||||||
|
<head>
|
||||||
|
<!-- Book generated using mdBook -->
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Introduction - Tealdeer User Manual</title>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Custom HTML head -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||||
|
<meta name="description" content="">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="theme-color" content="#ffffff" />
|
||||||
|
|
||||||
|
|
||||||
|
<link rel="icon" href="favicon.svg">
|
||||||
|
|
||||||
|
|
||||||
|
<link rel="shortcut icon" href="favicon.png">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="css/variables.css">
|
||||||
|
<link rel="stylesheet" href="css/general.css">
|
||||||
|
<link rel="stylesheet" href="css/chrome.css">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="css/print.css" media="print">
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Fonts -->
|
||||||
|
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="fonts/fonts.css">
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Highlight.js Stylesheets -->
|
||||||
|
<link rel="stylesheet" href="highlight.css">
|
||||||
|
<link rel="stylesheet" href="tomorrow-night.css">
|
||||||
|
<link rel="stylesheet" href="ayu-highlight.css">
|
||||||
|
|
||||||
|
<!-- Custom theme stylesheets -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- Provide site root to javascript -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var path_to_root = "";
|
||||||
|
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
try {
|
||||||
|
var theme = localStorage.getItem('mdbook-theme');
|
||||||
|
var sidebar = localStorage.getItem('mdbook-sidebar');
|
||||||
|
|
||||||
|
if (theme.startsWith('"') && theme.endsWith('"')) {
|
||||||
|
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
||||||
|
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
||||||
|
}
|
||||||
|
} catch (e) { }
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Set the theme before any content is loaded, prevents flash -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var theme;
|
||||||
|
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||||||
|
if (theme === null || theme === undefined) { theme = default_theme; }
|
||||||
|
var html = document.querySelector('html');
|
||||||
|
html.classList.remove('no-js')
|
||||||
|
html.classList.remove('light')
|
||||||
|
html.classList.add(theme);
|
||||||
|
html.classList.add('js');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Hide / unhide sidebar before it is displayed -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var html = document.querySelector('html');
|
||||||
|
var sidebar = 'hidden';
|
||||||
|
if (document.body.clientWidth >= 1080) {
|
||||||
|
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
||||||
|
sidebar = sidebar || 'visible';
|
||||||
|
}
|
||||||
|
html.classList.remove('sidebar-visible');
|
||||||
|
html.classList.add("sidebar-" + sidebar);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||||
|
<div class="sidebar-scrollbox">
|
||||||
|
<ol class="chapter"><li class="chapter-item expanded affix "><a href="intro.html">Introduction</a></li><li class="chapter-item expanded "><a href="installing.html"><strong aria-hidden="true">1.</strong> Installing</a></li><li class="chapter-item expanded "><a href="usage.html"><strong aria-hidden="true">2.</strong> Usage</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="usage_custom_pages.html"><strong aria-hidden="true">2.1.</strong> Custom Pages and Patches</a></li></ol></li><li class="chapter-item expanded "><a href="config.html"><strong aria-hidden="true">3.</strong> Configuration</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="config_display.html"><strong aria-hidden="true">3.1.</strong> Section: [display]</a></li><li class="chapter-item expanded "><a href="config_style.html"><strong aria-hidden="true">3.2.</strong> Section: [style]</a></li><li class="chapter-item expanded "><a href="config_search.html"><strong aria-hidden="true">3.3.</strong> Section: [search]</a></li><li class="chapter-item expanded "><a href="config_updates.html"><strong aria-hidden="true">3.4.</strong> Section: [updates]</a></li><li class="chapter-item expanded "><a href="config_directories.html"><strong aria-hidden="true">3.5.</strong> Section: [directories]</a></li></ol></li><li class="chapter-item expanded "><a href="tips_and_tricks.html"><strong aria-hidden="true">4.</strong> Tips and Tricks</a></li></ol>
|
||||||
|
</div>
|
||||||
|
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div id="page-wrapper" class="page-wrapper">
|
||||||
|
|
||||||
|
<div class="page">
|
||||||
|
|
||||||
|
<div id="menu-bar-hover-placeholder"></div>
|
||||||
|
<div id="menu-bar" class="menu-bar sticky bordered">
|
||||||
|
<div class="left-buttons">
|
||||||
|
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
||||||
|
<i class="fa fa-bars"></i>
|
||||||
|
</button>
|
||||||
|
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
||||||
|
<i class="fa fa-paint-brush"></i>
|
||||||
|
</button>
|
||||||
|
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
||||||
|
<i class="fa fa-search"></i>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1 class="menu-title">Tealdeer User Manual</h1>
|
||||||
|
|
||||||
|
<div class="right-buttons">
|
||||||
|
|
||||||
|
<a href="print.html" title="Print this book" aria-label="Print this book">
|
||||||
|
<i id="print-button" class="fa fa-print"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="search-wrapper" class="hidden">
|
||||||
|
<form id="searchbar-outer" class="searchbar-outer">
|
||||||
|
<input type="search" name="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||||||
|
</form>
|
||||||
|
<div id="searchresults-outer" class="searchresults-outer hidden">
|
||||||
|
<div id="searchresults-header" class="searchresults-header"></div>
|
||||||
|
<ul id="searchresults">
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
||||||
|
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
||||||
|
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
||||||
|
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div id="content" class="content">
|
||||||
|
<main>
|
||||||
|
<h1><a class="header" href="#tealdeer-introduction" id="tealdeer-introduction">Tealdeer: Introduction</a></h1>
|
||||||
|
<p>Tealdeer is a very fast implementation of
|
||||||
|
<a href="https://github.com/tldr-pages/tldr">tldr</a> in Rust: Simplified, example based
|
||||||
|
and community-driven man pages.</p>
|
||||||
|
<p><img src="screenshot-default.png" alt="Screenshot" /></p>
|
||||||
|
<p>This documentation shows how to install, use and configure tealdeer.</p>
|
||||||
|
<h2><a class="header" href="#links" id="links">Links</a></h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="https://github.com/tealdeer-rs/tealdeer">GitHub Project Page</a></li>
|
||||||
|
<li><a href="https://tldr.sh/">TLDR Pages Project</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||||
|
<!-- Mobile navigation buttons -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a rel="next" href="installing.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||||
|
<i class="fa fa-angle-right"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
<div style="clear: both"></div>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a rel="next" href="installing.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||||
|
<i class="fa fa-angle-right"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
window.playground_copyable = true;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="searcher.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="highlight.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="book.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
||||||
|
<!-- Custom JS scripts -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
288
installing.html
Normal file
|
|
@ -0,0 +1,288 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html lang="en" class="sidebar-visible no-js light">
|
||||||
|
<head>
|
||||||
|
<!-- Book generated using mdBook -->
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Installing - Tealdeer User Manual</title>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Custom HTML head -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||||
|
<meta name="description" content="">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="theme-color" content="#ffffff" />
|
||||||
|
|
||||||
|
|
||||||
|
<link rel="icon" href="favicon.svg">
|
||||||
|
|
||||||
|
|
||||||
|
<link rel="shortcut icon" href="favicon.png">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="css/variables.css">
|
||||||
|
<link rel="stylesheet" href="css/general.css">
|
||||||
|
<link rel="stylesheet" href="css/chrome.css">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="css/print.css" media="print">
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Fonts -->
|
||||||
|
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="fonts/fonts.css">
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Highlight.js Stylesheets -->
|
||||||
|
<link rel="stylesheet" href="highlight.css">
|
||||||
|
<link rel="stylesheet" href="tomorrow-night.css">
|
||||||
|
<link rel="stylesheet" href="ayu-highlight.css">
|
||||||
|
|
||||||
|
<!-- Custom theme stylesheets -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- Provide site root to javascript -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var path_to_root = "";
|
||||||
|
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
try {
|
||||||
|
var theme = localStorage.getItem('mdbook-theme');
|
||||||
|
var sidebar = localStorage.getItem('mdbook-sidebar');
|
||||||
|
|
||||||
|
if (theme.startsWith('"') && theme.endsWith('"')) {
|
||||||
|
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
||||||
|
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
||||||
|
}
|
||||||
|
} catch (e) { }
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Set the theme before any content is loaded, prevents flash -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var theme;
|
||||||
|
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||||||
|
if (theme === null || theme === undefined) { theme = default_theme; }
|
||||||
|
var html = document.querySelector('html');
|
||||||
|
html.classList.remove('no-js')
|
||||||
|
html.classList.remove('light')
|
||||||
|
html.classList.add(theme);
|
||||||
|
html.classList.add('js');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Hide / unhide sidebar before it is displayed -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var html = document.querySelector('html');
|
||||||
|
var sidebar = 'hidden';
|
||||||
|
if (document.body.clientWidth >= 1080) {
|
||||||
|
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
||||||
|
sidebar = sidebar || 'visible';
|
||||||
|
}
|
||||||
|
html.classList.remove('sidebar-visible');
|
||||||
|
html.classList.add("sidebar-" + sidebar);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||||
|
<div class="sidebar-scrollbox">
|
||||||
|
<ol class="chapter"><li class="chapter-item expanded affix "><a href="intro.html">Introduction</a></li><li class="chapter-item expanded "><a href="installing.html" class="active"><strong aria-hidden="true">1.</strong> Installing</a></li><li class="chapter-item expanded "><a href="usage.html"><strong aria-hidden="true">2.</strong> Usage</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="usage_custom_pages.html"><strong aria-hidden="true">2.1.</strong> Custom Pages and Patches</a></li></ol></li><li class="chapter-item expanded "><a href="config.html"><strong aria-hidden="true">3.</strong> Configuration</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="config_display.html"><strong aria-hidden="true">3.1.</strong> Section: [display]</a></li><li class="chapter-item expanded "><a href="config_style.html"><strong aria-hidden="true">3.2.</strong> Section: [style]</a></li><li class="chapter-item expanded "><a href="config_search.html"><strong aria-hidden="true">3.3.</strong> Section: [search]</a></li><li class="chapter-item expanded "><a href="config_updates.html"><strong aria-hidden="true">3.4.</strong> Section: [updates]</a></li><li class="chapter-item expanded "><a href="config_directories.html"><strong aria-hidden="true">3.5.</strong> Section: [directories]</a></li></ol></li><li class="chapter-item expanded "><a href="tips_and_tricks.html"><strong aria-hidden="true">4.</strong> Tips and Tricks</a></li></ol>
|
||||||
|
</div>
|
||||||
|
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div id="page-wrapper" class="page-wrapper">
|
||||||
|
|
||||||
|
<div class="page">
|
||||||
|
|
||||||
|
<div id="menu-bar-hover-placeholder"></div>
|
||||||
|
<div id="menu-bar" class="menu-bar sticky bordered">
|
||||||
|
<div class="left-buttons">
|
||||||
|
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
||||||
|
<i class="fa fa-bars"></i>
|
||||||
|
</button>
|
||||||
|
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
||||||
|
<i class="fa fa-paint-brush"></i>
|
||||||
|
</button>
|
||||||
|
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
||||||
|
<i class="fa fa-search"></i>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1 class="menu-title">Tealdeer User Manual</h1>
|
||||||
|
|
||||||
|
<div class="right-buttons">
|
||||||
|
|
||||||
|
<a href="print.html" title="Print this book" aria-label="Print this book">
|
||||||
|
<i id="print-button" class="fa fa-print"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="search-wrapper" class="hidden">
|
||||||
|
<form id="searchbar-outer" class="searchbar-outer">
|
||||||
|
<input type="search" name="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||||||
|
</form>
|
||||||
|
<div id="searchresults-outer" class="searchresults-outer hidden">
|
||||||
|
<div id="searchresults-header" class="searchresults-header"></div>
|
||||||
|
<ul id="searchresults">
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
||||||
|
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
||||||
|
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
||||||
|
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div id="content" class="content">
|
||||||
|
<main>
|
||||||
|
<h1><a class="header" href="#installing" id="installing">Installing</a></h1>
|
||||||
|
<p>There are a few different ways to install tealdeer:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Through <a href="#package-managers">package managers</a></li>
|
||||||
|
<li>Through <a href="#static-binaries-linux">static binaries</a></li>
|
||||||
|
<li>Through <a href="#through-cargo-install">cargo install</a></li>
|
||||||
|
<li>By <a href="#build-from-source">building from source</a></li>
|
||||||
|
</ul>
|
||||||
|
<p>Additionally, when not using system packages, you can <a href="#autocompletion">manually install
|
||||||
|
autocompletions</a>.</p>
|
||||||
|
<h2><a class="header" href="#package-managers" id="package-managers">Package Managers</a></h2>
|
||||||
|
<p>Tealdeer has been added to a few package managers:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Arch Linux: <a href="https://archlinux.org/packages/extra/x86_64/tealdeer/"><code>tealdeer</code></a></li>
|
||||||
|
<li>Debian: <a href="https://tracker.debian.org/tealdeer"><code>tealdeer</code></a></li>
|
||||||
|
<li>Fedora: <a href="https://src.fedoraproject.org/rpms/rust-tealdeer"><code>tealdeer</code></a></li>
|
||||||
|
<li>FreeBSD: <a href="https://www.freshports.org/sysutils/tealdeer/"><code>sysutils/tealdeer</code></a></li>
|
||||||
|
<li>Funtoo: <a href="https://github.com/funtoo/core-kit/tree/1.4-release/app-misc/tealdeer"><code>app-misc/tealdeer</code></a></li>
|
||||||
|
<li>Homebrew: <a href="https://formulae.brew.sh/formula/tealdeer"><code>tealdeer</code></a></li>
|
||||||
|
<li>MacPorts: <a href="https://ports.macports.org/port/tealdeer/"><code>tealdeer</code></a></li>
|
||||||
|
<li>NetBSD: <a href="https://pkgsrc.se/sysutils/tealdeer"><code>sysutils/tealdeer</code></a></li>
|
||||||
|
<li>Nix: <a href="https://search.nixos.org/packages?query=tealdeer"><code>tealdeer</code></a></li>
|
||||||
|
<li>openSUSE: <a href="https://software.opensuse.org/package/tealdeer?search_term=tealdeer"><code>tealdeer</code></a></li>
|
||||||
|
<li>Scoop: <a href="https://github.com/ScoopInstaller/Main/blob/master/bucket/tealdeer.json"><code>tealdeer</code></a></li>
|
||||||
|
<li>Solus: <a href="https://packages.getsol.us/shannon/t/tealdeer/"><code>tealdeer</code></a></li>
|
||||||
|
<li>Void Linux: <a href="https://github.com/void-linux/void-packages/tree/master/srcpkgs/tealdeer"><code>tealdeer</code></a></li>
|
||||||
|
</ul>
|
||||||
|
<h2><a class="header" href="#static-binaries-linux" id="static-binaries-linux">Static Binaries (Linux)</a></h2>
|
||||||
|
<p>Static binary builds (currently for Linux only) are available on the
|
||||||
|
<a href="https://github.com/tealdeer-rs/tealdeer/releases">GitHub releases page</a>.
|
||||||
|
Simply download the binary for your platform and run it!</p>
|
||||||
|
<h2><a class="header" href="#through-cargo-install" id="through-cargo-install">Through <code>cargo install</code></a></h2>
|
||||||
|
<p>Build and install the tool via cargo...</p>
|
||||||
|
<pre><code class="language-shell">$ cargo install tealdeer
|
||||||
|
</code></pre>
|
||||||
|
<h2><a class="header" href="#build-from-source" id="build-from-source">Build From Source</a></h2>
|
||||||
|
<p>Release build:</p>
|
||||||
|
<pre><code class="language-shell">$ cargo build --release
|
||||||
|
</code></pre>
|
||||||
|
<p>Release build with native TLS support:</p>
|
||||||
|
<pre><code class="language-shell">$ cargo build --release --features native-tls
|
||||||
|
</code></pre>
|
||||||
|
<p>Debug build with logging support:</p>
|
||||||
|
<pre><code class="language-shell">$ cargo build --features logging
|
||||||
|
</code></pre>
|
||||||
|
<p>(To enable logging at runtime, export the <code>RUST_LOG=tldr=debug</code> env variable.)</p>
|
||||||
|
<h2><a class="header" href="#autocompletion" id="autocompletion">Autocompletion</a></h2>
|
||||||
|
<p>Shell completion scripts are located in the folder <code>completion</code>.
|
||||||
|
Just copy them to their designated location:</p>
|
||||||
|
<ul>
|
||||||
|
<li><em>Bash</em>: <code>cp completion/bash_tealdeer /usr/share/bash-completion/completions/tldr</code></li>
|
||||||
|
<li><em>Fish</em>: <code>cp completion/fish_tealdeer ~/.config/fish/completions/tldr.fish</code></li>
|
||||||
|
<li><em>Zsh</em>: <code>cp completion/zsh_tealdeer /usr/share/zsh/site-functions/_tldr</code></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||||
|
<!-- Mobile navigation buttons -->
|
||||||
|
|
||||||
|
<a rel="prev" href="intro.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||||
|
<i class="fa fa-angle-left"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a rel="next" href="usage.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||||
|
<i class="fa fa-angle-right"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
<div style="clear: both"></div>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||||
|
|
||||||
|
<a rel="prev" href="intro.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||||
|
<i class="fa fa-angle-left"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a rel="next" href="usage.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||||
|
<i class="fa fa-angle-right"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
window.playground_copyable = true;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="searcher.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="highlight.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="book.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
||||||
|
<!-- Custom JS scripts -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
237
intro.html
Normal file
|
|
@ -0,0 +1,237 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html lang="en" class="sidebar-visible no-js light">
|
||||||
|
<head>
|
||||||
|
<!-- Book generated using mdBook -->
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Introduction - Tealdeer User Manual</title>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Custom HTML head -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||||
|
<meta name="description" content="">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="theme-color" content="#ffffff" />
|
||||||
|
|
||||||
|
|
||||||
|
<link rel="icon" href="favicon.svg">
|
||||||
|
|
||||||
|
|
||||||
|
<link rel="shortcut icon" href="favicon.png">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="css/variables.css">
|
||||||
|
<link rel="stylesheet" href="css/general.css">
|
||||||
|
<link rel="stylesheet" href="css/chrome.css">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="css/print.css" media="print">
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Fonts -->
|
||||||
|
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="fonts/fonts.css">
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Highlight.js Stylesheets -->
|
||||||
|
<link rel="stylesheet" href="highlight.css">
|
||||||
|
<link rel="stylesheet" href="tomorrow-night.css">
|
||||||
|
<link rel="stylesheet" href="ayu-highlight.css">
|
||||||
|
|
||||||
|
<!-- Custom theme stylesheets -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- Provide site root to javascript -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var path_to_root = "";
|
||||||
|
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
try {
|
||||||
|
var theme = localStorage.getItem('mdbook-theme');
|
||||||
|
var sidebar = localStorage.getItem('mdbook-sidebar');
|
||||||
|
|
||||||
|
if (theme.startsWith('"') && theme.endsWith('"')) {
|
||||||
|
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
||||||
|
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
||||||
|
}
|
||||||
|
} catch (e) { }
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Set the theme before any content is loaded, prevents flash -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var theme;
|
||||||
|
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||||||
|
if (theme === null || theme === undefined) { theme = default_theme; }
|
||||||
|
var html = document.querySelector('html');
|
||||||
|
html.classList.remove('no-js')
|
||||||
|
html.classList.remove('light')
|
||||||
|
html.classList.add(theme);
|
||||||
|
html.classList.add('js');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Hide / unhide sidebar before it is displayed -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var html = document.querySelector('html');
|
||||||
|
var sidebar = 'hidden';
|
||||||
|
if (document.body.clientWidth >= 1080) {
|
||||||
|
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
||||||
|
sidebar = sidebar || 'visible';
|
||||||
|
}
|
||||||
|
html.classList.remove('sidebar-visible');
|
||||||
|
html.classList.add("sidebar-" + sidebar);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||||
|
<div class="sidebar-scrollbox">
|
||||||
|
<ol class="chapter"><li class="chapter-item expanded affix "><a href="intro.html" class="active">Introduction</a></li><li class="chapter-item expanded "><a href="installing.html"><strong aria-hidden="true">1.</strong> Installing</a></li><li class="chapter-item expanded "><a href="usage.html"><strong aria-hidden="true">2.</strong> Usage</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="usage_custom_pages.html"><strong aria-hidden="true">2.1.</strong> Custom Pages and Patches</a></li></ol></li><li class="chapter-item expanded "><a href="config.html"><strong aria-hidden="true">3.</strong> Configuration</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="config_display.html"><strong aria-hidden="true">3.1.</strong> Section: [display]</a></li><li class="chapter-item expanded "><a href="config_style.html"><strong aria-hidden="true">3.2.</strong> Section: [style]</a></li><li class="chapter-item expanded "><a href="config_search.html"><strong aria-hidden="true">3.3.</strong> Section: [search]</a></li><li class="chapter-item expanded "><a href="config_updates.html"><strong aria-hidden="true">3.4.</strong> Section: [updates]</a></li><li class="chapter-item expanded "><a href="config_directories.html"><strong aria-hidden="true">3.5.</strong> Section: [directories]</a></li></ol></li><li class="chapter-item expanded "><a href="tips_and_tricks.html"><strong aria-hidden="true">4.</strong> Tips and Tricks</a></li></ol>
|
||||||
|
</div>
|
||||||
|
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div id="page-wrapper" class="page-wrapper">
|
||||||
|
|
||||||
|
<div class="page">
|
||||||
|
|
||||||
|
<div id="menu-bar-hover-placeholder"></div>
|
||||||
|
<div id="menu-bar" class="menu-bar sticky bordered">
|
||||||
|
<div class="left-buttons">
|
||||||
|
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
||||||
|
<i class="fa fa-bars"></i>
|
||||||
|
</button>
|
||||||
|
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
||||||
|
<i class="fa fa-paint-brush"></i>
|
||||||
|
</button>
|
||||||
|
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
||||||
|
<i class="fa fa-search"></i>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1 class="menu-title">Tealdeer User Manual</h1>
|
||||||
|
|
||||||
|
<div class="right-buttons">
|
||||||
|
|
||||||
|
<a href="print.html" title="Print this book" aria-label="Print this book">
|
||||||
|
<i id="print-button" class="fa fa-print"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="search-wrapper" class="hidden">
|
||||||
|
<form id="searchbar-outer" class="searchbar-outer">
|
||||||
|
<input type="search" name="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||||||
|
</form>
|
||||||
|
<div id="searchresults-outer" class="searchresults-outer hidden">
|
||||||
|
<div id="searchresults-header" class="searchresults-header"></div>
|
||||||
|
<ul id="searchresults">
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
||||||
|
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
||||||
|
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
||||||
|
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div id="content" class="content">
|
||||||
|
<main>
|
||||||
|
<h1><a class="header" href="#tealdeer-introduction" id="tealdeer-introduction">Tealdeer: Introduction</a></h1>
|
||||||
|
<p>Tealdeer is a very fast implementation of
|
||||||
|
<a href="https://github.com/tldr-pages/tldr">tldr</a> in Rust: Simplified, example based
|
||||||
|
and community-driven man pages.</p>
|
||||||
|
<p><img src="screenshot-default.png" alt="Screenshot" /></p>
|
||||||
|
<p>This documentation shows how to install, use and configure tealdeer.</p>
|
||||||
|
<h2><a class="header" href="#links" id="links">Links</a></h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="https://github.com/tealdeer-rs/tealdeer">GitHub Project Page</a></li>
|
||||||
|
<li><a href="https://tldr.sh/">TLDR Pages Project</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||||
|
<!-- Mobile navigation buttons -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a rel="next" href="installing.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||||
|
<i class="fa fa-angle-right"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
<div style="clear: both"></div>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a rel="next" href="installing.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||||
|
<i class="fa fa-angle-right"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
window.playground_copyable = true;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="searcher.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="highlight.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="book.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
||||||
|
<!-- Custom JS scripts -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
7
mark.min.js
vendored
Normal file
|
|
@ -1,42 +0,0 @@
|
||||||
# tldr
|
|
||||||
|
|
||||||
> This is a builtin page that shows information for your installed tealdeer version.
|
|
||||||
> More information: <https://tealdeer-rs.github.io/tealdeer/>.
|
|
||||||
|
|
||||||
> 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 <FILE>`
|
|
||||||
|
|
||||||
- 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`
|
|
||||||
615
print.html
Normal file
|
|
@ -0,0 +1,615 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html lang="en" class="sidebar-visible no-js light">
|
||||||
|
<head>
|
||||||
|
<!-- Book generated using mdBook -->
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Tealdeer User Manual</title>
|
||||||
|
|
||||||
|
<meta name="robots" content="noindex" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Custom HTML head -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||||
|
<meta name="description" content="">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="theme-color" content="#ffffff" />
|
||||||
|
|
||||||
|
|
||||||
|
<link rel="icon" href="favicon.svg">
|
||||||
|
|
||||||
|
|
||||||
|
<link rel="shortcut icon" href="favicon.png">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="css/variables.css">
|
||||||
|
<link rel="stylesheet" href="css/general.css">
|
||||||
|
<link rel="stylesheet" href="css/chrome.css">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="css/print.css" media="print">
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Fonts -->
|
||||||
|
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="fonts/fonts.css">
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Highlight.js Stylesheets -->
|
||||||
|
<link rel="stylesheet" href="highlight.css">
|
||||||
|
<link rel="stylesheet" href="tomorrow-night.css">
|
||||||
|
<link rel="stylesheet" href="ayu-highlight.css">
|
||||||
|
|
||||||
|
<!-- Custom theme stylesheets -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- Provide site root to javascript -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var path_to_root = "";
|
||||||
|
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
try {
|
||||||
|
var theme = localStorage.getItem('mdbook-theme');
|
||||||
|
var sidebar = localStorage.getItem('mdbook-sidebar');
|
||||||
|
|
||||||
|
if (theme.startsWith('"') && theme.endsWith('"')) {
|
||||||
|
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
||||||
|
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
||||||
|
}
|
||||||
|
} catch (e) { }
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Set the theme before any content is loaded, prevents flash -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var theme;
|
||||||
|
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||||||
|
if (theme === null || theme === undefined) { theme = default_theme; }
|
||||||
|
var html = document.querySelector('html');
|
||||||
|
html.classList.remove('no-js')
|
||||||
|
html.classList.remove('light')
|
||||||
|
html.classList.add(theme);
|
||||||
|
html.classList.add('js');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Hide / unhide sidebar before it is displayed -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var html = document.querySelector('html');
|
||||||
|
var sidebar = 'hidden';
|
||||||
|
if (document.body.clientWidth >= 1080) {
|
||||||
|
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
||||||
|
sidebar = sidebar || 'visible';
|
||||||
|
}
|
||||||
|
html.classList.remove('sidebar-visible');
|
||||||
|
html.classList.add("sidebar-" + sidebar);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||||
|
<div class="sidebar-scrollbox">
|
||||||
|
<ol class="chapter"><li class="chapter-item expanded affix "><a href="intro.html">Introduction</a></li><li class="chapter-item expanded "><a href="installing.html"><strong aria-hidden="true">1.</strong> Installing</a></li><li class="chapter-item expanded "><a href="usage.html"><strong aria-hidden="true">2.</strong> Usage</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="usage_custom_pages.html"><strong aria-hidden="true">2.1.</strong> Custom Pages and Patches</a></li></ol></li><li class="chapter-item expanded "><a href="config.html"><strong aria-hidden="true">3.</strong> Configuration</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="config_display.html"><strong aria-hidden="true">3.1.</strong> Section: [display]</a></li><li class="chapter-item expanded "><a href="config_style.html"><strong aria-hidden="true">3.2.</strong> Section: [style]</a></li><li class="chapter-item expanded "><a href="config_search.html"><strong aria-hidden="true">3.3.</strong> Section: [search]</a></li><li class="chapter-item expanded "><a href="config_updates.html"><strong aria-hidden="true">3.4.</strong> Section: [updates]</a></li><li class="chapter-item expanded "><a href="config_directories.html"><strong aria-hidden="true">3.5.</strong> Section: [directories]</a></li></ol></li><li class="chapter-item expanded "><a href="tips_and_tricks.html"><strong aria-hidden="true">4.</strong> Tips and Tricks</a></li></ol>
|
||||||
|
</div>
|
||||||
|
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div id="page-wrapper" class="page-wrapper">
|
||||||
|
|
||||||
|
<div class="page">
|
||||||
|
|
||||||
|
<div id="menu-bar-hover-placeholder"></div>
|
||||||
|
<div id="menu-bar" class="menu-bar sticky bordered">
|
||||||
|
<div class="left-buttons">
|
||||||
|
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
||||||
|
<i class="fa fa-bars"></i>
|
||||||
|
</button>
|
||||||
|
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
||||||
|
<i class="fa fa-paint-brush"></i>
|
||||||
|
</button>
|
||||||
|
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
||||||
|
<i class="fa fa-search"></i>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1 class="menu-title">Tealdeer User Manual</h1>
|
||||||
|
|
||||||
|
<div class="right-buttons">
|
||||||
|
|
||||||
|
<a href="print.html" title="Print this book" aria-label="Print this book">
|
||||||
|
<i id="print-button" class="fa fa-print"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="search-wrapper" class="hidden">
|
||||||
|
<form id="searchbar-outer" class="searchbar-outer">
|
||||||
|
<input type="search" name="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||||||
|
</form>
|
||||||
|
<div id="searchresults-outer" class="searchresults-outer hidden">
|
||||||
|
<div id="searchresults-header" class="searchresults-header"></div>
|
||||||
|
<ul id="searchresults">
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
||||||
|
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
||||||
|
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
||||||
|
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div id="content" class="content">
|
||||||
|
<main>
|
||||||
|
<h1><a class="header" href="#tealdeer-introduction" id="tealdeer-introduction">Tealdeer: Introduction</a></h1>
|
||||||
|
<p>Tealdeer is a very fast implementation of
|
||||||
|
<a href="https://github.com/tldr-pages/tldr">tldr</a> in Rust: Simplified, example based
|
||||||
|
and community-driven man pages.</p>
|
||||||
|
<p><img src="screenshot-default.png" alt="Screenshot" /></p>
|
||||||
|
<p>This documentation shows how to install, use and configure tealdeer.</p>
|
||||||
|
<h2><a class="header" href="#links" id="links">Links</a></h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="https://github.com/tealdeer-rs/tealdeer">GitHub Project Page</a></li>
|
||||||
|
<li><a href="https://tldr.sh/">TLDR Pages Project</a></li>
|
||||||
|
</ul>
|
||||||
|
<h1><a class="header" href="#installing" id="installing">Installing</a></h1>
|
||||||
|
<p>There are a few different ways to install tealdeer:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Through <a href="installing.html#package-managers">package managers</a></li>
|
||||||
|
<li>Through <a href="installing.html#static-binaries-linux">static binaries</a></li>
|
||||||
|
<li>Through <a href="installing.html#through-cargo-install">cargo install</a></li>
|
||||||
|
<li>By <a href="installing.html#build-from-source">building from source</a></li>
|
||||||
|
</ul>
|
||||||
|
<p>Additionally, when not using system packages, you can <a href="installing.html#autocompletion">manually install
|
||||||
|
autocompletions</a>.</p>
|
||||||
|
<h2><a class="header" href="#package-managers" id="package-managers">Package Managers</a></h2>
|
||||||
|
<p>Tealdeer has been added to a few package managers:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Arch Linux: <a href="https://archlinux.org/packages/extra/x86_64/tealdeer/"><code>tealdeer</code></a></li>
|
||||||
|
<li>Debian: <a href="https://tracker.debian.org/tealdeer"><code>tealdeer</code></a></li>
|
||||||
|
<li>Fedora: <a href="https://src.fedoraproject.org/rpms/rust-tealdeer"><code>tealdeer</code></a></li>
|
||||||
|
<li>FreeBSD: <a href="https://www.freshports.org/sysutils/tealdeer/"><code>sysutils/tealdeer</code></a></li>
|
||||||
|
<li>Funtoo: <a href="https://github.com/funtoo/core-kit/tree/1.4-release/app-misc/tealdeer"><code>app-misc/tealdeer</code></a></li>
|
||||||
|
<li>Homebrew: <a href="https://formulae.brew.sh/formula/tealdeer"><code>tealdeer</code></a></li>
|
||||||
|
<li>MacPorts: <a href="https://ports.macports.org/port/tealdeer/"><code>tealdeer</code></a></li>
|
||||||
|
<li>NetBSD: <a href="https://pkgsrc.se/sysutils/tealdeer"><code>sysutils/tealdeer</code></a></li>
|
||||||
|
<li>Nix: <a href="https://search.nixos.org/packages?query=tealdeer"><code>tealdeer</code></a></li>
|
||||||
|
<li>openSUSE: <a href="https://software.opensuse.org/package/tealdeer?search_term=tealdeer"><code>tealdeer</code></a></li>
|
||||||
|
<li>Scoop: <a href="https://github.com/ScoopInstaller/Main/blob/master/bucket/tealdeer.json"><code>tealdeer</code></a></li>
|
||||||
|
<li>Solus: <a href="https://packages.getsol.us/shannon/t/tealdeer/"><code>tealdeer</code></a></li>
|
||||||
|
<li>Void Linux: <a href="https://github.com/void-linux/void-packages/tree/master/srcpkgs/tealdeer"><code>tealdeer</code></a></li>
|
||||||
|
</ul>
|
||||||
|
<h2><a class="header" href="#static-binaries-linux" id="static-binaries-linux">Static Binaries (Linux)</a></h2>
|
||||||
|
<p>Static binary builds (currently for Linux only) are available on the
|
||||||
|
<a href="https://github.com/tealdeer-rs/tealdeer/releases">GitHub releases page</a>.
|
||||||
|
Simply download the binary for your platform and run it!</p>
|
||||||
|
<h2><a class="header" href="#through-cargo-install" id="through-cargo-install">Through <code>cargo install</code></a></h2>
|
||||||
|
<p>Build and install the tool via cargo...</p>
|
||||||
|
<pre><code class="language-shell">$ cargo install tealdeer
|
||||||
|
</code></pre>
|
||||||
|
<h2><a class="header" href="#build-from-source" id="build-from-source">Build From Source</a></h2>
|
||||||
|
<p>Release build:</p>
|
||||||
|
<pre><code class="language-shell">$ cargo build --release
|
||||||
|
</code></pre>
|
||||||
|
<p>Release build with native TLS support:</p>
|
||||||
|
<pre><code class="language-shell">$ cargo build --release --features native-tls
|
||||||
|
</code></pre>
|
||||||
|
<p>Debug build with logging support:</p>
|
||||||
|
<pre><code class="language-shell">$ cargo build --features logging
|
||||||
|
</code></pre>
|
||||||
|
<p>(To enable logging at runtime, export the <code>RUST_LOG=tldr=debug</code> env variable.)</p>
|
||||||
|
<h2><a class="header" href="#autocompletion" id="autocompletion">Autocompletion</a></h2>
|
||||||
|
<p>Shell completion scripts are located in the folder <code>completion</code>.
|
||||||
|
Just copy them to their designated location:</p>
|
||||||
|
<ul>
|
||||||
|
<li><em>Bash</em>: <code>cp completion/bash_tealdeer /usr/share/bash-completion/completions/tldr</code></li>
|
||||||
|
<li><em>Fish</em>: <code>cp completion/fish_tealdeer ~/.config/fish/completions/tldr.fish</code></li>
|
||||||
|
<li><em>Zsh</em>: <code>cp completion/zsh_tealdeer /usr/share/zsh/site-functions/_tldr</code></li>
|
||||||
|
</ul>
|
||||||
|
<h1><a class="header" href="#usage" id="usage">Usage</a></h1>
|
||||||
|
<p>Tealdeer is straightforward to use, through the binary named <code>tldr</code>.</p>
|
||||||
|
<p>You can view the available options using <code>tldr --help</code>:</p>
|
||||||
|
<!-- Note: To update the file below, run `cargo run -- --help > docs/src/usage.txt`. -->
|
||||||
|
<pre><code>tealdeer 1.8.1: A fast TLDR client
|
||||||
|
Danilo Bargen <mail@dbrgn.ch>, Niklas Mohrin <dev@niklasmohrin.de>
|
||||||
|
|
||||||
|
Usage: tldr [OPTIONS] [COMMAND]...
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
[COMMAND]... The command to show (e.g. `tar` or `git log`)
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-l, --list List all commands in the cache
|
||||||
|
--edit-page Edit custom page with `EDITOR`
|
||||||
|
--edit-patch Edit custom patch with `EDITOR`
|
||||||
|
-f, --render <FILE> Render a specific markdown file
|
||||||
|
-p, --platform <PLATFORM> Override the operating system, can be specified multiple times in order
|
||||||
|
of preference [possible values: linux, macos, sunos, windows, android,
|
||||||
|
freebsd, netbsd, openbsd, common]
|
||||||
|
-L, --language <LANGUAGE> Override the language
|
||||||
|
-u, --update Update the local cache
|
||||||
|
--no-auto-update If auto update is configured, disable it for this run
|
||||||
|
-c, --clear-cache Clear the local cache
|
||||||
|
--config-path <FILE> Override config file location
|
||||||
|
--pager Use a pager to page output
|
||||||
|
-r, --raw Display the raw markdown instead of rendering it
|
||||||
|
-q, --quiet Suppress informational messages
|
||||||
|
--show-paths Show file and directory paths used by tealdeer
|
||||||
|
--seed-config Create a basic config
|
||||||
|
--color <WHEN> Control whether to use color [possible values: always, auto, never]
|
||||||
|
-v, --version Print the version
|
||||||
|
-h, --help Print help
|
||||||
|
|
||||||
|
To view the user documentation, please visit https://tealdeer-rs.github.io/tealdeer/.
|
||||||
|
</code></pre>
|
||||||
|
<h1><a class="header" href="#custom-pages-and-patches" id="custom-pages-and-patches">Custom Pages and Patches</a></h1>
|
||||||
|
<blockquote>
|
||||||
|
<p>⚠️ <strong>Breaking change in version 1.7.0:</strong> The file name extension for custom
|
||||||
|
pages and patches was changed:</p>
|
||||||
|
<ul>
|
||||||
|
<li><code><name>.page</code> → <code><name>.page.md</code></li>
|
||||||
|
<li><code><name>.patch</code> → <code><name>.patch.md</code></li>
|
||||||
|
</ul>
|
||||||
|
<p>If you have custom pages or patches, you need to rename them.</p>
|
||||||
|
</blockquote>
|
||||||
|
<p>Tealdeer allows creating new custom pages, overriding existing pages as well as
|
||||||
|
extending existing pages.</p>
|
||||||
|
<p>The directory, where these custom pages and patches can be placed, follows OS
|
||||||
|
conventions. On Linux for instance, the default location is
|
||||||
|
<code>~/.local/share/tealdeer/pages/</code>. To print the path used on your system, simply
|
||||||
|
run <code>tldr --show-paths</code>.</p>
|
||||||
|
<p>The custom pages directory can be <a href="config_directories.html">overridden by the config
|
||||||
|
file</a>.</p>
|
||||||
|
<h2><a class="header" href="#custom-pages" id="custom-pages">Custom Pages</a></h2>
|
||||||
|
<p>To document internal command line tools, or if you want to replace an existing
|
||||||
|
tldr page with one that's better suited for you, place a file with the name
|
||||||
|
<code><command>.page.md</code> in the custom pages directory. When calling <code>tldr <command></code>,
|
||||||
|
your custom page will be shown instead of the upstream version in the cache.</p>
|
||||||
|
<p>Path:</p>
|
||||||
|
<pre><code class="language-plain">$CUSTOM_PAGES_DIR/<command>.page.md
|
||||||
|
</code></pre>
|
||||||
|
<p>Example:</p>
|
||||||
|
<pre><code class="language-plain">~/.local/share/tealdeer/pages/ufw.page.md
|
||||||
|
</code></pre>
|
||||||
|
<h2><a class="header" href="#custom-patches" id="custom-patches">Custom Patches</a></h2>
|
||||||
|
<p>Sometimes you don't want to fully replace an existing upstream page, but just
|
||||||
|
want to extend it with your own examples that you frequently need. In this
|
||||||
|
case, use a file called <code><command>.patch.md</code>, it will be appended to existing
|
||||||
|
pages.</p>
|
||||||
|
<p>Path:</p>
|
||||||
|
<pre><code class="language-plain">$CUSTOM_PAGES_DIR/<command>.patch.md
|
||||||
|
</code></pre>
|
||||||
|
<p>Example:</p>
|
||||||
|
<pre><code class="language-plain">~/.local/share/tealdeer/pages/ufw.patch.md
|
||||||
|
</code></pre>
|
||||||
|
<h1><a class="header" href="#configuration" id="configuration">Configuration</a></h1>
|
||||||
|
<p>Tealdeer can be customized with a config file in <a href="https://toml.io/">TOML
|
||||||
|
format</a> called <code>config.toml</code>.</p>
|
||||||
|
<h2><a class="header" href="#configfile-path" id="configfile-path">Configfile Path</a></h2>
|
||||||
|
<p>The configuration file path follows OS conventions (e.g.
|
||||||
|
<code>$XDG_CONFIG_HOME/tealdeer/config.toml</code> on Linux). The paths can be queried
|
||||||
|
with the following command:</p>
|
||||||
|
<pre><code class="language-shell">$ tldr --show-paths
|
||||||
|
</code></pre>
|
||||||
|
<p>Creating the config file can be done manually or with the help of <code>tldr</code>:</p>
|
||||||
|
<pre><code class="language-shell">$ tldr --seed-config
|
||||||
|
</code></pre>
|
||||||
|
<p>On Linux, this will usually be <code>~/.config/tealdeer/config.toml</code>.</p>
|
||||||
|
<h2><a class="header" href="#config-example" id="config-example">Config Example</a></h2>
|
||||||
|
<p>Here's an example configuration file. Note that this example does not contain
|
||||||
|
all possible config options. For details on the things that can be configured,
|
||||||
|
please refer to the subsections of this documentation page
|
||||||
|
(<a href="config_display.html">display</a>, <a href="config_style.html">style</a>, <a href="config_search.html">search</a>,
|
||||||
|
<a href="config_updates.html">updates</a> or <a href="config_directories.html">directories</a>).</p>
|
||||||
|
<pre><code class="language-toml">[display]
|
||||||
|
compact = false
|
||||||
|
use_pager = true
|
||||||
|
show_title = false
|
||||||
|
|
||||||
|
[style.command_name]
|
||||||
|
foreground = "red"
|
||||||
|
|
||||||
|
[style.example_text]
|
||||||
|
foreground = "green"
|
||||||
|
|
||||||
|
[style.example_code]
|
||||||
|
foreground = "blue"
|
||||||
|
|
||||||
|
[style.example_variable]
|
||||||
|
foreground = "blue"
|
||||||
|
underline = true
|
||||||
|
|
||||||
|
[updates]
|
||||||
|
auto_update = true
|
||||||
|
</code></pre>
|
||||||
|
<h2><a class="header" href="#override-config-directory" id="override-config-directory">Override Config Directory</a></h2>
|
||||||
|
<p>The directory where the configuration file resides may be overwritten by the
|
||||||
|
environment variable <code>TEALDEER_CONFIG_DIR</code>. Remember to use an absolute path.
|
||||||
|
Variable expansion will not be performed on the path.</p>
|
||||||
|
<h1><a class="header" href="#section-display" id="section-display">Section: [display]</a></h1>
|
||||||
|
<p>In the <code>display</code> section you can configure the output format.</p>
|
||||||
|
<h2><a class="header" href="#use_pager" id="use_pager"><code>use_pager</code></a></h2>
|
||||||
|
<p>Specifies whether the pager should be used by default or not (default <code>false</code>).</p>
|
||||||
|
<pre><code class="language-toml">[display]
|
||||||
|
use_pager = true
|
||||||
|
</code></pre>
|
||||||
|
<p>When enabled, <code>less -R</code> is used as pager. To override the pager command used,
|
||||||
|
set the <code>PAGER</code> environment variable.</p>
|
||||||
|
<p>NOTE: This feature is not available on Windows.</p>
|
||||||
|
<h2><a class="header" href="#compact" id="compact"><code>compact</code></a></h2>
|
||||||
|
<p>Set this to enforce more compact output, where empty lines are stripped out
|
||||||
|
(default <code>false</code>).</p>
|
||||||
|
<pre><code class="language-toml">[display]
|
||||||
|
compact = true
|
||||||
|
</code></pre>
|
||||||
|
<h2><a class="header" href="#show_title" id="show_title"><code>show_title</code></a></h2>
|
||||||
|
<p>Display the command name at the top of the page output (default <code>false</code>).</p>
|
||||||
|
<pre><code class="language-toml">[display]
|
||||||
|
show_title = true
|
||||||
|
</code></pre>
|
||||||
|
<p>When enabled, the command name will be displayed at the top of the output,
|
||||||
|
styled with the <code>command_name</code> style configuration.</p>
|
||||||
|
<h1><a class="header" href="#section-style" id="section-style">Section: [style]</a></h1>
|
||||||
|
<p>Using the config file, the style (e.g. colors or underlines) can be customized.</p>
|
||||||
|
<img src="screenshot-custom.png" alt="Screenshot of customized version" width="600">
|
||||||
|
<h2><a class="header" href="#style-targets" id="style-targets">Style Targets</a></h2>
|
||||||
|
<ul>
|
||||||
|
<li><code>description</code>: The initial description text</li>
|
||||||
|
<li><code>command_name</code>: The command name as part of the example code</li>
|
||||||
|
<li><code>example_text</code>: The text that describes an example</li>
|
||||||
|
<li><code>example_code</code>: The example itself (except the <code>command_name</code> and <code>example_variable</code>)</li>
|
||||||
|
<li><code>example_variable</code>: The variables in the example</li>
|
||||||
|
</ul>
|
||||||
|
<h2><a class="header" href="#attributes" id="attributes">Attributes</a></h2>
|
||||||
|
<ul>
|
||||||
|
<li><code>foreground</code> (color string, ANSI code, or RGB, see below)</li>
|
||||||
|
<li><code>background</code> (color string, ANSI code, or RGB, see below)</li>
|
||||||
|
<li><code>underline</code> (<code>true</code> or <code>false</code>)</li>
|
||||||
|
<li><code>bold</code> (<code>true</code> or <code>false</code>)</li>
|
||||||
|
<li><code>italic</code> (<code>true</code> or <code>false</code>)</li>
|
||||||
|
</ul>
|
||||||
|
<p>Colors can be specified in one of three ways:</p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<p>Color string (<code>black</code>, <code>red</code>, <code>green</code>, <code>yellow</code>, <code>blue</code>, <code>magenta</code>, <code>cyan</code>, <code>white</code>):</p>
|
||||||
|
<p>Example:</p>
|
||||||
|
<pre><code class="language-toml">foreground = "green"
|
||||||
|
</code></pre>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p>256 color ANSI code (<em>tealdeer v1.5.0+</em>)</p>
|
||||||
|
<p>Example:</p>
|
||||||
|
<pre><code class="language-toml">foreground = { ansi = 4 }
|
||||||
|
</code></pre>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p>24-bit RGB color (<em>tealdeer v1.5.0+</em>)</p>
|
||||||
|
<p>Example:</p>
|
||||||
|
<pre><code class="language-toml">background = { rgb = { r = 255, g = 255, b = 255 } }
|
||||||
|
</code></pre>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<h1><a class="header" href="#section-search" id="section-search">Section: [search]</a></h1>
|
||||||
|
<p>This config section is used to configure the page search in the cache.
|
||||||
|
The settings apply to <code>tldr <page></code> and <code>tldr --list</code>.</p>
|
||||||
|
<h2><a class="header" href="#languages" id="languages"><code>languages</code></a></h2>
|
||||||
|
<p>The list of languages that should be considered when searching.
|
||||||
|
If unspecified, the list of languages will be inferred from the <code>LANG</code> and <code>LANGUAGE</code> environment variables.
|
||||||
|
Either way, the language used can be overwritten using the <code>--language</code> command line flag.</p>
|
||||||
|
<pre><code class="language-toml">[search]
|
||||||
|
# Show pages in German if available, otherwise show in English
|
||||||
|
languages = ["de", "en"]
|
||||||
|
</code></pre>
|
||||||
|
<h2><a class="header" href="#platforms" id="platforms"><code>platforms</code></a></h2>
|
||||||
|
<p>The list of platforms that should be considered when searching.
|
||||||
|
In addition to the platforms listed in the help text of the <code>--platform</code> flag, there are two special platforms available:</p>
|
||||||
|
<ul>
|
||||||
|
<li><code>"current"</code>: equals the platform that tealdeer was compiled for</li>
|
||||||
|
<li><code>"all"</code>: adds all remaining platforms to the list</li>
|
||||||
|
</ul>
|
||||||
|
<p>Tealdeer searches the platforms in order of appearance in this list.
|
||||||
|
The default list of platforms is <code>["current", "common", "all"]</code>.
|
||||||
|
The list of platforms can be overwritten using the <code>--platform</code> command line flag.</p>
|
||||||
|
<pre><code class="language-toml">[search]
|
||||||
|
# Search for linux and common, and then search windows before trying the remaining platforms
|
||||||
|
platforms = ["linux", "common", "windows", "all"]
|
||||||
|
</code></pre>
|
||||||
|
<h1><a class="header" href="#section-updates" id="section-updates">Section: [updates]</a></h1>
|
||||||
|
<p>This config section contains settings related to updating the tealdeer cache.</p>
|
||||||
|
<h2><a class="header" href="#automatic-updates" id="automatic-updates">Automatic updates</a></h2>
|
||||||
|
<p>Tealdeer can refresh the cache automatically when it is outdated. This
|
||||||
|
behavior can be configured in the <code>updates</code> section and is disabled by
|
||||||
|
default.</p>
|
||||||
|
<h3><a class="header" href="#auto_update" id="auto_update"><code>auto_update</code></a></h3>
|
||||||
|
<p>Specifies whether the auto-update feature should be enabled (defaults to
|
||||||
|
<code>false</code>).</p>
|
||||||
|
<pre><code class="language-toml">[updates]
|
||||||
|
auto_update = true
|
||||||
|
</code></pre>
|
||||||
|
<h3><a class="header" href="#auto_update_interval_hours" id="auto_update_interval_hours"><code>auto_update_interval_hours</code></a></h3>
|
||||||
|
<p>Duration, since the last cache update, after which the cache will be
|
||||||
|
refreshed (defaults to 720 hours). This parameter is ignored if <code>auto_update</code>
|
||||||
|
is set to <code>false</code>.</p>
|
||||||
|
<pre><code class="language-toml">[updates]
|
||||||
|
auto_update = true
|
||||||
|
auto_update_interval_hours = 24
|
||||||
|
</code></pre>
|
||||||
|
<h2><a class="header" href="#download-configuration" id="download-configuration">Download configuration</a></h2>
|
||||||
|
<h3><a class="header" href="#download_languages" id="download_languages"><code>download_languages</code></a></h3>
|
||||||
|
<p>The list of languages which should be downloaded when updating.
|
||||||
|
If unspecified, the languages listed in the <code>search.languages</code> setting are used.
|
||||||
|
Thus, this setting is the most useful to instruct tealdeer to download pages in additional languages that are not searched by default.
|
||||||
|
Either way, the language used can be overwritten using the <code>--language</code> command line flag.</p>
|
||||||
|
<pre><code class="language-toml">[search]
|
||||||
|
languages = ["de", "en"]
|
||||||
|
|
||||||
|
[updates]
|
||||||
|
# sometimes I like to read the Italian description
|
||||||
|
download_languages = ["de", "en", "it"]
|
||||||
|
</code></pre>
|
||||||
|
<h3><a class="header" href="#archive_source" id="archive_source"><code>archive_source</code></a></h3>
|
||||||
|
<p>URL for the location of the tldr pages archive. By default the pages are
|
||||||
|
fetched from the latest <code>tldr-pages/tldr</code> GitHub release.</p>
|
||||||
|
<pre><code class="language-toml">[updates]
|
||||||
|
archive_source = "https://my-company.example.com/tldr/"
|
||||||
|
</code></pre>
|
||||||
|
<h3><a class="header" href="#tls_backend" id="tls_backend"><code>tls_backend</code></a></h3>
|
||||||
|
<p>Specifies which TLS backend to use. Try changing this setting if you encounter certificate errors.</p>
|
||||||
|
<p>Available options:</p>
|
||||||
|
<ul>
|
||||||
|
<li><code>rustls-with-native-roots</code> - <a href="https://github.com/rustls/rustls">Rustls</a> (a TLS library in Rust) with native roots</li>
|
||||||
|
<li><code>rustls-with-webpki-roots</code> - Rustls with <a href="https://github.com/rustls/webpki">WebPKI</a> roots</li>
|
||||||
|
<li><code>native-tls</code> - Native TLS
|
||||||
|
<ul>
|
||||||
|
<li>SChannel on Windows</li>
|
||||||
|
<li>Secure Transport on macOS</li>
|
||||||
|
<li>OpenSSL on other platforms</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<pre><code class="language-toml">[updates]
|
||||||
|
tls_backend = "native-tls"
|
||||||
|
</code></pre>
|
||||||
|
<h1><a class="header" href="#section-directories" id="section-directories">Section: [directories]</a></h1>
|
||||||
|
<p>This section allows overriding some directory paths.</p>
|
||||||
|
<h2><a class="header" href="#cache_dir" id="cache_dir"><code>cache_dir</code></a></h2>
|
||||||
|
<p>Override the cache directory. Remember to use an absolute path. Variable
|
||||||
|
expansion will not be performed on the path. If the directory does not yet
|
||||||
|
exist, it will be created.</p>
|
||||||
|
<pre><code class="language-toml">[directories]
|
||||||
|
cache_dir = "/home/myuser/.tealdeer-cache/"
|
||||||
|
</code></pre>
|
||||||
|
<p>If no <code>cache_dir</code> is specified, tealdeer will fall back to a location that
|
||||||
|
follows OS conventions. On Linux, it will usually be at <code>~/.cache/tealdeer/</code>.
|
||||||
|
Use <code>tldr --show-paths</code> to show the path that is being used.</p>
|
||||||
|
<h2><a class="header" href="#custom_pages_dir" id="custom_pages_dir"><code>custom_pages_dir</code></a></h2>
|
||||||
|
<p>Set the directory to be used to look up <a href="usage_custom_pages.html">custom
|
||||||
|
pages</a>. Remember to use an absolute path. Variable
|
||||||
|
expansion will not be performed on the path.</p>
|
||||||
|
<pre><code class="language-toml">[directories]
|
||||||
|
custom_pages_dir = "/home/myuser/custom-tldr-pages/"
|
||||||
|
</code></pre>
|
||||||
|
<h1><a class="header" href="#tips-and-tricks" id="tips-and-tricks">Tips and Tricks</a></h1>
|
||||||
|
<p>This page features some example use cases of Tealdeer.</p>
|
||||||
|
<h2><a class="header" href="#showing-a-random-page-on-shell-start" id="showing-a-random-page-on-shell-start">Showing a random page on shell start</a></h2>
|
||||||
|
<p>To display a randomly selected page, you can invoke <code>tldr</code> twice: One time to
|
||||||
|
select a page and a second time to display this page. To randomly select a page,
|
||||||
|
we use <code>shuf</code> from the GNU coreutils:</p>
|
||||||
|
<pre><code class="language-bash">tldr --quiet $(tldr --quiet --list | shuf -n1)
|
||||||
|
</code></pre>
|
||||||
|
<p>You can also add the above command to your <code>.bashrc</code> (or similar shell
|
||||||
|
configuration file) to display a random page every time you start a new shell
|
||||||
|
session.</p>
|
||||||
|
<h2><a class="header" href="#displaying-all-pages-with-their-summary" id="displaying-all-pages-with-their-summary">Displaying all pages with their summary</a></h2>
|
||||||
|
<p>If you want to extend the output of <code>tldr --list</code> with the first line summary of
|
||||||
|
each page, you can run the following Python script:</p>
|
||||||
|
<pre><code class="language-python">#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
commands = subprocess.run(
|
||||||
|
["tldr", "--quiet", "--list"],
|
||||||
|
capture_output=True,
|
||||||
|
encoding="utf-8",
|
||||||
|
).stdout.splitlines()
|
||||||
|
|
||||||
|
for command in commands:
|
||||||
|
output = subprocess.run(
|
||||||
|
["tldr", "--quiet", command],
|
||||||
|
capture_output=True,
|
||||||
|
encoding="utf-8",
|
||||||
|
).stdout
|
||||||
|
description = output.lstrip().split("\n\n")[0]
|
||||||
|
description = " ".join(description.split())
|
||||||
|
print(f"{command} => {description}")
|
||||||
|
</code></pre>
|
||||||
|
<p>Note that there are a lot of pages and the script will run Tealdeer once for
|
||||||
|
every page, so the script may take a couple of seconds to finish.</p>
|
||||||
|
<h2><a class="header" href="#extending-this-chapter" id="extending-this-chapter">Extending this chapter</a></h2>
|
||||||
|
<p>If you have an interesting setup with Tealdeer, feel free to share your
|
||||||
|
configuration on <a href="https://github.com/tealdeer-rs/tealdeer">our Github repository</a>.</p>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||||
|
<!-- Mobile navigation buttons -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div style="clear: both"></div>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
window.playground_copyable = true;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="searcher.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="highlight.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="book.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
||||||
|
<!-- Custom JS scripts -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
window.addEventListener('load', function() {
|
||||||
|
window.setTimeout(window.print, 100);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
# Empty file, use defaults and disregard global settings
|
|
||||||
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
|
|
@ -1,88 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
#
|
|
||||||
# Upload artifacts to GitHub Actions.
|
|
||||||
#
|
|
||||||
# Based on: https://gist.github.com/schell/2fe896953b6728cc3c5d8d5f9f3a17a3
|
|
||||||
#
|
|
||||||
# Requires curl and jq on PATH
|
|
||||||
|
|
||||||
# Args:
|
|
||||||
# token: GitHub API user token
|
|
||||||
# repo: GitHub username/reponame
|
|
||||||
# tag: Name of the tag for which to create a release
|
|
||||||
# description: Release description
|
|
||||||
create_release() {
|
|
||||||
# Args
|
|
||||||
token=$1
|
|
||||||
repo=$2
|
|
||||||
tag=$3
|
|
||||||
description=$4
|
|
||||||
echo "Creating release:"
|
|
||||||
echo " repo=$repo"
|
|
||||||
echo " tag=$tag"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Create release
|
|
||||||
http_code=$(
|
|
||||||
curl -s -o create.json -w '%{http_code}' \
|
|
||||||
--header "Accept: application/vnd.github.v3+json" \
|
|
||||||
--header "Authorization: Bearer $token" \
|
|
||||||
--header "Content-Type:application/json" \
|
|
||||||
"https://api.github.com/repos/$repo/releases" \
|
|
||||||
-d '{"tag_name":"'"$tag"'","name":"'"${tag/v/Version }"'","draft":true,"body":"'"${description/\"/\\\"}"'"}'
|
|
||||||
)
|
|
||||||
if [ "$http_code" == "201" ]; then
|
|
||||||
echo "Release for tag $tag created."
|
|
||||||
else
|
|
||||||
echo "Asset upload failed with code '$http_code'."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Args:
|
|
||||||
# token: GitHub API user token
|
|
||||||
# repo: GitHub username/reponame
|
|
||||||
# tag: Name of the tag for which to upload the assets
|
|
||||||
# file: Path to the asset file to upload
|
|
||||||
# name: Name to use for the uploaded asset
|
|
||||||
upload_release_file() {
|
|
||||||
# Args
|
|
||||||
token=$1
|
|
||||||
repo=$2
|
|
||||||
tag=$3
|
|
||||||
file=$4
|
|
||||||
name=$5
|
|
||||||
echo "Uploading:"
|
|
||||||
echo " repo=$repo"
|
|
||||||
echo " tag=$tag"
|
|
||||||
echo " file=$file"
|
|
||||||
echo " name=$name"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Determine upload URL of latest draft release for the specified tag
|
|
||||||
upload_url=$(
|
|
||||||
curl -s \
|
|
||||||
--header "Accept: application/vnd.github.v3+json" \
|
|
||||||
--header "Authorization: Bearer $token" \
|
|
||||||
"https://api.github.com/repos/$repo/releases" \
|
|
||||||
| jq -r '[.[] | select(.tag_name == "'"$tag"'" and .draft)][0].upload_url' \
|
|
||||||
| cut -d"{" -f'1'
|
|
||||||
)
|
|
||||||
echo "Determined upload URL: $upload_url"
|
|
||||||
http_code=$(
|
|
||||||
curl -s -o upload.json -w '%{http_code}' \
|
|
||||||
--request POST \
|
|
||||||
--header "Accept: application/vnd.github.v3+json" \
|
|
||||||
--header "Authorization: Bearer $token" \
|
|
||||||
--header "Content-Type: application/octet-stream" \
|
|
||||||
--data-binary "@$file" "$upload_url?name=$name"
|
|
||||||
)
|
|
||||||
if [ "$http_code" == "201" ]; then
|
|
||||||
echo "Asset $name uploaded:"
|
|
||||||
jq -r .browser_download_url upload.json
|
|
||||||
else
|
|
||||||
echo "Asset upload failed with code '$http_code':"
|
|
||||||
cat upload.json
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
477
searcher.js
Normal file
|
|
@ -0,0 +1,477 @@
|
||||||
|
"use strict";
|
||||||
|
window.search = window.search || {};
|
||||||
|
(function search(search) {
|
||||||
|
// Search functionality
|
||||||
|
//
|
||||||
|
// You can use !hasFocus() to prevent keyhandling in your key
|
||||||
|
// event handlers while the user is typing their search.
|
||||||
|
|
||||||
|
if (!Mark || !elasticlunr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//IE 11 Compatibility from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith
|
||||||
|
if (!String.prototype.startsWith) {
|
||||||
|
String.prototype.startsWith = function(search, pos) {
|
||||||
|
return this.substr(!pos || pos < 0 ? 0 : +pos, search.length) === search;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var search_wrap = document.getElementById('search-wrapper'),
|
||||||
|
searchbar = document.getElementById('searchbar'),
|
||||||
|
searchbar_outer = document.getElementById('searchbar-outer'),
|
||||||
|
searchresults = document.getElementById('searchresults'),
|
||||||
|
searchresults_outer = document.getElementById('searchresults-outer'),
|
||||||
|
searchresults_header = document.getElementById('searchresults-header'),
|
||||||
|
searchicon = document.getElementById('search-toggle'),
|
||||||
|
content = document.getElementById('content'),
|
||||||
|
|
||||||
|
searchindex = null,
|
||||||
|
doc_urls = [],
|
||||||
|
results_options = {
|
||||||
|
teaser_word_count: 30,
|
||||||
|
limit_results: 30,
|
||||||
|
},
|
||||||
|
search_options = {
|
||||||
|
bool: "AND",
|
||||||
|
expand: true,
|
||||||
|
fields: {
|
||||||
|
title: {boost: 1},
|
||||||
|
body: {boost: 1},
|
||||||
|
breadcrumbs: {boost: 0}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mark_exclude = [],
|
||||||
|
marker = new Mark(content),
|
||||||
|
current_searchterm = "",
|
||||||
|
URL_SEARCH_PARAM = 'search',
|
||||||
|
URL_MARK_PARAM = 'highlight',
|
||||||
|
teaser_count = 0,
|
||||||
|
|
||||||
|
SEARCH_HOTKEY_KEYCODE = 83,
|
||||||
|
ESCAPE_KEYCODE = 27,
|
||||||
|
DOWN_KEYCODE = 40,
|
||||||
|
UP_KEYCODE = 38,
|
||||||
|
SELECT_KEYCODE = 13;
|
||||||
|
|
||||||
|
function hasFocus() {
|
||||||
|
return searchbar === document.activeElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeChildren(elem) {
|
||||||
|
while (elem.firstChild) {
|
||||||
|
elem.removeChild(elem.firstChild);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper to parse a url into its building blocks.
|
||||||
|
function parseURL(url) {
|
||||||
|
var a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
return {
|
||||||
|
source: url,
|
||||||
|
protocol: a.protocol.replace(':',''),
|
||||||
|
host: a.hostname,
|
||||||
|
port: a.port,
|
||||||
|
params: (function(){
|
||||||
|
var ret = {};
|
||||||
|
var seg = a.search.replace(/^\?/,'').split('&');
|
||||||
|
var len = seg.length, i = 0, s;
|
||||||
|
for (;i<len;i++) {
|
||||||
|
if (!seg[i]) { continue; }
|
||||||
|
s = seg[i].split('=');
|
||||||
|
ret[s[0]] = s[1];
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
})(),
|
||||||
|
file: (a.pathname.match(/\/([^/?#]+)$/i) || [,''])[1],
|
||||||
|
hash: a.hash.replace('#',''),
|
||||||
|
path: a.pathname.replace(/^([^/])/,'/$1')
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper to recreate a url string from its building blocks.
|
||||||
|
function renderURL(urlobject) {
|
||||||
|
var url = urlobject.protocol + "://" + urlobject.host;
|
||||||
|
if (urlobject.port != "") {
|
||||||
|
url += ":" + urlobject.port;
|
||||||
|
}
|
||||||
|
url += urlobject.path;
|
||||||
|
var joiner = "?";
|
||||||
|
for(var prop in urlobject.params) {
|
||||||
|
if(urlobject.params.hasOwnProperty(prop)) {
|
||||||
|
url += joiner + prop + "=" + urlobject.params[prop];
|
||||||
|
joiner = "&";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (urlobject.hash != "") {
|
||||||
|
url += "#" + urlobject.hash;
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper to escape html special chars for displaying the teasers
|
||||||
|
var escapeHTML = (function() {
|
||||||
|
var MAP = {
|
||||||
|
'&': '&',
|
||||||
|
'<': '<',
|
||||||
|
'>': '>',
|
||||||
|
'"': '"',
|
||||||
|
"'": '''
|
||||||
|
};
|
||||||
|
var repl = function(c) { return MAP[c]; };
|
||||||
|
return function(s) {
|
||||||
|
return s.replace(/[&<>'"]/g, repl);
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
function formatSearchMetric(count, searchterm) {
|
||||||
|
if (count == 1) {
|
||||||
|
return count + " search result for '" + searchterm + "':";
|
||||||
|
} else if (count == 0) {
|
||||||
|
return "No search results for '" + searchterm + "'.";
|
||||||
|
} else {
|
||||||
|
return count + " search results for '" + searchterm + "':";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatSearchResult(result, searchterms) {
|
||||||
|
var teaser = makeTeaser(escapeHTML(result.doc.body), searchterms);
|
||||||
|
teaser_count++;
|
||||||
|
|
||||||
|
// The ?URL_MARK_PARAM= parameter belongs inbetween the page and the #heading-anchor
|
||||||
|
var url = doc_urls[result.ref].split("#");
|
||||||
|
if (url.length == 1) { // no anchor found
|
||||||
|
url.push("");
|
||||||
|
}
|
||||||
|
|
||||||
|
return '<a href="' + path_to_root + url[0] + '?' + URL_MARK_PARAM + '=' + searchterms + '#' + url[1]
|
||||||
|
+ '" aria-details="teaser_' + teaser_count + '">' + result.doc.breadcrumbs + '</a>'
|
||||||
|
+ '<span class="teaser" id="teaser_' + teaser_count + '" aria-label="Search Result Teaser">'
|
||||||
|
+ teaser + '</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeTeaser(body, searchterms) {
|
||||||
|
// The strategy is as follows:
|
||||||
|
// First, assign a value to each word in the document:
|
||||||
|
// Words that correspond to search terms (stemmer aware): 40
|
||||||
|
// Normal words: 2
|
||||||
|
// First word in a sentence: 8
|
||||||
|
// Then use a sliding window with a constant number of words and count the
|
||||||
|
// sum of the values of the words within the window. Then use the window that got the
|
||||||
|
// maximum sum. If there are multiple maximas, then get the last one.
|
||||||
|
// Enclose the terms in <em>.
|
||||||
|
var stemmed_searchterms = searchterms.map(function(w) {
|
||||||
|
return elasticlunr.stemmer(w.toLowerCase());
|
||||||
|
});
|
||||||
|
var searchterm_weight = 40;
|
||||||
|
var weighted = []; // contains elements of ["word", weight, index_in_document]
|
||||||
|
// split in sentences, then words
|
||||||
|
var sentences = body.toLowerCase().split('. ');
|
||||||
|
var index = 0;
|
||||||
|
var value = 0;
|
||||||
|
var searchterm_found = false;
|
||||||
|
for (var sentenceindex in sentences) {
|
||||||
|
var words = sentences[sentenceindex].split(' ');
|
||||||
|
value = 8;
|
||||||
|
for (var wordindex in words) {
|
||||||
|
var word = words[wordindex];
|
||||||
|
if (word.length > 0) {
|
||||||
|
for (var searchtermindex in stemmed_searchterms) {
|
||||||
|
if (elasticlunr.stemmer(word).startsWith(stemmed_searchterms[searchtermindex])) {
|
||||||
|
value = searchterm_weight;
|
||||||
|
searchterm_found = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
weighted.push([word, value, index]);
|
||||||
|
value = 2;
|
||||||
|
}
|
||||||
|
index += word.length;
|
||||||
|
index += 1; // ' ' or '.' if last word in sentence
|
||||||
|
};
|
||||||
|
index += 1; // because we split at a two-char boundary '. '
|
||||||
|
};
|
||||||
|
|
||||||
|
if (weighted.length == 0) {
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
var window_weight = [];
|
||||||
|
var window_size = Math.min(weighted.length, results_options.teaser_word_count);
|
||||||
|
|
||||||
|
var cur_sum = 0;
|
||||||
|
for (var wordindex = 0; wordindex < window_size; wordindex++) {
|
||||||
|
cur_sum += weighted[wordindex][1];
|
||||||
|
};
|
||||||
|
window_weight.push(cur_sum);
|
||||||
|
for (var wordindex = 0; wordindex < weighted.length - window_size; wordindex++) {
|
||||||
|
cur_sum -= weighted[wordindex][1];
|
||||||
|
cur_sum += weighted[wordindex + window_size][1];
|
||||||
|
window_weight.push(cur_sum);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (searchterm_found) {
|
||||||
|
var max_sum = 0;
|
||||||
|
var max_sum_window_index = 0;
|
||||||
|
// backwards
|
||||||
|
for (var i = window_weight.length - 1; i >= 0; i--) {
|
||||||
|
if (window_weight[i] > max_sum) {
|
||||||
|
max_sum = window_weight[i];
|
||||||
|
max_sum_window_index = i;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
max_sum_window_index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add <em/> around searchterms
|
||||||
|
var teaser_split = [];
|
||||||
|
var index = weighted[max_sum_window_index][2];
|
||||||
|
for (var i = max_sum_window_index; i < max_sum_window_index+window_size; i++) {
|
||||||
|
var word = weighted[i];
|
||||||
|
if (index < word[2]) {
|
||||||
|
// missing text from index to start of `word`
|
||||||
|
teaser_split.push(body.substring(index, word[2]));
|
||||||
|
index = word[2];
|
||||||
|
}
|
||||||
|
if (word[1] == searchterm_weight) {
|
||||||
|
teaser_split.push("<em>")
|
||||||
|
}
|
||||||
|
index = word[2] + word[0].length;
|
||||||
|
teaser_split.push(body.substring(word[2], index));
|
||||||
|
if (word[1] == searchterm_weight) {
|
||||||
|
teaser_split.push("</em>")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return teaser_split.join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
function init(config) {
|
||||||
|
results_options = config.results_options;
|
||||||
|
search_options = config.search_options;
|
||||||
|
searchbar_outer = config.searchbar_outer;
|
||||||
|
doc_urls = config.doc_urls;
|
||||||
|
searchindex = elasticlunr.Index.load(config.index);
|
||||||
|
|
||||||
|
// Set up events
|
||||||
|
searchicon.addEventListener('click', function(e) { searchIconClickHandler(); }, false);
|
||||||
|
searchbar.addEventListener('keyup', function(e) { searchbarKeyUpHandler(); }, false);
|
||||||
|
document.addEventListener('keydown', function(e) { globalKeyHandler(e); }, false);
|
||||||
|
// If the user uses the browser buttons, do the same as if a reload happened
|
||||||
|
window.onpopstate = function(e) { doSearchOrMarkFromUrl(); };
|
||||||
|
// Suppress "submit" events so the page doesn't reload when the user presses Enter
|
||||||
|
document.addEventListener('submit', function(e) { e.preventDefault(); }, false);
|
||||||
|
|
||||||
|
// If reloaded, do the search or mark again, depending on the current url parameters
|
||||||
|
doSearchOrMarkFromUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
function unfocusSearchbar() {
|
||||||
|
// hacky, but just focusing a div only works once
|
||||||
|
var tmp = document.createElement('input');
|
||||||
|
tmp.setAttribute('style', 'position: absolute; opacity: 0;');
|
||||||
|
searchicon.appendChild(tmp);
|
||||||
|
tmp.focus();
|
||||||
|
tmp.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
// On reload or browser history backwards/forwards events, parse the url and do search or mark
|
||||||
|
function doSearchOrMarkFromUrl() {
|
||||||
|
// Check current URL for search request
|
||||||
|
var url = parseURL(window.location.href);
|
||||||
|
if (url.params.hasOwnProperty(URL_SEARCH_PARAM)
|
||||||
|
&& url.params[URL_SEARCH_PARAM] != "") {
|
||||||
|
showSearch(true);
|
||||||
|
searchbar.value = decodeURIComponent(
|
||||||
|
(url.params[URL_SEARCH_PARAM]+'').replace(/\+/g, '%20'));
|
||||||
|
searchbarKeyUpHandler(); // -> doSearch()
|
||||||
|
} else {
|
||||||
|
showSearch(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (url.params.hasOwnProperty(URL_MARK_PARAM)) {
|
||||||
|
var words = url.params[URL_MARK_PARAM].split(' ');
|
||||||
|
marker.mark(words, {
|
||||||
|
exclude: mark_exclude
|
||||||
|
});
|
||||||
|
|
||||||
|
var markers = document.querySelectorAll("mark");
|
||||||
|
function hide() {
|
||||||
|
for (var i = 0; i < markers.length; i++) {
|
||||||
|
markers[i].classList.add("fade-out");
|
||||||
|
window.setTimeout(function(e) { marker.unmark(); }, 300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var i = 0; i < markers.length; i++) {
|
||||||
|
markers[i].addEventListener('click', hide);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Eventhandler for keyevents on `document`
|
||||||
|
function globalKeyHandler(e) {
|
||||||
|
if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey || e.target.type === 'textarea' || e.target.type === 'text') { return; }
|
||||||
|
|
||||||
|
if (e.keyCode === ESCAPE_KEYCODE) {
|
||||||
|
e.preventDefault();
|
||||||
|
searchbar.classList.remove("active");
|
||||||
|
setSearchUrlParameters("",
|
||||||
|
(searchbar.value.trim() !== "") ? "push" : "replace");
|
||||||
|
if (hasFocus()) {
|
||||||
|
unfocusSearchbar();
|
||||||
|
}
|
||||||
|
showSearch(false);
|
||||||
|
marker.unmark();
|
||||||
|
} else if (!hasFocus() && e.keyCode === SEARCH_HOTKEY_KEYCODE) {
|
||||||
|
e.preventDefault();
|
||||||
|
showSearch(true);
|
||||||
|
window.scrollTo(0, 0);
|
||||||
|
searchbar.select();
|
||||||
|
} else if (hasFocus() && e.keyCode === DOWN_KEYCODE) {
|
||||||
|
e.preventDefault();
|
||||||
|
unfocusSearchbar();
|
||||||
|
searchresults.firstElementChild.classList.add("focus");
|
||||||
|
} else if (!hasFocus() && (e.keyCode === DOWN_KEYCODE
|
||||||
|
|| e.keyCode === UP_KEYCODE
|
||||||
|
|| e.keyCode === SELECT_KEYCODE)) {
|
||||||
|
// not `:focus` because browser does annoying scrolling
|
||||||
|
var focused = searchresults.querySelector("li.focus");
|
||||||
|
if (!focused) return;
|
||||||
|
e.preventDefault();
|
||||||
|
if (e.keyCode === DOWN_KEYCODE) {
|
||||||
|
var next = focused.nextElementSibling;
|
||||||
|
if (next) {
|
||||||
|
focused.classList.remove("focus");
|
||||||
|
next.classList.add("focus");
|
||||||
|
}
|
||||||
|
} else if (e.keyCode === UP_KEYCODE) {
|
||||||
|
focused.classList.remove("focus");
|
||||||
|
var prev = focused.previousElementSibling;
|
||||||
|
if (prev) {
|
||||||
|
prev.classList.add("focus");
|
||||||
|
} else {
|
||||||
|
searchbar.select();
|
||||||
|
}
|
||||||
|
} else { // SELECT_KEYCODE
|
||||||
|
window.location.assign(focused.querySelector('a'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showSearch(yes) {
|
||||||
|
if (yes) {
|
||||||
|
search_wrap.classList.remove('hidden');
|
||||||
|
searchicon.setAttribute('aria-expanded', 'true');
|
||||||
|
} else {
|
||||||
|
search_wrap.classList.add('hidden');
|
||||||
|
searchicon.setAttribute('aria-expanded', 'false');
|
||||||
|
var results = searchresults.children;
|
||||||
|
for (var i = 0; i < results.length; i++) {
|
||||||
|
results[i].classList.remove("focus");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showResults(yes) {
|
||||||
|
if (yes) {
|
||||||
|
searchresults_outer.classList.remove('hidden');
|
||||||
|
} else {
|
||||||
|
searchresults_outer.classList.add('hidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Eventhandler for search icon
|
||||||
|
function searchIconClickHandler() {
|
||||||
|
if (search_wrap.classList.contains('hidden')) {
|
||||||
|
showSearch(true);
|
||||||
|
window.scrollTo(0, 0);
|
||||||
|
searchbar.select();
|
||||||
|
} else {
|
||||||
|
showSearch(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Eventhandler for keyevents while the searchbar is focused
|
||||||
|
function searchbarKeyUpHandler() {
|
||||||
|
var searchterm = searchbar.value.trim();
|
||||||
|
if (searchterm != "") {
|
||||||
|
searchbar.classList.add("active");
|
||||||
|
doSearch(searchterm);
|
||||||
|
} else {
|
||||||
|
searchbar.classList.remove("active");
|
||||||
|
showResults(false);
|
||||||
|
removeChildren(searchresults);
|
||||||
|
}
|
||||||
|
|
||||||
|
setSearchUrlParameters(searchterm, "push_if_new_search_else_replace");
|
||||||
|
|
||||||
|
// Remove marks
|
||||||
|
marker.unmark();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update current url with ?URL_SEARCH_PARAM= parameter, remove ?URL_MARK_PARAM and #heading-anchor .
|
||||||
|
// `action` can be one of "push", "replace", "push_if_new_search_else_replace"
|
||||||
|
// and replaces or pushes a new browser history item.
|
||||||
|
// "push_if_new_search_else_replace" pushes if there is no `?URL_SEARCH_PARAM=abc` yet.
|
||||||
|
function setSearchUrlParameters(searchterm, action) {
|
||||||
|
var url = parseURL(window.location.href);
|
||||||
|
var first_search = ! url.params.hasOwnProperty(URL_SEARCH_PARAM);
|
||||||
|
if (searchterm != "" || action == "push_if_new_search_else_replace") {
|
||||||
|
url.params[URL_SEARCH_PARAM] = searchterm;
|
||||||
|
delete url.params[URL_MARK_PARAM];
|
||||||
|
url.hash = "";
|
||||||
|
} else {
|
||||||
|
delete url.params[URL_SEARCH_PARAM];
|
||||||
|
}
|
||||||
|
// A new search will also add a new history item, so the user can go back
|
||||||
|
// to the page prior to searching. A updated search term will only replace
|
||||||
|
// the url.
|
||||||
|
if (action == "push" || (action == "push_if_new_search_else_replace" && first_search) ) {
|
||||||
|
history.pushState({}, document.title, renderURL(url));
|
||||||
|
} else if (action == "replace" || (action == "push_if_new_search_else_replace" && !first_search) ) {
|
||||||
|
history.replaceState({}, document.title, renderURL(url));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function doSearch(searchterm) {
|
||||||
|
|
||||||
|
// Don't search the same twice
|
||||||
|
if (current_searchterm == searchterm) { return; }
|
||||||
|
else { current_searchterm = searchterm; }
|
||||||
|
|
||||||
|
if (searchindex == null) { return; }
|
||||||
|
|
||||||
|
// Do the actual search
|
||||||
|
var results = searchindex.search(searchterm, search_options);
|
||||||
|
var resultcount = Math.min(results.length, results_options.limit_results);
|
||||||
|
|
||||||
|
// Display search metrics
|
||||||
|
searchresults_header.innerText = formatSearchMetric(resultcount, searchterm);
|
||||||
|
|
||||||
|
// Clear and insert results
|
||||||
|
var searchterms = searchterm.split(' ');
|
||||||
|
removeChildren(searchresults);
|
||||||
|
for(var i = 0; i < resultcount ; i++){
|
||||||
|
var resultElem = document.createElement('li');
|
||||||
|
resultElem.innerHTML = formatSearchResult(results[i], searchterms);
|
||||||
|
searchresults.appendChild(resultElem);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display results
|
||||||
|
showResults(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch(path_to_root + 'searchindex.json')
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(json => init(json))
|
||||||
|
.catch(error => { // Try to load searchindex.js if fetch failed
|
||||||
|
var script = document.createElement('script');
|
||||||
|
script.src = path_to_root + 'searchindex.js';
|
||||||
|
script.onload = () => init(window.search);
|
||||||
|
document.head.appendChild(script);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Exported functions
|
||||||
|
search.hasFocus = hasFocus;
|
||||||
|
})(window.search);
|
||||||
1
searchindex.js
Normal file
1
searchindex.json
Normal file
432
src/cache.rs
|
|
@ -1,432 +0,0 @@
|
||||||
use std::{
|
|
||||||
fs::{self, File},
|
|
||||||
io::{Cursor, ErrorKind, Read},
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
time::{Duration, SystemTime},
|
|
||||||
};
|
|
||||||
|
|
||||||
use anyhow::{anyhow, bail, ensure, Context, Result};
|
|
||||||
use log::{debug, info};
|
|
||||||
use ureq::{
|
|
||||||
http::StatusCode,
|
|
||||||
tls::{RootCerts, TlsConfig, TlsProvider},
|
|
||||||
Agent,
|
|
||||||
};
|
|
||||||
use zip::ZipArchive;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
config::{Language, TlsBackend},
|
|
||||||
types::PlatformType,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub static TLDR_PAGES_DIR: &str = "tldr-pages";
|
|
||||||
pub static TLDR_OLD_PAGES_DIR: &str = "tldr-master";
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct CacheConfig<'a> {
|
|
||||||
pub pages_directory: &'a Path,
|
|
||||||
pub custom_pages_directory: Option<&'a Path>,
|
|
||||||
pub platforms: &'a [PlatformType],
|
|
||||||
pub search_languages: &'a [Language<'a>],
|
|
||||||
pub download_languages: &'a [Language<'a>],
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The directory backing this cache is checked to be populated at construction.
|
|
||||||
pub struct Cache<'a> {
|
|
||||||
config: CacheConfig<'a>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct PageLookupResult {
|
|
||||||
pub page_path: PathBuf,
|
|
||||||
pub patch_path: Option<PathBuf>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Cache<'a> {
|
|
||||||
/// Try opening a cache at the location given by `config.pages_directory`. If no directory
|
|
||||||
/// exists at this location, `Ok(None)` is returned.
|
|
||||||
pub fn open(config: CacheConfig<'a>) -> Result<Option<Self>> {
|
|
||||||
match config.pages_directory.metadata() {
|
|
||||||
Ok(md) => {
|
|
||||||
ensure!(
|
|
||||||
md.is_dir(),
|
|
||||||
"Cache directory `{}` exists, but is not a directory.",
|
|
||||||
config.pages_directory.display(),
|
|
||||||
);
|
|
||||||
Ok(Some(Cache { config }))
|
|
||||||
}
|
|
||||||
Err(err) if err.kind() == ErrorKind::NotFound => Ok(None),
|
|
||||||
Err(err) => Err(anyhow!(err).context(format!(
|
|
||||||
"Error getting metdata of cache directory {}",
|
|
||||||
config.pages_directory.display()
|
|
||||||
))),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Open an existing cache at `config.pages_directory` or create one if no cache resides at
|
|
||||||
/// this location. In case of success, the return value is a tuple with the `Cache` and a
|
|
||||||
/// boolean indicating whether the cache was newly created.
|
|
||||||
pub fn open_or_create(config: CacheConfig<'a>) -> Result<(Self, bool)> {
|
|
||||||
if let Some(cache) = Self::open(config.clone())? {
|
|
||||||
return Ok((cache, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
fs::create_dir_all(config.pages_directory).with_context(|| {
|
|
||||||
format!(
|
|
||||||
"Cache directory `{}` cannot be created",
|
|
||||||
config.pages_directory.display(),
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
eprintln!(
|
|
||||||
"Successfully created cache directory `{}`.",
|
|
||||||
config.pages_directory.display(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok((Cache { config }, true))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn age(&self) -> Result<Duration> {
|
|
||||||
let mtime = self.config.pages_directory.metadata()?.modified()?;
|
|
||||||
SystemTime::now()
|
|
||||||
.duration_since(mtime)
|
|
||||||
.context("Error comparing cache mtime with current time")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn find_page(&self, command: &str) -> Option<PageLookupResult> {
|
|
||||||
let page_filename = format!("{command}.md");
|
|
||||||
let patch_filename = format!("{command}.patch.md");
|
|
||||||
let custom_filename = format!("{command}.page.md");
|
|
||||||
|
|
||||||
if let Some(custom_pages_dir) = self.config.custom_pages_directory {
|
|
||||||
let custom_page = custom_pages_dir.join(custom_filename);
|
|
||||||
if custom_page.is_file() {
|
|
||||||
return Some(PageLookupResult::with_page(custom_page));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let patch_path = self
|
|
||||||
.config
|
|
||||||
.custom_pages_directory
|
|
||||||
.map(|dir| dir.join(&patch_filename))
|
|
||||||
.filter(|path| path.is_file());
|
|
||||||
|
|
||||||
for &platform in self.config.platforms {
|
|
||||||
for language in self.config.search_languages {
|
|
||||||
let mut search_path = self.config.pages_directory.to_path_buf();
|
|
||||||
search_path.push(language.directory_name());
|
|
||||||
search_path.push(platform.directory_name());
|
|
||||||
search_path.push(&page_filename);
|
|
||||||
|
|
||||||
if search_path.is_file() {
|
|
||||||
return Some(
|
|
||||||
PageLookupResult::with_page(search_path).with_optional_patch(patch_path),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn list_pages(&self) -> Result<impl IntoIterator<Item = String>> {
|
|
||||||
let mut pages = Vec::new();
|
|
||||||
|
|
||||||
let mut append_all = |directory: &Path, suffix: &str| -> Result<()> {
|
|
||||||
let Ok(file_iter) = fs::read_dir(directory) else {
|
|
||||||
return Ok(());
|
|
||||||
};
|
|
||||||
|
|
||||||
for entry in file_iter {
|
|
||||||
let entry = entry?;
|
|
||||||
if entry.file_type()?.is_file() {
|
|
||||||
let mut page_path = entry
|
|
||||||
.file_name()
|
|
||||||
.into_string()
|
|
||||||
.map_err(|_| anyhow!("Found invalid filename: {:?}", entry.path()))?;
|
|
||||||
|
|
||||||
if page_path.ends_with(suffix) {
|
|
||||||
page_path.truncate(page_path.len() - suffix.len());
|
|
||||||
pages.push(page_path);
|
|
||||||
} else {
|
|
||||||
debug!(
|
|
||||||
"Skipping page entry not ending in \".md\": {:?}",
|
|
||||||
entry.path(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut search_path = self.config.pages_directory.to_path_buf();
|
|
||||||
for language in self.config.search_languages {
|
|
||||||
search_path.push(language.directory_name());
|
|
||||||
for platform in self.config.platforms {
|
|
||||||
search_path.push(platform.directory_name());
|
|
||||||
append_all(&search_path, ".md")?;
|
|
||||||
search_path.pop();
|
|
||||||
}
|
|
||||||
search_path.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(custom_pages_dir) = self.config.custom_pages_directory {
|
|
||||||
append_all(custom_pages_dir, ".page.md")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
pages.sort_unstable();
|
|
||||||
pages.dedup();
|
|
||||||
Ok(pages)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn old_custom_pages_exist(&self) -> Result<bool> {
|
|
||||||
let Some(directory) = self.config.custom_pages_directory else {
|
|
||||||
return Ok(false);
|
|
||||||
};
|
|
||||||
let Ok(file_iter) = fs::read_dir(directory) else {
|
|
||||||
return Ok(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
for entry in file_iter {
|
|
||||||
if let Some(extension) = entry?.path().extension() {
|
|
||||||
if extension == "page" || extension == "patch" {
|
|
||||||
return Ok(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear(self) -> Result<()> {
|
|
||||||
fs::remove_dir_all(self.config.pages_directory).with_context(|| {
|
|
||||||
format!(
|
|
||||||
"Could not remove pages directory at {}",
|
|
||||||
self.config.pages_directory.display(),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Download archives for the languages in `self.config().download_languages` and replace the
|
|
||||||
/// pages directory with the newly downloaded pages. As not all languages might have pages
|
|
||||||
/// available (for example, `en_US` instead of `en`), an iterator yielding all languages which
|
|
||||||
/// were successfully downloaded is returned.
|
|
||||||
pub fn update(
|
|
||||||
&mut self,
|
|
||||||
archive_url: &str,
|
|
||||||
tls_backend: TlsBackend,
|
|
||||||
) -> Result<impl IntoIterator<Item = Language<'_>>> {
|
|
||||||
let client = Self::build_client(tls_backend);
|
|
||||||
|
|
||||||
// Download everything before deleting anything
|
|
||||||
let mut archives = self
|
|
||||||
.config
|
|
||||||
.download_languages
|
|
||||||
.iter()
|
|
||||||
.map(|&lang| {
|
|
||||||
Ok((
|
|
||||||
lang,
|
|
||||||
Self::download(
|
|
||||||
&client,
|
|
||||||
&format!("{archive_url}/tldr-{}.zip", lang.directory_name()),
|
|
||||||
)?
|
|
||||||
.map(|bytes| ZipArchive::new(Cursor::new(bytes)))
|
|
||||||
.transpose()?,
|
|
||||||
))
|
|
||||||
})
|
|
||||||
.collect::<Result<Vec<_>>>()?;
|
|
||||||
|
|
||||||
// Clear cache directory
|
|
||||||
// Note: This is not the best solution. Ideally we would download the
|
|
||||||
// archive to a temporary directory and then swap the two directories.
|
|
||||||
// But renaming a directory doesn't work across filesystems and Rust
|
|
||||||
// does not yet offer a recursive directory copying function. So for
|
|
||||||
// now, we'll use this approach.
|
|
||||||
fs::remove_dir_all(self.config.pages_directory)?;
|
|
||||||
fs::create_dir(self.config.pages_directory)?;
|
|
||||||
|
|
||||||
for (lang, archive) in &mut archives {
|
|
||||||
if let Some(archive) = archive {
|
|
||||||
info!("Extracting archive for {lang:?}");
|
|
||||||
archive.extract(self.config.pages_directory.join(lang.directory_name()))?;
|
|
||||||
} else {
|
|
||||||
info!("No archive found for {lang:?}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(archives
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|(lang, archive)| archive.is_some().then_some(lang)))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn config(&self) -> &CacheConfig<'a> {
|
|
||||||
&self.config
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PageLookupResult {
|
|
||||||
pub fn with_page(page_path: PathBuf) -> Self {
|
|
||||||
Self {
|
|
||||||
page_path,
|
|
||||||
patch_path: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_optional_patch(mut self, patch_path: Option<PathBuf>) -> Self {
|
|
||||||
self.patch_path = patch_path;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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<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()))?;
|
|
||||||
|
|
||||||
// Open patch file
|
|
||||||
let patch_file_opt = match &self.patch_path {
|
|
||||||
Some(path) => Some(
|
|
||||||
File::open(path)
|
|
||||||
.with_context(|| format!("Could not open patch file at {}", path.display()))?,
|
|
||||||
),
|
|
||||||
None => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create chained reader from file(s)
|
|
||||||
//
|
|
||||||
// Note: It might be worthwhile to create our own struct that accepts
|
|
||||||
// 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(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>
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Language<'_> {
|
|
||||||
fn directory_name(&self) -> String {
|
|
||||||
format!("pages.{}", self.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PlatformType {
|
|
||||||
fn directory_name(self) -> &'static str {
|
|
||||||
match self {
|
|
||||||
PlatformType::Linux => "linux",
|
|
||||||
PlatformType::OsX => "osx",
|
|
||||||
PlatformType::SunOs => "sunos",
|
|
||||||
PlatformType::Windows => "windows",
|
|
||||||
PlatformType::Android => "android",
|
|
||||||
PlatformType::FreeBsd => "freebsd",
|
|
||||||
PlatformType::NetBsd => "netbsd",
|
|
||||||
PlatformType::OpenBsd => "openbsd",
|
|
||||||
PlatformType::Common => "common",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Cache<'_> {
|
|
||||||
fn build_client(tls_backend: TlsBackend) -> Agent {
|
|
||||||
let tls_builder = match tls_backend {
|
|
||||||
#[cfg(feature = "native-tls")]
|
|
||||||
TlsBackend::NativeTls => TlsConfig::builder()
|
|
||||||
.provider(TlsProvider::NativeTls)
|
|
||||||
.root_certs(RootCerts::PlatformVerifier),
|
|
||||||
#[cfg(feature = "rustls-with-webpki-roots")]
|
|
||||||
TlsBackend::RustlsWithWebpkiRoots => TlsConfig::builder()
|
|
||||||
.provider(TlsProvider::Rustls)
|
|
||||||
.root_certs(RootCerts::WebPki),
|
|
||||||
#[cfg(feature = "rustls-with-native-roots")]
|
|
||||||
TlsBackend::RustlsWithNativeRoots => TlsConfig::builder()
|
|
||||||
.provider(TlsProvider::Rustls)
|
|
||||||
.root_certs(RootCerts::PlatformVerifier),
|
|
||||||
};
|
|
||||||
let config = Agent::config_builder()
|
|
||||||
.http_status_as_error(false) // because we want to handle them
|
|
||||||
.tls_config(tls_builder.build())
|
|
||||||
.build();
|
|
||||||
|
|
||||||
config.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Download the archive from the specified URL.
|
|
||||||
fn download(client: &Agent, archive_url: &str) -> Result<Option<Vec<u8>>> {
|
|
||||||
info!("Downloading archive from {archive_url}");
|
|
||||||
let response = client.get(archive_url).call();
|
|
||||||
match response {
|
|
||||||
Ok(response) if response.status().is_success() => {
|
|
||||||
let mut buf: Vec<u8> = Vec::new();
|
|
||||||
response.into_body().into_reader().read_to_end(&mut buf)?;
|
|
||||||
debug!("{} bytes downloaded", buf.len());
|
|
||||||
Ok(Some(buf))
|
|
||||||
}
|
|
||||||
Ok(response) if response.status() == StatusCode::NOT_FOUND => Ok(None),
|
|
||||||
_ => {
|
|
||||||
bail!("Could not download tldr pages from {archive_url}: {response:?}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unit Tests for cache module
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
use std::{
|
|
||||||
fs::File,
|
|
||||||
io::{Read, Write},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_reader_with_patch() {
|
|
||||||
// Write test files
|
|
||||||
let dir = tempfile::tempdir().unwrap();
|
|
||||||
let page_path = dir.path().join("test.page.md");
|
|
||||||
let patch_path = dir.path().join("test.patch.md");
|
|
||||||
{
|
|
||||||
let mut f1 = File::create(&page_path).unwrap();
|
|
||||||
f1.write_all(b"Hello\n").unwrap();
|
|
||||||
let mut f2 = File::create(&patch_path).unwrap();
|
|
||||||
f2.write_all(b"World").unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create chained reader from lookup result
|
|
||||||
let lr = PageLookupResult::with_page(page_path).with_optional_patch(Some(patch_path));
|
|
||||||
let mut reader = lr.reader().unwrap();
|
|
||||||
|
|
||||||
// Read into a Vec
|
|
||||||
let mut buf = Vec::new();
|
|
||||||
reader.read_to_end(&mut buf).unwrap();
|
|
||||||
|
|
||||||
assert_eq!(&buf, b"Hello\n\nWorld");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_reader_without_patch() {
|
|
||||||
// Write test file
|
|
||||||
let dir = tempfile::tempdir().unwrap();
|
|
||||||
let page_path = dir.path().join("test.page.md");
|
|
||||||
{
|
|
||||||
let mut f = File::create(&page_path).unwrap();
|
|
||||||
f.write_all(b"Hello\n").unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create chained reader from lookup result
|
|
||||||
let lr = PageLookupResult::with_page(page_path);
|
|
||||||
let mut reader = lr.reader().unwrap();
|
|
||||||
|
|
||||||
// Read into a Vec
|
|
||||||
let mut buf = Vec::new();
|
|
||||||
reader.read_to_end(&mut buf).unwrap();
|
|
||||||
|
|
||||||
assert_eq!(&buf, b"Hello\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
112
src/cli.rs
|
|
@ -1,112 +0,0 @@
|
||||||
//! Definition of the CLI arguments and options.
|
|
||||||
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use clap::{builder::ArgAction, ArgGroup, Parser};
|
|
||||||
|
|
||||||
use crate::types::{ColorOptions, PlatformType};
|
|
||||||
|
|
||||||
// Note: flag names are specified explicitly in clap attributes
|
|
||||||
// to improve readability and allow contributors to grep names like "clear-cache"
|
|
||||||
#[derive(Parser, Debug)]
|
|
||||||
#[command(
|
|
||||||
about = "A fast TLDR client",
|
|
||||||
version,
|
|
||||||
disable_version_flag = true,
|
|
||||||
author,
|
|
||||||
help_template = "{before-help}{name} {version}: {about-with-newline}{author-with-newline}
|
|
||||||
{usage-heading} {usage}
|
|
||||||
|
|
||||||
{all-args}{after-help}",
|
|
||||||
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"]),
|
|
||||||
)]
|
|
||||||
pub(crate) struct Cli {
|
|
||||||
/// The command to show (e.g. `tar` or `git log`)
|
|
||||||
#[arg(num_args(1..))]
|
|
||||||
pub command: Vec<String>,
|
|
||||||
|
|
||||||
/// List all commands in the cache
|
|
||||||
#[arg(short = 'l', long = "list")]
|
|
||||||
pub list: bool,
|
|
||||||
|
|
||||||
/// Edit custom page with `EDITOR`
|
|
||||||
#[arg(long, requires = "command")]
|
|
||||||
pub edit_page: bool,
|
|
||||||
|
|
||||||
/// Edit custom patch with `EDITOR`
|
|
||||||
#[arg(long, requires = "command", conflicts_with = "edit_page")]
|
|
||||||
pub edit_patch: bool,
|
|
||||||
|
|
||||||
/// Render a specific markdown file
|
|
||||||
#[arg(
|
|
||||||
short = 'f',
|
|
||||||
long = "render",
|
|
||||||
value_name = "FILE",
|
|
||||||
conflicts_with = "command"
|
|
||||||
)]
|
|
||||||
pub render: Option<PathBuf>,
|
|
||||||
|
|
||||||
/// Override the operating system, can be specified multiple times in order of preference
|
|
||||||
#[arg(
|
|
||||||
short = 'p',
|
|
||||||
long = "platform",
|
|
||||||
value_name = "PLATFORM",
|
|
||||||
action = ArgAction::Append,
|
|
||||||
)]
|
|
||||||
pub platforms: Option<Vec<PlatformType>>,
|
|
||||||
|
|
||||||
/// Override the language
|
|
||||||
#[arg(short = 'L', long = "language")]
|
|
||||||
pub language: Option<String>,
|
|
||||||
|
|
||||||
/// Update the local cache
|
|
||||||
#[arg(short = 'u', long = "update")]
|
|
||||||
pub update: bool,
|
|
||||||
|
|
||||||
/// If auto update is configured, disable it for this run
|
|
||||||
#[arg(long = "no-auto-update", requires = "command_or_file")]
|
|
||||||
pub no_auto_update: bool,
|
|
||||||
|
|
||||||
/// Clear the local cache
|
|
||||||
#[arg(short = 'c', long = "clear-cache")]
|
|
||||||
pub clear_cache: bool,
|
|
||||||
|
|
||||||
/// Override config file location
|
|
||||||
#[arg(long = "config-path", value_name = "FILE")]
|
|
||||||
pub config_path: Option<PathBuf>,
|
|
||||||
|
|
||||||
/// Use a pager to page output
|
|
||||||
#[arg(long = "pager", requires = "command_or_file")]
|
|
||||||
pub pager: bool,
|
|
||||||
|
|
||||||
/// Display the raw markdown instead of rendering it
|
|
||||||
#[arg(short = 'r', long = "raw", requires = "command_or_file")]
|
|
||||||
pub raw: bool,
|
|
||||||
|
|
||||||
/// Suppress informational messages
|
|
||||||
#[arg(short = 'q', long = "quiet")]
|
|
||||||
pub quiet: bool,
|
|
||||||
|
|
||||||
/// Show file and directory paths used by tealdeer
|
|
||||||
#[arg(long = "show-paths")]
|
|
||||||
pub show_paths: bool,
|
|
||||||
|
|
||||||
/// Create a basic config
|
|
||||||
#[arg(long = "seed-config")]
|
|
||||||
pub seed_config: bool,
|
|
||||||
|
|
||||||
/// Control whether to use color
|
|
||||||
#[arg(long = "color", value_name = "WHEN")]
|
|
||||||
pub color: Option<ColorOptions>,
|
|
||||||
|
|
||||||
/// Print the version
|
|
||||||
// Note: We override the version flag because clap uses `-V` by default,
|
|
||||||
// while TLDR specification requires `-v` to be used.
|
|
||||||
#[arg(short = 'v', long = "version", action = ArgAction::Version)]
|
|
||||||
pub version: (),
|
|
||||||
}
|
|
||||||
1028
src/config.rs
|
|
@ -1,33 +0,0 @@
|
||||||
use std::mem;
|
|
||||||
|
|
||||||
/// An extension trait to clear duplicates from a collection.
|
|
||||||
pub(crate) trait Dedup<T: PartialEq> {
|
|
||||||
fn clear_duplicates(&mut self);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Clear duplicates from a collection, keep the first one seen.
|
|
||||||
///
|
|
||||||
/// For small vectors, this will be faster than a `HashSet`.
|
|
||||||
impl<T: PartialEq> Dedup<T> for Vec<T> {
|
|
||||||
fn clear_duplicates(&mut self) {
|
|
||||||
let orig = mem::replace(self, Vec::with_capacity(self.len()));
|
|
||||||
for item in orig {
|
|
||||||
if !self.contains(&item) {
|
|
||||||
self.push(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Like `str::find`, but starts searching at `start`.
|
|
||||||
pub(crate) trait FindFrom {
|
|
||||||
fn find_from(&self, needle: &Self, start: usize) -> Option<usize>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FindFrom for str {
|
|
||||||
fn find_from(&self, needle: &Self, start: usize) -> Option<usize> {
|
|
||||||
self.get(start..)
|
|
||||||
.and_then(|s| s.find(needle))
|
|
||||||
.map(|i| i + start)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
459
src/formatter.rs
|
|
@ -1,459 +0,0 @@
|
||||||
//! Functions related to formatting and printing lines from a `Tokenizer`.
|
|
||||||
|
|
||||||
use log::debug;
|
|
||||||
|
|
||||||
use crate::{config::Indent, extensions::FindFrom, types::LineType};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Eq)]
|
|
||||||
/// Represents a snippet from a page of a specific highlighting class.
|
|
||||||
pub enum PageSnippet<T> {
|
|
||||||
CommandName(T),
|
|
||||||
Variable(T),
|
|
||||||
NormalCode(T),
|
|
||||||
Description(T),
|
|
||||||
Text(T),
|
|
||||||
Title(T),
|
|
||||||
Linebreak,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(not(test), allow(dead_code))]
|
|
||||||
impl<T> PageSnippet<T> {
|
|
||||||
pub fn map<F, U>(self, f: F) -> PageSnippet<U>
|
|
||||||
where
|
|
||||||
F: FnOnce(T) -> U,
|
|
||||||
{
|
|
||||||
match self {
|
|
||||||
PageSnippet::CommandName(s) => PageSnippet::CommandName(f(s)),
|
|
||||||
PageSnippet::Variable(s) => PageSnippet::Variable(f(s)),
|
|
||||||
PageSnippet::NormalCode(s) => PageSnippet::NormalCode(f(s)),
|
|
||||||
PageSnippet::Description(s) => PageSnippet::Description(f(s)),
|
|
||||||
PageSnippet::Text(s) => PageSnippet::Text(f(s)),
|
|
||||||
PageSnippet::Title(s) => PageSnippet::Title(f(s)),
|
|
||||||
PageSnippet::Linebreak => PageSnippet::Linebreak,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: PartialEq<U>, U> PartialEq<PageSnippet<U>> for PageSnippet<T> {
|
|
||||||
fn eq(&self, other: &PageSnippet<U>) -> bool {
|
|
||||||
match (self, other) {
|
|
||||||
(PageSnippet::CommandName(s), PageSnippet::CommandName(t))
|
|
||||||
| (PageSnippet::Variable(s), PageSnippet::Variable(t))
|
|
||||||
| (PageSnippet::NormalCode(s), PageSnippet::NormalCode(t))
|
|
||||||
| (PageSnippet::Description(s), PageSnippet::Description(t))
|
|
||||||
| (PageSnippet::Text(s), PageSnippet::Text(t))
|
|
||||||
| (PageSnippet::Title(s), PageSnippet::Title(t)) => s == t,
|
|
||||||
(PageSnippet::Linebreak, PageSnippet::Linebreak) => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PageSnippet<&str> {
|
|
||||||
pub fn is_empty(&self) -> bool {
|
|
||||||
use PageSnippet::*;
|
|
||||||
|
|
||||||
match self {
|
|
||||||
CommandName(s) | Variable(s) | NormalCode(s) | Description(s) | Text(s) | Title(s) => {
|
|
||||||
s.is_empty()
|
|
||||||
}
|
|
||||||
Linebreak => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parse the content of each line yielded by `lines` and yield `HighLightingSnippet`s accordingly.
|
|
||||||
pub fn highlight_lines<L, F, E>(
|
|
||||||
lines: L,
|
|
||||||
process_snippet: &mut F,
|
|
||||||
keep_empty_lines: bool,
|
|
||||||
show_title: bool,
|
|
||||||
indent: Indent,
|
|
||||||
) -> Result<(), E>
|
|
||||||
where
|
|
||||||
L: Iterator<Item = LineType>,
|
|
||||||
F: for<'snip> FnMut(PageSnippet<&'snip str>) -> Result<(), E>,
|
|
||||||
{
|
|
||||||
let base_indent = " ".repeat(indent.base);
|
|
||||||
let command_indent = " ".repeat(indent.command);
|
|
||||||
let mut command = String::new();
|
|
||||||
for line in lines {
|
|
||||||
match line {
|
|
||||||
LineType::Empty => {
|
|
||||||
if keep_empty_lines {
|
|
||||||
process_snippet(PageSnippet::Linebreak)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LineType::Title(title) => {
|
|
||||||
if show_title {
|
|
||||||
process_snippet(PageSnippet::Linebreak)?;
|
|
||||||
process_snippet(PageSnippet::Title(&base_indent))?;
|
|
||||||
process_snippet(PageSnippet::Title(&title))?;
|
|
||||||
process_snippet(PageSnippet::Linebreak)?;
|
|
||||||
} else {
|
|
||||||
debug!("Ignoring title");
|
|
||||||
}
|
|
||||||
// This is safe as long as the parsed title is only the command,
|
|
||||||
// and the iterator yields values in order of appearance.
|
|
||||||
command = title;
|
|
||||||
debug!("Detected command name: {command}");
|
|
||||||
}
|
|
||||||
LineType::Description(text) => {
|
|
||||||
process_snippet(PageSnippet::Description(&base_indent))?;
|
|
||||||
process_snippet(PageSnippet::Description(&text))?;
|
|
||||||
process_snippet(PageSnippet::Linebreak)?;
|
|
||||||
}
|
|
||||||
LineType::ExampleText(text) => {
|
|
||||||
process_snippet(PageSnippet::Text(&base_indent))?;
|
|
||||||
process_snippet(PageSnippet::Text(&text))?;
|
|
||||||
process_snippet(PageSnippet::Linebreak)?;
|
|
||||||
}
|
|
||||||
LineType::ExampleCode(text) => {
|
|
||||||
process_snippet(PageSnippet::NormalCode(&command_indent))?;
|
|
||||||
highlight_code(&command, &text, process_snippet)?;
|
|
||||||
process_snippet(PageSnippet::Linebreak)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
LineType::Other(text) => debug!("Unknown line type: {text:?}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
process_snippet(PageSnippet::Linebreak)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Highlight code examples.
|
|
||||||
/// - parse placeholders (`{{ curly braces }}`)
|
|
||||||
/// - replace escaped placeholder markers (`\{\{` and `\}\}`)
|
|
||||||
fn highlight_code<E>(
|
|
||||||
command: &str,
|
|
||||||
mut text: &str,
|
|
||||||
process_snippet: &mut impl FnMut(PageSnippet<&str>) -> Result<(), E>,
|
|
||||||
) -> Result<(), E> {
|
|
||||||
// We replace escaped placeholder markers at the end so that our replacing does not interfere
|
|
||||||
// with finding the actual markers.
|
|
||||||
// NOTE: This is not optimal, as it allocates one String for each `replace`
|
|
||||||
let replace_escaped = |s: &str| s.replace(r"\{\{", "{{").replace(r"\}\}", "}}");
|
|
||||||
|
|
||||||
loop {
|
|
||||||
// Find placeholder markers and split into code and placeholder accordingly
|
|
||||||
|
|
||||||
let Some(start_marker) = find_marker(text, "{{", r"\{\{") else {
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
let Some(mut end_marker) = find_marker(&text[start_marker + 2..], "}}", r"\}\}") else {
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
end_marker += start_marker + 2;
|
|
||||||
|
|
||||||
// Greedily extend matched range
|
|
||||||
while end_marker + 2 < text.len() && text.as_bytes()[end_marker + 2] == b'}' {
|
|
||||||
end_marker += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
let placeholder_content = &text[start_marker + 2..end_marker];
|
|
||||||
|
|
||||||
if start_marker > 0 {
|
|
||||||
highlight_code_segment(
|
|
||||||
command,
|
|
||||||
&replace_escaped(&text[..start_marker]),
|
|
||||||
process_snippet,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
process_snippet(PageSnippet::Variable(&replace_escaped(placeholder_content)))?;
|
|
||||||
|
|
||||||
text = &text[end_marker + 2..];
|
|
||||||
}
|
|
||||||
|
|
||||||
if !text.is_empty() {
|
|
||||||
highlight_code_segment(command, &replace_escaped(text), process_snippet)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Find a "{{" (or "}}") substring that does not overlap with a preceding "\{\{" (or "\}\}").
|
|
||||||
fn find_marker(s: &str, marker: &str, forbidden_prefix: &str) -> Option<usize> {
|
|
||||||
let mut search_start = 0;
|
|
||||||
loop {
|
|
||||||
let marker_index = s.find_from(marker, search_start)?;
|
|
||||||
|
|
||||||
let overlaps_with_prefix = (forbidden_prefix.len() <= marker_index + 1) && {
|
|
||||||
let prefix_start = marker_index + 1 - forbidden_prefix.len();
|
|
||||||
// NOTE: The indices might not be valid character offsets, so we should do this
|
|
||||||
// comparison on raw bytes. If prefix_start is indeed not a character offset than the
|
|
||||||
// comparison is guaranteed to return false because forbidden_prefix[0] definitely _is_
|
|
||||||
// the start of a (single byte, ASCII) character.
|
|
||||||
&s.as_bytes()[prefix_start..=marker_index] == forbidden_prefix.as_bytes()
|
|
||||||
};
|
|
||||||
if !overlaps_with_prefix {
|
|
||||||
return Some(marker_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The next valid marker cannot include the first character of the current match
|
|
||||||
search_start = marker_index + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Yields `NormalCode` and `CommandName` in alternating order according to the occurrences of
|
|
||||||
/// `command_name` in `segment`. Variables are not detected here, see `highlight_code`
|
|
||||||
/// instead.
|
|
||||||
fn highlight_code_segment<'a, E>(
|
|
||||||
command_name: &'a str,
|
|
||||||
mut segment: &'a str,
|
|
||||||
process_snippet: &mut impl FnMut(PageSnippet<&'a str>) -> Result<(), E>,
|
|
||||||
) -> Result<(), E> {
|
|
||||||
if !command_name.is_empty() {
|
|
||||||
let mut search_start = 0;
|
|
||||||
while let Some(match_start) = segment.find_from(command_name, search_start) {
|
|
||||||
let match_end = match_start + command_name.len();
|
|
||||||
if is_freestanding_substring(segment, (match_start, match_end)) {
|
|
||||||
process_snippet(PageSnippet::NormalCode(&segment[..match_start]))?;
|
|
||||||
process_snippet(PageSnippet::CommandName(command_name))?;
|
|
||||||
segment = &segment[match_end..];
|
|
||||||
search_start = 0;
|
|
||||||
} else {
|
|
||||||
search_start = segment[match_start..]
|
|
||||||
.char_indices()
|
|
||||||
.nth(1)
|
|
||||||
.map_or(segment.len(), |(i, _)| match_start + i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
process_snippet(PageSnippet::NormalCode(segment))?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks whether the characters right before and after the substring (given by half-open index interval) are whitespace (if they exist).
|
|
||||||
fn is_freestanding_substring(surrounding: &str, substring: (usize, usize)) -> bool {
|
|
||||||
let (start, end) = substring;
|
|
||||||
// "okay" meaning <exists and is whitespace> or <doesn't exist>
|
|
||||||
let char_before_is_okay = surrounding[..start]
|
|
||||||
.chars()
|
|
||||||
.last()
|
|
||||||
.is_none_or(char::is_whitespace);
|
|
||||||
let char_after_is_okay = surrounding[end..]
|
|
||||||
.chars()
|
|
||||||
.next()
|
|
||||||
.is_none_or(char::is_whitespace);
|
|
||||||
char_before_is_okay && char_after_is_okay
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_is_freestanding_substring() {
|
|
||||||
assert!(is_freestanding_substring("I love tldr", (0, 1)));
|
|
||||||
assert!(is_freestanding_substring("I love tldr", (2, 6)));
|
|
||||||
assert!(is_freestanding_substring("I love tldr", (7, 11)));
|
|
||||||
|
|
||||||
assert!(is_freestanding_substring("tldr", (0, 4)));
|
|
||||||
assert!(is_freestanding_substring("tldr ", (0, 4)));
|
|
||||||
assert!(is_freestanding_substring(" tldr", (1, 5)));
|
|
||||||
assert!(is_freestanding_substring(" tldr ", (1, 5)));
|
|
||||||
|
|
||||||
assert!(!is_freestanding_substring("tldr", (1, 3)));
|
|
||||||
assert!(!is_freestanding_substring("tldr ", (1, 4)));
|
|
||||||
assert!(!is_freestanding_substring(" tldr", (1, 4)));
|
|
||||||
|
|
||||||
assert!(is_freestanding_substring(
|
|
||||||
" épicé ",
|
|
||||||
(1, " épicé".len()) // note the missing trailing space
|
|
||||||
));
|
|
||||||
assert!(!is_freestanding_substring(
|
|
||||||
" épicé ",
|
|
||||||
(1, " épic".len()) // note the missing trailing space and character
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run<'a>(cmd: &'a str, segment: &'a str) -> Vec<PageSnippet<String>> {
|
|
||||||
let mut yielded = Vec::new();
|
|
||||||
let mut process_snippet = |snip: PageSnippet<&str>| {
|
|
||||||
if !snip.is_empty() {
|
|
||||||
yielded.push(snip.map(str::to_string));
|
|
||||||
}
|
|
||||||
Ok::<(), ()>(())
|
|
||||||
};
|
|
||||||
|
|
||||||
highlight_code(cmd, segment, &mut process_snippet).expect("highlight code segment failed");
|
|
||||||
yielded
|
|
||||||
}
|
|
||||||
|
|
||||||
mod highlight_code_segment {
|
|
||||||
use super::*;
|
|
||||||
use PageSnippet::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_highlight_code_segment() {
|
|
||||||
assert!(run("make", "").is_empty());
|
|
||||||
assert_eq!(
|
|
||||||
&run("make", "make all CC=clang -q"),
|
|
||||||
&[CommandName("make"), NormalCode(" all CC=clang -q")]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
&run("make", " make money --always-make"),
|
|
||||||
&[
|
|
||||||
NormalCode(" "),
|
|
||||||
CommandName("make"),
|
|
||||||
NormalCode(" money --always-make")
|
|
||||||
]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
&run("git commit", "git commit -m 'git commit'"),
|
|
||||||
&[CommandName("git commit"), NormalCode(" -m 'git commit'"),]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_i18n() {
|
|
||||||
assert_eq!(
|
|
||||||
&run("mäke", "mäke höhlenrätselbücher"),
|
|
||||||
&[CommandName("mäke"), NormalCode(" höhlenrätselbücher")]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
&run(
|
|
||||||
"Müll",
|
|
||||||
"1000 Gründe warum Müll heute größer ist als Müll früher, ärgerlich"
|
|
||||||
),
|
|
||||||
&[
|
|
||||||
NormalCode("1000 Gründe warum "),
|
|
||||||
CommandName("Müll"),
|
|
||||||
NormalCode(" heute größer ist als "),
|
|
||||||
CommandName("Müll"),
|
|
||||||
NormalCode(" früher, ärgerlich")
|
|
||||||
]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
&run(
|
|
||||||
"übergang",
|
|
||||||
"die Zustandsübergangsfunktion übergang Änderungen",
|
|
||||||
),
|
|
||||||
&[
|
|
||||||
NormalCode("die Zustandsübergangsfunktion "),
|
|
||||||
CommandName("übergang"),
|
|
||||||
NormalCode(" Änderungen")
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_empty_command() {
|
|
||||||
let segment = "some code";
|
|
||||||
let snippets = [NormalCode(segment)];
|
|
||||||
|
|
||||||
assert_eq!(run("", segment), snippets);
|
|
||||||
assert_eq!(run(" ", segment), snippets);
|
|
||||||
assert_eq!(run(" \t ", segment), snippets);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod placeholders {
|
|
||||||
use super::*;
|
|
||||||
use PageSnippet::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn variable_vs_escaped() {
|
|
||||||
assert_eq!(
|
|
||||||
run("ping", "ping {{example.com}}"),
|
|
||||||
[
|
|
||||||
CommandName("ping"),
|
|
||||||
NormalCode(" "),
|
|
||||||
Variable("example.com"),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
run(
|
|
||||||
"docker inspect",
|
|
||||||
r"docker inspect --format '\{\{range.NetworkSettings.Networks\}\}\{\{.IPAddress\}\}\{\{end\}\}' {{container}}"
|
|
||||||
),
|
|
||||||
[
|
|
||||||
CommandName("docker inspect"),
|
|
||||||
NormalCode(
|
|
||||||
" --format '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "
|
|
||||||
),
|
|
||||||
Variable("container"),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
run("mount", r"mount \\{{computer_name}}\{{share_name}} Z:"),
|
|
||||||
[
|
|
||||||
CommandName("mount"),
|
|
||||||
NormalCode(r" \\"),
|
|
||||||
Variable("computer_name"),
|
|
||||||
NormalCode(r"\"),
|
|
||||||
Variable("share_name"),
|
|
||||||
NormalCode(" Z:"),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(run("", r"\{"), [NormalCode(r"\{")]);
|
|
||||||
assert_eq!(run("", r"\{{a"), [NormalCode(r"\{{a")]);
|
|
||||||
assert_eq!(run("", r"\{{a}}"), [NormalCode(r"\"), Variable("a")]);
|
|
||||||
|
|
||||||
// Placeholder has begin marker, but no end marker
|
|
||||||
assert_eq!(run("", r"{{\}\}}"), [NormalCode("{{}}}")]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn outer_precedence() {
|
|
||||||
assert_eq!(
|
|
||||||
run("git stash", "git stash show --patch {{stash@{0}}}"),
|
|
||||||
[
|
|
||||||
CommandName("git stash"),
|
|
||||||
NormalCode(" show --patch "),
|
|
||||||
Variable("stash@{0}"),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
// The following is not listed in the specification, but this is the highlighting I would expect.
|
|
||||||
assert_eq!(
|
|
||||||
run("rg", "rg {{}}}"),
|
|
||||||
[CommandName("rg"), NormalCode(" "), Variable("}")]
|
|
||||||
);
|
|
||||||
|
|
||||||
// And these are just to document the current behavior
|
|
||||||
assert_eq!(run("", "{{{}}}"), [Variable("{}")]);
|
|
||||||
assert_eq!(run("", "{{{{}}}"), [Variable("{{}")]);
|
|
||||||
assert_eq!(run("", "{{{}}}}"), [Variable("{}}")]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn escaped_inside_placeholder() {
|
|
||||||
assert_eq!(
|
|
||||||
run(
|
|
||||||
"playerctl",
|
|
||||||
r#"playerctl metadata {{[-f|--format]}} "{{Now playing: \{\{artist\}\} - \{\{album\}\} - \{\{title\}\}}}""#
|
|
||||||
),
|
|
||||||
[
|
|
||||||
CommandName("playerctl"),
|
|
||||||
NormalCode(" metadata "),
|
|
||||||
Variable("[-f|--format]"),
|
|
||||||
NormalCode(" \""),
|
|
||||||
Variable("Now playing: {{artist}} - {{album}} - {{title}}"),
|
|
||||||
NormalCode("\""),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn placeholder_inside_escaped() {
|
|
||||||
assert_eq!(
|
|
||||||
run("test", r"test \{\{{{var}} normal\}\}"),
|
|
||||||
[
|
|
||||||
CommandName("test"),
|
|
||||||
NormalCode(" {{"),
|
|
||||||
Variable("var"),
|
|
||||||
NormalCode(" normal}}"),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
/// Regression test for <https://github.com/tealdeer-rs/tealdeer/issues/473>
|
|
||||||
fn prefix_check_character_boundary() {
|
|
||||||
assert_eq!("Ä".len(), 2);
|
|
||||||
assert_eq!(run("", r"Äxx{{x}}"), [NormalCode("Äxx"), Variable("x")],);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,122 +0,0 @@
|
||||||
//! Code to split a `BufRead` instance into an iterator of `LineType`s.
|
|
||||||
|
|
||||||
use std::io::{BufRead, Read};
|
|
||||||
|
|
||||||
use log::warn;
|
|
||||||
|
|
||||||
use crate::types::LineType;
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
|
||||||
pub enum TldrFormat {
|
|
||||||
/// Not yet clear
|
|
||||||
Undecided,
|
|
||||||
/// The original format
|
|
||||||
V1,
|
|
||||||
/// The new format (see <https://github.com/tldr-pages/tldr/pull/958>)
|
|
||||||
V2,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A `LineIterator` is initialized with a `BufReader` instance that contains the
|
|
||||||
/// entire Tldr page. It then implements `Iterator<Item = LineType>`.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct LineIterator<R: BufRead> {
|
|
||||||
/// An instance of `R: BufRead`.
|
|
||||||
reader: R,
|
|
||||||
/// Whether the first line has already been processed or not.
|
|
||||||
first_line: bool,
|
|
||||||
/// Buffer for the current line. Used internally.
|
|
||||||
current_line: String,
|
|
||||||
/// The tldr page format.
|
|
||||||
format: TldrFormat,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R> LineIterator<R>
|
|
||||||
where
|
|
||||||
R: BufRead,
|
|
||||||
{
|
|
||||||
pub fn new(reader: R) -> Self {
|
|
||||||
Self {
|
|
||||||
reader,
|
|
||||||
first_line: true,
|
|
||||||
current_line: String::new(),
|
|
||||||
format: TldrFormat::Undecided,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: BufRead> Iterator for LineIterator<R> {
|
|
||||||
type Item = LineType;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<LineType> {
|
|
||||||
self.current_line.clear();
|
|
||||||
let bytes_read = self.reader.read_line(&mut self.current_line);
|
|
||||||
match bytes_read {
|
|
||||||
Ok(0) => None,
|
|
||||||
Err(e) => {
|
|
||||||
warn!("Could not read line from reader: {e:?}");
|
|
||||||
None
|
|
||||||
}
|
|
||||||
Ok(_) => {
|
|
||||||
// Handle new titles
|
|
||||||
if self.first_line {
|
|
||||||
if self.current_line.starts_with('#') {
|
|
||||||
// It's the old format.
|
|
||||||
self.format = TldrFormat::V1;
|
|
||||||
} else {
|
|
||||||
// It's the new format! Drop next line.
|
|
||||||
if let Err(e) = Read::bytes(&mut self.reader)
|
|
||||||
.find(|b| matches!(b, Ok(b'\n') | Err(_)))
|
|
||||||
.transpose()
|
|
||||||
{
|
|
||||||
warn!("Could not read line from reader: {e:?}");
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
self.first_line = false;
|
|
||||||
self.format = TldrFormat::V2;
|
|
||||||
return Some(LineType::Title(self.current_line.trim_end().to_string()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.first_line = false;
|
|
||||||
|
|
||||||
// Convert line to a `LineType` instance
|
|
||||||
match self.format {
|
|
||||||
TldrFormat::V1 => Some(LineType::from_v1(&self.current_line[..])),
|
|
||||||
TldrFormat::V2 => Some(LineType::from(&self.current_line[..])),
|
|
||||||
TldrFormat::Undecided => panic!("Could not determine page format version"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::LineIterator;
|
|
||||||
use crate::types::LineType;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_first_line_old_format() {
|
|
||||||
let input = "# The Title\n> Description\n";
|
|
||||||
let mut lines = LineIterator::new(input.as_bytes());
|
|
||||||
let title = lines.next().unwrap();
|
|
||||||
assert_eq!(title, LineType::Title("The Title".to_string()));
|
|
||||||
let description = lines.next().unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
description,
|
|
||||||
LineType::Description("Description".to_string())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_first_line_new_format() {
|
|
||||||
let input = "The Title\n=========\n> Description\n";
|
|
||||||
let mut lines = LineIterator::new(input.as_bytes());
|
|
||||||
let title = lines.next().unwrap();
|
|
||||||
assert_eq!(title, LineType::Title("The Title".to_string()));
|
|
||||||
let description = lines.next().unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
description,
|
|
||||||
LineType::Description("Description".to_string())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
444
src/main.rs
|
|
@ -1,444 +0,0 @@
|
||||||
//! An implementation of [tldr](https://github.com/tldr-pages/tldr) in Rust.
|
|
||||||
//
|
|
||||||
// Copyright (c) 2015-2021 tealdeer developers
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. All files in the project carrying such notice may not be
|
|
||||||
// copied, modified, or distributed except according to those terms.
|
|
||||||
|
|
||||||
#![deny(clippy::all)]
|
|
||||||
#![warn(clippy::pedantic)]
|
|
||||||
#![allow(clippy::enum_glob_use)]
|
|
||||||
#![allow(clippy::module_name_repetitions)]
|
|
||||||
#![allow(clippy::similar_names)]
|
|
||||||
#![allow(clippy::struct_excessive_bools)]
|
|
||||||
#![allow(clippy::too_many_lines)]
|
|
||||||
#![allow(clippy::unnecessary_debug_formatting)]
|
|
||||||
#![allow(clippy::while_let_loop)]
|
|
||||||
|
|
||||||
#[cfg(not(any(
|
|
||||||
feature = "native-tls",
|
|
||||||
feature = "rustls-with-webpki-roots",
|
|
||||||
feature = "rustls-with-native-roots",
|
|
||||||
)))]
|
|
||||||
compile_error!(
|
|
||||||
"at least one of the features \"native-tls\", \"rustls-with-webpki-roots\" or \"rustls-with-native-roots\" must be enabled"
|
|
||||||
);
|
|
||||||
|
|
||||||
use std::{
|
|
||||||
env,
|
|
||||||
fs::create_dir_all,
|
|
||||||
io::{self, IsTerminal},
|
|
||||||
path::Path,
|
|
||||||
process::{Command, ExitCode},
|
|
||||||
};
|
|
||||||
|
|
||||||
use anyhow::{anyhow, Context, Result};
|
|
||||||
use cache::{CacheConfig, TLDR_OLD_PAGES_DIR};
|
|
||||||
use clap::Parser;
|
|
||||||
use config::{ConfigLoader, Language, StyleConfig, TlsBackend};
|
|
||||||
use log::debug;
|
|
||||||
use types::PlatformType;
|
|
||||||
|
|
||||||
mod cache;
|
|
||||||
mod cli;
|
|
||||||
mod config;
|
|
||||||
pub mod extensions;
|
|
||||||
mod formatter;
|
|
||||||
mod line_iterator;
|
|
||||||
mod output;
|
|
||||||
mod types;
|
|
||||||
mod utils;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
cache::{Cache, PageLookupResult, TLDR_PAGES_DIR},
|
|
||||||
cli::Cli,
|
|
||||||
config::{
|
|
||||||
get_config_dir, make_default_config, supported_tls_backends_string, Config, PathWithSource,
|
|
||||||
},
|
|
||||||
output::print_page,
|
|
||||||
types::ColorOptions,
|
|
||||||
utils::{print_error, print_warning},
|
|
||||||
};
|
|
||||||
|
|
||||||
const NAME: &str = "tealdeer";
|
|
||||||
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<()> {
|
|
||||||
let cache_dir = cache.config().pages_directory.display();
|
|
||||||
cache.clear().context("Could not clear cache")?;
|
|
||||||
if !quietly {
|
|
||||||
eprintln!("Successfully cleared cache at `{cache_dir}`.");
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Update the cache
|
|
||||||
fn update_cache(
|
|
||||||
cache: &mut Cache,
|
|
||||||
archive_source: &str,
|
|
||||||
tls_backend: TlsBackend,
|
|
||||||
quietly: bool,
|
|
||||||
) -> Result<()> {
|
|
||||||
let downloaded_languages = cache
|
|
||||||
.update(archive_source, tls_backend)
|
|
||||||
.context("Could not update cache")?;
|
|
||||||
if !quietly {
|
|
||||||
eprintln!("Successfully updated cache.");
|
|
||||||
eprint!("Pages for the following languages were downloaded: ");
|
|
||||||
let language_strings: Vec<_> = downloaded_languages
|
|
||||||
.into_iter()
|
|
||||||
.map(|lang| lang.0)
|
|
||||||
.collect();
|
|
||||||
if language_strings.is_empty() {
|
|
||||||
eprintln!("(none)");
|
|
||||||
} else {
|
|
||||||
eprintln!("{}", language_strings.join(", "));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Show file paths
|
|
||||||
fn show_paths(config: &Config) {
|
|
||||||
let config_dir = {
|
|
||||||
let (mut path, source) = get_config_dir();
|
|
||||||
path.push(""); // Trailing path separator
|
|
||||||
match path.to_str() {
|
|
||||||
Some(path) => format!("{path} ({source})"),
|
|
||||||
None => "[Invalid]".to_string(),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let config_path = config.file_path.to_string();
|
|
||||||
let cache_dir = config.directories.cache_dir.to_string();
|
|
||||||
let pages_dir = {
|
|
||||||
let mut path = config.directories.cache_dir.path.clone();
|
|
||||||
path.push(TLDR_PAGES_DIR);
|
|
||||||
path.push(""); // Trailing path separator
|
|
||||||
path.display().to_string()
|
|
||||||
};
|
|
||||||
let custom_pages_dir = match config.directories.custom_pages_dir {
|
|
||||||
Some(ref path_with_source) => path_with_source.to_string(),
|
|
||||||
None => "[None]".to_string(),
|
|
||||||
};
|
|
||||||
println!("Config dir: {config_dir}");
|
|
||||||
println!("Config path: {config_path}");
|
|
||||||
println!("Cache dir: {cache_dir}");
|
|
||||||
println!("Pages dir: {pages_dir}");
|
|
||||||
println!("Custom pages dir: {custom_pages_dir}");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_config(path: Option<&Path>) -> Result<()> {
|
|
||||||
let config_file_path = make_default_config(path).context("Could not create seed config")?;
|
|
||||||
eprintln!(
|
|
||||||
"Successfully created seed config file here: {}",
|
|
||||||
config_file_path.to_str().unwrap()
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "logging")]
|
|
||||||
fn init_log() {
|
|
||||||
env_logger::init();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "logging"))]
|
|
||||||
fn init_log() {}
|
|
||||||
|
|
||||||
fn spawn_editor(custom_pages_dir: &Path, file_name: &str) -> Result<()> {
|
|
||||||
create_dir_all(custom_pages_dir).context("Failed to create custom pages directory")?;
|
|
||||||
|
|
||||||
let custom_page_path = custom_pages_dir.join(file_name);
|
|
||||||
let Some(custom_page_path) = custom_page_path.to_str() else {
|
|
||||||
return Err(anyhow!("`custom_page_path.to_str()` failed"));
|
|
||||||
};
|
|
||||||
let Ok(editor) = env::var("EDITOR") else {
|
|
||||||
return Err(anyhow!(
|
|
||||||
"To edit a custom page, please set the `EDITOR` environment variable."
|
|
||||||
));
|
|
||||||
};
|
|
||||||
println!("Editing {custom_page_path:?}");
|
|
||||||
|
|
||||||
let status = Command::new(&editor).arg(custom_page_path).status()?;
|
|
||||||
if !status.success() {
|
|
||||||
return Err(anyhow!("{editor} exit with code {:?}", status.code()));
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> ExitCode {
|
|
||||||
// Initialize logger
|
|
||||||
init_log();
|
|
||||||
|
|
||||||
// Parse arguments
|
|
||||||
let args = Cli::parse();
|
|
||||||
|
|
||||||
// Determine the usage of styles
|
|
||||||
let enable_styles = match args.color.unwrap_or_default() {
|
|
||||||
// Attempt to use styling if instructed
|
|
||||||
ColorOptions::Always => {
|
|
||||||
yansi::enable(); // disable yansi's automatic detection for ANSI support on Windows
|
|
||||||
true
|
|
||||||
}
|
|
||||||
// Enable styling if:
|
|
||||||
// * NO_COLOR env var isn't set: https://no-color.org/
|
|
||||||
// * The output stream is stdout (not being piped)
|
|
||||||
ColorOptions::Auto => env::var_os("NO_COLOR").is_none() && io::stdout().is_terminal(),
|
|
||||||
// Disable styling
|
|
||||||
ColorOptions::Never => false,
|
|
||||||
};
|
|
||||||
|
|
||||||
try_main(args, enable_styles).unwrap_or_else(|error| {
|
|
||||||
print_error(enable_styles, &error);
|
|
||||||
ExitCode::FAILURE
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn try_main(args: Cli, enable_styles: bool) -> Result<ExitCode> {
|
|
||||||
// Look up config file, if none is found fall back to default config.
|
|
||||||
debug!("Loading config");
|
|
||||||
let config_loader = match &args.config_path {
|
|
||||||
Some(path) if !args.seed_config => {
|
|
||||||
ConfigLoader::read(path.clone()).context("Could not read config from given path")?
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
ConfigLoader::read_default_path().context("Could not read config from default path")?
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let mut config = config_loader.load()?;
|
|
||||||
|
|
||||||
// Override styles if needed
|
|
||||||
if !enable_styles {
|
|
||||||
config.style = StyleConfig::default();
|
|
||||||
}
|
|
||||||
|
|
||||||
let custom_pages_dir = config
|
|
||||||
.directories
|
|
||||||
.custom_pages_dir
|
|
||||||
.as_ref()
|
|
||||||
.map(PathWithSource::path);
|
|
||||||
|
|
||||||
// Note: According to the TLDR client spec, page names must be transparently
|
|
||||||
// lowercased before lookup:
|
|
||||||
// https://github.com/tldr-pages/tldr/blob/main/CLIENT-SPECIFICATION.md#page-names
|
|
||||||
let command = args.command.join("-").to_lowercase();
|
|
||||||
|
|
||||||
if args.edit_patch || args.edit_page {
|
|
||||||
let file_name = if args.edit_patch {
|
|
||||||
format!("{command}.patch.md")
|
|
||||||
} else {
|
|
||||||
format!("{command}.page.md")
|
|
||||||
};
|
|
||||||
|
|
||||||
custom_pages_dir
|
|
||||||
.context("To edit custom pages/patches, please specify a custom pages directory.")
|
|
||||||
.and_then(|custom_pages_dir| spawn_editor(custom_pages_dir, &file_name))?;
|
|
||||||
|
|
||||||
return Ok(ExitCode::SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show various paths
|
|
||||||
if args.show_paths {
|
|
||||||
show_paths(&config);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a basic config and exit
|
|
||||||
if args.seed_config {
|
|
||||||
create_config(args.config_path.as_deref())?;
|
|
||||||
return Ok(ExitCode::SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If a local file was passed in, render it and exit
|
|
||||||
if let Some(file) = args.render {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(platforms) = args.platforms {
|
|
||||||
config.search.platforms = platforms;
|
|
||||||
if !config.search.platforms.contains(&PlatformType::Common) {
|
|
||||||
config.search.platforms.push(PlatformType::Common);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let (search_languages, download_languages): (&[_], &[_]) = match args.language.as_deref() {
|
|
||||||
Some(lang) => (&[Language(lang)], &[Language(lang)]),
|
|
||||||
None => (&config.search.languages, &config.updates.download_languages),
|
|
||||||
};
|
|
||||||
|
|
||||||
let cache_config = CacheConfig {
|
|
||||||
pages_directory: &config.directories.cache_dir.path().join(TLDR_PAGES_DIR),
|
|
||||||
custom_pages_directory: config
|
|
||||||
.directories
|
|
||||||
.custom_pages_dir
|
|
||||||
.as_ref()
|
|
||||||
.map(PathWithSource::path),
|
|
||||||
platforms: &config.search.platforms,
|
|
||||||
search_languages,
|
|
||||||
download_languages,
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: remove in tealdeer 1.9
|
|
||||||
let old_config = CacheConfig {
|
|
||||||
pages_directory: &config.directories.cache_dir.path().join(TLDR_OLD_PAGES_DIR),
|
|
||||||
..cache_config
|
|
||||||
};
|
|
||||||
if let Ok(Some(old_cache)) = Cache::open(old_config) {
|
|
||||||
old_cache.clear()?;
|
|
||||||
eprintln!("Cleared pages from old cache location.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if args.clear_cache {
|
|
||||||
if let Some(cache) = Cache::open(cache_config)? {
|
|
||||||
clear_cache(cache, args.quiet)?;
|
|
||||||
}
|
|
||||||
return Ok(ExitCode::SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
let cache = if args.update || config.updates.auto_update && !args.no_auto_update {
|
|
||||||
let (mut cache, was_created) = Cache::open_or_create(cache_config)?;
|
|
||||||
if was_created || args.update || cache.age()? >= config.updates.auto_update_interval {
|
|
||||||
let result = update_cache(
|
|
||||||
&mut cache,
|
|
||||||
config.updates.archive_source,
|
|
||||||
config.updates.tls_backend,
|
|
||||||
args.quiet,
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Err(e) = result {
|
|
||||||
print_error(enable_styles, &e);
|
|
||||||
|
|
||||||
eprintln!();
|
|
||||||
eprintln!("Note: Update errors are often caused by unexpected or missing TLS certificates.");
|
|
||||||
eprintln!(
|
|
||||||
"You are currently using the following TLS backend: {}",
|
|
||||||
config.updates.tls_backend,
|
|
||||||
);
|
|
||||||
eprintln!(
|
|
||||||
"Try changing the updates.tls_backend setting in the config file, for example:"
|
|
||||||
);
|
|
||||||
eprintln!();
|
|
||||||
eprintln!(" [updates]");
|
|
||||||
eprintln!(" tls_backend = \"rustls-with-native-roots\"");
|
|
||||||
eprintln!();
|
|
||||||
eprintln!(
|
|
||||||
"This build of tealdeer has support for the following options: {}",
|
|
||||||
supported_tls_backends_string(),
|
|
||||||
);
|
|
||||||
|
|
||||||
return Ok(ExitCode::FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cache
|
|
||||||
} else if args.list || !command.is_empty() {
|
|
||||||
// Cache is needed for these commands to work
|
|
||||||
let Some(cache) = Cache::open(cache_config)? else {
|
|
||||||
print_error(
|
|
||||||
enable_styles,
|
|
||||||
&anyhow::anyhow!(
|
|
||||||
"Page cache not found. Please run `tldr --update` to download the cache."
|
|
||||||
),
|
|
||||||
);
|
|
||||||
println!("\nNote: You can optionally enable automatic cache updates by adding the");
|
|
||||||
println!("following config to your config file:\n");
|
|
||||||
println!(" [updates]");
|
|
||||||
println!(" auto_update = true\n");
|
|
||||||
println!("The path to your config file can be looked up with `tldr --show-paths`.");
|
|
||||||
println!("To create an initial config file, use `tldr --seed-config`.\n");
|
|
||||||
println!("You can find more tips and tricks in our docs:\n");
|
|
||||||
println!(" https://tealdeer-rs.github.io/tealdeer/config_updates.html");
|
|
||||||
|
|
||||||
return Ok(ExitCode::FAILURE);
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(max_cache_age) = config.updates.warn_cache_age {
|
|
||||||
let age = cache.age()?;
|
|
||||||
if age > max_cache_age && !args.quiet {
|
|
||||||
print_warning(
|
|
||||||
enable_styles,
|
|
||||||
&format!(
|
|
||||||
"The cache hasn't been updated for {} days.\n\
|
|
||||||
You should probably run `tldr --update` soon.",
|
|
||||||
age.as_secs() / 24 / 3600
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cache
|
|
||||||
} else {
|
|
||||||
// There is nothing left to do
|
|
||||||
return Ok(ExitCode::SUCCESS);
|
|
||||||
};
|
|
||||||
|
|
||||||
if args.list {
|
|
||||||
for page in cache.list_pages()? {
|
|
||||||
println!("{page}");
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ok(ExitCode::SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show command from cache
|
|
||||||
if !command.is_empty() {
|
|
||||||
// TODO: Remove this check 1 year after version 1.7.0 was released
|
|
||||||
if cache.old_custom_pages_exist()? {
|
|
||||||
print_warning(
|
|
||||||
enable_styles,
|
|
||||||
&format!(
|
|
||||||
"Custom pages using the old naming convention were found in {}.\n\
|
|
||||||
Please rename them to follow the new convention:\n\
|
|
||||||
- `<name>.page` → `<name>.page.md`\n\
|
|
||||||
- `<name>.patch` → `<name>.patch.md`",
|
|
||||||
cache
|
|
||||||
.config()
|
|
||||||
.custom_pages_directory
|
|
||||||
.expect("Old custom pages can only exist in custom pages directory")
|
|
||||||
.display(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let Some(result) = cache.find_page(&command) else {
|
|
||||||
if !args.quiet {
|
|
||||||
print_warning(
|
|
||||||
enable_styles,
|
|
||||||
&format!(
|
|
||||||
"Page `{command}` not found in cache.\n\
|
|
||||||
Try updating with `tldr --update`, or submit a pull request to:\n\
|
|
||||||
https://github.com/tldr-pages/tldr"
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return Ok(ExitCode::FAILURE);
|
|
||||||
};
|
|
||||||
|
|
||||||
print_page(
|
|
||||||
result.reader()?,
|
|
||||||
args.raw,
|
|
||||||
enable_styles,
|
|
||||||
args.pager,
|
|
||||||
&config,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(ExitCode::SUCCESS)
|
|
||||||
}
|
|
||||||
|
|
@ -1,97 +0,0 @@
|
||||||
//! Functions for printing pages to the terminal
|
|
||||||
|
|
||||||
use std::io::{self, BufRead, BufReader, Read, Write};
|
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
|
||||||
use yansi::Paint;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
config::{Config, StyleConfig},
|
|
||||||
formatter::{highlight_lines, PageSnippet},
|
|
||||||
line_iterator::LineIterator,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Set up display pager
|
|
||||||
///
|
|
||||||
/// SAFETY: this function may be called multiple times
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
|
||||||
fn configure_pager(_: bool) {
|
|
||||||
use std::sync::Once;
|
|
||||||
static INIT: Once = Once::new();
|
|
||||||
INIT.call_once(|| pager::Pager::with_default_pager("less -R").setup());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
fn configure_pager(enable_styles: bool) {
|
|
||||||
use crate::utils::print_warning;
|
|
||||||
print_warning(enable_styles, "--pager flag not available on Windows!");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Print page by path
|
|
||||||
pub fn print_page(
|
|
||||||
reader: impl Read,
|
|
||||||
enable_markdown: bool,
|
|
||||||
enable_styles: bool,
|
|
||||||
use_pager: bool,
|
|
||||||
config: &Config,
|
|
||||||
) -> Result<()> {
|
|
||||||
let reader = BufReader::new(reader);
|
|
||||||
|
|
||||||
// Configure pager if applicable
|
|
||||||
if use_pager || config.display.use_pager {
|
|
||||||
configure_pager(enable_styles);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lock stdout only once, this improves performance considerably
|
|
||||||
let stdout = io::stdout();
|
|
||||||
let mut handle = stdout.lock();
|
|
||||||
|
|
||||||
if enable_markdown {
|
|
||||||
// Print the raw markdown of the file.
|
|
||||||
for line in reader.lines() {
|
|
||||||
let line = line.context("Error while reading from a page")?;
|
|
||||||
writeln!(handle, "{line}").context("Could not write to stdout")?;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Closure that processes a page snippet and writes it to stdout
|
|
||||||
let mut process_snippet = |snip: PageSnippet<&str>| {
|
|
||||||
if snip.is_empty() {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
print_snippet(&mut handle, snip, &config.style).context("Failed to print snippet")
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Print highlighted lines
|
|
||||||
highlight_lines(
|
|
||||||
LineIterator::new(reader),
|
|
||||||
&mut process_snippet,
|
|
||||||
!config.display.compact,
|
|
||||||
config.display.show_title,
|
|
||||||
config.display.indent,
|
|
||||||
)
|
|
||||||
.context("Could not write to stdout")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We're done outputting data, flush stdout now!
|
|
||||||
handle.flush().context("Could not flush stdout")?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn print_snippet(
|
|
||||||
writer: &mut impl Write,
|
|
||||||
snip: PageSnippet<&str>,
|
|
||||||
style: &StyleConfig,
|
|
||||||
) -> io::Result<()> {
|
|
||||||
use PageSnippet::*;
|
|
||||||
|
|
||||||
match snip {
|
|
||||||
CommandName(s) | Title(s) => write!(writer, "{}", s.paint(style.command_name)),
|
|
||||||
Variable(s) => write!(writer, "{}", s.paint(style.example_variable)),
|
|
||||||
NormalCode(s) => write!(writer, "{}", s.paint(style.example_code)),
|
|
||||||
Description(s) => write!(writer, "{}", s.paint(style.description)),
|
|
||||||
Text(s) => write!(writer, "{}", s.paint(style.example_text)),
|
|
||||||
Linebreak => writeln!(writer),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
248
src/types.rs
|
|
@ -1,248 +0,0 @@
|
||||||
//! Shared types used in tealdeer.
|
|
||||||
|
|
||||||
use std::{fmt, str};
|
|
||||||
|
|
||||||
use serde_derive::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Copy, Clone, Serialize, Deserialize)]
|
|
||||||
#[serde(rename_all = "lowercase")]
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub enum PlatformType {
|
|
||||||
Linux,
|
|
||||||
OsX,
|
|
||||||
Windows,
|
|
||||||
SunOs,
|
|
||||||
Android,
|
|
||||||
FreeBsd,
|
|
||||||
NetBsd,
|
|
||||||
OpenBsd,
|
|
||||||
Common,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for PlatformType {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
Self::Linux => write!(f, "Linux"),
|
|
||||||
Self::OsX => write!(f, "macOS / BSD"),
|
|
||||||
Self::Windows => write!(f, "Windows"),
|
|
||||||
Self::SunOs => write!(f, "SunOS"),
|
|
||||||
Self::Android => write!(f, "Android"),
|
|
||||||
Self::FreeBsd => write!(f, "FreeBSD"),
|
|
||||||
Self::NetBsd => write!(f, "NetBSD"),
|
|
||||||
Self::OpenBsd => write!(f, "OpenBSD"),
|
|
||||||
Self::Common => write!(f, "Common"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl clap::ValueEnum for PlatformType {
|
|
||||||
fn value_variants<'a>() -> &'a [Self] {
|
|
||||||
&[
|
|
||||||
Self::Linux,
|
|
||||||
Self::OsX,
|
|
||||||
Self::SunOs,
|
|
||||||
Self::Windows,
|
|
||||||
Self::Android,
|
|
||||||
Self::FreeBsd,
|
|
||||||
Self::NetBsd,
|
|
||||||
Self::OpenBsd,
|
|
||||||
Self::Common,
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_possible_value<'a>(&self) -> Option<clap::builder::PossibleValue> {
|
|
||||||
match self {
|
|
||||||
Self::Linux => Some(clap::builder::PossibleValue::new("linux")),
|
|
||||||
Self::OsX => Some(clap::builder::PossibleValue::new("macos").alias("osx")),
|
|
||||||
Self::Windows => Some(clap::builder::PossibleValue::new("windows")),
|
|
||||||
Self::SunOs => Some(clap::builder::PossibleValue::new("sunos")),
|
|
||||||
Self::Android => Some(clap::builder::PossibleValue::new("android")),
|
|
||||||
Self::FreeBsd => Some(clap::builder::PossibleValue::new("freebsd")),
|
|
||||||
Self::NetBsd => Some(clap::builder::PossibleValue::new("netbsd")),
|
|
||||||
Self::OpenBsd => Some(clap::builder::PossibleValue::new("openbsd")),
|
|
||||||
Self::Common => Some(clap::builder::PossibleValue::new("common")),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PlatformType {
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
pub fn current() -> Self {
|
|
||||||
Self::Linux
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(target_os = "macos", target_os = "dragonfly"))]
|
|
||||||
pub fn current() -> Self {
|
|
||||||
Self::OsX
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
pub fn current() -> Self {
|
|
||||||
Self::Windows
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
|
||||||
pub fn current() -> Self {
|
|
||||||
Self::Android
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "freebsd")]
|
|
||||||
pub fn current() -> Self {
|
|
||||||
Self::FreeBsd
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "netbsd")]
|
|
||||||
pub fn current() -> Self {
|
|
||||||
Self::NetBsd
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "openbsd")]
|
|
||||||
pub fn current() -> Self {
|
|
||||||
Self::OpenBsd
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(any(
|
|
||||||
target_os = "linux",
|
|
||||||
target_os = "macos",
|
|
||||||
target_os = "freebsd",
|
|
||||||
target_os = "netbsd",
|
|
||||||
target_os = "openbsd",
|
|
||||||
target_os = "dragonfly",
|
|
||||||
target_os = "windows",
|
|
||||||
target_os = "android",
|
|
||||||
)))]
|
|
||||||
pub fn current() -> Self {
|
|
||||||
Self::Other
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Copy, Clone, Deserialize, clap::ValueEnum)]
|
|
||||||
#[serde(rename_all = "lowercase")]
|
|
||||||
#[derive(Default)]
|
|
||||||
pub enum ColorOptions {
|
|
||||||
Always,
|
|
||||||
#[default]
|
|
||||||
Auto,
|
|
||||||
Never,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq)]
|
|
||||||
pub enum LineType {
|
|
||||||
Empty,
|
|
||||||
Title(String),
|
|
||||||
Description(String),
|
|
||||||
ExampleText(String),
|
|
||||||
ExampleCode(String),
|
|
||||||
Other(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<&'a str> for LineType {
|
|
||||||
/// Convert a string slice to a `LineType`. Newlines and trailing whitespace are trimmed.
|
|
||||||
fn from(line: &'a str) -> Self {
|
|
||||||
let trimmed: &str = line.trim_end();
|
|
||||||
let mut chars = trimmed.chars();
|
|
||||||
match chars.next() {
|
|
||||||
None => Self::Empty,
|
|
||||||
Some('#') => Self::Title(
|
|
||||||
trimmed
|
|
||||||
.trim_start_matches(|chr: char| chr == '#' || chr.is_whitespace())
|
|
||||||
.into(),
|
|
||||||
),
|
|
||||||
Some('>') => Self::Description(
|
|
||||||
trimmed
|
|
||||||
.trim_start_matches(|chr: char| chr == '>' || chr.is_whitespace())
|
|
||||||
.into(),
|
|
||||||
),
|
|
||||||
Some(' ') => Self::ExampleCode(trimmed.trim_start_matches(char::is_whitespace).into()),
|
|
||||||
Some(_) => Self::ExampleText(trimmed.into()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LineType {
|
|
||||||
/// Support for old format.
|
|
||||||
/// TODO: Remove once old format has been phased out!
|
|
||||||
pub fn from_v1(line: &str) -> Self {
|
|
||||||
let trimmed = line.trim();
|
|
||||||
let mut chars = trimmed.chars();
|
|
||||||
match chars.next() {
|
|
||||||
None => Self::Empty,
|
|
||||||
Some('#') => Self::Title(
|
|
||||||
trimmed
|
|
||||||
.trim_start_matches(|chr: char| chr == '#' || chr.is_whitespace())
|
|
||||||
.into(),
|
|
||||||
),
|
|
||||||
Some('>') => Self::Description(
|
|
||||||
trimmed
|
|
||||||
.trim_start_matches(|chr: char| chr == '>' || chr.is_whitespace())
|
|
||||||
.into(),
|
|
||||||
),
|
|
||||||
Some('-') => Self::ExampleText(
|
|
||||||
trimmed
|
|
||||||
.trim_start_matches(|chr: char| chr == '-' || chr.is_whitespace())
|
|
||||||
.into(),
|
|
||||||
),
|
|
||||||
Some('`') if chars.last() == Some('`') => Self::ExampleCode(
|
|
||||||
trimmed
|
|
||||||
.trim_matches(|chr: char| chr == '`' || chr.is_whitespace())
|
|
||||||
.into(),
|
|
||||||
),
|
|
||||||
Some(_) => Self::Other(trimmed.into()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The reason why a certain path (e.g. config path or cache dir) was chosen.
|
|
||||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
|
||||||
pub enum PathSource {
|
|
||||||
/// OS convention (e.g. XDG on Linux)
|
|
||||||
OsConvention,
|
|
||||||
/// Env variable (TEALDEER_*)
|
|
||||||
EnvVar,
|
|
||||||
/// Config file
|
|
||||||
ConfigFile,
|
|
||||||
/// CLI argument override
|
|
||||||
Cli,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for PathSource {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"{}",
|
|
||||||
match self {
|
|
||||||
Self::OsConvention => "OS convention",
|
|
||||||
Self::EnvVar => "env variable",
|
|
||||||
Self::ConfigFile => "config file",
|
|
||||||
Self::Cli => "command line argument",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::LineType;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_linetype_from_str() {
|
|
||||||
assert_eq!(LineType::from(""), LineType::Empty);
|
|
||||||
assert_eq!(LineType::from(" \n \r"), LineType::Empty);
|
|
||||||
assert_eq!(
|
|
||||||
LineType::from("# Hello there"),
|
|
||||||
LineType::Title("Hello there".into())
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
LineType::from("> tis a description \n"),
|
|
||||||
LineType::Description("tis a description".into())
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
LineType::from("some command "),
|
|
||||||
LineType::ExampleText("some command".into())
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
LineType::from(" $ cargo run "),
|
|
||||||
LineType::ExampleCode("$ cargo run".into())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
21
src/utils.rs
|
|
@ -1,21 +0,0 @@
|
||||||
use yansi::{Color, Paint};
|
|
||||||
|
|
||||||
/// Print a warning to stderr. If `enable_styles` is true, then a yellow
|
|
||||||
/// message will be printed.
|
|
||||||
pub fn print_warning(enable_styles: bool, message: &str) {
|
|
||||||
print_msg(enable_styles, message, "Warning: ", Color::Yellow);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Print an anyhow error to stderr. If `enable_styles` is true, then a red
|
|
||||||
/// message will be printed.
|
|
||||||
pub fn print_error(enable_styles: bool, error: &anyhow::Error) {
|
|
||||||
print_msg(enable_styles, &format!("{error:?}"), "Error: ", Color::Red);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn print_msg(enable_styles: bool, message: &str, prefix: &'static str, color: Color) {
|
|
||||||
if enable_styles {
|
|
||||||
eprintln!("{}{}", prefix.paint(color), message.paint(color));
|
|
||||||
} else {
|
|
||||||
eprintln!("{message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
36
tests/cache/pages.en/common/git-checkout.md
vendored
|
|
@ -1,36 +0,0 @@
|
||||||
# git checkout
|
|
||||||
|
|
||||||
> Checkout a branch or paths to the working tree.
|
|
||||||
> More information: <https://git-scm.com/docs/git-checkout>.
|
|
||||||
|
|
||||||
- Create and switch to a new branch:
|
|
||||||
|
|
||||||
`git checkout -b {{branch_name}}`
|
|
||||||
|
|
||||||
- Create and switch to a new branch based on a specific reference (branch, remote/branch, tag are examples of valid references):
|
|
||||||
|
|
||||||
`git checkout -b {{branch_name}} {{reference}}`
|
|
||||||
|
|
||||||
- Switch to an existing local branch:
|
|
||||||
|
|
||||||
`git checkout {{branch_name}}`
|
|
||||||
|
|
||||||
- Switch to the previously checked out branch:
|
|
||||||
|
|
||||||
`git checkout -`
|
|
||||||
|
|
||||||
- Switch to an existing remote branch:
|
|
||||||
|
|
||||||
`git checkout --track {{remote_name}}/{{branch_name}}`
|
|
||||||
|
|
||||||
- Discard all unstaged changes in the current directory (see `git reset` for more undo-like commands):
|
|
||||||
|
|
||||||
`git checkout .`
|
|
||||||
|
|
||||||
- Discard unstaged changes to a given file:
|
|
||||||
|
|
||||||
`git checkout {{path/to/file}}`
|
|
||||||
|
|
||||||
- Replace a file in the current directory with the version of it committed in a given branch:
|
|
||||||
|
|
||||||
`git checkout {{branch_name}} -- {{path/to/file}}`
|
|
||||||