Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/typing history #96

Merged
merged 5 commits into from
Jul 4, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Added:
- New configuration option `dashboard.sidebar_default_action` allows controlling the pane behaviour when selecting channels in the sidebar
- Support for RAW command
- Messages from other users containing your nickname are now highlighted using the `info` colour
- Previously sent messages can be accessed per buffer in the text input with up / down arrows

Changed:

Expand Down
9 changes: 9 additions & 0 deletions src/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,15 @@ impl Buffer {
}
}

pub fn reset(&self) -> Command<Message> {
match self {
Buffer::Empty => Command::none(),
Buffer::Channel(channel) => channel.reset().map(Message::Channel),
Buffer::Server(server) => server.reset().map(Message::Server),
Buffer::Query(query) => query.reset().map(Message::Query),
}
}

pub fn scroll_to_start(&mut self) -> Command<Message> {
match self {
Buffer::Empty => Command::none(),
Expand Down
4 changes: 4 additions & 0 deletions src/buffer/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,10 @@ impl Channel {
pub fn focus(&self) -> Command<Message> {
self.input_view.focus().map(Message::InputView)
}

pub fn reset(&self) -> Command<Message> {
self.input_view.reset().map(Message::InputView)
}
}

mod nick_list {
Expand Down
4 changes: 4 additions & 0 deletions src/buffer/input_view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,8 @@ impl State {
pub fn focus(&self) -> Command<Message> {
input::focus(self.input_id.clone())
}

pub fn reset(&self) -> Command<Message> {
input::reset(self.input_id.clone())
}
}
4 changes: 4 additions & 0 deletions src/buffer/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,4 +148,8 @@ impl Query {
pub fn focus(&self) -> Command<Message> {
self.input_view.focus().map(Message::InputView)
}

pub fn reset(&self) -> Command<Message> {
self.input_view.reset().map(Message::InputView)
}
}
4 changes: 4 additions & 0 deletions src/buffer/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,8 @@ impl Server {
pub fn focus(&self) -> Command<Message> {
self.input_view.focus().map(Message::InputView)
}

pub fn reset(&self) -> Command<Message> {
self.input_view.reset().map(Message::InputView)
}
}
19 changes: 18 additions & 1 deletion src/screen/dashboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,10 @@ impl Dashboard {
if let Some(state) = self.panes.get_mut(&pane) {
state.buffer = Buffer::from(kind);
self.last_changed = Some(Instant::now());
return self.focus_pane(pane);
return Command::batch(vec![
self.reset_pane(pane),
self.focus_pane(pane),
]);
}
}
side_menu::Event::Close(pane) => {
Expand Down Expand Up @@ -526,6 +529,20 @@ impl Dashboard {
}
}

fn reset_pane(&mut self, pane: pane_grid::Pane) -> Command<Message> {
self.panes
.iter()
.find_map(|(p, state)| {
(*p == pane).then(|| {
state
.buffer
.reset()
.map(move |message| Message::Pane(pane::Message::Buffer(pane, message)))
})
})
.unwrap_or(Command::none())
}

pub fn track(&mut self) -> Command<Message> {
let resources = self
.panes
Expand Down
102 changes: 100 additions & 2 deletions src/widget/input.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use std::collections::VecDeque;

use data::{input, Buffer, Command};
use iced::advanced::widget::{self, Operation};
pub use iced::widget::text_input::{focus, move_cursor_to_end};
use iced::widget::{component, container, row, text, text_input, Component};

Expand Down Expand Up @@ -39,6 +42,8 @@ pub enum Event {
Input(String),
Send,
Tab,
Up,
Down,
}

pub struct Input<'a, Message> {
Expand All @@ -53,6 +58,8 @@ pub struct State {
input: String,
error: Option<String>,
completion: Completion,
history: VecDeque<String>,
selected_history: Option<usize>,
}

impl<'a, Message> Component<Message, Renderer> for Input<'a, Message>
Expand All @@ -65,7 +72,11 @@ where
fn update(&mut self, state: &mut Self::State, event: Self::Event) -> Option<Message> {
match event {
Event::Input(input) => {
// Reset error state
state.error = None;
// Reset selected history
state.selected_history = None;

state.input = input;

state.completion.process(&state.input);
Expand All @@ -75,6 +86,8 @@ where
Event::Send => {
// Reset error state
state.error = None;
// Reset selected history
state.selected_history = None;

if let Some(command) = state.completion.select() {
state.input = command;
Expand All @@ -91,8 +104,8 @@ where
}
};

// Clear message, we parsed it succesfully
state.input = String::new();
// Clear message and add it to history
state.history.push_front(std::mem::take(&mut state.input));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this grow unbounded?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, we should probably have some limit

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

64905a2

I've truncated to 100 here. Shouldn't have much memory footprint and is more than enough.


Some((self.on_submit)(input))
} else {
Expand All @@ -103,6 +116,46 @@ where
state.completion.tab();
None
}
Event::Up => {
state.completion.reset();

if !state.history.is_empty() {
if let Some(index) = state.selected_history.as_mut() {
*index = (*index + 1).min(state.history.len() - 1);
} else {
state.selected_history = Some(0);
}

state.input = state
.history
.get(state.selected_history.unwrap())
.unwrap()
.clone();
state.completion.process(&state.input);

return Some(self.on_completion.clone());
}

None
}
Event::Down => {
state.completion.reset();

if let Some(index) = state.selected_history.as_mut() {
if *index == 0 {
state.selected_history = None;
state.input.clear();
} else {
*index -= 1;
state.input = state.history.get(*index).unwrap().clone();
state.completion.process(&state.input);
}

return Some(self.on_completion.clone());
}

None
}
}
}

Expand All @@ -121,6 +174,7 @@ where
.style(style)
.into();

// Add tab support if selecting a completion
let input = if state.completion.is_selecting() {
key_press(
text_input,
Expand All @@ -132,6 +186,19 @@ where
text_input
};

// Add up / down support for history cycling
let input = key_press(
key_press(
input,
key_press::KeyCode::Up,
key_press::Modifiers::default(),
Event::Up,
),
key_press::KeyCode::Down,
key_press::Modifiers::default(),
Event::Down,
);

let overlay = state
.error
.as_ref()
Expand All @@ -141,6 +208,10 @@ where

anchored_overlay(input, overlay)
}

fn operate(&self, state: &mut State, operation: &mut dyn widget::Operation<Message>) {
operation.custom(state, Some(&self.id.clone().into()));
}
}

fn error<'a, Message: 'a>(error: impl ToString) -> Element<'a, Message> {
Expand All @@ -159,3 +230,30 @@ where
component(input)
}
}

pub fn reset<Message: 'static>(id: impl Into<widget::Id>) -> iced::Command<Message> {
struct Reset {
id: widget::Id,
}

impl<T> Operation<T> for Reset {
fn container(
&mut self,
_id: Option<&widget::Id>,
operate_on_children: &mut dyn FnMut(&mut dyn Operation<T>),
) {
operate_on_children(self)
}

fn custom(&mut self, state: &mut dyn std::any::Any, id: Option<&widget::Id>) {
if Some(&self.id) == id {
dbg!("asdfasdf");
if let Some(state) = state.downcast_mut::<State>() {
*state = State::default();
}
}
}
}

iced::Command::widget(Reset { id: id.into() })
}