1
1
use std:: { pin:: Pin , sync:: Arc , vec} ;
2
2
3
3
use chrono:: { DateTime , Utc } ;
4
+ use color_eyre:: { Section , SectionExt } ;
4
5
use derive_builder:: Builder ;
5
6
use eyre:: { eyre, Result } ;
6
7
use futures:: StreamExt ;
8
+ use itertools:: Itertools ;
7
9
use k8s_openapi:: api:: core:: v1:: Pod ;
8
10
use kube:: {
9
11
api:: { Api , AttachParams } ,
10
12
ResourceExt ,
11
13
} ;
12
14
use lazy_static:: lazy_static;
13
15
use prometheus:: { histogram_opts, register_histogram, Histogram } ;
14
- use ratatui:: {
15
- layout:: Rect ,
16
- prelude:: * ,
17
- style:: { palette:: tailwind, Modifier , Style } ,
18
- widgets,
19
- widgets:: { Block , Borders , Row } ,
20
- } ;
16
+ use ratatui:: { layout:: Rect , prelude:: * } ;
21
17
use tokio:: {
22
18
io:: { AsyncWrite , AsyncWriteExt } ,
23
19
sync:: mpsc:: UnboundedReceiver ,
@@ -81,14 +77,17 @@ impl Widget for Shell {
81
77
}
82
78
83
79
fn draw ( & mut self , frame : & mut Frame , area : Rect ) -> Result < ( ) > {
84
- self . table . draw ( frame, area, & self . pod )
80
+ if let Err ( err) = self . table . draw ( frame, area, & self . pod ) {
81
+ tracing:: info!( "failed to draw table: {}" , err) ;
82
+ }
83
+
84
+ Ok ( ( ) )
85
85
}
86
86
}
87
87
88
88
enum CommandState {
89
89
Input ( Text ) ,
90
90
Attached ,
91
- Error ( String ) ,
92
91
}
93
92
94
93
static COMMAND : & str = "/bin/bash" ;
@@ -163,23 +162,6 @@ impl Command {
163
162
}
164
163
}
165
164
166
- #[ allow( clippy:: unnecessary_wraps) ]
167
- fn dispatch_error ( & mut self , event : & Event ) -> Result < Broadcast > {
168
- if !matches ! ( self . state, CommandState :: Error ( _) ) {
169
- return Ok ( Broadcast :: Ignored ) ;
170
- }
171
-
172
- match event. key ( ) {
173
- // TODO: should handle scrolling inside the error message.
174
- Some ( _) => {
175
- self . state = CommandState :: Input ( Command :: input ( & self . container ) ) ;
176
-
177
- Ok ( Broadcast :: Consumed )
178
- }
179
- _ => Ok ( Broadcast :: Ignored ) ,
180
- }
181
- }
182
-
183
165
fn draw_input ( & mut self , frame : & mut Frame , area : Rect ) -> Result < ( ) > {
184
166
let CommandState :: Input ( ref mut txt) = self . state else {
185
167
return Ok ( ( ) ) ;
@@ -201,77 +183,40 @@ impl Command {
201
183
202
184
txt. draw ( frame, area)
203
185
}
204
-
205
- // TODO: this should be a separate widget of its own.
206
- #[ allow( clippy:: cast_possible_truncation, clippy:: unnecessary_wraps) ]
207
- fn draw_error ( & mut self , frame : & mut Frame , area : Rect ) -> Result < ( ) > {
208
- let CommandState :: Error ( ref err) = self . state else {
209
- return Ok ( ( ) ) ;
210
- } ;
211
-
212
- let block = Block :: default ( )
213
- . title ( "Error" )
214
- . borders ( Borders :: ALL )
215
- . border_style ( Style :: default ( ) . fg ( Color :: Red ) )
216
- . title_style ( Style :: default ( ) . fg ( Color :: Red ) . add_modifier ( Modifier :: BOLD ) ) ;
217
-
218
- // TODO: get this into a variable so that it can be styled.
219
- let rows: Vec < Row > = err
220
- . split ( '\n' )
221
- . enumerate ( )
222
- . map ( |( i, line) | {
223
- Row :: new ( vec ! [
224
- Span :: from( format!( "{i}: " ) )
225
- . style( style:: Style :: default ( ) . fg( tailwind:: RED . c300) ) ,
226
- Span :: from( line) ,
227
- ] )
228
- } )
229
- . collect ( ) ;
230
-
231
- let height = rows. len ( ) as u16 + 2 ;
232
-
233
- let content =
234
- widgets:: Table :: new ( rows, vec ! [ Constraint :: Max ( 3 ) , Constraint :: Fill ( 0 ) ] ) . block ( block) ;
235
-
236
- let [ _, area, _] = Layout :: horizontal ( [
237
- Constraint :: Max ( 10 ) ,
238
- Constraint :: Fill ( 0 ) ,
239
- Constraint :: Max ( 10 ) ,
240
- ] )
241
- . areas ( area) ;
242
-
243
- let [ _, mut vert, _] = Layout :: vertical ( [
244
- Constraint :: Max ( 10 ) ,
245
- Constraint :: Fill ( 0 ) ,
246
- Constraint :: Max ( 10 ) ,
247
- ] )
248
- . areas ( area) ;
249
-
250
- if vert. height > height {
251
- vert. height = height;
252
- }
253
-
254
- frame. render_widget ( content, vert) ;
255
-
256
- Ok ( ( ) )
257
- }
258
186
}
259
187
260
188
impl Widget for Command {
261
189
fn dispatch ( & mut self , event : & Event ) -> Result < Broadcast > {
262
190
propagate ! ( self . dispatch_input( event) ) ;
263
- propagate ! ( self . dispatch_error( event) ) ;
264
191
265
192
match event {
266
- Event :: Finished ( result) => {
267
- let Err ( err) = result else {
268
- return Ok ( Broadcast :: Exited ) ;
193
+ Event :: Finished ( result) => result . as_ref ( ) . map ( | ( ) | Broadcast :: Exited ) . map_err ( |err| {
194
+ let Some ( err) = err . downcast_ref :: < StatusError > ( ) else {
195
+ return eyre ! ( err . to_string ( ) ) ;
269
196
} ;
270
197
271
- self . state = CommandState :: Error ( err. to_string ( ) ) ;
272
-
273
- Ok ( Broadcast :: Consumed )
274
- }
198
+ let separated = err. message . splitn ( 8 , ':' ) ;
199
+
200
+ eyre ! (
201
+ "{}" ,
202
+ separated. clone( ) . last( ) . unwrap_or( "unknown error" ) . trim( )
203
+ )
204
+ . section (
205
+ separated
206
+ . with_position ( )
207
+ . map ( |( i, line) | {
208
+ let l = line. trim ( ) . to_string ( ) ;
209
+
210
+ match i {
211
+ itertools:: Position :: Middle => format ! ( "├─ {l}" ) ,
212
+ itertools:: Position :: Last => format ! ( "└─ {l}" ) ,
213
+ _ => l,
214
+ }
215
+ } )
216
+ . join ( "\n " )
217
+ . header ( "Raw:" ) ,
218
+ )
219
+ } ) ,
275
220
_ => Ok ( Broadcast :: Ignored ) ,
276
221
}
277
222
}
@@ -280,7 +225,6 @@ impl Widget for Command {
280
225
match self . state {
281
226
CommandState :: Input ( _) => self . draw_input ( frame, area) ?,
282
227
CommandState :: Attached => { }
283
- CommandState :: Error ( _) => self . draw_error ( frame, area) ?,
284
228
}
285
229
286
230
Ok ( ( ) )
0 commit comments