1mod opts;
6
7use crate::OptCfg;
8
9use linebreak;
10use std::cmp;
11
12pub struct Help {
16 margin_left: usize,
17 margin_right: usize,
18 blocks: Vec<Block>,
19}
20
21struct Block {
22 indent: usize,
23 margin_left: usize,
24 margin_right: usize,
25 bodies: Vec<(usize, String)>, _spaces: String,
28}
29
30impl Help {
31 pub fn new() -> Self {
33 Self {
34 margin_left: 0,
35 margin_right: 0,
36 blocks: Vec::<Block>::with_capacity(2),
37 }
38 }
39
40 pub fn with_margins(margin_left: usize, margin_right: usize) -> Self {
42 Self {
43 margin_left: margin_left,
44 margin_right: margin_right,
45 blocks: Vec::<Block>::with_capacity(2),
46 }
47 }
48
49 pub fn add_text(&mut self, text: String) {
55 self.add_text_with_indent_and_margins(text, 0, 0, 0)
56 }
57
58 pub fn add_text_with_indent(&mut self, text: String, indent: usize) {
65 self.add_text_with_indent_and_margins(text, indent, 0, 0)
66 }
67
68 pub fn add_text_with_margins(&mut self, text: String, margin_left: usize, margin_right: usize) {
74 self.add_text_with_indent_and_margins(text, 0, margin_left, margin_right)
75 }
76
77 pub fn add_text_with_indent_and_margins(
84 &mut self,
85 text: String,
86 indent: usize,
87 margin_left: usize,
88 margin_right: usize,
89 ) {
90 let margin_left = self.margin_left + margin_left;
91 let margin_right = self.margin_right + margin_right;
92 let max_len = cmp::max(margin_left, indent);
93 let block = Block {
94 indent: indent,
95 margin_left: margin_left,
96 margin_right: margin_right,
97 bodies: vec![(0, text)],
98 _spaces: " ".repeat(max_len),
99 };
100 self.blocks.push(block);
101 }
102
103 pub fn add_texts(&mut self, texts: Vec<String>) {
109 self.add_texts_with_indent_and_margins(texts, 0, 0, 0);
110 }
111
112 pub fn add_texts_with_indent(&mut self, texts: Vec<String>, indent: usize) {
119 self.add_texts_with_indent_and_margins(texts, indent, 0, 0);
120 }
121
122 pub fn add_texts_with_margins(
128 &mut self,
129 texts: Vec<String>,
130 margin_left: usize,
131 margin_right: usize,
132 ) {
133 self.add_texts_with_indent_and_margins(texts, 0, margin_left, margin_right);
134 }
135
136 pub fn add_texts_with_indent_and_margins(
143 &mut self,
144 texts: Vec<String>,
145 indent: usize,
146 margin_left: usize,
147 margin_right: usize,
148 ) {
149 let margin_left = self.margin_left + margin_left;
150 let margin_right = self.margin_right + margin_right;
151 let max_len = cmp::max(margin_left, indent);
152 let block = Block {
153 indent: indent,
154 margin_left: margin_left,
155 margin_right: margin_right,
156 bodies: texts.into_iter().map(|s| (0, s)).collect(),
157 _spaces: " ".repeat(max_len),
158 };
159 self.blocks.push(block);
160 }
161
162 pub fn add_opts(&mut self, cfgs: &[OptCfg]) {
168 self.add_opts_with_indent_and_margins(cfgs, 0, 0, 0);
169 }
170
171 pub fn add_opts_with_indent(&mut self, cfgs: &[OptCfg], indent: usize) {
178 self.add_opts_with_indent_and_margins(cfgs, indent, 0, 0);
179 }
180
181 pub fn add_opts_with_margins(
188 &mut self,
189 cfgs: &[OptCfg],
190 margin_left: usize,
191 margin_right: usize,
192 ) {
193 self.add_opts_with_indent_and_margins(cfgs, 0, margin_left, margin_right);
194 }
195
196 pub fn add_opts_with_indent_and_margins(
204 &mut self,
205 cfgs: &[OptCfg],
206 indent: usize,
207 margin_left: usize,
208 margin_right: usize,
209 ) {
210 let mut indent = indent;
211 let bodies = opts::create_opts_help(cfgs, &mut indent);
212
213 let mut max_len = 0;
214 for (i, _) in &bodies {
215 max_len = cmp::max(max_len, *i);
216 }
217
218 let margin_left = self.margin_left + margin_left;
219 let margin_right = self.margin_right + margin_right;
220 let max_len = cmp::max(max_len, cmp::max(margin_left, indent));
221
222 let block = Block {
223 indent: indent,
224 margin_left: margin_left,
225 margin_right: margin_right,
226 bodies: bodies,
227 _spaces: " ".repeat(max_len),
228 };
229 self.blocks.push(block);
230 }
231
232 pub fn iter(&self) -> HelpIter {
234 if self.blocks.is_empty() {
235 return HelpIter {
236 line_width: 0,
237 blocks: &self.blocks,
238 block_iter: BlockIter::empty(),
239 };
240 }
241
242 let line_width = linebreak::term_cols();
243
244 HelpIter {
245 line_width: line_width,
246 blocks: &self.blocks,
247 block_iter: BlockIter::new(&self.blocks[0], line_width),
248 }
249 }
250
251 pub fn print(&self) {
253 let mut iter = self.iter();
254 while let Some(line) = iter.next() {
255 println!("{}", line);
256 }
257 }
258}
259
260pub struct HelpIter<'a> {
264 line_width: usize,
265 blocks: &'a [Block],
266 block_iter: BlockIter<'a>,
267}
268
269struct BlockIter<'a> {
270 bodies: &'a [(usize, String)],
271 index: usize,
272 indent: &'a str,
273 margin: &'a str,
274 line_iter: linebreak::LineIter<'a>,
275}
276
277impl Iterator for HelpIter<'_> {
278 type Item = String;
279
280 fn next(&mut self) -> Option<String> {
281 loop {
282 if let Some(line) = self.block_iter.next() {
283 return Some(line);
284 }
285 if self.blocks.len() <= 1 {
286 break;
287 }
288 self.blocks = &self.blocks[1..];
289 self.block_iter = BlockIter::new(&self.blocks[0], self.line_width);
290 }
291 None
292 }
293}
294
295impl<'a> BlockIter<'a> {
296 fn new(block: &'a Block, line_width: usize) -> Self {
297 let print_width = line_width - block.margin_left - block.margin_right;
298 if block.bodies.is_empty() || print_width <= block.indent {
299 return Self::empty();
300 }
301 let (indent, text) = &block.bodies[0];
302 let mut line_iter = linebreak::LineIter::new(&text, print_width);
303 line_iter.set_indent(&block._spaces[0..(*indent)]);
304 Self {
305 bodies: &block.bodies,
306 index: 0,
307 indent: &(&block._spaces)[0..block.indent],
308 margin: &(&block._spaces)[0..block.margin_left],
309 line_iter: line_iter,
310 }
311 }
312
313 fn empty() -> Self {
314 Self {
315 bodies: &[] as &'a [(usize, String)],
316 index: 0,
317 indent: "",
318 margin: "",
319 line_iter: linebreak::LineIter::new("", 0),
320 }
321 }
322}
323
324impl<'a> Iterator for BlockIter<'a> {
325 type Item = String;
326
327 fn next(&mut self) -> Option<String> {
328 if self.bodies.is_empty() {
329 return None;
330 }
331
332 loop {
333 if let Some(mut line) = self.line_iter.next() {
334 line.insert_str(0, self.margin);
335 self.line_iter.set_indent(&self.indent);
336 return Some(line);
337 }
338
339 self.index += 1;
340 if self.index >= self.bodies.len() {
341 break;
342 }
343
344 let (indent, text) = &self.bodies[self.index];
345 self.line_iter.init(&text);
346 self.line_iter.set_indent(&self.indent[0..(*indent)]);
347 }
348
349 None
350 }
351}
352
353#[cfg(test)]
354mod tests_of_help {
355 use super::*;
356
357 #[test]
358 fn new() {
359 let help = Help::new();
360
361 let mut iter = help.iter();
362
363 let line = iter.next();
364 assert_eq!(line, None);
365
366 let line = iter.next();
367 assert_eq!(line, None);
368 }
369
370 #[test]
371 fn new_and_add_text_if_one_line_with_zero_wrapping() {
372 let mut help = Help::new();
373 help.add_text("abc".to_string());
374
375 let mut iter = help.iter();
376
377 let line = iter.next();
378 assert_eq!(line, Some("abc".to_string()));
379
380 let line = iter.next();
381 assert_eq!(line, None);
382
383 let line = iter.next();
384 assert_eq!(line, None);
385 }
386
387 #[test]
388 fn new_and_add_text_if_one_line_with_wrapping() {
389 let term_cols = linebreak::term_cols();
390 let mut text = "a".repeat(term_cols);
391 text.push_str("123456");
392
393 let mut help = Help::new();
394 help.add_text(text);
395
396 let mut iter = help.iter();
397
398 let line = iter.next();
399 assert_eq!(line, Some("a".repeat(term_cols)));
400
401 let line = iter.next();
402 assert_eq!(line, Some("123456".to_string()));
403
404 let line = iter.next();
405 assert_eq!(line, None);
406 }
407
408 #[test]
409 fn new_add_text_if_multi_lines_with_wrapping() {
410 let term_cols = linebreak::term_cols();
411 let mut text = "a".repeat(term_cols);
412 text.push_str("123456\n");
413 text.push_str(&"b".repeat(term_cols));
414 text.push_str("789");
415
416 let mut help = Help::new();
417 help.add_text(text);
418 let mut iter = help.iter();
419
420 let line = iter.next();
421 assert_eq!(line, Some("a".repeat(term_cols)));
422
423 let line = iter.next();
424 assert_eq!(line, Some("123456".to_string()));
425
426 let line = iter.next();
427 assert_eq!(line, Some("b".repeat(term_cols)));
428
429 let line = iter.next();
430 assert_eq!(line, Some("789".to_string()));
431
432 let line = iter.next();
433 assert_eq!(line, None);
434 }
435
436 #[test]
437 fn with_margins_and_add_text() {
438 let term_cols = linebreak::term_cols();
439 let mut text = "a".repeat(term_cols - 5 - 3);
440 text.push_str("12345\n");
441 text.push_str(&"b".repeat(term_cols - 5 - 3));
442 text.push_str("6789");
443
444 let mut help = Help::with_margins(5, 3);
445 help.add_text(text);
446 let mut iter = help.iter();
447
448 let line = iter.next();
449 let mut expected = "a".repeat(term_cols - 5 - 3);
450 expected.insert_str(0, " ");
451 assert_eq!(line, Some(expected));
452
453 let line = iter.next();
454 let expected = " 12345".to_string();
455 assert_eq!(line, Some(expected));
456
457 let line = iter.next();
458 let mut expected = "b".repeat(term_cols - 5 - 3);
459 expected.insert_str(0, " ");
460 assert_eq!(line, Some(expected));
461
462 let line = iter.next();
463 let expected = " 6789".to_string();
464 assert_eq!(line, Some(expected));
465
466 let line = iter.next();
467 assert_eq!(line, None);
468 }
469
470 #[test]
471 fn add_text_with_margins() {
472 let term_cols = linebreak::term_cols();
473 let mut text = "a".repeat(term_cols - 5 - 3);
474 text.push_str("12345\n");
475 text.push_str(&"b".repeat(term_cols - 5 - 3));
476 text.push_str("6789");
477
478 let mut help = Help::new();
479 help.add_text_with_margins(text, 5, 3);
480 let mut iter = help.iter();
481
482 let line = iter.next();
483 let mut expected = "a".repeat(term_cols - 5 - 3);
484 expected.insert_str(0, " ");
485 assert_eq!(line, Some(expected));
486
487 let line = iter.next();
488 let expected = " 12345".to_string();
489 assert_eq!(line, Some(expected));
490
491 let line = iter.next();
492 let mut expected = "b".repeat(term_cols - 5 - 3);
493 expected.insert_str(0, " ");
494 assert_eq!(line, Some(expected));
495
496 let line = iter.next();
497 let expected = " 6789".to_string();
498 assert_eq!(line, Some(expected));
499
500 let line = iter.next();
501 assert_eq!(line, None);
502 }
503
504 #[test]
505 fn add_text_with_indent() {
506 let term_cols = linebreak::term_cols();
507 let mut text = "a".repeat(term_cols);
508 text.push_str("12345\n");
509 text.push_str(&"b".repeat(term_cols - 8));
510 text.push_str("6789");
511
512 let mut help = Help::new();
513 help.add_text_with_indent(text, 8);
514 let mut iter = help.iter();
515
516 let line = iter.next();
517 let expected = "a".repeat(term_cols);
518 assert_eq!(line, Some(expected));
519
520 let line = iter.next();
521 let expected = " 12345".to_string();
522 assert_eq!(line, Some(expected));
523
524 let line = iter.next();
525 let mut expected = "b".repeat(term_cols - 8);
526 expected.insert_str(0, " ");
527 assert_eq!(line, Some(expected));
528
529 let line = iter.next();
530 let expected = " 6789".to_string();
531 assert_eq!(line, Some(expected));
532
533 let line = iter.next();
534 assert_eq!(line, None);
535 }
536
537 #[test]
538 fn add_text_with_indent_and_margins() {
539 let term_cols = linebreak::term_cols();
540 let mut text = "a".repeat(term_cols - 1 - 2);
541 text.push_str("12345\n");
542 text.push_str(&"b".repeat(term_cols - 8 - 1 - 2));
543 text.push_str("6789");
544
545 let mut help = Help::new();
546 help.add_text_with_indent_and_margins(text, 8, 1, 2);
547 let mut iter = help.iter();
548
549 let line = iter.next();
550 let mut expected = "a".repeat(term_cols - 1 - 2);
551 expected.insert_str(0, " ");
552 assert_eq!(line, Some(expected));
553
554 let line = iter.next();
555 let expected = " 12345".to_string();
556 assert_eq!(line, Some(expected));
557
558 let line = iter.next();
559 let mut expected = "b".repeat(term_cols - 8 - 1 - 2);
560 expected.insert_str(0, " ");
561 assert_eq!(line, Some(expected));
562
563 let line = iter.next();
564 let expected = " 6789".to_string();
565 assert_eq!(line, Some(expected));
566
567 let line = iter.next();
568 assert_eq!(line, None);
569 }
570
571 #[test]
572 fn add_text_if_text_is_empty() {
573 let mut help = Help::new();
574 help.add_text("".to_string());
575 let mut iter = help.iter();
576
577 let line = iter.next();
578 assert_eq!(line, Some("".to_string()));
579
580 let line = iter.next();
581 assert_eq!(line, None);
582 }
583
584 #[test]
585 fn add_text_multiple_times() {
586 let term_cols = linebreak::term_cols();
587
588 let mut text = "a".repeat(term_cols - 4 - 3);
589 text.push_str(&"b".repeat(term_cols - 4 - 5 - 3));
590 text.push_str(&"c".repeat(term_cols - 4 - 5 - 3));
591
592 let mut help = Help::with_margins(1, 1);
593 help.add_text_with_indent_and_margins(text, 5, 3, 2);
594
595 let mut text = "d".repeat(term_cols - 2 - 2);
596 text.push_str(&"e".repeat(term_cols - 2 - 5 - 2));
597 text.push_str(&"f".repeat(term_cols - 2 - 5 - 2));
598
599 help.add_text_with_indent_and_margins(text, 5, 1, 1);
600
601 let mut iter = help.iter();
602
603 let line = iter.next();
604 assert_eq!(line, Some(" ".to_string() + &"a".repeat(term_cols - 7)));
605
606 let line = iter.next();
607 assert_eq!(
608 line,
609 Some(" ".to_string() + &"b".repeat(term_cols - 12))
610 );
611
612 let line = iter.next();
613 assert_eq!(
614 line,
615 Some(" ".to_string() + &"c".repeat(term_cols - 12))
616 );
617
618 let line = iter.next();
619 assert_eq!(line, Some(" ".to_string() + &"d".repeat(term_cols - 4)));
620
621 let line = iter.next();
622 assert_eq!(
623 line,
624 Some(" ".to_string() + &"e".repeat(term_cols - 9))
625 );
626
627 let line = iter.next();
628 assert_eq!(
629 line,
630 Some(" ".to_string() + &"f".repeat(term_cols - 9))
631 );
632 }
633
634 #[test]
635 fn add_texts_if_array_is_empty() {
636 let mut help = Help::new();
637 help.add_texts(Vec::<String>::new());
638
639 let mut iter = help.iter();
640
641 let line = iter.next();
642 assert_eq!(line, None);
643
644 let line = iter.next();
645 assert_eq!(line, None);
646 }
647
648 #[test]
649 fn add_texts_if_array_has_a_text() {
650 let term_cols = linebreak::term_cols();
651
652 let mut texts = Vec::<String>::new();
653
654 let mut text = "a".repeat(term_cols);
655 text.push_str(&"b".repeat(term_cols));
656 text.push_str(&"c".repeat(term_cols));
657 texts.push(text);
658
659 let mut help = Help::new();
660 help.add_texts(texts);
661
662 let mut iter = help.iter();
663
664 let line = iter.next();
665 assert_eq!(line, Some("a".repeat(term_cols)));
666
667 let line = iter.next();
668 assert_eq!(line, Some("b".repeat(term_cols)));
669
670 let line = iter.next();
671 assert_eq!(line, Some("c".repeat(term_cols)));
672
673 let line = iter.next();
674 assert_eq!(line, None);
675 }
676
677 #[test]
678 fn add_texts_if_array_has_multiple_texts() {
679 let term_cols = linebreak::term_cols();
680
681 let mut texts = Vec::<String>::new();
682
683 let mut text = "a".repeat(term_cols);
684 text.push_str(&"b".repeat(term_cols));
685 text.push_str(&"c".repeat(term_cols));
686 texts.push(text);
687
688 let mut text = "d".repeat(term_cols);
689 text.push_str(&"e".repeat(term_cols));
690 text.push_str(&"f".repeat(term_cols));
691 texts.push(text);
692
693 let mut help = Help::new();
694 help.add_texts(texts);
695
696 let mut iter = help.iter();
697
698 let line = iter.next();
699 assert_eq!(line, Some("a".repeat(term_cols)));
700
701 let line = iter.next();
702 assert_eq!(line, Some("b".repeat(term_cols)));
703
704 let line = iter.next();
705 assert_eq!(line, Some("c".repeat(term_cols)));
706
707 let line = iter.next();
708 assert_eq!(line, Some("d".repeat(term_cols)));
709
710 let line = iter.next();
711 assert_eq!(line, Some("e".repeat(term_cols)));
712
713 let line = iter.next();
714 assert_eq!(line, Some("f".repeat(term_cols)));
715
716 let line = iter.next();
717 assert_eq!(line, None);
718 }
719
720 #[test]
721 fn add_texts_with_indent() {
722 let term_cols = linebreak::term_cols();
723
724 let mut texts = Vec::<String>::new();
725
726 let mut text = "a".repeat(term_cols);
727 text.push_str(&"b".repeat(term_cols - 5));
728 text.push_str(&"c".repeat(term_cols - 5));
729 texts.push(text);
730
731 let mut text = "d".repeat(term_cols);
732 text.push_str(&"e".repeat(term_cols - 5));
733 text.push_str(&"f".repeat(term_cols - 5));
734 texts.push(text);
735
736 let mut help = Help::new();
737 help.add_texts_with_indent(texts, 5);
738
739 let mut iter = help.iter();
740
741 let line = iter.next();
742 assert_eq!(line, Some("a".repeat(term_cols)));
743
744 let line = iter.next();
745 assert_eq!(line, Some(" ".repeat(5) + &"b".repeat(term_cols - 5)));
746
747 let line = iter.next();
748 assert_eq!(line, Some(" ".repeat(5) + &"c".repeat(term_cols - 5)));
749
750 let line = iter.next();
751 assert_eq!(line, Some("d".repeat(term_cols)));
752
753 let line = iter.next();
754 assert_eq!(line, Some(" ".repeat(5) + &"e".repeat(term_cols - 5)));
755
756 let line = iter.next();
757 assert_eq!(line, Some(" ".repeat(5) + &"f".repeat(term_cols - 5)));
758
759 let line = iter.next();
760 assert_eq!(line, None);
761 }
762
763 #[test]
764 fn add_texts_with_margins() {
765 let term_cols = linebreak::term_cols();
766
767 let mut texts = Vec::<String>::new();
768
769 let mut text = "a".repeat(term_cols - 3 - 3);
770 text.push_str(&"b".repeat(term_cols - 3 - 3));
771 text.push_str(&"c".repeat(term_cols - 3 - 3));
772 texts.push(text);
773
774 let mut text = "d".repeat(term_cols - 3 - 3);
775 text.push_str(&"e".repeat(term_cols - 3 - 3));
776 text.push_str(&"f".repeat(term_cols - 3 - 3));
777 texts.push(text);
778
779 let mut help = Help::with_margins(1, 1);
780 help.add_texts_with_margins(texts, 2, 2);
781
782 let mut iter = help.iter();
783
784 let line = iter.next();
785 assert_eq!(line, Some(" ".repeat(3) + &"a".repeat(term_cols - 6)));
786
787 let line = iter.next();
788 assert_eq!(line, Some(" ".repeat(3) + &"b".repeat(term_cols - 6)));
789
790 let line = iter.next();
791 assert_eq!(line, Some(" ".repeat(3) + &"c".repeat(term_cols - 6)));
792
793 let line = iter.next();
794 assert_eq!(line, Some(" ".repeat(3) + &"d".repeat(term_cols - 6)));
795
796 let line = iter.next();
797 assert_eq!(line, Some(" ".repeat(3) + &"e".repeat(term_cols - 6)));
798
799 let line = iter.next();
800 assert_eq!(line, Some(" ".repeat(3) + &"f".repeat(term_cols - 6)));
801
802 let line = iter.next();
803 assert_eq!(line, None);
804 }
805
806 #[test]
807 fn add_texts_with_indent_and_margins() {
808 let term_cols = linebreak::term_cols();
809
810 let mut texts = Vec::<String>::new();
811
812 let mut text = "a".repeat(term_cols - 3 - 3);
813 text.push_str(&"b".repeat(term_cols - 3 - 5 - 3));
814 text.push_str(&"c".repeat(term_cols - 3 - 5 - 3));
815 texts.push(text);
816
817 let mut text = "d".repeat(term_cols - 3 - 3);
818 text.push_str(&"e".repeat(term_cols - 3 - 5 - 3));
819 text.push_str(&"f".repeat(term_cols - 3 - 5 - 3));
820 texts.push(text);
821
822 let mut help = Help::with_margins(1, 1);
823 help.add_texts_with_indent_and_margins(texts, 5, 2, 2);
824
825 let mut iter = help.iter();
826
827 let line = iter.next();
828 assert_eq!(line, Some(" ".repeat(3) + &"a".repeat(term_cols - 6)));
829
830 let line = iter.next();
831 assert_eq!(line, Some(" ".repeat(8) + &"b".repeat(term_cols - 11)));
832
833 let line = iter.next();
834 assert_eq!(line, Some(" ".repeat(8) + &"c".repeat(term_cols - 11)));
835
836 let line = iter.next();
837 assert_eq!(line, Some(" ".repeat(3) + &"d".repeat(term_cols - 6)));
838
839 let line = iter.next();
840 assert_eq!(line, Some(" ".repeat(8) + &"e".repeat(term_cols - 11)));
841
842 let line = iter.next();
843 assert_eq!(line, Some(" ".repeat(8) + &"f".repeat(term_cols - 11)));
844
845 let line = iter.next();
846 assert_eq!(line, None);
847 }
848
849 #[test]
850 fn add_opts_with_no_wrapping() {
851 use crate::OptCfgParam::*;
852
853 let mut help = Help::new();
854 help.add_opts(&[OptCfg::with([
855 names(&["foo-bar"]),
856 desc("This is a description of option."),
857 ])]);
858
859 let mut iter = help.iter();
860
861 let line = iter.next();
862 assert_eq!(
863 line,
864 Some("--foo-bar This is a description of option.".to_string())
865 );
866
867 let line = iter.next();
868 assert_eq!(line, None);
869 }
870
871 #[test]
872 fn add_opts_with_wrapping() {
873 use crate::OptCfgParam::*;
874
875 let cols = linebreak::term_cols();
876
877 let mut help = Help::new();
878 help.add_opts(&[OptCfg::with([
879 names(&["foo-bar"]),
880 desc(&("a".repeat(cols - 11) + " bcdef")),
881 ])]);
882
883 let mut iter = help.iter();
884
885 let line = iter.next();
886 assert_eq!(
887 line,
888 Some("--foo-bar ".to_string() + &"a".repeat(cols - 11))
889 );
890
891 let line = iter.next();
892 assert_eq!(line, Some(" ".to_string() + "bcdef"));
893
894 let line = iter.next();
895 assert_eq!(line, None);
896 }
897
898 #[test]
899 fn with_margins_and_add_opts() {
900 use crate::OptCfgParam::*;
901
902 let cols = linebreak::term_cols();
903
904 let mut help = Help::with_margins(4, 2);
905
906 help.add_opts(&[OptCfg::with([
907 names(&["foo-bar"]),
908 desc(&("a".repeat(cols - 11 - 4 - 2) + " " + &"b".repeat(cols - 11 - 4 - 2) + "ccc")),
909 ])]);
910
911 let mut iter = help.iter();
912
913 let line = iter.next();
914 assert_eq!(
915 line,
916 Some(" --foo-bar ".to_string() + &"a".repeat(cols - 11 - 4 - 2))
917 );
918
919 let line = iter.next();
920 assert_eq!(
921 line,
922 Some(" ".repeat(11 + 4) + &"b".repeat(cols - 11 - 4 - 2))
923 );
924
925 let line = iter.next();
926 assert_eq!(line, Some(" ".repeat(11 + 4) + "ccc"));
927
928 let line = iter.next();
929 assert_eq!(line, None);
930 }
931
932 #[test]
933 fn add_opts_with_margins() {
934 use crate::OptCfgParam::*;
935
936 let cols = linebreak::term_cols();
937
938 let mut help = Help::new();
939
940 help.add_opts_with_margins(
941 &[OptCfg::with([
942 names(&["foo-bar"]),
943 desc(
944 &("a".repeat(cols - 11 - 5 - 4) + " " + &"b".repeat(cols - 11 - 5 - 4) + "ccc"),
945 ),
946 ])],
947 5,
948 4,
949 );
950
951 let mut iter = help.iter();
952
953 let line = iter.next();
954 assert_eq!(
955 line,
956 Some(" --foo-bar ".to_string() + &"a".repeat(cols - 11 - 5 - 4))
957 );
958
959 let line = iter.next();
960 assert_eq!(
961 line,
962 Some(" ".repeat(11 + 5) + &"b".repeat(cols - 11 - 5 - 4))
963 );
964
965 let line = iter.next();
966 assert_eq!(line, Some(" ".repeat(11 + 5) + "ccc"));
967
968 let line = iter.next();
969 assert_eq!(line, None);
970 }
971
972 #[test]
973 fn add_opts_with_margins_by_constructor_and_add_text_with_margins() {
974 use crate::OptCfgParam::*;
975
976 let cols = linebreak::term_cols();
977
978 let mut help = Help::with_margins(4, 2);
979
980 help.add_opts_with_margins(
981 &[OptCfg::with([
982 names(&["foo-bar"]),
983 desc(
984 &("a".repeat(cols - 11 - 5 - 4) + " " + &"b".repeat(cols - 11 - 5 - 4) + "ccc"),
985 ),
986 ])],
987 1,
988 2,
989 );
990
991 let mut iter = help.iter();
992
993 let line = iter.next();
994 assert_eq!(
995 line,
996 Some(" --foo-bar ".to_string() + &"a".repeat(cols - 11 - 5 - 4))
997 );
998
999 let line = iter.next();
1000 assert_eq!(
1001 line,
1002 Some(" ".repeat(11 + 5) + &"b".repeat(cols - 11 - 5 - 4))
1003 );
1004
1005 let line = iter.next();
1006 assert_eq!(line, Some(" ".repeat(11 + 5) + "ccc"));
1007
1008 let line = iter.next();
1009 assert_eq!(line, None);
1010 }
1011
1012 #[test]
1013 fn add_opts_with_indent_if_indent_is_longer_than_title() {
1014 use crate::OptCfgParam::*;
1015
1016 let cols = linebreak::term_cols();
1017
1018 let mut help = Help::new();
1019 help.add_opts_with_indent(
1020 &[OptCfg::with([
1021 names(&["foo-bar"]),
1022 desc(&("a".repeat(cols - 12) + " " + &"b".repeat(cols - 12) + "ccc")),
1023 ])],
1024 12,
1025 );
1026
1027 let mut iter = help.iter();
1028
1029 let line = iter.next();
1030 assert_eq!(
1031 line,
1032 Some("--foo-bar".to_string() + " " + &"a".repeat(cols - 12))
1033 );
1034
1035 let line = iter.next();
1036 assert_eq!(line, Some(" ".repeat(12) + &"b".repeat(cols - 12)));
1037
1038 let line = iter.next();
1039 assert_eq!(line, Some(" ".repeat(12) + &"ccc"));
1040
1041 let line = iter.next();
1042 assert_eq!(line, None);
1043 }
1044
1045 #[test]
1046 fn add_opts_with_indent_if_indent_is_shorter_than_title() {
1047 use crate::OptCfgParam::*;
1048
1049 let cols = linebreak::term_cols();
1050
1051 let mut help = Help::new();
1052 help.add_opts_with_indent(
1053 &[OptCfg::with([
1054 names(&["foo-bar"]),
1055 desc(&("a".repeat(cols))),
1056 ])],
1057 10,
1058 );
1059
1060 let mut iter = help.iter();
1061
1062 let line = iter.next();
1063 assert_eq!(line, Some("--foo-bar".to_string()));
1064
1065 let line = iter.next();
1066 assert_eq!(line, Some(" ".repeat(10) + &"a".repeat(cols - 10)));
1067
1068 let line = iter.next();
1069 assert_eq!(line, Some(" ".repeat(10) + &"a".repeat(10)));
1070
1071 let line = iter.next();
1072 assert_eq!(line, None);
1073 }
1074
1075 #[test]
1076 fn add_opts_with_indent_and_margins() {
1077 use crate::OptCfgParam::*;
1078
1079 let cols = linebreak::term_cols();
1080
1081 let mut help = Help::new();
1082 help.add_opts_with_indent_and_margins(
1083 &[OptCfg::with([
1084 names(&["foo-bar"]),
1085 desc(&("a".repeat(cols))),
1086 ])],
1087 6,
1088 4,
1089 2,
1090 );
1091
1092 let mut iter = help.iter();
1093
1094 let line = iter.next();
1095 assert_eq!(line, Some(" --foo-bar".to_string()));
1096
1097 let line = iter.next();
1098 assert_eq!(line, Some(" ".repeat(10) + &"a".repeat(cols - 6 - 4 - 2)));
1099
1100 let line = iter.next();
1101 assert_eq!(line, Some(" ".repeat(10) + &"a".repeat(6 + 4 + 2)));
1102
1103 let line = iter.next();
1104 assert_eq!(line, None);
1105 }
1106
1107 #[test]
1108 fn add_opts_if_opts_are_multiple() {
1109 use crate::OptCfgParam::*;
1110
1111 let cols = linebreak::term_cols();
1112
1113 let mut help = Help::new();
1114 help.add_opts(&[
1115 OptCfg::with([
1116 names(&["foo-bar", "f"]),
1117 has_arg(true),
1118 desc(&("a".repeat(cols - 22) + " " + &"b".repeat(cols - 22) + "ccc")),
1119 arg_in_help("<text>"),
1120 ]),
1121 OptCfg::with([
1122 names(&["baz", "b"]),
1123 desc(&("d".repeat(cols - 22) + " " + &"e".repeat(cols - 22) + "fff")),
1124 ]),
1125 ]);
1126
1127 let mut iter = help.iter();
1128
1129 let line = iter.next();
1130 assert_eq!(
1131 line,
1132 Some("--foo-bar, -f <text> ".to_string() + &"a".repeat(cols - 22)),
1133 );
1134
1135 let line = iter.next();
1136 assert_eq!(line, Some(" ".repeat(22) + &"b".repeat(cols - 22)),);
1137
1138 let line = iter.next();
1139 assert_eq!(line, Some(" ".repeat(22) + "ccc"),);
1140
1141 let line = iter.next();
1142 assert_eq!(
1143 line,
1144 Some("--baz, -b ".to_string() + &"d".repeat(cols - 22)),
1145 );
1146
1147 let line = iter.next();
1148 assert_eq!(line, Some(" ".repeat(22) + &"e".repeat(cols - 22)),);
1149
1150 let line = iter.next();
1151 assert_eq!(line, Some(" ".repeat(22) + "fff"),);
1152
1153 let line = iter.next();
1154 assert_eq!(line, None);
1155 }
1156
1157 #[test]
1158 fn add_opts_if_names_are_empty_and_store_key_is_specified() {
1159 use crate::OptCfgParam::*;
1160
1161 let mut help = Help::new();
1162 help.add_opts(&[
1163 OptCfg::with([store_key("foo"), desc("description")]),
1164 OptCfg::with([store_key("bar"), names(&["", ""]), desc("description")]),
1165 ]);
1166
1167 let mut iter = help.iter();
1168
1169 let line = iter.next();
1170 assert_eq!(line, Some("--foo description".to_string()));
1171
1172 let line = iter.next();
1173 assert_eq!(line, Some(" --bar description".to_string()));
1174
1175 let line = iter.next();
1176 assert_eq!(line, None);
1177 }
1178
1179 #[test]
1180 fn add_opts_if_store_key_is_any_option() {
1181 use crate::OptCfgParam::*;
1182
1183 let mut help = Help::new();
1184 help.add_opts(&[
1185 OptCfg::with([store_key("foo"), desc("description")]),
1186 OptCfg::with([store_key("*"), desc("any option")]),
1187 ]);
1188
1189 let mut iter = help.iter();
1190
1191 let line = iter.next();
1192 assert_eq!(line, Some("--foo description".to_string()));
1193
1194 let line = iter.next();
1195 assert_eq!(line, None);
1196 }
1197
1198 #[test]
1199 fn add_opts_if_first_element_of_names_is_any_option() {
1200 use crate::OptCfgParam::*;
1201
1202 let mut help = Help::new();
1203 help.add_opts(&[
1204 OptCfg::with([names(&["foo-bar"]), desc("description")]),
1205 OptCfg::with([names(&["*"]), desc("any option")]),
1206 ]);
1207
1208 let mut iter = help.iter();
1209
1210 let line = iter.next();
1211 assert_eq!(line, Some("--foo-bar description".to_string()));
1212
1213 let line = iter.next();
1214 assert_eq!(line, None);
1215 }
1216
1217 #[test]
1218 fn add_opts_with_indent_if_indent_is_longer_than_line_width() {
1219 use crate::OptCfgParam::*;
1220
1221 let cols = linebreak::term_cols();
1222
1223 let mut help = Help::new();
1224 help.add_opts_with_indent(
1225 &[
1226 OptCfg::with([names(&["foo-bar"]), desc("description")]),
1227 OptCfg::with([names(&["baz"]), desc("description")]),
1228 ],
1229 cols + 1,
1230 );
1231
1232 let mut iter = help.iter();
1233
1234 let line = iter.next();
1235 assert_eq!(line, None);
1236
1237 let line = iter.next();
1238 assert_eq!(line, None);
1239 }
1240
1241 #[test]
1242 fn add_opts_with_margins_if_sum_of_margins_are_equal_to_line_width() {
1243 use crate::OptCfgParam::*;
1244
1245 let cols = linebreak::term_cols();
1246
1247 let mut help = Help::new();
1248 help.add_opts_with_margins(
1249 &[
1250 OptCfg::with([names(&["foo-bar"]), desc("description")]),
1251 OptCfg::with([names(&["baz"]), desc("description")]),
1252 ],
1253 cols - 1,
1254 1,
1255 );
1256
1257 let mut iter = help.iter();
1258
1259 let line = iter.next();
1260 assert_eq!(line, None);
1261
1262 let line = iter.next();
1263 assert_eq!(line, None);
1264 }
1265
1266 #[test]
1267 fn add_opts_if_names_contains_empty_strings() {
1268 use crate::OptCfgParam::*;
1269
1270 let mut help = Help::new();
1271 help.add_opts(&[
1272 OptCfg::with([names(&["", "f", "foo-bar", "", ""]), desc("description")]),
1273 OptCfg::with([names(&["b", "", "z", "baz"]), desc("description")]),
1274 ]);
1275
1276 let mut iter = help.iter();
1277
1278 let line = iter.next();
1279 assert_eq!(line, Some(" -f, --foo-bar description".to_string()));
1280
1281 let line = iter.next();
1282 assert_eq!(line, Some("-b, -z, --baz description".to_string()));
1283
1284 let line = iter.next();
1285 assert_eq!(line, None);
1286 }
1287}