• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

MitMaro / git-interactive-rebase-tool / 6883077488

15 Nov 2023 09:23PM CUT coverage: 93.248% (-0.4%) from 93.64%
6883077488

Pull #873

github

web-flow
Merge 0ab516642 into d7655157f
Pull Request #873: When editing in the middle of a rebase, dont clear on quit

45 of 72 new or added lines in 14 files covered. (62.5%)

1 existing line in 1 file now uncovered.

4792 of 5139 relevant lines covered (93.25%)

3.67 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.63
/src/display/src/lib.rs
1
// LINT-REPLACE-START
2
// This section is autogenerated, do not modify directly
3
// nightly sometimes removes/renames lints
4
#![cfg_attr(allow_unknown_lints, allow(unknown_lints))]
5
#![cfg_attr(allow_unknown_lints, allow(renamed_and_removed_lints))]
6
// enable all rustc's built-in lints
7
#![deny(
8
        future_incompatible,
9
        nonstandard_style,
10
        rust_2018_compatibility,
11
        rust_2018_idioms,
12
        rust_2021_compatibility,
13
        unused,
14
        warnings
15
)]
16
// rustc's additional allowed by default lints
17
#![deny(
18
        absolute_paths_not_starting_with_crate,
19
        deprecated_in_future,
20
        elided_lifetimes_in_paths,
21
        explicit_outlives_requirements,
22
        ffi_unwind_calls,
23
        keyword_idents,
24
        let_underscore_drop,
25
        macro_use_extern_crate,
26
        meta_variable_misuse,
27
        missing_abi,
28
        missing_copy_implementations,
29
        missing_debug_implementations,
30
        missing_docs,
31
        non_ascii_idents,
32
        noop_method_call,
33
        pointer_structural_match,
34
        rust_2021_incompatible_closure_captures,
35
        rust_2021_incompatible_or_patterns,
36
        rust_2021_prefixes_incompatible_syntax,
37
        rust_2021_prelude_collisions,
38
        single_use_lifetimes,
39
        trivial_casts,
40
        trivial_numeric_casts,
41
        unreachable_pub,
42
        unsafe_code,
43
        unsafe_op_in_unsafe_fn,
44
        unused_crate_dependencies,
45
        unused_extern_crates,
46
        unused_import_braces,
47
        unused_lifetimes,
48
        unused_macro_rules,
49
        unused_qualifications,
50
        unused_results,
51
        unused_tuple_struct_fields,
52
        variant_size_differences
53
)]
54
// enable all of Clippy's lints
55
#![deny(clippy::all, clippy::cargo, clippy::pedantic, clippy::restriction)]
56
#![allow(
57
        clippy::arithmetic_side_effects,
58
        clippy::arithmetic_side_effects,
59
        clippy::blanket_clippy_restriction_lints,
60
        clippy::bool_to_int_with_if,
61
        clippy::default_numeric_fallback,
62
        clippy::else_if_without_else,
63
        clippy::expect_used,
64
        clippy::float_arithmetic,
65
        clippy::implicit_return,
66
        clippy::indexing_slicing,
67
        clippy::map_err_ignore,
68
        clippy::min_ident_chars,
69
        clippy::missing_docs_in_private_items,
70
        clippy::missing_trait_methods,
71
        clippy::mod_module_files,
72
        clippy::module_name_repetitions,
73
        clippy::needless_raw_strings,
74
        clippy::new_without_default,
75
        clippy::non_ascii_literal,
76
        clippy::option_if_let_else,
77
        clippy::pattern_type_mismatch,
78
        clippy::pub_use,
79
        clippy::pub_with_shorthand,
80
        clippy::question_mark_used,
81
        clippy::redundant_closure_call,
82
        clippy::redundant_pub_crate,
83
        clippy::ref_patterns,
84
        clippy::single_call_fn,
85
        clippy::std_instead_of_alloc,
86
        clippy::std_instead_of_core,
87
        clippy::tabs_in_doc_comments,
88
        clippy::tests_outside_test_module,
89
        clippy::too_many_lines,
90
        clippy::unwrap_used
91
)]
92
#![deny(
93
        rustdoc::bare_urls,
94
        rustdoc::broken_intra_doc_links,
95
        rustdoc::invalid_codeblock_attributes,
96
        rustdoc::invalid_html_tags,
97
        rustdoc::missing_crate_level_docs,
98
        rustdoc::private_doc_tests,
99
        rustdoc::private_intra_doc_links
100
)]
101
// allow some things in tests
102
#![cfg_attr(
103
        test,
104
        allow(
105
                let_underscore_drop,
106
                clippy::cognitive_complexity,
107
                clippy::let_underscore_must_use,
108
                clippy::let_underscore_untyped,
109
                clippy::needless_pass_by_value,
110
                clippy::panic,
111
                clippy::shadow_reuse,
112
                clippy::shadow_unrelated,
113
                clippy::undocumented_unsafe_blocks,
114
                clippy::unimplemented,
115
                clippy::unreachable
116
        )
117
)]
118
// allowable upcoming nightly lints
119
#![cfg_attr(include_nightly_lints, allow(clippy::absolute_paths, clippy::arc_with_non_send_sync))]
120
// LINT-REPLACE-END
121

122
//! Git Interactive Rebase Tool - Display Module
123
//!
124
//! # Description
125
//! This module is used to handle working with the terminal display.
126
//!
127
//! ```
128
//! use config::Theme;
129
//! use display::{CrossTerm, Display, DisplayColor};
130
//! let theme = Theme::new();
131
//! let tui = CrossTerm::new();
132
//! let mut display = Display::new(tui, &theme);
133
//!
134
//! display.start();
135
//! display.clear();
136
//! display.draw_str("Hello world!");
137
//! display.color(DisplayColor::IndicatorColor, false);
138
//! display.set_style(false, true, false);
139
//! display.draw_str("Hello colorful, underlined world!");
140
//! display.refresh();
141
//! display.end();
142
//! ```
143
//!
144
//! ## Test Utilities
145
//! To facilitate testing the usages of this crate, a set of testing utilities are provided. Since
146
//! these utilities are not tested, and often are optimized for developer experience than
147
//! performance should only be used in test code.
148

149
mod color_mode;
150
#[cfg(not(tarpaulin_include))]
151
mod crossterm;
152
mod display_color;
153
mod error;
154
mod size;
155
#[cfg(not(tarpaulin_include))]
156
pub mod testutil;
157
mod tui;
158
mod utils;
159

160
use ::crossterm::style::{Color, Colors};
161
use config::Theme;
162

163
use self::utils::register_selectable_color_pairs;
164
pub use self::{
165
        color_mode::ColorMode,
166
        crossterm::CrossTerm,
167
        display_color::DisplayColor,
168
        error::DisplayError,
169
        size::Size,
170
        tui::Tui,
171
};
172

173
/// A high level interface to the terminal display.
174
#[derive(Debug)]
175
pub struct Display<T: Tui> {
176
        action_break: (Colors, Colors),
177
        action_cut: (Colors, Colors),
178
        action_drop: (Colors, Colors),
179
        action_edit: (Colors, Colors),
180
        action_exec: (Colors, Colors),
181
        action_fixup: (Colors, Colors),
182
        action_index: (Colors, Colors),
183
        action_label: (Colors, Colors),
184
        action_merge: (Colors, Colors),
185
        action_pick: (Colors, Colors),
186
        action_reset: (Colors, Colors),
187
        action_reword: (Colors, Colors),
188
        action_squash: (Colors, Colors),
189
        action_update_ref: (Colors, Colors),
190
        tui: T,
191
        diff_add: (Colors, Colors),
192
        diff_change: (Colors, Colors),
193
        diff_context: (Colors, Colors),
194
        diff_remove: (Colors, Colors),
195
        diff_whitespace: (Colors, Colors),
196
        indicator: (Colors, Colors),
197
        normal: (Colors, Colors),
198
}
199

200
impl<T: Tui> Display<T> {
201
        /// Create a new display instance.
202
        #[inline]
203
        pub fn new(tui: T, theme: &Theme) -> Self {
11✔
204
                let color_mode = tui.get_color_mode();
22✔
205
                let normal = register_selectable_color_pairs(
206
                        color_mode,
×
207
                        theme.color_foreground,
11✔
208
                        theme.color_background,
11✔
209
                        theme.color_selected_background,
11✔
210
                );
211
                let indicator = register_selectable_color_pairs(
212
                        color_mode,
×
213
                        theme.color_indicator,
11✔
214
                        theme.color_background,
11✔
215
                        theme.color_selected_background,
11✔
216
                );
217
                let action_break = register_selectable_color_pairs(
218
                        color_mode,
×
219
                        theme.color_action_break,
11✔
220
                        theme.color_background,
11✔
221
                        theme.color_selected_background,
11✔
222
                );
223
                let action_cut = register_selectable_color_pairs(
NEW
224
                        color_mode,
×
225
                        theme.color_action_cut,
11✔
226
                        theme.color_background,
11✔
227
                        theme.color_selected_background,
11✔
228
                );
229
                let action_drop = register_selectable_color_pairs(
230
                        color_mode,
×
231
                        theme.color_action_drop,
11✔
232
                        theme.color_background,
11✔
233
                        theme.color_selected_background,
11✔
234
                );
235
                let action_edit = register_selectable_color_pairs(
236
                        color_mode,
×
237
                        theme.color_action_edit,
11✔
238
                        theme.color_background,
11✔
239
                        theme.color_selected_background,
11✔
240
                );
241
                let action_exec = register_selectable_color_pairs(
242
                        color_mode,
×
243
                        theme.color_action_exec,
11✔
244
                        theme.color_background,
12✔
245
                        theme.color_selected_background,
11✔
246
                );
247
                let action_fixup = register_selectable_color_pairs(
248
                        color_mode,
×
249
                        theme.color_action_fixup,
12✔
250
                        theme.color_background,
11✔
251
                        theme.color_selected_background,
12✔
252
                );
253
                let action_index = register_selectable_color_pairs(
NEW
254
                        color_mode,
×
255
                        theme.color_action_index,
12✔
256
                        theme.color_background,
11✔
257
                        theme.color_selected_background,
13✔
258
                );
259
                let action_pick = register_selectable_color_pairs(
260
                        color_mode,
×
261
                        theme.color_action_pick,
13✔
262
                        theme.color_background,
11✔
263
                        theme.color_selected_background,
13✔
264
                );
265
                let action_reword = register_selectable_color_pairs(
266
                        color_mode,
×
267
                        theme.color_action_reword,
13✔
268
                        theme.color_background,
11✔
269
                        theme.color_selected_background,
13✔
270
                );
271
                let action_squash = register_selectable_color_pairs(
272
                        color_mode,
×
273
                        theme.color_action_squash,
13✔
274
                        theme.color_background,
11✔
275
                        theme.color_selected_background,
13✔
276
                );
277
                let action_label = register_selectable_color_pairs(
278
                        color_mode,
×
279
                        theme.color_action_label,
11✔
280
                        theme.color_background,
13✔
281
                        theme.color_selected_background,
11✔
282
                );
283
                let action_reset = register_selectable_color_pairs(
284
                        color_mode,
×
285
                        theme.color_action_reset,
11✔
286
                        theme.color_background,
13✔
287
                        theme.color_selected_background,
11✔
288
                );
289
                let action_merge = register_selectable_color_pairs(
290
                        color_mode,
×
291
                        theme.color_action_merge,
13✔
292
                        theme.color_background,
11✔
293
                        theme.color_selected_background,
13✔
294
                );
295
                let action_update_ref = register_selectable_color_pairs(
296
                        color_mode,
×
297
                        theme.color_action_update_ref,
11✔
298
                        theme.color_background,
13✔
299
                        theme.color_selected_background,
11✔
300
                );
301
                let diff_add = register_selectable_color_pairs(
302
                        color_mode,
×
303
                        theme.color_diff_add,
11✔
304
                        theme.color_background,
13✔
305
                        theme.color_selected_background,
11✔
306
                );
307
                let diff_change = register_selectable_color_pairs(
308
                        color_mode,
×
309
                        theme.color_diff_change,
13✔
310
                        theme.color_background,
11✔
311
                        theme.color_selected_background,
13✔
312
                );
313
                let diff_remove = register_selectable_color_pairs(
314
                        color_mode,
×
315
                        theme.color_diff_remove,
11✔
316
                        theme.color_background,
13✔
317
                        theme.color_selected_background,
11✔
318
                );
319
                let diff_context = register_selectable_color_pairs(
320
                        color_mode,
×
321
                        theme.color_diff_context,
13✔
322
                        theme.color_background,
11✔
323
                        theme.color_selected_background,
13✔
324
                );
325
                let diff_whitespace = register_selectable_color_pairs(
326
                        color_mode,
×
327
                        theme.color_diff_whitespace,
11✔
328
                        theme.color_background,
13✔
329
                        theme.color_selected_background,
11✔
330
                );
331

332
                Self {
333
                        action_break,
334
                        action_cut,
335
                        action_drop,
336
                        action_edit,
337
                        action_exec,
338
                        action_fixup,
339
                        action_index,
340
                        action_label,
341
                        action_merge,
342
                        action_pick,
343
                        action_reset,
344
                        action_reword,
345
                        action_squash,
346
                        action_update_ref,
347
                        tui,
348
                        diff_add,
349
                        diff_change,
350
                        diff_context,
351
                        diff_remove,
352
                        diff_whitespace,
353
                        indicator,
354
                        normal,
355
                }
356
        }
357

358
        /// Draws a string of text to the terminal interface.
359
        ///
360
        /// # Errors
361
        /// Will error if the underlying terminal interface is in an error state.
362
        #[inline]
363
        pub fn draw_str(&mut self, s: &str) -> Result<(), DisplayError> {
6✔
364
                self.tui.print(s)
9✔
365
        }
366

367
        /// Clear the terminal interface and reset any style and color attributes.
368
        ///
369
        /// # Errors
370
        /// Will error if the underlying terminal interface is in an error state.
371
        #[inline]
372
        pub fn clear(&mut self) -> Result<(), DisplayError> {
10✔
373
                self.color(DisplayColor::Normal, false)?;
10✔
374
                self.set_style(false, false, false)?;
20✔
375
                self.tui.reset()
10✔
376
        }
377

378
        /// Force a refresh of the terminal interface. This normally should be called after after all
379
        /// text has been drawn to the terminal interface. This is considered a slow operation, so
380
        /// should be called only as needed.
381
        ///
382
        /// # Errors
383
        /// Will error if the underlying terminal interface is in an error state.
384
        #[inline]
385
        pub fn refresh(&mut self) -> Result<(), DisplayError> {
7✔
386
                self.tui.flush()
8✔
387
        }
388

389
        /// Set the color of text drawn to the terminal interface. This will only change text drawn to
390
        /// the terminal after this function call.
391
        ///
392
        /// # Errors
393
        /// Will error if the underlying terminal interface is in an error state.
394
        #[inline]
395
        pub fn color(&mut self, color: DisplayColor, selected: bool) -> Result<(), DisplayError> {
10✔
396
                self.tui.set_color(
21✔
397
                        if selected {
10✔
398
                                match color {
3✔
399
                                        DisplayColor::ActionBreak => self.action_break.1,
1✔
NEW
400
                                        DisplayColor::ActionCut => self.action_cut.1,
×
401
                                        DisplayColor::ActionDrop => self.action_drop.1,
1✔
402
                                        DisplayColor::ActionEdit => self.action_edit.1,
1✔
403
                                        DisplayColor::ActionExec => self.action_exec.1,
1✔
404
                                        DisplayColor::ActionFixup => self.action_fixup.1,
1✔
405
                                        DisplayColor::ActionIndex => self.action_index.1,
1✔
406
                                        DisplayColor::ActionPick => self.action_pick.1,
2✔
407
                                        DisplayColor::ActionReword => self.action_reword.1,
1✔
408
                                        DisplayColor::ActionSquash => self.action_squash.1,
1✔
409
                                        DisplayColor::ActionLabel => self.action_label.1,
1✔
410
                                        DisplayColor::ActionReset => self.action_reset.1,
1✔
411
                                        DisplayColor::ActionMerge => self.action_merge.1,
1✔
412
                                        DisplayColor::ActionUpdateRef => self.action_update_ref.1,
1✔
413
                                        DisplayColor::Normal => self.normal.1,
3✔
414
                                        DisplayColor::IndicatorColor => self.indicator.1,
1✔
415
                                        DisplayColor::DiffAddColor => self.diff_add.1,
1✔
416
                                        DisplayColor::DiffRemoveColor => self.diff_remove.1,
1✔
417
                                        DisplayColor::DiffChangeColor => self.diff_change.1,
1✔
418
                                        DisplayColor::DiffContextColor => self.diff_context.1,
1✔
419
                                        DisplayColor::DiffWhitespaceColor => self.diff_whitespace.1,
1✔
420
                                }
421
                        }
422
                        else {
×
423
                                match color {
10✔
424
                                        DisplayColor::ActionBreak => self.action_break.0,
1✔
NEW
425
                                        DisplayColor::ActionCut => self.action_cut.0,
×
426
                                        DisplayColor::ActionDrop => self.action_drop.0,
1✔
427
                                        DisplayColor::ActionEdit => self.action_edit.0,
1✔
428
                                        DisplayColor::ActionExec => self.action_exec.0,
1✔
429
                                        DisplayColor::ActionFixup => self.action_fixup.0,
1✔
430
                                        DisplayColor::ActionIndex => self.action_index.0,
1✔
431
                                        DisplayColor::ActionPick => self.action_pick.0,
1✔
432
                                        DisplayColor::ActionReword => self.action_reword.0,
1✔
433
                                        DisplayColor::ActionSquash => self.action_squash.0,
1✔
434
                                        DisplayColor::ActionLabel => self.action_label.0,
1✔
435
                                        DisplayColor::ActionReset => self.action_reset.0,
1✔
436
                                        DisplayColor::ActionMerge => self.action_merge.0,
1✔
437
                                        DisplayColor::ActionUpdateRef => self.action_update_ref.0,
1✔
438
                                        DisplayColor::Normal => self.normal.0,
10✔
439
                                        DisplayColor::IndicatorColor => self.indicator.0,
1✔
440
                                        DisplayColor::DiffAddColor => self.diff_add.0,
1✔
441
                                        DisplayColor::DiffRemoveColor => self.diff_remove.0,
1✔
442
                                        DisplayColor::DiffChangeColor => self.diff_change.0,
1✔
443
                                        DisplayColor::DiffContextColor => self.diff_context.0,
1✔
444
                                        DisplayColor::DiffWhitespaceColor => self.diff_whitespace.0,
1✔
445
                                }
446
                        },
447
                )
448
        }
449

450
        /// Set the style attributes of text drawn to the terminal interface. This will only change text
451
        /// drawn to the terminal after this function call.
452
        ///
453
        /// # Errors
454
        /// Will error if the underlying terminal interface is in an error state.
455
        #[inline]
456
        pub fn set_style(&mut self, dim: bool, underline: bool, reverse: bool) -> Result<(), DisplayError> {
10✔
457
                self.set_dim(dim)?;
10✔
458
                self.set_underline(underline)?;
20✔
459
                self.set_reverse(reverse)
10✔
460
        }
461

462
        /// Get the width and height of the terminal interface. This can be a slow operation, so should
463
        /// not be called unless absolutely needed.
464
        ///
465
        /// # Errors
466
        /// Will error if the underlying terminal interface is in an error state.
467
        #[inline]
468
        pub fn get_window_size(&self) -> Size {
10✔
469
                self.tui.get_size()
10✔
470
        }
471

472
        /// Reset the cursor position to the start of the line.
473
        ///
474
        /// # Errors
475
        /// Will error if the underlying terminal interface is in an error state.
476
        #[inline]
477
        pub fn ensure_at_line_start(&mut self) -> Result<(), DisplayError> {
9✔
478
                self.tui.move_to_column(0)
9✔
479
        }
480

481
        /// Move the cursor position `right` characters from the end of the line.
482
        ///
483
        /// # Errors
484
        /// Will error if the underlying terminal interface is in an error state.
485
        #[inline]
486
        pub fn move_from_end_of_line(&mut self, right: u16) -> Result<(), DisplayError> {
2✔
487
                let width = self.get_window_size().width().try_into().unwrap_or(u16::MAX);
2✔
488
                self.tui.move_to_column(width - right)
2✔
489
        }
490

491
        /// Move the cursor to the next line.
492
        ///
493
        /// # Errors
494
        /// Will error if the underlying terminal interface is in an error state.
495
        #[inline]
496
        pub fn next_line(&mut self) -> Result<(), DisplayError> {
5✔
497
                self.tui.move_next_line()
5✔
498
        }
499

500
        /// Start the terminal interface interactions. This should be called before any terminal
501
        /// interactions are performed.
502
        ///
503
        /// # Errors
504
        /// Will error if the underlying terminal interface is in an error state.
505
        #[inline]
506
        pub fn start(&mut self) -> Result<(), DisplayError> {
8✔
507
                self.tui.start()?;
9✔
508
                self.tui.flush()
7✔
509
        }
510

511
        /// End the terminal interface interactions. This should be called after all terminal
512
        /// interactions are complete. This resets the terminal interface to the default state, and
513
        /// should be called on program exit.
514
        ///
515
        /// # Errors
516
        /// Will error if the underlying terminal interface is in an error state.
517
        #[inline]
518
        pub fn end(&mut self) -> Result<(), DisplayError> {
6✔
519
                self.tui.end()?;
7✔
520
                self.tui.flush()
5✔
521
        }
522

523
        fn set_dim(&mut self, on: bool) -> Result<(), DisplayError> {
10✔
524
                self.tui.set_dim(on)
10✔
525
        }
526

527
        fn set_underline(&mut self, on: bool) -> Result<(), DisplayError> {
10✔
528
                self.tui.set_underline(on)
10✔
529
        }
530

531
        fn set_reverse(&mut self, on: bool) -> Result<(), DisplayError> {
10✔
532
                self.tui.set_reverse(on)
10✔
533
        }
534
}
535

536
#[cfg(test)]
537
mod tests {
538
        use ::crossterm::style::Color as CrosstermColor;
539
        use rstest::rstest;
540

541
        use super::{testutil::CrossTerm, *};
542
        use crate::testutil::State;
543

544
        #[test]
545
        fn draw_str() {
546
                let mut display = Display::new(CrossTerm::new(), &Theme::new());
547
                display.draw_str("Test String").unwrap();
548
                assert_eq!(display.tui.get_output(), &["Test String"]);
549
        }
550

551
        #[test]
552
        fn clear() {
553
                let mut display = Display::new(CrossTerm::new(), &Theme::new());
554
                display.draw_str("Test String").unwrap();
555
                display.set_dim(true).unwrap();
556
                display.set_reverse(true).unwrap();
557
                display.set_underline(true).unwrap();
558
                display.clear().unwrap();
559
                assert!(display.tui.get_output().is_empty());
560
                assert!(!display.tui.is_dimmed());
561
                assert!(!display.tui.is_reverse());
562
                assert!(!display.tui.is_underline());
563
        }
564

565
        #[test]
566
        fn refresh() {
567
                let mut display = Display::new(CrossTerm::new(), &Theme::new());
568
                display.refresh().unwrap();
569
                assert!(!display.tui.is_dirty());
570
        }
571

572
        #[rstest]
573
        #[case::action_break(DisplayColor::ActionBreak, false, CrosstermColor::White, CrosstermColor::Reset)]
574
        #[case::action_break_selected(
575
                DisplayColor::ActionBreak,
576
                true,
577
                CrosstermColor::White,
578
                CrosstermColor::AnsiValue(237)
579
        )]
580
        #[case::action_drop(DisplayColor::ActionDrop, false, CrosstermColor::Red, CrosstermColor::Reset)]
581
        #[case::action_drop_selected(DisplayColor::ActionDrop, true, CrosstermColor::Red, CrosstermColor::AnsiValue(237))]
582
        #[case::action_edit(DisplayColor::ActionEdit, false, CrosstermColor::Blue, CrosstermColor::Reset)]
583
        #[case::action_edit_selected(DisplayColor::ActionEdit, true, CrosstermColor::Blue, CrosstermColor::AnsiValue(237))]
584
        #[case::action_exec(DisplayColor::ActionExec, false, CrosstermColor::White, CrosstermColor::Reset)]
585
        #[case::action_exec_selected(
586
                DisplayColor::ActionExec,
587
                true,
588
                CrosstermColor::White,
589
                CrosstermColor::AnsiValue(237)
590
        )]
591
        #[case::action_fixup(DisplayColor::ActionFixup, false, CrosstermColor::Magenta, CrosstermColor::Reset)]
592
        #[case::action_fixup_selected(
593
                DisplayColor::ActionFixup,
594
                true,
595
                CrosstermColor::Magenta,
596
                CrosstermColor::AnsiValue(237)
597
        )]
598
        #[case::action_index(DisplayColor::ActionIndex, false, CrosstermColor::DarkGreen, CrosstermColor::Reset)]
599
        #[case::action_index_selected(
600
                DisplayColor::ActionIndex,
601
                true,
602
                CrosstermColor::DarkGreen,
603
                CrosstermColor::AnsiValue(237)
604
        )]
605
        #[case::action_pick(DisplayColor::ActionPick, false, CrosstermColor::Green, CrosstermColor::Reset)]
606
        #[case::action_pick_selected(
607
                DisplayColor::ActionPick,
608
                true,
609
                CrosstermColor::Green,
610
                CrosstermColor::AnsiValue(237)
611
        )]
612
        #[case::action_reword(DisplayColor::ActionReword, false, CrosstermColor::Yellow, CrosstermColor::Reset)]
613
        #[case::action_reword_selected(
614
                DisplayColor::ActionReword,
615
                true,
616
                CrosstermColor::Yellow,
617
                CrosstermColor::AnsiValue(237)
618
        )]
619
        #[case::action_squash(DisplayColor::ActionSquash, false, CrosstermColor::Cyan, CrosstermColor::Reset)]
620
        #[case::action_squash_selected(
621
                DisplayColor::ActionSquash,
622
                true,
623
                CrosstermColor::Cyan,
624
                CrosstermColor::AnsiValue(237)
625
        )]
626
        #[case::action_label(DisplayColor::ActionLabel, false, CrosstermColor::DarkYellow, CrosstermColor::Reset)]
627
        #[case::action_label_selected(
628
                DisplayColor::ActionLabel,
629
                true,
630
                CrosstermColor::DarkYellow,
631
                CrosstermColor::AnsiValue(237)
632
        )]
633
        #[case::action_reset(DisplayColor::ActionReset, false, CrosstermColor::DarkYellow, CrosstermColor::Reset)]
634
        #[case::action_reset_selected(
635
                DisplayColor::ActionReset,
636
                true,
637
                CrosstermColor::DarkYellow,
638
                CrosstermColor::AnsiValue(237)
639
        )]
640
        #[case::action_merge(DisplayColor::ActionMerge, false, CrosstermColor::DarkYellow, CrosstermColor::Reset)]
641
        #[case::action_merge_selected(
642
                DisplayColor::ActionMerge,
643
                true,
644
                CrosstermColor::DarkYellow,
645
                CrosstermColor::AnsiValue(237)
646
        )]
647
        #[case::action_update_ref(
648
                DisplayColor::ActionUpdateRef,
649
                false,
650
                CrosstermColor::DarkMagenta,
651
                CrosstermColor::Reset
652
        )]
653
        #[case::action_update_ref_selected(
654
                DisplayColor::ActionUpdateRef,
655
                true,
656
                CrosstermColor::DarkMagenta,
657
                CrosstermColor::AnsiValue(237)
658
        )]
659
        #[case::normal(DisplayColor::Normal, false, CrosstermColor::Reset, CrosstermColor::Reset)]
660
        #[case::normal_selected(DisplayColor::Normal, true, CrosstermColor::Reset, CrosstermColor::AnsiValue(237))]
661
        #[case::indicator(DisplayColor::IndicatorColor, false, CrosstermColor::Cyan, CrosstermColor::Reset)]
662
        #[case::indicator_selected(
663
                DisplayColor::IndicatorColor,
664
                true,
665
                CrosstermColor::Cyan,
666
                CrosstermColor::AnsiValue(237)
667
        )]
668
        #[case::diff_add(DisplayColor::DiffAddColor, false, CrosstermColor::Green, CrosstermColor::Reset)]
669
        #[case::diff_add_selected(
670
                DisplayColor::DiffAddColor,
671
                true,
672
                CrosstermColor::Green,
673
                CrosstermColor::AnsiValue(237)
674
        )]
675
        #[case::diff_remove(DisplayColor::DiffRemoveColor, false, CrosstermColor::Red, CrosstermColor::Reset)]
676
        #[case::diff_remove_selected(
677
                DisplayColor::DiffRemoveColor,
678
                true,
679
                CrosstermColor::Red,
680
                CrosstermColor::AnsiValue(237)
681
        )]
682
        #[case::diff_change(DisplayColor::DiffChangeColor, false, CrosstermColor::Yellow, CrosstermColor::Reset)]
683
        #[case::diff_change_selected(
684
                DisplayColor::DiffChangeColor,
685
                true,
686
                CrosstermColor::Yellow,
687
                CrosstermColor::AnsiValue(237)
688
        )]
689
        #[case::diff_context(DisplayColor::DiffContextColor, false, CrosstermColor::White, CrosstermColor::Reset)]
690
        #[case::diff_context_selected(
691
                DisplayColor::DiffContextColor,
692
                true,
693
                CrosstermColor::White,
694
                CrosstermColor::AnsiValue(237)
695
        )]
696
        #[case::diff_whitespace(
697
                DisplayColor::DiffWhitespaceColor,
698
                false,
699
                CrosstermColor::DarkGrey,
700
                CrosstermColor::Reset
701
        )]
702
        #[case::diff_whitespace_selected(
703
                DisplayColor::DiffWhitespaceColor,
704
                true,
705
                CrosstermColor::DarkGrey,
706
                CrosstermColor::AnsiValue(237)
707
        )]
708
        fn color(
709
                #[case] display_color: DisplayColor,
710
                #[case] selected: bool,
711
                #[case] expected_foreground: CrosstermColor,
712
                #[case] expected_background: CrosstermColor,
713
        ) {
714
                let mut display = Display::new(CrossTerm::new(), &Theme::new());
715
                display.color(display_color, selected).unwrap();
716
                assert!(
717
                        display
718
                                .tui
719
                                .is_colors_enabled(Colors::new(expected_foreground, expected_background))
720
                );
721
        }
722

723
        #[rstest]
724
        #[case::all_off(false, false, false)]
725
        #[case::reverse(false, false, true)]
726
        #[case::underline(false, true, false)]
727
        #[case::underline_reverse(false, true, true)]
728
        #[case::dim(true, false, false)]
729
        #[case::dim_reverse(true, false, true)]
730
        #[case::dim_underline(true, true, false)]
731
        #[case::all_on(true, true, true)]
732
        fn style(#[case] dim: bool, #[case] underline: bool, #[case] reverse: bool) {
733
                let mut display = Display::new(CrossTerm::new(), &Theme::new());
734
                display.set_style(dim, underline, reverse).unwrap();
735
                assert_eq!(display.tui.is_dimmed(), dim);
736
                assert_eq!(display.tui.is_underline(), underline);
737
                assert_eq!(display.tui.is_reverse(), reverse);
738
        }
739

740
        #[test]
741
        fn get_window_size() {
742
                let mut display = Display::new(CrossTerm::new(), &Theme::new());
743
                display.tui.set_size(Size::new(12, 10));
744
                assert_eq!(display.get_window_size(), Size::new(12, 10));
745
        }
746

747
        #[test]
748
        fn ensure_at_line_start() {
749
                let mut display = Display::new(CrossTerm::new(), &Theme::new());
750
                display.ensure_at_line_start().unwrap();
751
                assert_eq!(display.tui.get_position(), (0, 0));
752
        }
753

754
        #[test]
755
        fn move_from_end_of_line() {
756
                let mut display = Display::new(CrossTerm::new(), &Theme::new());
757
                display.tui.set_size(Size::new(20, 10));
758
                display.move_from_end_of_line(5).unwrap();
759
                // character after the 15th character (0-indexed)
760
                assert_eq!(display.tui.get_position(), (15, 0));
761
        }
762

763
        #[test]
764
        fn start() {
765
                let mut display = Display::new(CrossTerm::new(), &Theme::new());
766
                display.start().unwrap();
767
                assert_eq!(display.tui.get_state(), State::Normal);
768
        }
769

770
        #[test]
771
        fn end() {
772
                let mut display = Display::new(CrossTerm::new(), &Theme::new());
773
                display.end().unwrap();
774
                assert_eq!(display.tui.get_state(), State::Ended);
775
        }
776
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc