Add TUI viewer using cursive
This patch adds a new viewer, tui, that provides an interactive interface using cursive. This viewer makes it possible to follow links to other documentation items and to open external links in a web browser.
This commit is contained in:
parent
4260aab85a
commit
e222a1f443
@ -12,6 +12,8 @@ SPDX-License-Identifier: MIT
|
||||
the configuration file.
|
||||
- Add `merge` dependency in version 0.1.0.
|
||||
- Add syntax highlighting for code snippets in the doc comments.
|
||||
- Add interactive tui viewer that adds support for following links from the
|
||||
documentation.
|
||||
|
||||
## v0.3.0 (2020-09-11)
|
||||
|
||||
|
480
Cargo.lock
generated
480
Cargo.lock
generated
@ -7,6 +7,22 @@ name = "adler"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"const-random 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"const-random 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.12.1"
|
||||
@ -20,6 +36,16 @@ name = "anyhow"
|
||||
version = "1.0.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "array-macro"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "assert_cmd"
|
||||
version = "1.0.1"
|
||||
@ -66,6 +92,11 @@ name = "bitflags"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.3.4"
|
||||
@ -88,6 +119,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -113,6 +145,24 @@ dependencies = [
|
||||
"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const-random"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"const-random-macro 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro-hack 0.5.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const-random-macro"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro-hack 0.5.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.2.0"
|
||||
@ -121,6 +171,25 @@ dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cssparser"
|
||||
version = "0.27.2"
|
||||
@ -146,6 +215,80 @@ dependencies = [
|
||||
"syn 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cursive"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ahash 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-channel 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cursive_core 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"enumset 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.72 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ncurses 5.99.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"signal-hook 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"term_size 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cursive_core"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ahash 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"chrono 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-channel 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"enum-map 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"enumset 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.72 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"owning_ref 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"signal-hook 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"xi-unicode 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"darling_core 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"darling_macro 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"fnv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ident_case 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"strsim 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"darling_core 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_more"
|
||||
version = "0.99.9"
|
||||
@ -184,6 +327,45 @@ name = "encode_unicode"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "enum-map"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"array-macro 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"enum-map-derive 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enum-map-derive"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enumset"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"enumset_derive 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enumset_derive"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"darling 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.7.1"
|
||||
@ -306,6 +488,21 @@ dependencies = [
|
||||
"syn 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-normalization 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.5.1"
|
||||
@ -333,6 +530,14 @@ name = "itoa"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"wasm-bindgen 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kuchiki"
|
||||
version = "0.8.0"
|
||||
@ -385,6 +590,11 @@ name = "mac"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "maplit"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "markup5ever"
|
||||
version = "0.10.0"
|
||||
@ -417,6 +627,11 @@ name = "matches"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "maybe-uninit"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "merge"
|
||||
version = "0.1.0"
|
||||
@ -445,6 +660,16 @@ dependencies = [
|
||||
"adler 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ncurses"
|
||||
version = "5.99.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.72 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "new_debug_unreachable"
|
||||
version = "1.0.4"
|
||||
@ -455,6 +680,26 @@ name = "nodrop"
|
||||
version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "num"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-complex 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-iter 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-rational 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-complex"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.43"
|
||||
@ -464,6 +709,26 @@ dependencies = [
|
||||
"num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-iter"
|
||||
version = "0.1.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.12"
|
||||
@ -492,6 +757,14 @@ dependencies = [
|
||||
"pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "owning_ref"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"stable_deref_trait 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pager"
|
||||
version = "0.15.0"
|
||||
@ -501,6 +774,11 @@ dependencies = [
|
||||
"libc 0.2.72 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "phf"
|
||||
version = "0.8.0"
|
||||
@ -726,6 +1004,7 @@ dependencies = [
|
||||
"anyhow 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"assert_cmd 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cursive 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"html2text 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"insta 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -744,7 +1023,10 @@ dependencies = [
|
||||
"tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"terminal_size 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"text-style 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"textwrap 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"webbrowser 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@ -865,6 +1147,24 @@ dependencies = [
|
||||
"stable_deref_trait 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.72 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"signal-hook-registry 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"arc-swap 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.72 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "siphasher"
|
||||
version = "0.3.3"
|
||||
@ -903,6 +1203,11 @@ dependencies = [
|
||||
"quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "structopt"
|
||||
version = "0.3.15"
|
||||
@ -989,6 +1294,15 @@ dependencies = [
|
||||
"utf-8 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "term_size"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.72 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "terminal_size"
|
||||
version = "0.1.13"
|
||||
@ -1012,6 +1326,7 @@ version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ansi_term 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cursive 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syntect 4.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@ -1023,6 +1338,14 @@ dependencies = [
|
||||
"unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thin-slice"
|
||||
version = "0.1.1"
|
||||
@ -1037,6 +1360,11 @@ dependencies = [
|
||||
"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.5.6"
|
||||
@ -1050,6 +1378,22 @@ name = "treeline"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"tinyvec 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.6.0"
|
||||
@ -1065,6 +1409,16 @@ name = "unicode-xid"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf-8"
|
||||
version = "0.7.5"
|
||||
@ -1098,6 +1452,79 @@ name = "wasi"
|
||||
version = "0.9.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.68"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasm-bindgen-macro 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.68"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bumpalo 3.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasm-bindgen-shared 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.68"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasm-bindgen-macro-support 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.68"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasm-bindgen-backend 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasm-bindgen-shared 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.68"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"js-sys 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasm-bindgen 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webbrowser"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"web-sys 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"widestring 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "widestring"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
@ -1130,6 +1557,11 @@ name = "xdg"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "xi-unicode"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "xml-rs"
|
||||
version = "0.8.3"
|
||||
@ -1156,29 +1588,47 @@ dependencies = [
|
||||
|
||||
[metadata]
|
||||
"checksum adler 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
|
||||
"checksum ahash 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "e8fd72866655d1904d6b0997d0b07ba561047d070fbe29de039031c641b61217"
|
||||
"checksum ahash 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0adac150c2dd5a9c864d054e07bda5e6bc010cd10036ea5f17e82a2f5867f735"
|
||||
"checksum ansi_term 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||
"checksum anyhow 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "85bb70cc08ec97ca5450e6eba421deeea5f172c0fc61f78b5357b2a8e8be195f"
|
||||
"checksum arc-swap 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "4d25d88fd6b8041580a654f9d0c581a047baee2b3efee13275f2fc392fc75034"
|
||||
"checksum array-macro 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "06e97b4e522f9e55523001238ac59d13a8603af57f69980de5d8de4bbbe8ada6"
|
||||
"checksum assert_cmd 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c88b9ca26f9c16ec830350d309397e74ee9abdfd8eb1f71cb6ecc71a3fc818da"
|
||||
"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
|
||||
"checksum base64 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
|
||||
"checksum bincode 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f30d3a39baa26f9651f17b375061f3233dde33424a8b72b0dbe93a68a0bc896d"
|
||||
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
"checksum bumpalo 3.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820"
|
||||
"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
||||
"checksum cc 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)" = "f9a06fb2e53271d7c279ec1efea6ab691c35a2ae67ec0d91d7acec0caf13b518"
|
||||
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
"checksum chrono 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "c74d84029116787153e02106bf53e66828452a4b325cc8652b788b5967c0a0b6"
|
||||
"checksum clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129"
|
||||
"checksum console 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8c0994e656bba7b922d8dd1245db90672ffb701e684e45be58f20719d69abc5a"
|
||||
"checksum const-random 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "2f1af9ac737b2dd2d577701e59fd09ba34822f6f2ebdb30a7647405d9e55e16a"
|
||||
"checksum const-random-macro 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "25e4c606eb459dd29f7c57b2e0879f2b6f14ee130918c2b78ccb58a9624e6c7a"
|
||||
"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
|
||||
"checksum crossbeam-channel 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87"
|
||||
"checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
||||
"checksum cssparser 0.27.2 (registry+https://github.com/rust-lang/crates.io-index)" = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a"
|
||||
"checksum cssparser-macros 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dfae75de57f2b2e85e8768c3ea840fd159c8f33e2b6522c7835b7abac81be16e"
|
||||
"checksum cursive 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a9f12332ab2bca26979ef00cfef9a1c2e287db03b787a83d892ad9961f81374"
|
||||
"checksum cursive_core 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "85fc5b6a8ba2f1bc743892068bde466438f78d6247197e2dc094bfd53fdea4b7"
|
||||
"checksum darling 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858"
|
||||
"checksum darling_core 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b"
|
||||
"checksum darling_macro 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72"
|
||||
"checksum derive_more 0.99.9 (registry+https://github.com/rust-lang/crates.io-index)" = "298998b1cf6b5b2c8a7b023dfd45821825ce3ba8a8af55c921a0e734e4653f76"
|
||||
"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
|
||||
"checksum doc-comment 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
|
||||
"checksum dtoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "134951f4028bdadb9b84baf4232681efbf277da25144b9b0ad65df75946c422b"
|
||||
"checksum dtoa-short 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "59020b8513b76630c49d918c33db9f4c91638e7d3404a28084083b87e33f76f2"
|
||||
"checksum encode_unicode 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
||||
"checksum enum-map 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2f81f09b9cb18af2ea1da2688a1d6b1762b4f938d7495bb034bce48d4c608043"
|
||||
"checksum enum-map-derive 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e57001dfb2532f5a103ff869656887fae9a8defa7d236f3e39d2ee86ed629ad7"
|
||||
"checksum enumset 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "959a80a2062fedd66ed41d99736212de987b3a8c83a4c2cef243968075256bd1"
|
||||
"checksum enumset_derive 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "74bef436ac71820c5cf768d7af9ba33121246b09a00e09a55d94ef8095a875ac"
|
||||
"checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
|
||||
"checksum errno 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6eab5ee3df98a279d9b316b1af6ac95422127b1290317e6d18c1743c99418b01"
|
||||
"checksum errno-dragonfly 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "14ca354e36190500e1e1fb267c647932382b54053c50b14970856c0b00a35067"
|
||||
@ -1193,9 +1643,12 @@ dependencies = [
|
||||
"checksum hermit-abi 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c30f6d0bc6b00693347368a67d41b58f2fb851215ff1da49e90fe2c5c667151"
|
||||
"checksum html2text 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a26379dcb715e237b96102a12b505c553e2bffa74bae2e54658748d298660ef1"
|
||||
"checksum html5ever 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcf38a1a36118242d29b92e1b08ef84e67e4a5ed06e0a80be20e6a32bfed6b"
|
||||
"checksum ident_case 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
"checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9"
|
||||
"checksum indexmap 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "86b45e59b16c76b11bf9738fd5d38879d3bd28ad292d7b313608becb17ae2df9"
|
||||
"checksum insta 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "617e921abc813f96a3b00958c079e7bf1e2db998f8a04f1546dd967373a418ee"
|
||||
"checksum itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6"
|
||||
"checksum js-sys 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)" = "ca059e81d9486668f12d455a4ea6daa600bd408134cd17e3d3fb5a32d1f016f8"
|
||||
"checksum kuchiki 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1beeffc5ae5ab0def2cb85e26063a8e6b4f579b0adec3805bf87472086948956"
|
||||
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
|
||||
@ -1204,19 +1657,28 @@ dependencies = [
|
||||
"checksum linked-hash-map 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a"
|
||||
"checksum log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
|
||||
"checksum mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
|
||||
"checksum maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
|
||||
"checksum markup5ever 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aae38d669396ca9b707bfc3db254bc382ddb94f57cc5c235f34623a669a01dab"
|
||||
"checksum markup5ever_rcdom 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f015da43bcd8d4f144559a3423f4591d69b8ce0652c905374da7205df336ae2b"
|
||||
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
|
||||
"checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
|
||||
"checksum merge 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "10bbef93abb1da61525bbc45eeaff6473a41907d19f8f9aa5168d214e10693e9"
|
||||
"checksum merge_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "209d075476da2e63b4b29e72a2ef627b840589588e71400a25e3565c4f849d07"
|
||||
"checksum miniz_oxide 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "be0f75932c1f6cfae3c04000e40114adf955636e19040f9c0a2c380702aa1c7f"
|
||||
"checksum ncurses 5.99.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15699bee2f37e9f8828c7b35b2bc70d13846db453f2d507713b758fabe536b82"
|
||||
"checksum new_debug_unreachable 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
|
||||
"checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
|
||||
"checksum num 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab3e176191bc4faad357e3122c4747aa098ac880e88b168f106386128736cf4a"
|
||||
"checksum num-complex 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b05ad05bd8977050b171b3f6b48175fea6e0565b7981059b486075e1026a9fb5"
|
||||
"checksum num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b"
|
||||
"checksum num-iter 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e6b7c748f995c4c29c5f5ae0248536e04a5739927c74ec0fa564805094b9f"
|
||||
"checksum num-rational 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b4d7360f362cfb50dde8143501e6940b22f644be75a4cc90b2d81968908138"
|
||||
"checksum num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611"
|
||||
"checksum onig 6.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd91ccd8a02fce2f7e8a86655aec67bc6c171e6f8e704118a0e8c4b866a05a8a"
|
||||
"checksum onig_sys 69.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3814583fad89f3c60ae0701d80e87e1fd3028741723deda72d0d4a0ecf0cb0db"
|
||||
"checksum owning_ref 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce"
|
||||
"checksum pager 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b69ced2bfa977c4541743a7427b89c94120684791a9629941fe6028dccab6528"
|
||||
"checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
|
||||
"checksum phf 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12"
|
||||
"checksum phf_codegen 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815"
|
||||
"checksum phf_generator 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526"
|
||||
@ -1256,11 +1718,14 @@ dependencies = [
|
||||
"checksum serde_tuple_macros 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4076151d1a2b688e25aaf236997933c66e18b870d0369f8b248b8ab2be630d7e"
|
||||
"checksum serde_yaml 0.8.13 (registry+https://github.com/rust-lang/crates.io-index)" = "ae3e2dd40a7cdc18ca80db804b7f461a39bb721160a85c9a1fa30134bf3c02a5"
|
||||
"checksum servo_arc 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432"
|
||||
"checksum signal-hook 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "604508c1418b99dfe1925ca9224829bb2a8a9a04dda655cc01fcad46f4ab05ed"
|
||||
"checksum signal-hook-registry 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a3e12110bc539e657a646068aaf5eb5b63af9d0c1f7b29c97113fad80e15f035"
|
||||
"checksum siphasher 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fa8f3741c7372e75519bd9346068370c9cdaabcc1f9599cbcf2a2719352286b7"
|
||||
"checksum smallvec 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3757cb9d89161a2f24e1cf78efa0c1fcff485d18e3f55e0aa3480824ddaa0f3f"
|
||||
"checksum stable_deref_trait 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||
"checksum string_cache 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2940c75beb4e3bf3a494cef919a747a2cb81e52571e212bfbd185074add7208a"
|
||||
"checksum string_cache_codegen 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f24c8e5e19d22a726626f1a5e16fe15b132dcf21d10177fa5a45ce7962996b97"
|
||||
"checksum strsim 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c"
|
||||
"checksum structopt 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "de2f5e239ee807089b62adce73e48c625e0ed80df02c7ab3f068f5db5281065c"
|
||||
"checksum structopt-derive 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "510413f9de616762a4fbeab62509bf15c729603b72d7cd71280fbca431b1c118"
|
||||
"checksum syn 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)" = "936cae2873c940d92e697597c5eee105fb570cd5689c695806f672883653349b"
|
||||
@ -1268,27 +1733,42 @@ dependencies = [
|
||||
"checksum syntect 4.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b57a45fdcf4891bc79f635be5c559210a4cfa464891f969724944c713282eedb"
|
||||
"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
|
||||
"checksum tendril 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "707feda9f2582d5d680d733e38755547a3e8fb471e7ba11452ecfd9ce93a5d3b"
|
||||
"checksum term_size 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1e4129646ca0ed8f45d09b929036bafad5377103edd06e50bf574b353d2b08d9"
|
||||
"checksum terminal_size 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9a14cd9f8c72704232f0bfc8455c0e861f0ad4eb60cc9ec8a170e231414c1e13"
|
||||
"checksum termios 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6f0fcee7b24a25675de40d5bb4de6e41b0df07bc9856295e7e2b3a3600c400c2"
|
||||
"checksum text-style 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "01ecc55ab699ed1b4d0ebe64d7a8ee2611f55d0de4042e9c1ee5a81dee89e332"
|
||||
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
"checksum textwrap 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "203008d98caf094106cfaba70acfed15e18ed3ddb7d94e49baec153a2b462789"
|
||||
"checksum thin-slice 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c"
|
||||
"checksum time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438"
|
||||
"checksum tinyvec 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "238ce071d267c5710f9d31451efec16c5ee22de34df17cc05e56cbc92e967117"
|
||||
"checksum toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a"
|
||||
"checksum treeline 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41"
|
||||
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
|
||||
"checksum unicode-normalization 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6fb19cf769fa8c6a80a162df694621ebeb4dafb606470b2b2fce0be40a98a977"
|
||||
"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
|
||||
"checksum unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
|
||||
"checksum unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
||||
"checksum url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb"
|
||||
"checksum utf-8 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)" = "05e42f7c18b8f902290b009cde6d651262f956c98bc51bca4cd1d511c9cd85c7"
|
||||
"checksum version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
|
||||
"checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
|
||||
"checksum walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
|
||||
"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||
"checksum wasm-bindgen 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)" = "1ac64ead5ea5f05873d7c12b545865ca2b8d28adfc50a49b84770a3a97265d42"
|
||||
"checksum wasm-bindgen-backend 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)" = "f22b422e2a757c35a73774860af8e112bff612ce6cb604224e8e47641a9e4f68"
|
||||
"checksum wasm-bindgen-macro 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)" = "6b13312a745c08c469f0b292dd2fcd6411dba5f7160f593da6ef69b64e407038"
|
||||
"checksum wasm-bindgen-macro-support 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)" = "f249f06ef7ee334cc3b8ff031bfc11ec99d00f34d86da7498396dc1e3b1498fe"
|
||||
"checksum wasm-bindgen-shared 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)" = "1d649a3145108d7d3fbcde896a468d1bd636791823c9921135218ad89be08307"
|
||||
"checksum web-sys 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf6ef87ad7ae8008e15a355ce696bed26012b7caa21605188cfd8214ab51e2d"
|
||||
"checksum webbrowser 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ecad156490d6b620308ed411cfee90d280b3cbd13e189ea0d3fada8acc89158a"
|
||||
"checksum widestring 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a763e303c0e0f23b0da40888724762e802a8ffefbc22de4127ef42493c2ea68c"
|
||||
"checksum winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
"checksum winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
"checksum xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57"
|
||||
"checksum xi-unicode 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e71b85d8b1b8bfaf4b5c834187554d201a8cd621c2bbfa33efd41a3ecabd48b2"
|
||||
"checksum xml-rs 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a"
|
||||
"checksum xml5ever 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b1b52e6e8614d4a58b8e70cf51ec0cc21b256ad8206708bcff8139b5bbd6a59"
|
||||
"checksum yaml-rust 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "39f0c922f1a334134dc2f7a8b67dc5d25f0735263feec974345ff706bcf20b0d"
|
||||
|
@ -19,6 +19,7 @@ exclude = [".builds/*", "tests/html/*", "tests/snapshots/*"]
|
||||
ansi_term = "0.12.1"
|
||||
anyhow = "1.0.31"
|
||||
atty = "0.2.14"
|
||||
cursive = "0.15.0"
|
||||
html2text = "0.2.1"
|
||||
kuchiki = "0.8.0"
|
||||
log = "0.4.11"
|
||||
@ -28,7 +29,10 @@ pager = "0.15.0"
|
||||
serde_json = "1.0.56"
|
||||
serde_tuple = "0.5.0"
|
||||
terminal_size = "0.1.13"
|
||||
textwrap = "0.12.1"
|
||||
toml = "0.5.6"
|
||||
url = "2.1.1"
|
||||
webbrowser = "0.5.5"
|
||||
xdg = "2.2.0"
|
||||
|
||||
[dependencies.env_logger]
|
||||
@ -50,7 +54,7 @@ features = ["parsing", "regex-onig", "assets", "dump-load"]
|
||||
|
||||
[dependencies.text-style]
|
||||
version = "0.2.0"
|
||||
features = ["ansi_term", "syntect"]
|
||||
features = ["ansi_term", "cursive", "syntect"]
|
||||
|
||||
[dev-dependencies]
|
||||
assert_cmd = "1.0.1"
|
||||
|
18
INSTALL.md
18
INSTALL.md
@ -16,7 +16,23 @@ rusty-man packages are available for these distributions:
|
||||
|
||||
### Build Requirements
|
||||
|
||||
To compile rusty-man, you need Rust 1.40 or later.
|
||||
To compile rusty-man, you need Rust 1.40 or later. The `tui` backend requires
|
||||
the ncurses library in the default search path and a C compiler.
|
||||
|
||||
If you don’t want to use ncurses, you can select another [`cursive`][] backend
|
||||
by replacing this line in `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
cursive = "0.15.0"
|
||||
```
|
||||
|
||||
with this:
|
||||
|
||||
```toml
|
||||
cursive = { version = "0.15.0", default-features = false, feature = ["termion-backend"] }
|
||||
```
|
||||
|
||||
[`cursive`]: https://lib.rs/cursive
|
||||
|
||||
### Installing from Git
|
||||
|
||||
|
17
README.md
17
README.md
@ -53,6 +53,17 @@ Found mulitple matches for u8 – select one of:
|
||||
|
||||
For more usage information, run `rusty-man --help`.
|
||||
|
||||
## Viewers
|
||||
|
||||
rusty-man has three viewers (select one with the `--viewer` option) that
|
||||
determine the output format:
|
||||
- `plain` prints the documentation to the standard output without formatting.
|
||||
This is the default for non-interactive use.
|
||||
- `rich` prints the documentation to the standard output with formatting and
|
||||
optional syntax highlighting. This is the default for interactive use.
|
||||
- `tui` is an interactive terminal interface. You can read the documentation
|
||||
and follow links.
|
||||
|
||||
## Installation
|
||||
|
||||
To install rusty-man from source, clone this repository and use cargo to build
|
||||
@ -60,8 +71,10 @@ the project, or use `cargo install`. See the [`INSTALL.md`][] file for more
|
||||
information. rusty-man is also available as a package for these distributions:
|
||||
- Arch Linux: [`rusty-man`][pkg-aur] in the Arch User Repository
|
||||
|
||||
rusty-man should run on all platforms, but the `rich` viewer is only available
|
||||
for ANSI terminals. If you have trouble running rusty-man on your platform or
|
||||
rusty-man is developed for Unix-like systems. It should run on other platforms
|
||||
too, but with some limitations: The `rich` viewer uses ANSI escape codes,
|
||||
which are not supported on older Windows versions. The `tui` viewer requires
|
||||
the ncurses library. If you have trouble running rusty-man on your platform or
|
||||
if you want to help porting rusty-man to other platforms, please let me know.
|
||||
|
||||
## Integrations
|
||||
|
@ -65,9 +65,9 @@ fn main() -> anyhow::Result<()> {
|
||||
"Could not find examples for {}",
|
||||
&args.keyword
|
||||
);
|
||||
viewer.open_examples(args.viewer_args, &doc, examples)
|
||||
viewer.open_examples(sources, args.viewer_args, &doc, examples)
|
||||
} else {
|
||||
viewer.open(args.viewer_args, &doc)
|
||||
viewer.open(sources, args.viewer_args, &doc)
|
||||
}
|
||||
} else {
|
||||
// item selection cancelled by user
|
||||
|
@ -2,18 +2,26 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
mod text;
|
||||
mod tui;
|
||||
mod utils;
|
||||
|
||||
use std::fmt;
|
||||
|
||||
use crate::args;
|
||||
use crate::doc;
|
||||
use crate::source;
|
||||
|
||||
pub trait Viewer: fmt::Debug {
|
||||
fn open(&self, args: args::ViewerArgs, doc: &doc::Doc) -> anyhow::Result<()>;
|
||||
fn open(
|
||||
&self,
|
||||
sources: Vec<Box<dyn source::Source>>,
|
||||
args: args::ViewerArgs,
|
||||
doc: &doc::Doc,
|
||||
) -> anyhow::Result<()>;
|
||||
|
||||
fn open_examples(
|
||||
&self,
|
||||
sources: Vec<Box<dyn source::Source>>,
|
||||
args: args::ViewerArgs,
|
||||
doc: &doc::Doc,
|
||||
examples: Vec<doc::Example>,
|
||||
@ -24,6 +32,7 @@ pub fn get_viewer(s: &str) -> anyhow::Result<Box<dyn Viewer>> {
|
||||
let viewer: Box<dyn Viewer> = match s.to_lowercase().as_ref() {
|
||||
"plain" => Box::new(text::TextViewer::new(text::TextMode::Plain)),
|
||||
"rich" => Box::new(text::TextViewer::new(text::TextMode::Rich)),
|
||||
"tui" => Box::new(tui::TuiViewer::new()),
|
||||
_ => anyhow::bail!("The viewer {} is not supported", s),
|
||||
};
|
||||
Ok(viewer)
|
||||
|
@ -8,6 +8,7 @@ use std::io;
|
||||
|
||||
use crate::args;
|
||||
use crate::doc;
|
||||
use crate::source;
|
||||
use crate::viewer::{self, utils};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@ -41,12 +42,18 @@ impl TextViewer {
|
||||
}
|
||||
|
||||
impl viewer::Viewer for TextViewer {
|
||||
fn open(&self, args: args::ViewerArgs, doc: &doc::Doc) -> anyhow::Result<()> {
|
||||
fn open(
|
||||
&self,
|
||||
_sources: Vec<Box<dyn source::Source>>,
|
||||
args: args::ViewerArgs,
|
||||
doc: &doc::Doc,
|
||||
) -> anyhow::Result<()> {
|
||||
self.exec(args, |mut viewer| viewer.render_doc(doc))
|
||||
}
|
||||
|
||||
fn open_examples(
|
||||
&self,
|
||||
_sources: Vec<Box<dyn source::Source>>,
|
||||
args: args::ViewerArgs,
|
||||
doc: &doc::Doc,
|
||||
examples: Vec<doc::Example>,
|
||||
|
@ -40,7 +40,7 @@ impl utils::ManRenderer for RichTextRenderer {
|
||||
} else {
|
||||
indent
|
||||
};
|
||||
let decorator = utils::RichDecorator::new(super::list_link);
|
||||
let decorator = utils::RichDecorator::new(super::list_link, utils::LinkMode::List);
|
||||
let lines = html2text::parse(s.html.as_bytes())
|
||||
.render(self.line_length - indent, decorator)
|
||||
.into_lines();
|
||||
|
376
src/viewer/tui/mod.rs
Normal file
376
src/viewer/tui/mod.rs
Normal file
@ -0,0 +1,376 @@
|
||||
// SPDX-FileCopyrightText: 2020 Robin Krahl <robin.krahl@ireas.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
mod views;
|
||||
|
||||
use std::convert;
|
||||
|
||||
use anyhow::Context as _;
|
||||
use cursive::view::{Resizable as _, Scrollable as _};
|
||||
use cursive::views::{Dialog, LinearLayout, PaddedView, Panel, TextView};
|
||||
use cursive::{event, theme};
|
||||
|
||||
use crate::args;
|
||||
use crate::doc;
|
||||
use crate::source;
|
||||
use crate::viewer::{self, utils, utils::ManRenderer as _};
|
||||
|
||||
use views::{CodeView, HtmlView};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TuiViewer {}
|
||||
|
||||
impl TuiViewer {
|
||||
pub fn new() -> TuiViewer {
|
||||
TuiViewer {}
|
||||
}
|
||||
|
||||
fn render<F>(
|
||||
&self,
|
||||
sources: Vec<Box<dyn source::Source>>,
|
||||
args: args::ViewerArgs,
|
||||
doc: &doc::Doc,
|
||||
f: F,
|
||||
) -> anyhow::Result<()>
|
||||
where
|
||||
F: Fn(&mut TuiManRenderer) -> Result<(), convert::Infallible>,
|
||||
{
|
||||
let mut s = create_cursive(sources, args)?;
|
||||
let mut renderer = context(&mut s).create_renderer(&doc);
|
||||
f(&mut renderer)?;
|
||||
let view = renderer.into_view();
|
||||
s.add_fullscreen_layer(view);
|
||||
s.run();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl viewer::Viewer for TuiViewer {
|
||||
fn open(
|
||||
&self,
|
||||
sources: Vec<Box<dyn source::Source>>,
|
||||
args: args::ViewerArgs,
|
||||
doc: &doc::Doc,
|
||||
) -> anyhow::Result<()> {
|
||||
self.render(sources, args, doc, |renderer| renderer.render_doc(doc))
|
||||
}
|
||||
|
||||
fn open_examples(
|
||||
&self,
|
||||
sources: Vec<Box<dyn source::Source>>,
|
||||
args: args::ViewerArgs,
|
||||
doc: &doc::Doc,
|
||||
examples: Vec<doc::Example>,
|
||||
) -> anyhow::Result<()> {
|
||||
self.render(sources, args, doc, |renderer| {
|
||||
renderer.render_examples(doc, &examples)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Context {
|
||||
pub sources: Vec<Box<dyn source::Source>>,
|
||||
pub args: args::ViewerArgs,
|
||||
pub highlighter: Option<utils::Highlighter>,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
pub fn new(
|
||||
sources: Vec<Box<dyn source::Source>>,
|
||||
args: args::ViewerArgs,
|
||||
) -> anyhow::Result<Context> {
|
||||
let highlighter = utils::get_highlighter(&args)?;
|
||||
Ok(Context {
|
||||
sources,
|
||||
args,
|
||||
highlighter,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn create_renderer(&self, doc: &doc::Doc) -> TuiManRenderer {
|
||||
TuiManRenderer::new(
|
||||
doc,
|
||||
self.args.max_width.unwrap_or(100),
|
||||
self.highlighter.as_ref(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TuiManRenderer<'s> {
|
||||
doc_name: doc::Fqn,
|
||||
doc_ty: doc::ItemType,
|
||||
layout: LinearLayout,
|
||||
max_width: usize,
|
||||
highlighter: Option<&'s utils::Highlighter>,
|
||||
}
|
||||
|
||||
impl<'s> TuiManRenderer<'s> {
|
||||
pub fn new(
|
||||
doc: &doc::Doc,
|
||||
max_width: usize,
|
||||
highlighter: Option<&'s utils::Highlighter>,
|
||||
) -> TuiManRenderer<'s> {
|
||||
TuiManRenderer {
|
||||
doc_name: doc.name.clone(),
|
||||
doc_ty: doc.ty,
|
||||
layout: LinearLayout::vertical(),
|
||||
max_width,
|
||||
highlighter,
|
||||
}
|
||||
}
|
||||
|
||||
fn into_view(self) -> impl cursive::View {
|
||||
let title = format!("{} {}", self.doc_ty.name(), self.doc_name);
|
||||
let scroll = self.layout.scrollable().full_screen();
|
||||
Panel::new(scroll).title(title)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s> utils::ManRenderer for TuiManRenderer<'s> {
|
||||
type Error = convert::Infallible;
|
||||
|
||||
fn print_title(&mut self, _left: &str, _center: &str, _right: &str) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_heading(&mut self, indent: u8, text: &str) -> Result<(), Self::Error> {
|
||||
let heading = TextView::new(text).effect(theme::Effect::Bold);
|
||||
self.layout.add_child(indent_view(indent, heading));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_code(&mut self, indent: u8, code: &doc::Code) -> Result<(), Self::Error> {
|
||||
if let Some(highlighter) = self.highlighter {
|
||||
let code = CodeView::new(&code.to_string(), highlighter);
|
||||
self.layout.add_child(indent_view(indent, code));
|
||||
} else {
|
||||
let text = TextView::new(code.to_string());
|
||||
self.layout.add_child(indent_view(indent, text));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_text(&mut self, indent: u8, text: &doc::Text) -> Result<(), Self::Error> {
|
||||
let indent = usize::from(indent);
|
||||
let mut text = HtmlView::new(
|
||||
&text.html,
|
||||
self.highlighter.cloned(),
|
||||
self.max_width.saturating_sub(indent),
|
||||
);
|
||||
let doc_name = self.doc_name.clone();
|
||||
let doc_ty = self.doc_ty;
|
||||
text.set_on_link(move |s, link| handle_link(s, &doc_name.clone(), doc_ty, link));
|
||||
self.layout.add_child(indent_view(indent, text));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn println(&mut self) -> Result<(), Self::Error> {
|
||||
self.layout.add_child(TextView::new(" "));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn indent_view<V>(indent: impl Into<usize>, view: V) -> PaddedView<V> {
|
||||
PaddedView::lrtb(indent.into(), 0, 0, 0, view)
|
||||
}
|
||||
|
||||
fn create_cursive(
|
||||
sources: Vec<Box<dyn source::Source>>,
|
||||
args: args::ViewerArgs,
|
||||
) -> anyhow::Result<cursive::Cursive> {
|
||||
let mut cursive = cursive::default();
|
||||
|
||||
cursive.set_user_data(Context::new(sources, args)?);
|
||||
|
||||
cursive.add_global_callback('q', |s| s.quit());
|
||||
cursive.add_global_callback(event::Key::Backspace, |s| {
|
||||
let screen = s.screen_mut();
|
||||
if screen.len() > 1 {
|
||||
screen.pop_layer();
|
||||
}
|
||||
});
|
||||
|
||||
let mut theme = theme::Theme::default();
|
||||
theme.shadow = false;
|
||||
theme.palette[theme::PaletteColor::Background] = theme::Color::TerminalDefault;
|
||||
theme.palette[theme::PaletteColor::View] = theme::Color::TerminalDefault;
|
||||
theme.palette[theme::PaletteColor::Primary] = theme::Color::TerminalDefault;
|
||||
cursive.set_theme(theme);
|
||||
|
||||
Ok(cursive)
|
||||
}
|
||||
|
||||
fn context(s: &mut cursive::Cursive) -> &mut Context {
|
||||
s.user_data()
|
||||
.expect("Missing context in cursive application")
|
||||
}
|
||||
|
||||
fn report_error(s: &mut cursive::Cursive, error: anyhow::Error) {
|
||||
let context: Vec<_> = error
|
||||
.chain()
|
||||
.skip(1)
|
||||
.map(|e| format!(" {}", e.to_string()))
|
||||
.collect();
|
||||
|
||||
let mut msg = error.to_string();
|
||||
if !context.is_empty() {
|
||||
msg.push_str("\n\nContext:\n");
|
||||
msg.push_str(&context.join("\n"));
|
||||
}
|
||||
|
||||
let dialog = Dialog::info(msg).title("Error");
|
||||
s.add_layer(dialog);
|
||||
}
|
||||
|
||||
fn handle_link(s: &mut cursive::Cursive, doc_name: &doc::Fqn, doc_ty: doc::ItemType, link: String) {
|
||||
let result = resolve_link(doc_name, doc_ty, link).and_then(|link| open_link(s, link));
|
||||
if let Err(err) = result {
|
||||
report_error(s, err);
|
||||
}
|
||||
}
|
||||
|
||||
fn find_doc(
|
||||
sources: &[Box<dyn source::Source>],
|
||||
ty: Option<doc::ItemType>,
|
||||
name: &doc::Fqn,
|
||||
) -> anyhow::Result<doc::Doc> {
|
||||
for source in sources {
|
||||
if let Some(doc) = source.find_doc(name, ty)? {
|
||||
return Ok(doc);
|
||||
}
|
||||
}
|
||||
Err(anyhow::anyhow!(
|
||||
"Could not find documentation for item: {}",
|
||||
name
|
||||
))
|
||||
}
|
||||
|
||||
fn open_link(s: &mut cursive::Cursive, link: ResolvedLink) -> anyhow::Result<()> {
|
||||
match link {
|
||||
ResolvedLink::Doc(ty, name) => {
|
||||
let doc = find_doc(&context(s).sources, ty, &name)?;
|
||||
let mut renderer = context(s).create_renderer(&doc);
|
||||
renderer.render_doc(&doc).unwrap();
|
||||
let view = renderer.into_view();
|
||||
s.add_fullscreen_layer(view);
|
||||
Ok(())
|
||||
}
|
||||
ResolvedLink::External(link) => webbrowser::open(&link)
|
||||
.map(|_| {})
|
||||
.context("Failed to open web browser"),
|
||||
}
|
||||
}
|
||||
|
||||
enum ResolvedLink {
|
||||
Doc(Option<doc::ItemType>, doc::Fqn),
|
||||
External(String),
|
||||
}
|
||||
|
||||
fn resolve_link(
|
||||
doc_name: &doc::Fqn,
|
||||
doc_ty: doc::ItemType,
|
||||
link: String,
|
||||
) -> anyhow::Result<ResolvedLink> {
|
||||
// TODO: support docs.rs and doc.rust-lang.org links
|
||||
match url::Url::parse(&link) {
|
||||
Ok(_) => Ok(ResolvedLink::External(link)),
|
||||
Err(url::ParseError::RelativeUrlWithoutBase) => resolve_doc_link(doc_name, doc_ty, &link)
|
||||
.with_context(|| format!("Could not parse relative link URL: {}", &link)),
|
||||
Err(e) => {
|
||||
Err(anyhow::Error::new(e).context(format!("Could not parse link URL: {}", &link)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_doc_link(
|
||||
doc_name: &doc::Fqn,
|
||||
doc_ty: doc::ItemType,
|
||||
link: &str,
|
||||
) -> anyhow::Result<ResolvedLink> {
|
||||
// TODO: use a proper URL parser instead of manually parsing the URL
|
||||
let (link, fragment) = {
|
||||
let parts: Vec<_> = link.splitn(2, '#').collect();
|
||||
if parts.len() > 1 {
|
||||
(parts[0], Some(parts[1]))
|
||||
} else {
|
||||
(parts[0], None)
|
||||
}
|
||||
};
|
||||
let parts: Vec<_> = link
|
||||
.split('/')
|
||||
.filter(|s| !s.is_empty())
|
||||
.filter(|s| *s != ".")
|
||||
.collect();
|
||||
|
||||
let (mut ty, mut name) = if doc_ty != doc::ItemType::Module && !parts.is_empty() {
|
||||
(None, doc_name.parent())
|
||||
} else {
|
||||
(Some(doc_ty), Some(doc_name.to_owned()))
|
||||
};
|
||||
|
||||
for part in parts {
|
||||
// We support "..", "index.html", "<module>" and "<type>.<name>.html".
|
||||
match part {
|
||||
".." => {
|
||||
ty = None;
|
||||
name = name.context("Exceeded root level")?.parent();
|
||||
}
|
||||
"index.html" => {}
|
||||
_ => {
|
||||
if let Some((part_ty, part_name)) = parse_url_part(part, Some(".html")) {
|
||||
// part == "type.name.html"
|
||||
ty = Some(part_ty.parse()?);
|
||||
name = if let Some(name) = name {
|
||||
Some(name.child(&part_name))
|
||||
} else {
|
||||
Some(part_name.to_owned().into())
|
||||
};
|
||||
} else {
|
||||
// part == "<module>"
|
||||
ty = Some(doc::ItemType::Module);
|
||||
name = if let Some(name) = name {
|
||||
Some(name.child(&part))
|
||||
} else {
|
||||
Some(part.to_owned().into())
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(fragment) = fragment {
|
||||
// If the fragment is "<type>.:name>", we add it to the name, otherwise we ignore it
|
||||
// because it just points to some other element on the page.
|
||||
if let Some((fragment_ty, fragment_name)) = parse_url_part(fragment, None) {
|
||||
ty = Some(fragment_ty.parse()?);
|
||||
name = if let Some(name) = name {
|
||||
Some(name.child(&fragment_name))
|
||||
} else {
|
||||
Some(fragment_name.to_owned().into())
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Ok(ResolvedLink::Doc(
|
||||
ty,
|
||||
name.context("Cannot handle link to root")?,
|
||||
))
|
||||
}
|
||||
|
||||
fn parse_url_part<'s>(s: &'s str, suffix: Option<&str>) -> Option<(&'s str, &'s str)> {
|
||||
let s = if let Some(suffix) = suffix {
|
||||
if s.ends_with(suffix) {
|
||||
&s[..s.len() - suffix.len()]
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
} else {
|
||||
s
|
||||
};
|
||||
let parts: Vec<_> = s.split('.').collect();
|
||||
if parts.len() == 2 {
|
||||
Some((parts[0], parts[1]))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
383
src/viewer/tui/views.rs
Normal file
383
src/viewer/tui/views.rs
Normal file
@ -0,0 +1,383 @@
|
||||
// SPDX-FileCopyrightText: 2020 Robin Krahl <robin.krahl@ireas.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use std::cmp;
|
||||
use std::iter;
|
||||
use std::rc;
|
||||
|
||||
use cursive::{event, theme, utils::markup};
|
||||
use html2text::render::text_renderer;
|
||||
|
||||
use crate::viewer::utils;
|
||||
|
||||
pub struct HtmlView {
|
||||
render_tree: html2text::RenderTree,
|
||||
highlighter: Option<utils::Highlighter>,
|
||||
max_width: usize,
|
||||
rendered_html: Option<RenderedHtml>,
|
||||
focus: Option<usize>,
|
||||
on_link: Option<rc::Rc<dyn Fn(&mut cursive::Cursive, String)>>,
|
||||
}
|
||||
|
||||
impl HtmlView {
|
||||
pub fn new(html: &str, highlighter: Option<utils::Highlighter>, max_width: usize) -> HtmlView {
|
||||
HtmlView {
|
||||
render_tree: html2text::parse(html.as_bytes()),
|
||||
highlighter,
|
||||
max_width,
|
||||
rendered_html: None,
|
||||
focus: None,
|
||||
on_link: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_on_link<F>(&mut self, cb: F)
|
||||
where
|
||||
F: Fn(&mut cursive::Cursive, String) + 'static,
|
||||
{
|
||||
self.on_link = Some(rc::Rc::new(cb));
|
||||
}
|
||||
|
||||
fn render(&self, width: usize) -> RenderedHtml {
|
||||
let mut rendered_html = RenderedHtml::new(width);
|
||||
let decorator = utils::RichDecorator::new(show_link, utils::LinkMode::Annotate);
|
||||
let raw_lines = self
|
||||
.render_tree
|
||||
.clone()
|
||||
.render(width, decorator)
|
||||
.into_lines();
|
||||
let highlighted_lines = utils::highlight_html(&raw_lines, self.highlighter.as_ref());
|
||||
for (y, line) in highlighted_lines.enumerate() {
|
||||
rendered_html.push_line(y, line);
|
||||
}
|
||||
rendered_html
|
||||
}
|
||||
|
||||
fn update(&mut self, constraint: cursive::XY<usize>) -> cursive::XY<usize> {
|
||||
let width = cmp::min(self.max_width, constraint.x);
|
||||
|
||||
// If we already have rendered the tree with the same width, we can reuse the cached data.
|
||||
if let Some(rendered_html) = &self.rendered_html {
|
||||
if rendered_html.width == width {
|
||||
return rendered_html.size;
|
||||
}
|
||||
}
|
||||
|
||||
let rendered_html = self.render(width);
|
||||
|
||||
// Due to changed wrapping, the link count may have changed. So we have to make sure that
|
||||
// our focus is still valid.
|
||||
if let Some(focus) = self.focus {
|
||||
// TODO: Ideally, we would also want to adjust the focus if a previous link was
|
||||
// re-wrapped.
|
||||
if focus >= rendered_html.links.len() {
|
||||
self.focus = Some(rendered_html.links.len() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
let size = rendered_html.size;
|
||||
self.rendered_html = Some(rendered_html);
|
||||
size
|
||||
}
|
||||
}
|
||||
|
||||
impl cursive::View for HtmlView {
|
||||
fn draw(&self, printer: &cursive::Printer) {
|
||||
let lines = &self
|
||||
.rendered_html
|
||||
.as_ref()
|
||||
.expect("layout not called before draw")
|
||||
.lines;
|
||||
for (y, line) in lines.iter().enumerate() {
|
||||
let mut x = 0;
|
||||
for element in line {
|
||||
let mut style = element.style;
|
||||
if element.link_idx == self.focus && printer.focused {
|
||||
style = style.combine(theme::PaletteColor::Highlight);
|
||||
}
|
||||
printer.with_style(style, |printer| printer.print((x, y), &element.text));
|
||||
x += element.text.len();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn layout(&mut self, constraint: cursive::XY<usize>) {
|
||||
self.update(constraint);
|
||||
}
|
||||
|
||||
fn required_size(&mut self, constraint: cursive::XY<usize>) -> cursive::XY<usize> {
|
||||
self.update(constraint)
|
||||
}
|
||||
|
||||
fn take_focus(&mut self, direction: cursive::direction::Direction) -> bool {
|
||||
let link_count = self
|
||||
.rendered_html
|
||||
.as_ref()
|
||||
.map(|html| html.links.len())
|
||||
.unwrap_or_default();
|
||||
if link_count > 0 {
|
||||
use cursive::direction::{Absolute, Direction, Relative};
|
||||
let focus = match direction {
|
||||
Direction::Abs(abs) => match abs {
|
||||
Absolute::Up | Absolute::Left | Absolute::None => 0,
|
||||
Absolute::Down | Absolute::Right => link_count - 1,
|
||||
},
|
||||
Direction::Rel(rel) => match rel {
|
||||
Relative::Front => 0,
|
||||
Relative::Back => link_count - 1,
|
||||
},
|
||||
};
|
||||
self.focus = Some(focus);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn on_event(&mut self, event: event::Event) -> event::EventResult {
|
||||
use event::{Event, EventResult, Key};
|
||||
|
||||
let links = if let Some(rendered_html) = &self.rendered_html {
|
||||
if rendered_html.links.is_empty() {
|
||||
return EventResult::Ignored;
|
||||
} else {
|
||||
&rendered_html.links
|
||||
}
|
||||
} else {
|
||||
return EventResult::Ignored;
|
||||
};
|
||||
let focus = if let Some(focus) = self.focus {
|
||||
focus
|
||||
} else {
|
||||
return EventResult::Ignored;
|
||||
};
|
||||
|
||||
match event {
|
||||
Event::Key(Key::Left) => {
|
||||
if focus == 0 {
|
||||
EventResult::Ignored
|
||||
} else if links[focus].position.y == links[focus - 1].position.y {
|
||||
self.focus = Some(focus - 1);
|
||||
EventResult::Consumed(None)
|
||||
} else {
|
||||
EventResult::Ignored
|
||||
}
|
||||
}
|
||||
Event::Key(Key::Up) => {
|
||||
let y = links[focus].position.y;
|
||||
let next_focus = links[..focus]
|
||||
.iter()
|
||||
.enumerate()
|
||||
.rev()
|
||||
.find(|(_, link)| link.position.y < y)
|
||||
.map(|(idx, _)| idx);
|
||||
match next_focus {
|
||||
Some(focus) => {
|
||||
self.focus = Some(focus);
|
||||
EventResult::Consumed(None)
|
||||
}
|
||||
None => EventResult::Ignored,
|
||||
}
|
||||
}
|
||||
Event::Key(Key::Down) => {
|
||||
let y = links[focus].position.y;
|
||||
let next_focus = links
|
||||
.iter()
|
||||
.enumerate()
|
||||
.skip(focus)
|
||||
.find(|(_, link)| link.position.y > y)
|
||||
.map(|(idx, _)| idx);
|
||||
match next_focus {
|
||||
Some(focus) => {
|
||||
self.focus = Some(focus);
|
||||
EventResult::Consumed(None)
|
||||
}
|
||||
None => EventResult::Ignored,
|
||||
}
|
||||
}
|
||||
Event::Key(Key::Right) => {
|
||||
if focus + 1 >= links.len() {
|
||||
EventResult::Ignored
|
||||
} else if links[focus].position.y == links[focus + 1].position.y {
|
||||
self.focus = Some(focus + 1);
|
||||
EventResult::Consumed(None)
|
||||
} else {
|
||||
EventResult::Ignored
|
||||
}
|
||||
}
|
||||
Event::Key(Key::Enter) => {
|
||||
let link = links[focus].target.clone();
|
||||
let cb = self
|
||||
.on_link
|
||||
.clone()
|
||||
.map(|cb| event::Callback::from_fn(move |s| cb(s, link.clone())));
|
||||
EventResult::Consumed(cb)
|
||||
}
|
||||
_ => EventResult::Ignored,
|
||||
}
|
||||
}
|
||||
|
||||
fn important_area(&self, _: cursive::XY<usize>) -> cursive::Rect {
|
||||
if let Some((focus, rendered_html)) = self.focus.zip(self.rendered_html.as_ref()) {
|
||||
let origin = rendered_html.links[focus].position;
|
||||
cursive::Rect::from_size(origin, (rendered_html.links[focus].width, 1))
|
||||
} else {
|
||||
cursive::Rect::from((0, 0))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn show_link(url: &str) -> bool {
|
||||
// We don’t want to show fragment links as we cannot jump to HTML elements by ID
|
||||
!url.starts_with('#')
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct HtmlElement {
|
||||
text: String,
|
||||
style: theme::Style,
|
||||
link_idx: Option<usize>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct Link {
|
||||
position: cursive::XY<usize>,
|
||||
target: String,
|
||||
width: usize,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct RenderedHtml {
|
||||
width: usize,
|
||||
size: cursive::XY<usize>,
|
||||
lines: Vec<Vec<HtmlElement>>,
|
||||
links: Vec<Link>,
|
||||
}
|
||||
|
||||
impl RenderedHtml {
|
||||
pub fn new(width: usize) -> RenderedHtml {
|
||||
RenderedHtml {
|
||||
width,
|
||||
size: (0, 0).into(),
|
||||
lines: Vec::new(),
|
||||
links: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_link(&mut self, link: Link) -> usize {
|
||||
self.links.push(link);
|
||||
self.links.len() - 1
|
||||
}
|
||||
|
||||
pub fn push_line(&mut self, y: usize, elements: Vec<utils::HighlightedHtmlElement>) {
|
||||
let mut len = 0;
|
||||
let mut line = Vec::new();
|
||||
|
||||
for element in elements {
|
||||
let element = match element {
|
||||
utils::HighlightedHtmlElement::RichString(ts) => {
|
||||
let tag: Tag = ts.tag.iter().collect();
|
||||
HtmlElement {
|
||||
text: ts.s.clone(),
|
||||
style: tag.style,
|
||||
link_idx: tag.link_target.map(|target| {
|
||||
self.push_link(Link {
|
||||
position: (len, y).into(),
|
||||
target,
|
||||
width: ts.s.len(),
|
||||
})
|
||||
}),
|
||||
}
|
||||
}
|
||||
utils::HighlightedHtmlElement::StyledString(s) => {
|
||||
let s = utils::reset_background(s);
|
||||
HtmlElement {
|
||||
text: s.s.to_owned(),
|
||||
style: s.style.map_or_else(Default::default, From::from),
|
||||
link_idx: None,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
len += element.text.len();
|
||||
line.push(element);
|
||||
}
|
||||
|
||||
self.lines.push(line);
|
||||
self.size = self.size.stack_vertical(&(len, 1).into());
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
struct Tag {
|
||||
style: theme::Style,
|
||||
link_target: Option<String>,
|
||||
}
|
||||
|
||||
impl<'a> iter::FromIterator<&'a text_renderer::RichAnnotation> for Tag {
|
||||
fn from_iter<I: IntoIterator<Item = &'a text_renderer::RichAnnotation>>(iter: I) -> Tag {
|
||||
let mut tag = Tag::default();
|
||||
for annotation in iter {
|
||||
if let text_renderer::RichAnnotation::Link(target) = annotation {
|
||||
tag.link_target = Some(target.clone());
|
||||
}
|
||||
if let Some(style) = get_rich_style(annotation) {
|
||||
tag.style = tag.style.combine(style);
|
||||
}
|
||||
}
|
||||
tag
|
||||
}
|
||||
}
|
||||
|
||||
fn get_rich_style(annotation: &text_renderer::RichAnnotation) -> Option<theme::Style> {
|
||||
use text_renderer::RichAnnotation;
|
||||
|
||||
match annotation {
|
||||
RichAnnotation::Default => None,
|
||||
RichAnnotation::Link(_) => Some(theme::Effect::Underline.into()),
|
||||
RichAnnotation::Image => None,
|
||||
RichAnnotation::Emphasis => Some(theme::Effect::Italic.into()),
|
||||
RichAnnotation::Strong => Some(theme::Effect::Bold.into()),
|
||||
RichAnnotation::Strikeout => Some(theme::Effect::Strikethrough.into()),
|
||||
RichAnnotation::Code => Some(theme::PaletteColor::Secondary.into()),
|
||||
RichAnnotation::Preformat(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CodeView {
|
||||
lines: Vec<markup::StyledString>,
|
||||
width: usize,
|
||||
}
|
||||
|
||||
impl CodeView {
|
||||
pub fn new(code: &str, highlighter: &utils::Highlighter) -> CodeView {
|
||||
let mut lines = Vec::new();
|
||||
let mut width = 0;
|
||||
for line in highlighter.highlight(code) {
|
||||
let s = line
|
||||
.iter()
|
||||
.map(text_style::StyledStr::from)
|
||||
.map(utils::reset_background)
|
||||
.map(markup::StyledString::from)
|
||||
.fold(markup::StyledString::new(), |mut acc, s| {
|
||||
acc.append(s);
|
||||
acc
|
||||
});
|
||||
width = cmp::max(width, s.width());
|
||||
lines.push(s);
|
||||
}
|
||||
CodeView { lines, width }
|
||||
}
|
||||
}
|
||||
|
||||
impl cursive::View for CodeView {
|
||||
fn draw(&self, printer: &cursive::Printer) {
|
||||
for (y, line) in self.lines.iter().enumerate() {
|
||||
printer.print_styled((0, y), line.into());
|
||||
}
|
||||
}
|
||||
|
||||
fn required_size(&mut self, _constraint: cursive::XY<usize>) -> cursive::XY<usize> {
|
||||
(self.width, self.lines.len()).into()
|
||||
}
|
||||
}
|
@ -285,18 +285,29 @@ fn print_heading<M: ManRenderer + ?Sized>(
|
||||
viewer.print_heading(indent, text.as_ref())
|
||||
}
|
||||
|
||||
/// Link handling mode for the [`RichDecorator`].
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum LinkMode {
|
||||
/// Annotate links with `RichAnnotation::Link`.
|
||||
Annotate,
|
||||
/// List links at the end of the block.
|
||||
List,
|
||||
}
|
||||
|
||||
/// A decorator that generates rich text.
|
||||
#[derive(Clone)]
|
||||
pub struct RichDecorator {
|
||||
link_filter: fn(&str) -> bool,
|
||||
link_mode: LinkMode,
|
||||
ignore_next_link: bool,
|
||||
links: Vec<String>,
|
||||
}
|
||||
|
||||
impl RichDecorator {
|
||||
pub fn new(link_filter: fn(&str) -> bool) -> RichDecorator {
|
||||
pub fn new(link_filter: fn(&str) -> bool, link_mode: LinkMode) -> RichDecorator {
|
||||
RichDecorator {
|
||||
link_filter,
|
||||
link_mode,
|
||||
ignore_next_link: false,
|
||||
links: Vec::new(),
|
||||
}
|
||||
@ -311,11 +322,14 @@ impl text_renderer::TextDecorator for RichDecorator {
|
||||
if self.ignore_next_link {
|
||||
(String::new(), text_renderer::RichAnnotation::Default)
|
||||
} else {
|
||||
self.links.push(url.to_owned());
|
||||
(
|
||||
"[".to_owned(),
|
||||
text_renderer::RichAnnotation::Link(url.to_owned()),
|
||||
)
|
||||
let annotation = text_renderer::RichAnnotation::Link(url.to_owned());
|
||||
match self.link_mode {
|
||||
LinkMode::Annotate => (String::new(), annotation),
|
||||
LinkMode::List => {
|
||||
self.links.push(url.to_owned());
|
||||
("[".to_owned(), annotation)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -323,7 +337,10 @@ impl text_renderer::TextDecorator for RichDecorator {
|
||||
if self.ignore_next_link {
|
||||
String::new()
|
||||
} else {
|
||||
format!("][{}]", self.links.len() - 1)
|
||||
match self.link_mode {
|
||||
LinkMode::Annotate => String::new(),
|
||||
LinkMode::List => format!("][{}]", self.links.len() - 1),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -373,23 +390,25 @@ impl text_renderer::TextDecorator for RichDecorator {
|
||||
|
||||
fn finalise(self) -> Vec<text_renderer::TaggedLine<text_renderer::RichAnnotation>> {
|
||||
let mut lines = Vec::new();
|
||||
for (idx, link) in self.links.into_iter().enumerate() {
|
||||
let mut line = text_renderer::TaggedLine::new();
|
||||
line.push_str(text_renderer::TaggedString {
|
||||
s: format!("[{}] ", idx),
|
||||
tag: text_renderer::RichAnnotation::Default,
|
||||
});
|
||||
line.push_str(text_renderer::TaggedString {
|
||||
s: link.clone(),
|
||||
tag: text_renderer::RichAnnotation::Link(link),
|
||||
});
|
||||
lines.push(line);
|
||||
if self.link_mode == LinkMode::List {
|
||||
for (idx, link) in self.links.into_iter().enumerate() {
|
||||
let mut line = text_renderer::TaggedLine::new();
|
||||
line.push_str(text_renderer::TaggedString {
|
||||
s: format!("[{}] ", idx),
|
||||
tag: text_renderer::RichAnnotation::Default,
|
||||
});
|
||||
line.push_str(text_renderer::TaggedString {
|
||||
s: link.clone(),
|
||||
tag: text_renderer::RichAnnotation::Link(link),
|
||||
});
|
||||
lines.push(line);
|
||||
}
|
||||
}
|
||||
lines
|
||||
}
|
||||
|
||||
fn make_subblock_decorator(&self) -> Self {
|
||||
RichDecorator::new(self.link_filter)
|
||||
RichDecorator::new(self.link_filter, self.link_mode)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user