summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThang Pham <phamducthang1234@gmail.com>2021-06-12 12:38:31 +0900
committerGitHub <noreply@github.com>2021-06-12 12:38:31 +0900
commit46ac43b1f5be948086a3ea65d6086ca3cdec5106 (patch)
treef653e1c1bdf4f47db6d62afbc955c6a3c04d667e
parent19f3eba419ebd65c7152ffbcc904eef2af8822a4 (diff)
Implement `config_parser` crates to allow optional configurations (#39)
-rw-r--r--Cargo.lock126
-rw-r--r--Cargo.toml34
-rw-r--r--README.md19
-rw-r--r--config_parser/Cargo.toml10
-rw-r--r--config_parser/src/lib.rs37
-rw-r--r--config_parser/tests/test.rs107
-rw-r--r--config_parser_derive/Cargo.lock76
-rw-r--r--config_parser_derive/Cargo.toml13
-rw-r--r--config_parser_derive/src/lib.rs13
-rw-r--r--config_parser_derive/src/parser.rs44
-rw-r--r--hackernews_tui/Cargo.lock1264
-rw-r--r--hackernews_tui/Cargo.toml35
-rw-r--r--hackernews_tui/src/config.rs (renamed from src/config.rs)40
-rw-r--r--hackernews_tui/src/hn-tui-default.toml (renamed from src/hn-tui-default.toml)17
-rw-r--r--hackernews_tui/src/hn_client.rs (renamed from src/hn_client.rs)5
-rw-r--r--hackernews_tui/src/keybindings.rs (renamed from src/keybindings.rs)17
-rw-r--r--hackernews_tui/src/main.rs (renamed from src/main.rs)0
-rw-r--r--hackernews_tui/src/prelude.rs (renamed from src/prelude.rs)0
-rw-r--r--hackernews_tui/src/utils.rs (renamed from src/utils.rs)0
-rw-r--r--hackernews_tui/src/view/article_view.rs (renamed from src/view/article_view.rs)0
-rw-r--r--hackernews_tui/src/view/async_view.rs (renamed from src/view/async_view.rs)0
-rw-r--r--hackernews_tui/src/view/comment_view.rs (renamed from src/view/comment_view.rs)6
-rw-r--r--hackernews_tui/src/view/error_view.rs (renamed from src/view/error_view.rs)0
-rw-r--r--hackernews_tui/src/view/fn_view_wrapper.rs (renamed from src/view/fn_view_wrapper.rs)0
-rw-r--r--hackernews_tui/src/view/help_view.rs (renamed from src/view/help_view.rs)0
-rw-r--r--hackernews_tui/src/view/list_view.rs (renamed from src/view/list_view.rs)0
-rw-r--r--hackernews_tui/src/view/mod.rs (renamed from src/view/mod.rs)0
-rw-r--r--hackernews_tui/src/view/search_view.rs (renamed from src/view/search_view.rs)0
-rw-r--r--hackernews_tui/src/view/story_view.rs (renamed from src/view/story_view.rs)0
-rw-r--r--hackernews_tui/src/view/text_view.rs (renamed from src/view/text_view.rs)0
-rwxr-xr-xrun_debug2
31 files changed, 1727 insertions, 138 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 01ef524..d7ea473 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -72,15 +72,15 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "bumpalo"
-version = "3.6.1"
+version = "3.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe"
+checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631"
[[package]]
name = "cc"
-version = "1.0.67"
+version = "1.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd"
+checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787"
[[package]]
name = "cfg-if"
@@ -123,10 +123,28 @@ dependencies = [
]
[[package]]
+name = "config_parser"
+version = "0.1.0"
+dependencies = [
+ "config_parser_derive",
+ "serde",
+ "toml",
+]
+
+[[package]]
+name = "config_parser_derive"
+version = "0.1.0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "crossbeam"
-version = "0.8.0"
+version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd01a6eb3daaafa260f6fc94c3a6c36390abc2080e38e3e34ced87393fb77d80"
+checksum = "4ae5588f6b3c3cb05239e90bd110f257254aecd01e4635400391aeae07497845"
dependencies = [
"cfg-if",
"crossbeam-channel",
@@ -159,9 +177,9 @@ dependencies = [
[[package]]
name = "crossbeam-epoch"
-version = "0.9.3"
+version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2584f639eb95fea8c798496315b297cf81b9b58b6d30ab066a75455333cf4b12"
+checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd"
dependencies = [
"cfg-if",
"crossbeam-utils",
@@ -172,9 +190,9 @@ dependencies = [
[[package]]
name = "crossbeam-queue"
-version = "0.3.1"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f6cb3c7f5b8e51bc3ebb73a2327ad4abdbd119dc13223f14f961d2f38486756"
+checksum = "9b10ddc024425c88c2ad148c1b0fd53f4c6d38db9697c9f1588381212fa657c9"
dependencies = [
"cfg-if",
"crossbeam-utils",
@@ -182,11 +200,10 @@ dependencies = [
[[package]]
name = "crossbeam-utils"
-version = "0.8.3"
+version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49"
+checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db"
dependencies = [
- "autocfg",
"cfg-if",
"lazy_static",
]
@@ -230,7 +247,7 @@ dependencies = [
"lazy_static",
"libc",
"log",
- "signal-hook 0.3.8",
+ "signal-hook 0.3.9",
"unicode-segmentation",
"unicode-width",
"wasmer_enumset",
@@ -417,9 +434,9 @@ dependencies = [
[[package]]
name = "getrandom"
-version = "0.2.2"
+version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8"
+checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
dependencies = [
"cfg-if",
"libc",
@@ -432,6 +449,7 @@ version = "0.6.2"
dependencies = [
"anyhow",
"clap",
+ "config_parser",
"cursive",
"cursive-aligned-view",
"cursive-async-view",
@@ -480,9 +498,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "idna"
-version = "0.2.2"
+version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89829a5d69c23d348314a7ac337fe39173b61149a9864deabd260983aed48c21"
+checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
dependencies = [
"matches",
"unicode-bidi",
@@ -512,9 +530,9 @@ checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
[[package]]
name = "js-sys"
-version = "0.3.50"
+version = "0.3.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d99f9e3e84b8f67f846ef5b4cbbc3b1c29f6c759fcbce6f01aa0e73d932a24c"
+checksum = "83bdfbace3a0e81a4253f73b49e960b053e396a11012cbd49b9b74d6a2b67062"
dependencies = [
"wasm-bindgen",
]
@@ -527,15 +545,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
-version = "0.2.93"
+version = "0.2.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41"
+checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36"
[[package]]
name = "lock_api"
-version = "0.4.3"
+version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a3c91c24eae6777794bb1997ad98bbb87daf92890acab859f7eaa4320333176"
+checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb"
dependencies = [
"scopeguard",
]
@@ -563,9 +581,9 @@ checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
[[package]]
name = "memoffset"
-version = "0.6.3"
+version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f83fb6581e8ed1f85fd45c116db8405483899489e38406156c25eb743554361d"
+checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9"
dependencies = [
"autocfg",
]
@@ -735,9 +753,9 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "proc-macro2"
-version = "1.0.26"
+version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
+checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038"
dependencies = [
"unicode-xid",
]
@@ -778,9 +796,9 @@ dependencies = [
[[package]]
name = "redox_syscall"
-version = "0.2.5"
+version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9"
+checksum = "742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc"
dependencies = [
"bitflags",
]
@@ -829,9 +847,9 @@ dependencies = [
[[package]]
name = "rustls"
-version = "0.19.0"
+version = "0.19.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "064fd21ff87c6e87ed4506e68beb42459caa4a0e2eb144932e6776768556980b"
+checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7"
dependencies = [
"base64",
"log",
@@ -912,9 +930,9 @@ dependencies = [
[[package]]
name = "signal-hook"
-version = "0.3.8"
+version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ef33d6d0cd06e0840fba9985aab098c147e67e05cee14d412d3345ed14ff30ac"
+checksum = "470c5a6397076fae0094aaf06a08e6ba6f37acb77d3b1b91ea92b4d6c8650c39"
dependencies = [
"libc",
"signal-hook-registry",
@@ -922,9 +940,9 @@ dependencies = [
[[package]]
name = "signal-hook-registry"
-version = "1.3.0"
+version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6"
+checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
dependencies = [
"libc",
]
@@ -970,9 +988,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "1.0.69"
+version = "1.0.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "48fe99c6bd8b1cc636890bcc071842de909d902c81ac7dab53ba33c421ab8ffb"
+checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82"
dependencies = [
"proc-macro2",
"quote",
@@ -1042,9 +1060,9 @@ dependencies = [
[[package]]
name = "unicode-normalization"
-version = "0.1.17"
+version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07fbfce1c8a97d547e8b5334978438d9d6ec8c20e38f56d4a4374d181493eaef"
+checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9"
dependencies = [
"tinyvec",
]
@@ -1063,9 +1081,9 @@ checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
[[package]]
name = "unicode-xid"
-version = "0.2.1"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
+checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "untrusted"
@@ -1123,9 +1141,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "wasm-bindgen"
-version = "0.2.73"
+version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83240549659d187488f91f33c0f8547cbfef0b2088bc470c116d1d260ef623d9"
+checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
@@ -1133,9 +1151,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
-version = "0.2.73"
+version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae70622411ca953215ca6d06d3ebeb1e915f0f6613e3b495122878d7ebec7dae"
+checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900"
dependencies = [
"bumpalo",
"lazy_static",
@@ -1148,9 +1166,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
-version = "0.2.73"
+version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e734d91443f177bfdb41969de821e15c516931c3c3db3d318fa1b68975d0f6f"
+checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -1158,9 +1176,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
-version = "0.2.73"
+version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d53739ff08c8a68b0fdbcd54c372b8ab800b1449ab3c9d706503bc7dd1621b2c"
+checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97"
dependencies = [
"proc-macro2",
"quote",
@@ -1171,9 +1189,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
-version = "0.2.73"
+version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9a543ae66aa233d14bb765ed9af4a33e81b8b58d1584cf1b47ff8cd0b9e4489"
+checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f"
[[package]]
name = "wasmer_enumset"
@@ -1199,9 +1217,9 @@ dependencies = [
[[package]]
name = "web-sys"
-version = "0.3.50"
+version = "0.3.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a905d57e488fec8861446d3393670fb50d27a262344013181c2cdf9fff5481be"
+checksum = "e828417b379f3df7111d3a2a9e5753706cae29c41f7c4029ee9fd77f3e09e582"
dependencies = [
"js-sys",
"wasm-bindgen",
diff --git a/Cargo.toml b/Cargo.toml
index 74406fb..cb2a322 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,33 +1,3 @@
-[package]
-name = "hackernews_tui"
-version = "0.6.2"
-authors = ["Thang Pham <phamducthang1234@gmail.com>"]
-edition = "2018"
-license = "MIT"
-description = "A Terminal UI to browse Hacker News"
-repository = "https://github.com/aome510/hackernews-TUI"
-keywords = ["hackernews", "tui"]
-readme = "README.md"
-include = ["src/**/*", "LICENSE", "README.*", "!**/examples/**/*"]
+[workspace]
-[dependencies]
-cursive = { version = "0.16.3", default-features = false, features = ["crossterm-backend"] }
-cursive-async-view = "0.5.0"
-cursive_buffered_backend = "0.5.0"
-cursive-aligned-view = "0.4.0"
-
-ureq = { version = "2.1.1", features = ["json"] }
-serde = { version = "1.0.126", features = ["derive"] }
-serde_json = "1.0.64"
-anyhow = "1.0.40"
-rayon = "1.5.1"
-log = "0.4.14"
-env_logger = "0.8.3"
-htmlescape = "0.3.1"
-regex = "1.5.4"
-substring = "1.4.5"
-once_cell = "1.7.2"
-toml = "0.5.8"
-clap = "2.33.3"
-dirs-next = "2.0.0"
-url = "2.2.2"
+members = ["hackernews_tui", "config_parser", "config_parser_derive"]
diff --git a/README.md b/README.md
index 0d17f20..53308bf 100644
--- a/README.md
+++ b/README.md
@@ -210,23 +210,15 @@ Key shortcuts:
## Configuration
-By default, the application will look for `~/.config/hn-tui.toml` as its configuration file.
+By default, the application will look for `~/.config/hn-tui.toml` as the configuration file.
-You can specify the path by specifying the `-c` or `--config` argument when running the application:
+You can also specify the path with the `-c` or `--config` option when running the application:
```shell
hackernews_tui -c ~/.config/hn-tui.toml
```
-For further information about the config options, please refer to the example config file by running `hackernews_tui --example-config`.
-
-**Note**: all config options (as included in the example config file) are **required**. You can run
-
-```shell
-hackernews_tui --example-config > ~/.config/hn-tui.toml
-```
-
-then modify the config options in `~/.config/hn-tui.toml` based on your preferences.
+For further information about the configuration options, please refer to the example configuration file by running `hackernews_tui --example-config`.
### Article Parse Command
@@ -258,11 +250,11 @@ An alternative is to use [`article_md`](https://github.com/aome510/article-md-cl
### User-defined shortcuts
-Shortcuts in each `View` are fully customizable, for further information about the supported keys and the corresponding functionalities, please refer to the **user-defined key bindings** sections in the example config file by running `hackernews_tui --example-config`.
+Shortcuts in each `View` are fully customizable. For further information about the supported keys and the commands, please refer to the **user-defined key bindings** sections in the example configuration file by running `hackernews_tui --example-config`.
### Custom Keymap
-It's possible to define a custom shortcut to switch between different kinds of `StoryView` (`front_page`, `show_hn`, `ask_hn`, etc) with stories filtered by HN Algolia's [`numericFilters`](https://hn.algolia.com/api/). An example of defining such a custom shortcut can be found under the **Custom Keymap** section of the example configuration file.
+It's possible to define a custom shortcut to switch between different `StoryView` (`front_page`, `show_hn`, `ask_hn`, etc) with stories filtered by HN Algolia's [`numericFilters`](https://hn.algolia.com/api/). An example of defining such custom shortcuts can be found under the **custom keymap** section of the example configuration file.
## Debug
@@ -279,6 +271,7 @@ to view the application's log in `log.txt` file.
- [x] make all commands customizable
- [x] add a `View` to read the linked story in reader mode on the terminal. A list of possible suggestion can be found [here](https://news.ycombinator.com/item?id=26930466)
- [ ] add commands to navigate parent comments and collapse a comment
+- [x] make all the configuration options optional
- integrate [HackerNews Official APIs](https://github.com/HackerNews/API) for real-time updating, lazy-loading comments, and sorting stories
- [x] lazy-loading comments
- [x] front-page stories like the official site
diff --git a/config_parser/Cargo.toml b/config_parser/Cargo.toml
new file mode 100644
index 0000000..3aca09b
--- /dev/null
+++ b/config_parser/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "config_parser"
+version = "0.1.0"
+authors = ["Thang Pham <phamducthang1234@gmail.com>"]
+edition = "2018"
+
+[dependencies]
+toml = "0.5.8"
+config_parser_derive = { path = "../config_parser_derive" }
+serde = { version = "1.0.126", features = ["derive"] }
diff --git a/config_parser/src/lib.rs b/config_parser/src/lib.rs
new file mode 100644
index 0000000..6e5bfad
--- /dev/null
+++ b/config_parser/src/lib.rs
@@ -0,0 +1,37 @@
+pub trait ConfigParser {
+ fn parse(&mut self, value: toml::Value);
+}
+
+pub use config_parser_derive::ConfigParse;
+
+#[macro_export]
+macro_rules! config_parser_impl {
+ ($($t:ty),+) => {
+ $(
+ impl ConfigParser for $t {
+ fn parse(&mut self, value: toml::Value) {
+ *self = value.try_into::<$t>().unwrap();
+ }
+ }
+ )*
+ };
+}
+
+impl<T: ConfigParser + Default> ConfigParser for Vec<T> {
+ fn parse(&mut self, value: toml::Value) {
+ if let toml::Value::Array(array) = value {
+ *self = array
+ .into_iter()
+ .map(|e| {
+ let mut v = T::default();
+ v.parse(e);
+ v
+ })
+ .collect::<Vec<_>>();
+ }
+ }
+}
+
+config_parser_impl!(
+ String, usize, u128, u64, u32, u16, u8, isize, i128, i64, i32, i16, i8, f64, f32, bool, char
+);
diff --git a/config_parser/tests/test.rs b/config_parser/tests/test.rs
new file mode 100644
index 0000000..5c808c1
--- /dev/null
+++ b/config_parser/tests/test.rs
@@ -0,0 +1,107 @@
+use config_parser_derive::ConfigParser;
+use serde::Deserialize;
+
+#[derive(ConfigParser, Deserialize, Default, Debug, PartialEq)]
+struct A {
+ pub field_1: String,
+ pub field_2: u32,
+ pub field_3: bool,
+ pub field_4: Vec<B>,
+ pub field_5: C,
+}
+
+#[derive(ConfigParser, Deserialize, Default, Debug, PartialEq)]
+struct B {
+ pub field_1: String,
+ pub field_2: String,
+}
+
+#[derive(ConfigParser, Deserialize, Default, Debug, PartialEq)]
+struct C {
+ pub field_1: B,
+ pub field_2: bool,
+ pub field_3: bool,
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use config_parser::ConfigParser;
+
+ #[test]
+ fn simple_test() {
+ let value = "a = ['b', 'c', 'd']".parse::<toml::Value>().unwrap();
+ let mut a: Vec<String> = vec![];
+ a.parse(value["a"].clone());
+ assert!(a.len() == 3);
+ }
+
+ #[test]
+ fn complex_test() {
+ let mut value = A {
+ field_1: "field_1".to_owned(),
+ field_2: 510,
+ field_3: false,
+ field_4: vec![B {
+ field_1: "b_field_1".to_owned(),
+ field_2: "b_field_2".to_owned(),
+ }],
+ field_5: C {
+ field_1: B {
+ field_1: "cb_field_1".to_owned(),
+ field_2: "cb_field_2".to_owned(),
+ },
+ field_2: true,
+ field_3: false,
+ },
+ };
+
+ let toml = "
+field_1 = 'new_field_1'
+field_2 = 150
+
+[[field_4]]
+field_2 = 'new_field_2'
+
+[[field_4]]
+field_1 = 'new_field_1'
+
+[field_5.field_1]
+field_1 = 'new_field_1'
+field_2 = 'new_field_2'
+
+[field_5]
+field_2 = false
+field_3 = true
+"
+ .parse::<toml::Value>()
+ .unwrap();
+
+ let expected_value = A {
+ field_1: "new_field_1".to_owned(),
+ field_2: 150,
+ field_3: false,
+ field_4: vec![
+ B {
+ field_1: "".to_owned(),
+ field_2: "new_field_2".to_owned(),
+ },
+ B {
+ field_1: "new_field_1".to_owned(),
+ field_2: "".to_owned(),
+ },
+ ],
+ field_5: C {
+ field_1: B {
+ field_1: "new_field_1".to_owned(),
+ field_2: "new_field_2".to_owned(),
+ },
+ field_2: false,
+ field_3: true,
+ },
+ };
+
+ value.parse(toml);
+ assert!(value == expected_value);
+ }
+}
diff --git a/config_parser_derive/Cargo.lock b/config_parser_derive/Cargo.lock
new file mode 100644
index 0000000..a5b3524
--- /dev/null
+++ b/config_parser_derive/Cargo.lock
@@ -0,0 +1,76 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "config_parser"
+version = "0.1.0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "serde",
+ "syn",
+ "toml",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "serde"
+version = "1.0.126"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.126"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.72"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "toml"
+version = "0.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
diff --git a/config_parser_derive/Cargo.toml b/config_parser_derive/Cargo.toml
new file mode 100644
index 0000000..2e99934
--- /dev/null
+++ b/config_parser_derive/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "config_parser_derive"
+version = "0.1.0"
+authors = ["Thang Pham <phamducthang1234@gmail.com>"]
+edition = "2018"
+
+[lib]
+proc-macro = true
+
+[dependencies]
+proc-macro2 = "1.0.27"
+quote = "1.0.9"
+syn = "1.0.72"
diff --git a/config_parser_derive/src/lib.rs b/config_parser_derive/src/lib.rs
new file mode 100644
index 0000000..04e06ff
--- /dev/null
+++ b/config_parser_derive/src/lib.rs
@@ -0,0 +1,13 @@
+use proc_macro::TokenStream;
+use syn::{parse_macro_input, DeriveInput};
+
+mod parser;
+use parser::expand_config_parsers;
+
+#[proc_macro_derive(ConfigParse)]
+pub fn parsers(input: TokenStream) -> TokenStream {
+ let input = parse_macro_input!(input as DeriveInput);
+ expand_config_parsers(input)
+ .unwrap_or_else(syn::Error::into_compile_error)
+ .into()
+}
diff --git a/config_parser_derive/src/parser.rs b/config_parser_derive/src/parser.rs
new file mode 100644
index 0000000..6e7a781
--- /dev/null
+++ b/config_parser_derive/src/parser.rs
@@ -0,0 +1,44 @@
+use proc_macro2::TokenStream;
+use quote::quote;
+use syn::{Data, DataStruct, DeriveInput, Fields};
+
+pub fn expand_config_parsers(input: DeriveInput) -> syn::Result<TokenStream> {
+ let fields = match input.data {
+ Data::Struct(DataStruct {
+ fields: Fields::Named(fields),
+ ..
+ }) => fields.named,
+ _ => panic!("this derive macro only works on structs with named fields"),
+ };
+
+ let parsers = fields
+ .into_iter()
+ .map(|f| {
+ let field_name_str = f.ident.as_ref().unwrap().to_string();
+ let field_name = f.ident;
+
+ Ok(quote! {
+ #field_name_str => {
+ self.#field_name.parse(value);
+ }
+ })
+ })
+ .collect::<syn::Result<TokenStream>>()?;
+
+ let st_name = input.ident;
+ Ok(quote! {
+ #[automatically_derived]
+ impl config_parser::ConfigParser for #st_name {
+ fn parse(&mut self, value: toml::Value) {
+ if let(toml::Value::Table(table)) = value {
+ table.into_iter().for_each(|(key, value)| {
+ match key.as_str() {
+ #parsers
+ _ => {}
+ };
+ });
+ }
+ }
+ }
+ })
+}
diff --git a/hackernews_tui/Cargo.lock b/hackernews_tui/Cargo.lock
new file mode 100644
index 0000000..01ef524
--- /dev/null
+++ b/hackernews_tui/Cargo.lock
@@ -0,0 +1,1264 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "ahash"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "796540673305a66d127804eef19ad696f1f204b8c1025aaca4958c17eab32877"
+dependencies = [
+ "getrandom",
+ "once_cell",
+ "version_check",
+]
+
+[[package]]
+name = "aho-corasick"
+version = "0.7.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "ansi_term"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b"
+
+[[package]]
+name = "array-macro"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06e97b4e522f9e55523001238ac59d13a8603af57f69980de5d8de4bbbe8ada6"
+
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.0.1"