@@ -11,6 +11,7 @@ use crate::{
11
11
12
12
use ratatui:: {
13
13
layout:: Rect ,
14
+ style:: { Color , Style } ,
14
15
widgets:: { Block , Clear , Paragraph } ,
15
16
Frame ,
16
17
} ;
@@ -19,27 +20,44 @@ use anyhow::Result;
19
20
20
21
use crossterm:: event:: { Event , KeyCode } ;
21
22
23
+ #[ derive( Debug ) ]
24
+ pub struct GotoLineContext {
25
+ pub max_line : usize ,
26
+ }
27
+
28
+ #[ derive( Debug ) ]
29
+ pub struct GotoLineOpen {
30
+ pub context : GotoLineContext ,
31
+ }
32
+
22
33
pub struct GotoLinePopup {
23
34
visible : bool ,
24
- line : String ,
35
+ input : String ,
36
+ line_number : usize ,
25
37
key_config : SharedKeyConfig ,
26
38
queue : Queue ,
27
39
theme : SharedTheme ,
40
+ invalid_input : bool ,
41
+ context : GotoLineContext ,
28
42
}
29
43
30
44
impl GotoLinePopup {
31
45
pub fn new ( env : & Environment ) -> Self {
32
46
Self {
33
47
visible : false ,
34
- line : String :: new ( ) ,
48
+ input : String :: new ( ) ,
35
49
key_config : env. key_config . clone ( ) ,
36
50
queue : env. queue . clone ( ) ,
37
51
theme : env. theme . clone ( ) ,
52
+ invalid_input : false ,
53
+ context : GotoLineContext { max_line : 0 } ,
54
+ line_number : 0 ,
38
55
}
39
56
}
40
57
41
- pub fn open ( & mut self ) {
58
+ pub fn open ( & mut self , open : GotoLineOpen ) {
42
59
self . visible = true ;
60
+ self . context = open. context ;
43
61
}
44
62
}
45
63
@@ -63,41 +81,67 @@ impl Component for GotoLinePopup {
63
81
if let Event :: Key ( key) = event {
64
82
if key_match ( key, self . key_config . keys . exit_popup ) {
65
83
self . visible = false ;
66
- self . line . clear ( ) ;
84
+ self . input . clear ( ) ;
67
85
self . queue . push ( InternalEvent :: PopupStackPop ) ;
68
86
} else if let KeyCode :: Char ( c) = key. code {
69
- if c. is_ascii_digit ( ) {
70
- // I'd assume it's unusual for people to blame
71
- // files with milions of lines
72
- if self . line . len ( ) < 6 {
73
- self . line . push ( c) ;
74
- }
87
+ if c. is_ascii_digit ( ) || c == '-' {
88
+ self . input . push ( c) ;
75
89
}
76
90
} else if key. code == KeyCode :: Backspace {
77
- self . line . pop ( ) ;
91
+ self . input . pop ( ) ;
78
92
} else if key_match ( key, self . key_config . keys . enter ) {
79
93
self . visible = false ;
80
- if !self . line . is_empty ( ) {
94
+ if self . invalid_input {
95
+ self . queue . push ( InternalEvent :: ShowErrorMsg (
96
+ format ! ( "Invalid input: only numbers between -{0} and {0} (included) are allowed" , self . context. max_line) )
97
+ ,
98
+ ) ;
99
+ } else if !self . input . is_empty ( ) {
81
100
self . queue . push ( InternalEvent :: GotoLine (
82
- self . line . parse :: < usize > ( ) ? ,
101
+ self . line_number ,
83
102
) ) ;
84
103
}
85
104
self . queue . push ( InternalEvent :: PopupStackPop ) ;
86
- self . line . clear ( ) ;
105
+ self . input . clear ( ) ;
106
+ self . invalid_input = false ;
107
+ }
108
+ }
109
+ match self . input . parse :: < isize > ( ) {
110
+ Ok ( input) => {
111
+ if input. unsigned_abs ( ) > self . context . max_line {
112
+ self . invalid_input = true ;
113
+ } else {
114
+ self . invalid_input = false ;
115
+ self . line_number = if input > 0 {
116
+ input. unsigned_abs ( )
117
+ } else {
118
+ self . context . max_line
119
+ - input. unsigned_abs ( )
120
+ }
121
+ }
122
+ }
123
+ Err ( _) => {
124
+ if !self . input . is_empty ( ) {
125
+ self . invalid_input = true ;
126
+ }
87
127
}
88
- return Ok ( EventState :: Consumed ) ;
89
128
}
129
+ return Ok ( EventState :: Consumed ) ;
90
130
}
91
-
92
131
Ok ( EventState :: NotConsumed )
93
132
}
94
133
}
95
134
96
135
impl DrawableComponent for GotoLinePopup {
97
136
fn draw ( & self , f : & mut Frame , area : Rect ) -> Result < ( ) > {
98
137
if self . is_visible ( ) {
99
- let input = Paragraph :: new ( self . line . as_str ( ) )
100
- . style ( self . theme . text ( true , false ) )
138
+ let style = if self . invalid_input {
139
+ Style :: default ( ) . fg ( Color :: Red )
140
+ } else {
141
+ self . theme . text ( true , false )
142
+ } ;
143
+ let input = Paragraph :: new ( self . input . as_str ( ) )
144
+ . style ( style)
101
145
. block ( Block :: bordered ( ) . title ( "Go to Line" ) ) ;
102
146
103
147
let input_area = ui:: centered_rect_absolute ( 15 , 3 , area) ;
0 commit comments