chore: first forked commit
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -3,9 +3,6 @@
|
||||
# will have compiled files and executables
|
||||
/target/
|
||||
|
||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||
Cargo.lock
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
||||
392
Cargo.lock
generated
Normal file
392
Cargo.lock
generated
Normal file
@@ -0,0 +1,392 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86"
|
||||
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 = "arrayref"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
|
||||
|
||||
[[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.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
|
||||
[[package]]
|
||||
name = "blake2b_simd"
|
||||
version = "0.5.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"arrayvec",
|
||||
"constant_time_eq",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo-todo"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
"colored",
|
||||
"dirs",
|
||||
"glob",
|
||||
"regex",
|
||||
"string-parser",
|
||||
"string_format",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c74d84029116787153e02106bf53e66828452a4b325cc8652b788b5967c0a0b6"
|
||||
dependencies = [
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.33.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"atty",
|
||||
"bitflags",
|
||||
"strsim",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
"vec_map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colored"
|
||||
version = "1.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"lazy_static",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"redox_users",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.72"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9f8082297d534141b30c8d39e9b1773713ab50fdbe4ff30f750d063b3bfd701"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.57"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"redox_syscall",
|
||||
"rust-argon2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
"thread_local",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8"
|
||||
|
||||
[[package]]
|
||||
name = "rust-argon2"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"blake2b_simd",
|
||||
"constant_time_eq",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "string-parser"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46e079466fad2cd4673f6ccd80b3a2c8aa94e981a7ab7b4e5c023a0a37e23596"
|
||||
|
||||
[[package]]
|
||||
name = "string_format"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a0f5f60043c6e865cc477a5cd3981df2210ec02592bd9ba18d32bcd72abb4eb"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.9.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
23
Cargo.toml
Normal file
23
Cargo.toml
Normal file
@@ -0,0 +1,23 @@
|
||||
[package]
|
||||
name = "cargo-todo"
|
||||
version = "0.2.0"
|
||||
authors = ["Clément Guiton <clement.guiton.dev@gmail.com>"]
|
||||
edition = "2018"
|
||||
description = "Cargo tool to display TODOs"
|
||||
readme = "README.md"
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/ProbablyClem/cargo-todo"
|
||||
exclude = ["target"]
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
glob = "0.3.0"
|
||||
walkdir = "2.3.1"
|
||||
colored = "1.9.3"
|
||||
string-parser= "0.1.5"
|
||||
regex = "1.3.9"
|
||||
dirs = "2.0.2"
|
||||
string_format = "0.1.0"
|
||||
clap = "2.33.1"
|
||||
chrono = "0.4.13"
|
||||
108
README.md
108
README.md
@@ -1,3 +1,107 @@
|
||||
# cargo-todo
|
||||
# A tool to view every TODOs in the rust code
|
||||
|
||||
Fork from: https://github.com/ProbablyClem/cargo-todo
|
||||
> Fork from: https://github.com/ProbablyClem/cargo-todo
|
||||
|
||||
## Installation
|
||||
```
|
||||
$ cargo install cargo-todo
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
|
||||
you can add parameters to you TODOs
|
||||
```
|
||||
//todo 18-11-2001 5 !clement implement getters
|
||||
```
|
||||
The supported parameters are : </br>
|
||||
* Priority : A number between 1 and 9
|
||||
* Deadline : A date format yyyy/mm/dd
|
||||
* Member : A text that begin with '!'
|
||||
* Content : Every text other thant the previouses will be considered as content
|
||||
|
||||
</br>Those parameters can be added in any order as long as they follow the syntax they will be automaticaly added
|
||||
|
||||
### run
|
||||
```rust
|
||||
$cargo todo
|
||||
src/main.rs line: 331 //todo
|
||||
Member: clement
|
||||
Priority: 5
|
||||
Deadline: 2020-08-14
|
||||
implement getters
|
||||
```
|
||||
|
||||
### Default supported regex
|
||||
* ^s*//s*todo\b (//todo)
|
||||
* ^s*//s*fix\b (//fix)
|
||||
* ^s*//s*fixme\b (//fixme)
|
||||
### cargo todo now support customizable regex
|
||||
add all your customs regex in the ~/.cargo/todo_config file (will be created at launch)
|
||||
</br>all regex are case-insensitive </br>
|
||||
## Features
|
||||
* -i, --inline : display todo in one line
|
||||
```rust
|
||||
$cargo todo -i
|
||||
src/main.rs line: 331 //todo Member: clement Priority: 5 Deadline: 2020-08-14 implement getters
|
||||
```
|
||||
* -v, --verbose : Sets the level of verbosity
|
||||
</br>default or -vv
|
||||
</br> full verbose
|
||||
-v less verbose
|
||||
```rust
|
||||
$cargo todo -v
|
||||
src/main.rs line: 331 //todo
|
||||
implement getters
|
||||
```
|
||||
* -x, --exclude <exclude>... : Exclude some todos from the list
|
||||
```rust
|
||||
$cargo todo -x //fix
|
||||
//wil display every todos expect those having the '//fix' keyword
|
||||
```
|
||||
* -f, --filter <filter>... : Filter todos to show
|
||||
```rust
|
||||
$cargo todo -f //fix
|
||||
//wil only display todos having the '//fix' keyword
|
||||
```
|
||||
* -l, --list <list> : Number of values to display
|
||||
```rust
|
||||
$cargo todo -l 5
|
||||
///wil display the first 5 todos
|
||||
```
|
||||
* m, --member <member>... : Filter from member
|
||||
```rust
|
||||
$cargo todo -m clement
|
||||
///wil only display todos having as member clement
|
||||
```
|
||||
* -s, --sort <sort> : Sort todos [possible values: priority, deadline, member]
|
||||
```rust
|
||||
$cargo todo -s priority
|
||||
///wil display todos sorted by their priority
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Legacy mode
|
||||
### Can be used for legacy code base as it's support todo!() and unimplemented!()
|
||||
### Will display every line with a supported token (listed below) and the inside of the macro
|
||||
### /!\ Legacy mode is way slower the the default mode and lacks a lot of cool features
|
||||
#### Example
|
||||
code base
|
||||
```rust
|
||||
todo!("implement getters");
|
||||
```
|
||||
### run
|
||||
```rust
|
||||
$ cargo todo --legacy
|
||||
src/main.rs TODO Line 125 : implement getters
|
||||
```
|
||||
## Supported tokens
|
||||
- //todo
|
||||
- todo!()
|
||||
- unimplemented!()
|
||||
- fix
|
||||
|
||||
|
||||
### /!\ WARNING
|
||||
cargo todo will no longer use regex but only the default tokens listed above
|
||||
|
||||
331
src/main.rs
Normal file
331
src/main.rs
Normal file
@@ -0,0 +1,331 @@
|
||||
extern crate string_format;
|
||||
extern crate clap;
|
||||
extern crate walkdir;
|
||||
extern crate string_parser;
|
||||
extern crate dirs;
|
||||
extern crate glob;
|
||||
extern crate chrono;
|
||||
use glob::glob;
|
||||
use colored::Colorize;
|
||||
use clap::{Arg, App, SubCommand};
|
||||
use chrono::NaiveDate;
|
||||
|
||||
//local files
|
||||
mod parser;
|
||||
mod regex;
|
||||
mod token;
|
||||
use crate::parser::*;
|
||||
use crate::regex::regex_parser;
|
||||
use crate::token::Token;
|
||||
|
||||
//std
|
||||
use std::io::Write;
|
||||
use std::fs::OpenOptions;
|
||||
use std::env;
|
||||
use std::path::Path;
|
||||
use std::fs::File;
|
||||
use std::io::{self, BufRead};
|
||||
|
||||
|
||||
|
||||
fn main() -> std::io::Result<()> {
|
||||
|
||||
let matches = App::new("Cargo-todo")
|
||||
.author("Clément Guiton <clement.guiton.dev@gmail.com>")
|
||||
.about("cargo tool to find TODOs in your code")
|
||||
.arg(Arg::with_name("inline")
|
||||
.short("i")
|
||||
.long("inline")
|
||||
.value_name("inline")
|
||||
.help("display todos in one line")
|
||||
.takes_value(false))
|
||||
.arg(Arg::with_name("filter")
|
||||
.help("Filter todos to show")
|
||||
.short("f")
|
||||
.long("filter")
|
||||
.takes_value(true)
|
||||
.multiple(true)
|
||||
.min_values(1))
|
||||
.arg(Arg::with_name("verbose")
|
||||
.short("v")
|
||||
.long("verbose")
|
||||
.multiple(true)
|
||||
.help("Sets the level of verbosity"))
|
||||
.arg(Arg::with_name("exclude")
|
||||
.short("x")
|
||||
.long("exclude")
|
||||
.takes_value(true)
|
||||
.multiple(true)
|
||||
.help("Exclude some todos from the list"))
|
||||
.arg(Arg::with_name("list")
|
||||
.short("l")
|
||||
.long("list")
|
||||
.takes_value(true)
|
||||
.help("Number of values to display"))
|
||||
.arg(Arg::with_name("sort")
|
||||
.short("s")
|
||||
.long("sort")
|
||||
.takes_value(true)
|
||||
.possible_values(&["priority", "deadline", "member"])
|
||||
.help("Sort todos"))
|
||||
.arg(Arg::with_name("member")
|
||||
.short("m")
|
||||
.long("member")
|
||||
.takes_value(true)
|
||||
.multiple(true)
|
||||
.min_values(1)
|
||||
.help("Filter from member"))
|
||||
.subcommand(SubCommand::with_name("legacy")
|
||||
.about("Launch program in legacy mode (supports todo!(), etc..."))
|
||||
.get_matches();
|
||||
|
||||
|
||||
if let Some(_matches) = matches.subcommand_matches("legacy") {
|
||||
let mut parsers : Vec<Parser> = vec!();
|
||||
|
||||
let mut path = String::from(env::current_dir().unwrap().to_str().unwrap());
|
||||
path.push_str("/**/*.rs");
|
||||
|
||||
//we add a parser looking for the //todo keyword
|
||||
parsers.push(Parser::new(String::from("//todo"), Box::from(|x : Vec<char>| {if x.last().unwrap() == &'\n' {return true;} else { return false}})));
|
||||
//we add a parser looking for the todo!() token
|
||||
let _todo_macro_callback = Box::from(|mut text : String, line : usize, file : &str| {
|
||||
text.retain(|c| c != '\"');
|
||||
println!("{} {} {} {} : {}",file,"TODO".green() ,"Line ".green(), line.to_string().green(), text.blue());
|
||||
});
|
||||
parsers.push(Parser::new_callback(String::from("todo!("), Box::from(|x : Vec<char>| {if x.last().unwrap() == &')' {return true;} else { return false}}), _todo_macro_callback));
|
||||
|
||||
//support for unimplemented
|
||||
let _unimplemented_macro_callback = Box::from(|text : String, line : usize, file : &str| {
|
||||
println!("{} {} {} {} : {}{}{} ",file,"TODO".green() ,"Line ".green(), line.to_string().green(), "unimplemented!(".blue(), text.magenta(), ")".blue());
|
||||
});
|
||||
parsers.push(Parser::new_callback(String::from("unimplemented!("), Box::from(|x : Vec<char>| {if x.last().unwrap() == &')' {return true;} else { return false}}), _unimplemented_macro_callback));
|
||||
|
||||
parsers.push(Parser::new(String::from("//fix"), Box::from(|x : Vec<char>| {if x.last().unwrap() == &'\n' {return true;} else { return false}})));
|
||||
|
||||
|
||||
//loop on every file within the current dir
|
||||
for entry in match glob(&path) {
|
||||
Ok(entry) => entry,
|
||||
Err(e) => {
|
||||
println!("Couldn't access files. Error {}", e);
|
||||
Err(e).unwrap()
|
||||
}
|
||||
} {
|
||||
|
||||
let path = entry.unwrap();
|
||||
let path = Path::new(&path).strip_prefix(env::current_dir().unwrap().to_str().unwrap()).unwrap();
|
||||
if !path.starts_with("target/"){
|
||||
let path = path.to_str().unwrap();
|
||||
//execute each parsers on the current file
|
||||
for p in &parsers {
|
||||
p.parse(path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
else{
|
||||
let mut tokens : Vec<Token> = Vec::new();
|
||||
|
||||
let mut path = String::from(dirs::home_dir().unwrap().to_str().unwrap());
|
||||
path.push_str("/.cargo/todo_config");
|
||||
// println!("{}",path);
|
||||
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
|
||||
where P: AsRef<Path>, {
|
||||
let file = match File::open(&filename){
|
||||
Ok(line) => line,
|
||||
Err(_) => {
|
||||
println!("{}", "File '~/.cargo/todo_config' not found, creating it".red());
|
||||
let mut f = OpenOptions::new().write(true).read(true).create(true).open(&filename).unwrap();
|
||||
f.write_all(b"^s*//s*todo\\b\n").unwrap();
|
||||
f.write_all(b"^s*//s*fix\\b\n").unwrap();
|
||||
f.write_all(b"^s*//s*fixme\\b\n").unwrap();
|
||||
return read_lines(filename);
|
||||
}
|
||||
};
|
||||
Ok(io::BufReader::new(file).lines())
|
||||
}
|
||||
|
||||
let mut regex = Vec::new();
|
||||
for line in read_lines(path).unwrap() {
|
||||
let line = line.unwrap();
|
||||
regex.push(line);
|
||||
}
|
||||
|
||||
let mut path = String::from(env::current_dir().unwrap().to_str().unwrap());
|
||||
path.push_str("/**/*.rs");
|
||||
|
||||
for entry in match glob(&path) {
|
||||
Ok(entry) => entry,
|
||||
Err(e) => {
|
||||
println!("Couldn't access files. Error {}", e);
|
||||
Err(e).unwrap()
|
||||
}
|
||||
} {
|
||||
let path = entry.unwrap();
|
||||
let path = Path::new(&path).strip_prefix(env::current_dir().unwrap().to_str().unwrap()).unwrap();
|
||||
// println!("{}", path.to_str().unwrap());
|
||||
if !path.starts_with("target/"){
|
||||
let path = path.to_str().unwrap();
|
||||
|
||||
if matches.occurrences_of("verbose") == 0 || matches.occurrences_of("verbose") == 2{
|
||||
match regex_parser(path, regex.clone(), 2){
|
||||
Ok(mut t) => {
|
||||
tokens.append(&mut t);
|
||||
},
|
||||
Err(e) => eprintln!{"{}", e},
|
||||
}
|
||||
}
|
||||
else {
|
||||
match regex_parser(path, regex.clone(), 1){
|
||||
Ok(mut t) => {
|
||||
tokens.append(&mut t);
|
||||
},
|
||||
Err(e) => eprintln!{"{}", e},
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if matches.is_present("sort"){
|
||||
if matches.value_of("sort").unwrap() == "priority"{
|
||||
fn token_priority_sort(t : &Token) -> String {
|
||||
|
||||
if t.priority.is_none() {
|
||||
return String::from("z");
|
||||
}
|
||||
else {
|
||||
return t.priority.clone().unwrap()
|
||||
}
|
||||
}
|
||||
tokens.sort_unstable_by_key(token_priority_sort);
|
||||
}
|
||||
else if matches.value_of("sort").unwrap() == "deadline"{
|
||||
fn token_deadline_sort(t : &Token) -> NaiveDate {
|
||||
|
||||
if t.date.is_none() {
|
||||
return NaiveDate::from_ymd(3000,01,01);
|
||||
}
|
||||
else {
|
||||
return t.date.clone().unwrap()
|
||||
}
|
||||
}
|
||||
tokens.sort_unstable_by_key(token_deadline_sort);
|
||||
}
|
||||
else if matches.value_of("sort").unwrap() == "member"{
|
||||
fn token_member_sort(t : &Token) -> String {
|
||||
|
||||
if t.priority.is_none() {
|
||||
return String::from("z");
|
||||
}
|
||||
else {
|
||||
return t.priority.clone().unwrap()
|
||||
}
|
||||
}
|
||||
tokens.sort_unstable_by_key(token_member_sort);
|
||||
}
|
||||
}
|
||||
|
||||
if matches.is_present("list"){
|
||||
let lines = match matches.value_of("list").unwrap().parse::<usize>(){
|
||||
Ok(lines) => lines,
|
||||
Err(_) => {
|
||||
eprintln!("{}", "list argument should be a valid number!".red());
|
||||
panic!()
|
||||
}};
|
||||
|
||||
let mut new_tokens : Vec<Token> = Vec::new();
|
||||
for i in tokens{
|
||||
if new_tokens.len() < lines{
|
||||
&new_tokens.push(i.clone());
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
tokens = new_tokens;
|
||||
}
|
||||
|
||||
if matches.is_present("member"){
|
||||
let filters : Vec<&str> = matches.values_of("member").unwrap().collect();
|
||||
let mut new_tokens : Vec<Token> = Vec::new();
|
||||
for i in tokens{
|
||||
// println!("{}", i);
|
||||
for y in &filters {
|
||||
if i.member.clone().is_some() && i.member.clone().unwrap() == *y.to_string(){
|
||||
println!("pushing");
|
||||
&new_tokens.push(i.clone());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
tokens = new_tokens;
|
||||
}
|
||||
|
||||
if matches.is_present("filter"){
|
||||
let filters : Vec<&str> = matches.values_of("filter").unwrap().collect();
|
||||
let mut new_tokens : Vec<Token> = Vec::new();
|
||||
for i in tokens{
|
||||
for y in &filters {
|
||||
if i.keyword == String::from(*y){
|
||||
&new_tokens.push(i.clone());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
tokens = new_tokens;
|
||||
// tokens = new.into_iter().filter(|t| t.keyword == String::from(matches.value_of("filter").unwrap())).collect();
|
||||
}
|
||||
|
||||
if matches.is_present("exclude"){
|
||||
let excludes : Vec<&str> = matches.values_of("exclude").unwrap().collect();
|
||||
let mut new_tokens : Vec<Token> = Vec::new();
|
||||
for i in tokens{
|
||||
for y in 0..excludes.len() {
|
||||
if i.keyword == String::from(excludes[y]){
|
||||
break;
|
||||
}
|
||||
else if y == excludes.len() -1{
|
||||
&new_tokens.push(i.clone());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
tokens = new_tokens;
|
||||
// tokens = new.into_iter().filter(|t| t.keyword == String::from(matches.value_of("filter").unwrap())).collect();
|
||||
}
|
||||
if matches.is_present("inline"){
|
||||
for i in tokens{
|
||||
i.inline();
|
||||
}
|
||||
}
|
||||
else {
|
||||
for i in tokens {
|
||||
println!("{}", i);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
// test zone
|
||||
//TODO refactor
|
||||
//todo implement 2001/11/01 3 getters !clement
|
||||
//todo implement 2001/11/01 3 getters !thomas
|
||||
//fix implement 18/11/2001 getters
|
||||
//4
|
||||
//10/10/10
|
||||
fn test(){
|
||||
todo!("implements getters");
|
||||
}
|
||||
|
||||
//todo implement 2020/08/14 5 getters !clement
|
||||
40
src/parser.rs
Normal file
40
src/parser.rs
Normal file
@@ -0,0 +1,40 @@
|
||||
extern crate string_parser;
|
||||
use string_parser::string_parser_with_file;
|
||||
use colored::Colorize;
|
||||
|
||||
pub struct Parser{
|
||||
keyword : String,
|
||||
end_filter : Box<dyn Fn(Vec<char>) -> bool>,
|
||||
callback : Box<dyn Fn(String, usize, &str)>,
|
||||
}
|
||||
|
||||
impl Parser {
|
||||
pub fn new(keyword : String, end_filter : Box<dyn Fn(Vec<char>) -> bool>) -> Parser{
|
||||
let callback = Box::from(|text : String, line : usize, file : &str| {
|
||||
// let path = Path::new(file).strip_prefix(env::current_dir().unwrap().to_str().unwrap()).unwrap();
|
||||
println!("{} {} {} {} : {}",file,"TODO".green() ,"Line ".green(), line.to_string().green(), text.blue());
|
||||
});
|
||||
Parser{keyword: keyword, end_filter : end_filter, callback}
|
||||
}
|
||||
|
||||
pub fn new_callback(keyword : String, end_filter : Box<dyn Fn(Vec<char>) -> bool>, callback : Box<dyn Fn(String, usize, &str)>) -> Parser{
|
||||
|
||||
Parser{keyword: keyword, end_filter : end_filter, callback}
|
||||
}
|
||||
|
||||
fn get_keyword(&self) -> String {
|
||||
self.keyword.clone()
|
||||
}
|
||||
|
||||
fn get_end_filter(&self) -> &Box<dyn Fn(Vec<char>) -> bool> {
|
||||
&self.end_filter
|
||||
}
|
||||
|
||||
fn get_callback(&self) -> &Box<dyn Fn(String, usize, &str)> {
|
||||
&self.callback
|
||||
}
|
||||
|
||||
pub fn parse(&self, path : &str) {
|
||||
string_parser_with_file(path, self.get_keyword().as_str(), self.get_end_filter(), self.get_callback()).expect("failed to open file");
|
||||
}
|
||||
}
|
||||
32
src/regex.rs
Normal file
32
src/regex.rs
Normal file
@@ -0,0 +1,32 @@
|
||||
extern crate regex;
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::{self, BufRead};
|
||||
use std::path::Path;
|
||||
|
||||
use regex::{RegexSet};
|
||||
use crate::token::*;
|
||||
|
||||
// The output is wrapped in a Result to allow matching on errors
|
||||
// Returns an Iterator to the Reader of the lines of the file.
|
||||
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
|
||||
where P: AsRef<Path>, {
|
||||
let file = File::open(filename)?;
|
||||
Ok(io::BufReader::new(file).lines())
|
||||
}
|
||||
|
||||
pub fn regex_parser(path : &str, regex : Vec<String>, verbosity : i8) -> Result<Vec<Token>, io::Error>{
|
||||
|
||||
let set = RegexSet::new(regex).unwrap();
|
||||
let mut tokens = Vec::new();
|
||||
let mut line_cpt = 0;
|
||||
for line in read_lines(path)? {
|
||||
line_cpt +=1;
|
||||
let line = line.unwrap();
|
||||
if set.is_match(line.to_lowercase().as_str()){
|
||||
tokens.push(Token::new(path.to_string(), line_cpt, line, verbosity));
|
||||
// println!("{}", t);
|
||||
}
|
||||
}
|
||||
Ok(tokens)
|
||||
}
|
||||
133
src/token.rs
Normal file
133
src/token.rs
Normal file
@@ -0,0 +1,133 @@
|
||||
extern crate string_format;
|
||||
extern crate regex;
|
||||
extern crate chrono;
|
||||
|
||||
use chrono::NaiveDate;
|
||||
use string_format::string_format;
|
||||
use std::fmt;
|
||||
use colored::Colorize;
|
||||
use regex::Regex;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Token{
|
||||
file : String,
|
||||
line : usize,
|
||||
pub keyword : String,
|
||||
pub comment : Option<String>,
|
||||
pub priority : Option<String>,
|
||||
pub date : Option<NaiveDate>,
|
||||
pub member : Option<String>,
|
||||
verbosity : i8,
|
||||
}
|
||||
|
||||
impl Token {
|
||||
pub fn new (file : String, line : usize, s : String, verbosity : i8) -> Token{
|
||||
// println!("{}", s);
|
||||
let fields : Vec<&str>= s.split_whitespace().collect();
|
||||
let number_regex = Regex::new("\\b[1-9]\\b").unwrap();
|
||||
let date_regex = Regex::new("(\\d*/\\d*/\\d*)").unwrap();
|
||||
let member_regex = Regex::new("!\\w*").unwrap();
|
||||
if date_regex.is_match("5") {
|
||||
panic!("regex");
|
||||
}
|
||||
// for i in &fields {
|
||||
// println!("{}", i);
|
||||
// }
|
||||
|
||||
let mut t = Token {
|
||||
file : file,
|
||||
line : line,
|
||||
keyword: "todo".to_string(),
|
||||
comment : None,
|
||||
priority : None,
|
||||
date : None,
|
||||
member : None,
|
||||
verbosity : verbosity
|
||||
};
|
||||
|
||||
for i in 0..fields.len() {
|
||||
if i == 0{
|
||||
t.keyword = fields[0].to_string().to_lowercase();
|
||||
}
|
||||
else if number_regex.is_match(fields[i]) {
|
||||
t.priority = Some(fields[i].to_string());
|
||||
}
|
||||
else if date_regex.is_match(fields[i]){
|
||||
let date : Vec<&str> = fields[i].split("/").collect();
|
||||
t.date = NaiveDate::from_ymd_opt(date[0].parse::<i32>().unwrap(), date[1].parse::<u32>().unwrap(), date[2].parse::<u32>().unwrap());
|
||||
// t.date = Some(fields[i].to_string());
|
||||
}
|
||||
else if member_regex.is_match(fields[i]){
|
||||
let mut member = String::new(); //from(fields[i].clone()).chars().next().map(|c| &s[c.len_utf8()..]).unwrap();
|
||||
let it = fields[i].chars().skip(1);
|
||||
for i in it{
|
||||
member.push(i);
|
||||
}
|
||||
|
||||
t.member = Some(member);
|
||||
}
|
||||
else {
|
||||
if t.comment.is_none(){
|
||||
t.comment = Some(fields[i].to_string());
|
||||
}
|
||||
else{
|
||||
t.comment = Some(string_format!("{} {}".to_string(),t.comment.unwrap(), fields[i].to_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
t
|
||||
}
|
||||
|
||||
pub fn inline(&self) {
|
||||
let mut s;
|
||||
s = string_format!("{} line: {} {} ".to_string(), self.file.clone(), self.line.to_string().green().to_string(), self.keyword.clone().green().to_string());
|
||||
if self.member.is_some(){
|
||||
s = string_format!("{} Member: {}".to_string(),s ,self.member.clone().unwrap().red().to_string());
|
||||
}
|
||||
if self.priority.is_some(){
|
||||
s = string_format!("{} Priority: {}".to_string(), s, self.priority.clone().unwrap().red().to_string());
|
||||
}
|
||||
if self.date.is_some(){
|
||||
s = string_format!("{} Deadline: {}".to_string(), s, self.date.clone().unwrap().to_string().red().to_string());
|
||||
}
|
||||
if self.comment.is_some() {
|
||||
s = string_format!("{} {}".to_string(), s, self.comment.clone().unwrap().blue().to_string());
|
||||
}
|
||||
println!("{}", s);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// To use the `{}` marker, the trait `fmt::Display` must be implemented
|
||||
// manually for the type.
|
||||
impl fmt::Display for Token {
|
||||
// This trait requires `fmt` with this exact signature.
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut s;
|
||||
|
||||
s = string_format!("{} line: {} {} \n".to_string(), self.file.clone(), self.line.to_string().green().to_string(), self.keyword.clone().green().to_string());
|
||||
if self.verbosity <= 1{
|
||||
if self.comment.is_some() {
|
||||
s = string_format!("{}{}\n".to_string(), s, self.comment.clone().unwrap().blue().to_string());
|
||||
}
|
||||
}
|
||||
else {
|
||||
if self.member.is_some(){
|
||||
s = string_format!("{}Member: {}\n".to_string(),s ,self.member.clone().unwrap().red().to_string());
|
||||
}
|
||||
if self.priority.is_some(){
|
||||
s = string_format!("{}Priority: {}\n".to_string(), s, self.priority.clone().unwrap().red().to_string());
|
||||
}
|
||||
if self.date.is_some(){
|
||||
s = string_format!("{}Deadline: {}\n".to_string(), s, self.date.clone().unwrap().to_string().red().to_string());
|
||||
}
|
||||
if self.comment.is_some() {
|
||||
s = string_format!("{}{}\n".to_string(), s, self.comment.clone().unwrap().blue().to_string());
|
||||
}
|
||||
}
|
||||
|
||||
write!(f, "{}", s)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user