1- use std:: mem;
21use std:: process;
32
4- use clap:: Arg ;
5- use clap:: { crate_description, ArgMatches } ;
3+ use clap:: { crate_description, value_parser, Arg , ArgAction , ArgMatches } ;
64use colored:: Colorize ;
75use tokei:: { Config , LanguageType , Sort } ;
86
@@ -59,8 +57,8 @@ pub struct Cli {
5957
6058impl Cli {
6159 pub fn from_args ( ) -> Self {
62- let matches = clap:: App :: new ( "tokei" )
63- . version ( & * crate_version ( ) )
60+ let matches = clap:: Command :: new ( "tokei" )
61+ . version ( crate_version ( ) )
6462 . author ( "Erin P. <xampprocky@gmail.com> + Contributors" )
6563 . about ( concat ! (
6664 crate_description!( ) ,
@@ -71,7 +69,7 @@ impl Cli {
7169 Arg :: new ( "columns" )
7270 . long ( "columns" )
7371 . short ( 'c' )
74- . takes_value ( true )
72+ . value_parser ( value_parser ! ( usize ) )
7573 . conflicts_with ( "output" )
7674 . help (
7775 "Sets a strict column width of the output, only available for \
@@ -82,8 +80,7 @@ impl Cli {
8280 Arg :: new ( "exclude" )
8381 . long ( "exclude" )
8482 . short ( 'e' )
85- . takes_value ( true )
86- . multiple_values ( true )
83+ . num_args ( 0 ..)
8784 . help ( "Ignore all files & directories matching the pattern." ) ,
8885 )
8986 . arg (
@@ -96,7 +93,6 @@ impl Cli {
9693 Arg :: new ( "file_input" )
9794 . long ( "input" )
9895 . short ( 'i' )
99- . takes_value ( true )
10096 . help (
10197 "Gives statistics from a previous tokei run. Can be given a file path, \
10298 or \" stdin\" to read from stdin.",
@@ -109,7 +105,7 @@ impl Cli {
109105 )
110106 . arg (
111107 Arg :: new ( "input" )
112- . min_values ( 1 )
108+ . num_args ( 1 .. )
113109 . conflicts_with ( "languages" )
114110 . help ( "The path(s) to the file or directory to be counted.(default current directory)" ) ,
115111 )
@@ -140,8 +136,13 @@ impl Cli {
140136 Arg :: new ( "output" )
141137 . long ( "output" )
142138 . short ( 'o' )
143- . takes_value ( true )
144- . possible_values ( Format :: all ( ) )
139+ . value_parser ( |x : & str | {
140+ if Format :: all ( ) . contains ( & x) {
141+ Ok ( x. to_string ( ) )
142+ } else {
143+ Err ( format ! ( "Invalid output format: {x:?}" ) )
144+ }
145+ } )
145146 . help (
146147 "Outputs Tokei in a specific format. Compile with additional features for \
147148 more format support.",
@@ -150,8 +151,7 @@ impl Cli {
150151 . arg (
151152 Arg :: new ( "streaming" )
152153 . long ( "streaming" )
153- . takes_value ( true )
154- . possible_values ( [ "simple" , "json" ] )
154+ . value_parser ( [ "simple" , "json" ] )
155155 . ignore_case ( true )
156156 . help (
157157 "prints the (language, path, lines, blanks, code, comments) records as \
@@ -162,8 +162,7 @@ impl Cli {
162162 Arg :: new ( "sort" )
163163 . long ( "sort" )
164164 . short ( 's' )
165- . takes_value ( true )
166- . possible_values ( [ "files" , "lines" , "blanks" , "code" , "comments" ] )
165+ . value_parser ( [ "files" , "lines" , "blanks" , "code" , "comments" ] )
167166 . ignore_case ( true )
168167 . conflicts_with ( "rsort" )
169168 . help ( "Sort languages based on column" ) ,
@@ -172,8 +171,7 @@ impl Cli {
172171 Arg :: new ( "rsort" )
173172 . long ( "rsort" )
174173 . short ( 'r' )
175- . takes_value ( true )
176- . possible_values ( [ "files" , "lines" , "blanks" , "code" , "comments" ] )
174+ . value_parser ( [ "files" , "lines" , "blanks" , "code" , "comments" ] )
177175 . ignore_case ( true )
178176 . conflicts_with ( "sort" )
179177 . help ( "Reverse sort languages based on column" ) ,
@@ -182,7 +180,7 @@ impl Cli {
182180 Arg :: new ( "types" )
183181 . long ( "types" )
184182 . short ( 't' )
185- . takes_value ( true )
183+ . action ( ArgAction :: Append )
186184 . help (
187185 "Filters output by language type, separated by a comma. i.e. \
188186 -t=Rust,Markdown",
@@ -198,8 +196,7 @@ impl Cli {
198196 Arg :: new ( "num_format_style" )
199197 . long ( "num-format" )
200198 . short ( 'n' )
201- . takes_value ( true )
202- . possible_values ( NumberFormatStyle :: all ( ) )
199+ . value_parser ( [ "commas" , "dots" , "plain" , "underscores" ] )
203200 . conflicts_with ( "output" )
204201 . help (
205202 "Format of printed numbers, i.e., plain (1234, default), \
@@ -211,7 +208,7 @@ impl Cli {
211208 Arg :: new ( "verbose" )
212209 . long ( "verbose" )
213210 . short ( 'v' )
214- . multiple_occurrences ( true )
211+ . action ( ArgAction :: Count )
215212 . help (
216213 "Set log output level:
217214 1: to show unknown file extensions,
@@ -221,26 +218,29 @@ impl Cli {
221218 )
222219 . get_matches ( ) ;
223220
224- let columns = matches. value_of ( "columns" ) . map ( parse_or_exit :: < usize > ) ;
225- let files = matches. is_present ( "files" ) ;
226- let hidden = matches. is_present ( "hidden" ) ;
227- let no_ignore = matches. is_present ( "no_ignore" ) ;
228- let no_ignore_parent = matches. is_present ( "no_ignore_parent" ) ;
229- let no_ignore_dot = matches. is_present ( "no_ignore_dot" ) ;
230- let no_ignore_vcs = matches. is_present ( "no_ignore_vcs" ) ;
231- let print_languages = matches. is_present ( "languages" ) ;
232- let verbose = matches. occurrences_of ( "verbose" ) ;
233- let compact = matches. is_present ( "compact" ) ;
234- let types = matches. value_of ( "types" ) . map ( |e| {
235- e. split ( ',' )
236- . map ( str:: parse :: < LanguageType > )
237- . filter_map ( Result :: ok)
238- . collect ( )
221+ let columns = matches. get_one :: < usize > ( "columns" ) . cloned ( ) ;
222+ let files = matches. get_flag ( "files" ) ;
223+ let hidden = matches. get_flag ( "hidden" ) ;
224+ let no_ignore = matches. get_flag ( "no_ignore" ) ;
225+ let no_ignore_parent = matches. get_flag ( "no_ignore_parent" ) ;
226+ let no_ignore_dot = matches. get_flag ( "no_ignore_dot" ) ;
227+ let no_ignore_vcs = matches. get_flag ( "no_ignore_vcs" ) ;
228+ let print_languages = matches. get_flag ( "languages" ) ;
229+ let verbose = matches. get_count ( "verbose" ) as u64 ;
230+ let compact = matches. get_flag ( "compact" ) ;
231+ let types = matches. get_many ( "types" ) . map ( |e| {
232+ e. flat_map ( |x : & String | {
233+ x. split ( ',' )
234+ . map ( str:: parse :: < LanguageType > )
235+ . filter_map ( Result :: ok)
236+ . collect :: < Vec < _ > > ( )
237+ } )
238+ . collect ( )
239239 } ) ;
240240
241241 let num_format_style: NumberFormatStyle = matches
242- . value_of ( "num_format_style" )
243- . map ( parse_or_exit :: < NumberFormatStyle > )
242+ . get_one :: < NumberFormatStyle > ( "num_format_style" )
243+ . cloned ( )
244244 . unwrap_or_default ( ) ;
245245
246246 let number_format = match num_format_style. get_format ( ) {
@@ -253,18 +253,20 @@ impl Cli {
253253
254254 // Sorting category should be restricted by clap but parse before we do
255255 // work just in case.
256- let sort = matches
257- . value_of ( "sort" )
258- . or_else ( || matches. value_of ( "rsort" ) )
259- . map ( parse_or_exit :: < Sort > ) ;
260- let sort_reverse = matches. value_of ( "rsort" ) . is_some ( ) ;
256+ let ( sort, sort_reverse) = if let Some ( sort) = matches. get_one :: < Sort > ( "sort" ) {
257+ ( Some ( * sort) , false )
258+ } else {
259+ let sort = matches. get_one :: < Sort > ( "rsort" ) ;
260+ ( sort. cloned ( ) , sort. is_some ( ) )
261+ } ;
261262
262263 // Format category is overly accepting by clap (so the user knows what
263264 // is supported) but this will fail if support is not compiled in and
264265 // give a useful error to the user.
265- let output = matches. value_of ( "output" ) . map ( parse_or_exit :: < Format > ) ;
266+ let output = matches. get_one ( "output" ) . cloned ( ) ;
266267 let streaming = matches
267- . value_of ( "streaming" )
268+ . get_one ( "streaming" )
269+ . cloned ( )
268270 . map ( parse_or_exit :: < Streaming > ) ;
269271
270272 crate :: cli_utils:: setup_logger ( verbose) ;
@@ -295,20 +297,20 @@ impl Cli {
295297 }
296298
297299 pub fn file_input ( & self ) -> Option < & str > {
298- self . matches . value_of ( "file_input" )
300+ self . matches . get_one ( "file_input" ) . cloned ( )
299301 }
300302
301303 pub fn ignored_directories ( & self ) -> Vec < & str > {
302304 let mut ignored_directories: Vec < & str > = Vec :: new ( ) ;
303- if let Some ( user_ignored) = self . matches . values_of ( "exclude" ) {
305+ if let Some ( user_ignored) = self . matches . get_many :: < & str > ( "exclude" ) {
304306 ignored_directories. extend ( user_ignored) ;
305307 }
306308 ignored_directories
307309 }
308310
309311 pub fn input ( & self ) -> Vec < & str > {
310- match self . matches . values_of ( "input" ) {
311- Some ( vs) => vs. collect ( ) ,
312+ match self . matches . get_many :: < & str > ( "input" ) {
313+ Some ( vs) => vs. cloned ( ) . collect ( ) ,
312314 None => vec ! [ "." ] ,
313315 }
314316 }
@@ -330,14 +332,18 @@ impl Cli {
330332 padding = Padding :: NONE ,
331333 width = Some ( lang_w)
332334 )
333- . with_formatter( vec![ table_formatter:: table:: FormatterFunc :: Normal ( Colorize :: bold) ] ) ,
335+ . with_formatter( vec![ table_formatter:: table:: FormatterFunc :: Normal (
336+ Colorize :: bold,
337+ ) ] ) ,
334338 cell!(
335339 "Extensions" ,
336340 align = Align :: Left ,
337341 padding = Padding :: new( 3 , 0 ) ,
338342 width = Some ( suffix_w)
339343 )
340- . with_formatter( vec![ table_formatter:: table:: FormatterFunc :: Normal ( Colorize :: bold) ] ) ,
344+ . with_formatter( vec![ table_formatter:: table:: FormatterFunc :: Normal (
345+ Colorize :: bold,
346+ ) ] ) ,
341347 ] ;
342348 let content = LanguageType :: list ( )
343349 . iter ( )
@@ -429,7 +435,7 @@ impl Cli {
429435 _ => None ,
430436 } ;
431437
432- config. types = mem :: replace ( & mut self . types , None ) . or ( config. types ) ;
438+ config. types = self . types . take ( ) . or ( config. types ) ;
433439
434440 config
435441 }
0 commit comments