Skip to content

Commit

Permalink
feat: editor rendering and cursor motions
Browse files Browse the repository at this point in the history
  • Loading branch information
wllfaria committed May 6, 2024
1 parent a66efd6 commit b847fca
Show file tree
Hide file tree
Showing 11 changed files with 336 additions and 119 deletions.
1 change: 1 addition & 0 deletions reqtui/src/text_object.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod cursor;
#[allow(clippy::module_inception)]
mod text_object;

Expand Down
59 changes: 59 additions & 0 deletions reqtui/src/text_object/cursor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use std::ops::Add;

#[derive(Debug, Default, Clone, PartialEq)]
pub struct Cursor {
// row/col, this is where the cursor is displayed onscreen, we use these fields to determine
// where to do text operations.
row: usize,
col: usize,
// expand row/col are used to store where the cursor was when moving to a smaller line, so we
// can restore it to the position it was if the line length allows
expand_row: usize,
expand_col: usize,
}

impl Cursor {
pub fn move_left(&mut self, amount: usize) {
self.col = self.col.saturating_sub(amount);
self.expand_col = self.expand_col.saturating_sub(amount);
}

pub fn move_down(&mut self, amount: usize) {
self.row = self.row.add(amount);
self.expand_row = self.expand_row.add(amount);
}

pub fn move_up(&mut self, amount: usize) {
self.row = self.row.saturating_sub(amount);
self.expand_row = self.expand_row.saturating_sub(amount);
}

pub fn move_right(&mut self, amount: usize) {
self.col = self.col.add(amount);
self.expand_col = self.expand_col.add(amount);
}

pub fn move_to_newline_start(&mut self) {
self.col = 0;
self.expand_col = 0;
self.row = self.row.add(1);
self.expand_row = self.expand_row.add(1);
}

pub fn move_to_col(&mut self, col: usize) {
self.col = col;
self.expand_col = col;
}

pub fn row(&self) -> usize {
self.row
}

pub fn col(&self) -> usize {
self.col
}

pub fn readable_position(&self) -> (usize, usize) {
(self.col.add(1), self.row.add(1))
}
}
29 changes: 28 additions & 1 deletion reqtui/src/text_object/text_object.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
use std::ops::Sub;

use crate::text_object::cursor::Cursor;
use ropey::Rope;

#[derive(Debug, Clone, PartialEq)]
pub struct Readonly;
#[derive(Debug, Clone, PartialEq)]
pub struct Write;

#[derive(Debug, PartialEq, Clone)]
#[derive(Debug, Clone, PartialEq)]
pub struct TextObject<State = Readonly> {
content: Rope,
state: std::marker::PhantomData<State>,
Expand Down Expand Up @@ -39,6 +42,30 @@ impl TextObject<Readonly> {
}
}

impl TextObject<Write> {
pub fn insert_char(&mut self, c: char, cursor: &Cursor) {
let line = self.content.line_to_char(cursor.row());
let col_offset = line + cursor.col();
self.content.insert_char(col_offset, c);
}

pub fn erase_previous_char(&mut self, cursor: &Cursor) {
let line = self.content.line_to_char(cursor.row());
let col_offset = line + cursor.col();
self.content
.try_remove(col_offset.saturating_sub(1)..col_offset)
.ok();
}

pub fn current_line(&self, cursor: &Cursor) -> Option<&str> {
self.content.line(cursor.row()).as_str()
}

pub fn len_lines(&self) -> usize {
self.content.len_lines()
}
}

impl<State> std::fmt::Display for TextObject<State> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.content.to_string())
Expand Down
2 changes: 1 addition & 1 deletion tui/src/app.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
components::Component,
components::{Component, Eventful},
event_pool::{Event, EventPool},
screen_manager::ScreenManager,
};
Expand Down
14 changes: 8 additions & 6 deletions tui/src/components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@ use crossterm::event::KeyEvent;
use ratatui::{layout::Rect, Frame};
use tokio::sync::mpsc::UnboundedSender;

pub trait Component {
fn draw(&mut self, frame: &mut Frame, size: Rect) -> anyhow::Result<()>;

pub trait Eventful {
fn handle_event(&mut self, event: Option<Event>) -> anyhow::Result<Option<Command>> {
let action = match event {
Some(Event::Key(key_event)) => self.handle_key_event(key_event)?,
Expand All @@ -24,13 +22,17 @@ pub trait Component {
Ok(action)
}

#[allow(unused_variables)]
fn resize(&mut self, new_size: Rect) {}

#[allow(unused_variables)]
fn handle_key_event(&mut self, key_event: KeyEvent) -> anyhow::Result<Option<Command>> {
Ok(None)
}
}

pub trait Component {
fn draw(&mut self, frame: &mut Frame, size: Rect) -> anyhow::Result<()>;

#[allow(unused_variables)]
fn resize(&mut self, new_size: Rect) {}

#[allow(unused_variables)]
fn register_command_handler(&mut self, sender: UnboundedSender<Command>) -> anyhow::Result<()> {
Expand Down
49 changes: 20 additions & 29 deletions tui/src/components/api_explorer/api_explorer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::components::{
res_viewer::{ResViewer, ResViewerState, ResViewerTabs},
sidebar::{Sidebar, SidebarState},
},
Component,
Component, Eventful,
};
use anyhow::Context;
use crossterm::event::{KeyCode, KeyEvent};
Expand Down Expand Up @@ -38,12 +38,6 @@ enum VisitNode {
Prev,
}

#[derive(PartialEq, Debug)]
enum EditorMode {
Insert,
Normal,
}

#[derive(Debug, PartialEq)]
enum PaneFocus {
Sidebar,
Expand Down Expand Up @@ -71,7 +65,6 @@ pub struct ApiExplorer<'a> {
editor: ReqEditor<'a>,
editor_tab: ReqEditorTabs,
editor_body_scroll: usize,
editor_mode: EditorMode,

responses_map: HashMap<Request, ReqtuiResponse>,
}
Expand Down Expand Up @@ -107,7 +100,6 @@ impl<'a> ApiExplorer<'a> {
editor: ReqEditor::new(colors, selected_request.clone()),
editor_tab: ReqEditorTabs::Request,
editor_body_scroll: 0,
editor_mode: EditorMode::Normal,

hovered_request,
selected_request,
Expand Down Expand Up @@ -190,26 +182,11 @@ impl<'a> ApiExplorer<'a> {
}

fn handle_editor_key_event(&mut self, key_event: KeyEvent) -> anyhow::Result<Option<Command>> {
match key_event.code {
KeyCode::Char(c) => {
if let Some(req) = self.selected_request.as_mut() {
req.borrow_mut()
.body
.as_mut()
.map(|body| body.push(c))
.or_else(|| {
req.borrow_mut().body = Some(c.to_string());
Some(())
});

tracing::debug!("{:#?}", self.selected_request);
};
}
KeyCode::Enter => {}
_ => {}
};

Ok(None)
if key_event.code.eq(&KeyCode::Enter) && self.selected_pane.is_none() {
self.selected_pane = Some(PaneFocus::Editor);
return Ok(None);
}
self.editor.handle_key_event(key_event)
}

fn draw_background(&self, size: Rect, frame: &mut Frame) {
Expand Down Expand Up @@ -311,13 +288,27 @@ impl Component for ApiExplorer<'_> {
self.draw_req_uri(frame);
self.draw_sidebar(frame);

if self
.selected_pane
.as_ref()
.is_some_and(|pane| pane.eq(&PaneFocus::Editor))
{
let editor_position = self.layout.req_editor;
let cursor = self.editor.cursor();
let row_with_offset = editor_position.y.add(cursor.row() as u16).add(3);
let col_with_offset = editor_position.x.add(cursor.col() as u16).add(1);
frame.set_cursor(col_with_offset, row_with_offset);
}

Ok(())
}

fn resize(&mut self, new_size: Rect) {
self.layout = build_layout(new_size);
}
}

impl Eventful for ApiExplorer<'_> {
fn handle_key_event(&mut self, key_event: KeyEvent) -> anyhow::Result<Option<Command>> {
if let KeyCode::Tab = key_event.code {
match (&self.focused_pane, &self.selected_pane) {
Expand Down
Loading

0 comments on commit b847fca

Please sign in to comment.