Skip to content

Commit 7fb2ed1

Browse files
authored
The missing eval bits (#53)
Last PR was merged prematurely... - Makes dialogs general concept - Eval dialog - Eval result and expression stored in history - Do not allow eval dialog in history mode
1 parent 0634377 commit 7fb2ed1

File tree

10 files changed

+302
-140
lines changed

10 files changed

+302
-140
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
main
5+
----
6+
7+
- Introduce eval feature
8+
49
0.1.1
510
-----
611

src/app.rs

Lines changed: 117 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ use crate::dbgp::client::ContextGetResponse;
55
use crate::dbgp::client::ContinuationResponse;
66
use crate::dbgp::client::ContinuationStatus;
77
use crate::dbgp::client::DbgpClient;
8+
use crate::dbgp::client::EvalResponse;
89
use crate::dbgp::client::Property;
910
use crate::event::input::AppEvent;
1011
use crate::notification::Notification;
1112
use crate::theme::Scheme;
1213
use crate::theme::Theme;
13-
use crate::view::eval::draw_properties;
14+
use crate::view::eval::EvalDialog;
1415
use crate::view::help::HelpView;
1516
use crate::view::layout::LayoutView;
1617
use crate::view::listen::ListenView;
@@ -21,14 +22,13 @@ use crate::view::View;
2122
use crate::workspace::Workspace;
2223
use anyhow::Result;
2324
use crossterm::event::KeyCode;
25+
use log::error;
2426
use log::info;
2527
use log::warn;
26-
use log::error;
2728
use ratatui::layout::Rect;
2829
use ratatui::prelude::CrosstermBackend;
2930
use ratatui::style::Color;
3031
use ratatui::style::Style;
31-
use ratatui::text::Line;
3232
use ratatui::widgets::Block;
3333
use ratatui::widgets::Padding;
3434
use ratatui::widgets::Paragraph;
@@ -66,6 +66,13 @@ impl StackFrame {
6666
#[derive(Clone, Debug)]
6767
pub struct HistoryEntry {
6868
pub stacks: Vec<StackFrame>,
69+
pub eval: Option<EvalEntry>,
70+
}
71+
72+
#[derive(Clone, Debug)]
73+
pub struct EvalEntry {
74+
pub expr: String,
75+
pub response: EvalResponse,
6976
}
7077

7178
impl HistoryEntry {
@@ -74,7 +81,7 @@ impl HistoryEntry {
7481
}
7582
fn new() -> Self {
7683
let stacks = Vec::new();
77-
HistoryEntry { stacks }
84+
HistoryEntry { stacks, eval: None }
7885
}
7986

8087
fn initial(filename: String, source: String) -> HistoryEntry {
@@ -88,6 +95,7 @@ impl HistoryEntry {
8895
},
8996
context: None,
9097
}],
98+
eval: None,
9199
}
92100
}
93101

@@ -178,6 +186,11 @@ pub enum SelectedView {
178186
Help,
179187
}
180188

189+
#[derive(Debug, Clone)]
190+
pub enum ActiveDialog {
191+
Eval,
192+
}
193+
181194
#[derive(PartialEq)]
182195
pub enum ListenStatus {
183196
Connected,
@@ -189,7 +202,6 @@ impl ListenStatus {
189202
pub fn is_connected(&self) -> bool {
190203
*self == ListenStatus::Connected
191204
}
192-
193205
}
194206

195207
pub struct App {
@@ -213,6 +225,7 @@ pub struct App {
213225
pub view_current: SelectedView,
214226
pub focus_view: bool,
215227
pub session_view: SessionViewState,
228+
pub active_dialog: Option<ActiveDialog>,
216229
pub input_plurality: Vec<char>,
217230

218231
pub counter: u16,
@@ -251,6 +264,7 @@ impl App {
251264
command_input: Input::default(),
252265
command_response: None,
253266
view_current: SelectedView::Listen,
267+
active_dialog: None,
254268
focus_view: false,
255269
session_view: SessionViewState::new(),
256270

@@ -285,15 +299,10 @@ impl App {
285299

286300
loop {
287301
match listener.accept().await {
288-
Ok(s) => {
289-
match sender.send(AppEvent::ClientConnected(s.0)).await {
290-
Ok(_) => (),
291-
Err(e) => error!(
292-
"Could not send connection event: {}",
293-
e
294-
),
295-
}
296-
}
302+
Ok(s) => match sender.send(AppEvent::ClientConnected(s.0)).await {
303+
Ok(_) => (),
304+
Err(e) => error!("Could not send connection event: {}", e),
305+
},
297306
Err(_) => panic!("Could not connect"),
298307
}
299308
}
@@ -311,6 +320,7 @@ impl App {
311320
let event = event.unwrap();
312321

313322
if let Err(e) = self.handle_event(terminal, event).await {
323+
self.active_dialog = None;
314324
self.notification = Notification::error(e.to_string());
315325
continue;
316326
};
@@ -334,7 +344,7 @@ impl App {
334344
match event {
335345
AppEvent::Tick => {
336346
self.tick = self.tick.wrapping_add(1);
337-
},
347+
}
338348
_ => info!("Handling event {:?}", event),
339349
};
340350
match event {
@@ -374,7 +384,9 @@ impl App {
374384
for _ in 0..self.take_motion() {
375385
self.history.next();
376386
self.recenter();
377-
if self.history.is_current() && (self.listening_status == ListenStatus::Connected) {
387+
if self.history.is_current()
388+
&& (self.listening_status == ListenStatus::Connected)
389+
{
378390
self.sender
379391
.send(AppEvent::ChangeSessionViewMode(SessionViewMode::Current))
380392
.await?;
@@ -392,10 +404,11 @@ impl App {
392404
self.view_current = SelectedView::Listen;
393405
self.session_view.mode = SessionViewMode::Current;
394406
self.notification = Notification::info("listening for next connection".to_string())
395-
},
407+
}
396408
AppEvent::ClientConnected(s) => {
397409
if self.listening_status != ListenStatus::Listening {
398-
self.notification = Notification::warning("refused incoming connection".to_string());
410+
self.notification =
411+
Notification::warning("refused incoming connection".to_string());
399412
} else {
400413
self.notification = Notification::info("connected".to_string());
401414
let filepath = {
@@ -437,7 +450,7 @@ impl App {
437450
}
438451
AppEvent::ContextDepth(inc) => {
439452
let depth = self.context_depth;
440-
self.context_depth = depth.wrapping_add(inc as u16).max(0);
453+
self.context_depth = depth.wrapping_add(inc as u16);
441454
self.client
442455
.lock()
443456
.await
@@ -447,11 +460,11 @@ impl App {
447460
AppEvent::ContextFilterOpen => {
448461
self.session_view.context_filter.show = true;
449462
self.focus_view = true;
450-
},
463+
}
451464
AppEvent::ContextSearchClose => {
452465
self.session_view.context_filter.show = false;
453466
self.focus_view = false;
454-
},
467+
}
455468
AppEvent::ScrollSource(amount) => {
456469
self.session_view.source_scroll = apply_scroll(
457470
self.session_view.source_scroll,
@@ -466,6 +479,13 @@ impl App {
466479
self.take_motion() as i16,
467480
);
468481
}
482+
AppEvent::ScrollEval(amount) => {
483+
self.session_view.eval_state.scroll = apply_scroll(
484+
self.session_view.eval_state.scroll,
485+
amount,
486+
self.take_motion() as i16,
487+
);
488+
}
469489
AppEvent::ScrollStack(amount) => {
470490
self.session_view.stack_scroll = apply_scroll(
471491
self.session_view.stack_scroll,
@@ -493,29 +513,39 @@ impl App {
493513
}
494514
AppEvent::PushInputPlurality(char) => self.input_plurality.push(char),
495515
AppEvent::EvalStart => {
496-
self.session_view.eval_state.active = true;
497-
self.focus_view = true;
498-
},
516+
if !self.history.is_current() {
517+
self.notification =
518+
Notification::warning("Cannot eval in history mode".to_string());
519+
} else {
520+
self.active_dialog = Some(ActiveDialog::Eval);
521+
}
522+
}
499523
AppEvent::EvalCancel => {
500-
self.session_view.eval_state.active = false;
501-
self.focus_view = false;
502-
},
524+
self.active_dialog = None;
525+
}
503526
AppEvent::EvalExecute => {
504-
self.session_view.eval_state.active = false;
505-
self.focus_view = false;
506-
let response = self.client
507-
.lock()
508-
.await
509-
.eval(
510-
self.session_view.eval_state.input.to_string(),
511-
self.session_view.stack_depth()
512-
)
513-
.await?;
527+
if self.session_view.eval_state.input.to_string().is_empty() {
528+
self.session_view.eval_state.response = None;
529+
} else {
530+
let response = self
531+
.client
532+
.lock()
533+
.await
534+
.eval(
535+
self.session_view.eval_state.input.to_string(),
536+
self.session_view.stack_depth(),
537+
)
538+
.await?;
514539

515-
self.session_view.eval_state.properties = response.properties;
516-
},
540+
self.session_view.eval_state.response = Some(response);
541+
self.sender.send(AppEvent::Snapshot()).await.unwrap();
542+
}
543+
self.active_dialog = None;
544+
}
517545
AppEvent::Input(key_event) => {
518-
if self.focus_view {
546+
if self.active_dialog.is_some() {
547+
self.send_event_to_current_dialog(event).await;
548+
} else if self.focus_view {
519549
// event shandled exclusively by view (e.g. input needs focus)
520550
self.send_event_to_current_view(event).await;
521551
} else {
@@ -535,7 +565,7 @@ impl App {
535565
_ => self.send_event_to_current_view(event).await,
536566
}
537567
}
538-
},
568+
}
539569
_ => self.send_event_to_current_view(event).await,
540570
};
541571

@@ -599,6 +629,17 @@ impl App {
599629
});
600630
}
601631

632+
async fn send_event_to_current_dialog(&mut self, event: AppEvent) {
633+
if let Some(dialog) = &self.active_dialog {
634+
let subsequent_event = match &dialog {
635+
ActiveDialog::Eval => EvalDialog::handle(self, event),
636+
};
637+
if let Some(event) = subsequent_event {
638+
self.sender.send(event).await.unwrap()
639+
};
640+
}
641+
}
642+
602643
// route the event to the currently selected view
603644
async fn send_event_to_current_view(&mut self, event: AppEvent) {
604645
let subsequent_event = match self.view_current {
@@ -629,16 +670,21 @@ impl App {
629670

630671
/// capture the current status and push it onto the history stack
631672
pub async fn snapshot(&mut self) -> Result<()> {
632-
let stack = {
633-
self.client.lock().await.deref_mut().get_stack().await?
634-
};
673+
let stack = { self.client.lock().await.deref_mut().get_stack().await? };
635674
let mut entry = HistoryEntry::new();
636675
for (level, frame) in stack.entries.iter().enumerate() {
637676
let filename = &frame.filename;
638677
let line_no = frame.line;
639678
let context = {
640679
match (level as u16) < self.stack_max_context_fetch {
641-
true => Some(self.client.lock().await.deref_mut().context_get(level as u16).await?),
680+
true => Some(
681+
self.client
682+
.lock()
683+
.await
684+
.deref_mut()
685+
.context_get(level as u16)
686+
.await?,
687+
),
642688
false => None,
643689
}
644690
};
@@ -664,6 +710,28 @@ impl App {
664710
context,
665711
});
666712
}
713+
714+
// *xdebug* only evalutes expressions on the current stack frame
715+
let eval = if !self.session_view.eval_state.input.to_string().is_empty() {
716+
let response = self
717+
.client
718+
.lock()
719+
.await
720+
.eval(
721+
self.session_view.eval_state.input.to_string(),
722+
self.session_view.stack_depth(),
723+
)
724+
.await?;
725+
726+
Some(EvalEntry{
727+
expr: self.session_view.eval_state.input.to_string(),
728+
response
729+
})
730+
} else {
731+
None
732+
};
733+
734+
entry.eval = eval;
667735
self.session_view.reset();
668736
self.history.push(entry);
669737
self.recenter();
@@ -702,7 +770,10 @@ impl App {
702770

703771
fn recenter(&mut self) {
704772
let entry = self.history.current();
705-
if let Some(entry) = entry { self.session_view.scroll_to_line(entry.source(self.session_view.stack_depth()).line_no) }
773+
if let Some(entry) = entry {
774+
self.session_view
775+
.scroll_to_line(entry.source(self.session_view.stack_depth()).line_no)
776+
}
706777
}
707778
}
708779

src/event/input.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ pub enum AppEvent {
4343
ScrollSource(Scroll),
4444
ScrollContext(Scroll),
4545
ScrollStack(Scroll),
46+
ScrollEval(Scroll),
4647
ToggleFullscreen,
4748
PushInputPlurality(char),
4849
ContextDepth(i8),
@@ -52,6 +53,7 @@ pub enum AppEvent {
5253
Listen,
5354
EvalCancel,
5455
EvalExecute,
56+
EvalRefresh,
5557
EvalStart,
5658
}
5759

0 commit comments

Comments
 (0)