Skip to content

Commit

Permalink
make it possible to create multiple cursor with mouse
Browse files Browse the repository at this point in the history
  • Loading branch information
Kl4rry committed Dec 15, 2024
1 parent a5dfb5a commit d3ce5d8
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 83 deletions.
103 changes: 62 additions & 41 deletions crates/ferrite-core/src/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -826,6 +826,31 @@ impl Buffer {
}
}

fn select_word_raw(&mut self, view_id: ViewId, cursor_idx: usize) {
let mut start_byte_idx = self.views[view_id].cursors[cursor_idx].position;
loop {
let new_idx = self.rope.prev_grapheme_boundary_byte(start_byte_idx);
let grapheme = self.rope.byte_slice(new_idx..start_byte_idx);
if new_idx == start_byte_idx || !grapheme.is_word_char() {
break;
}
start_byte_idx = new_idx;
}

let mut end_byte_idx = self.views[view_id].cursors[cursor_idx].position;
loop {
let new_idx = self.rope.next_grapheme_boundary_byte(end_byte_idx);
let grapheme = self.rope.byte_slice(end_byte_idx..new_idx);
if new_idx == end_byte_idx || !grapheme.is_word_char() {
break;
}
end_byte_idx = new_idx;
}

self.views[view_id].cursors[cursor_idx].position = end_byte_idx;
self.views[view_id].cursors[cursor_idx].anchor = start_byte_idx;
}

pub fn select_word(&mut self, view_id: ViewId) {
self.views[view_id].coalesce_cursors();
let has_selection = self.views[view_id]
Expand Down Expand Up @@ -866,28 +891,7 @@ impl Buffer {
}
} else {
for i in 0..self.views[view_id].cursors.len() {
let mut start_byte_idx = self.views[view_id].cursors[i].position;
loop {
let new_idx = self.rope.prev_grapheme_boundary_byte(start_byte_idx);
let grapheme = self.rope.byte_slice(new_idx..start_byte_idx);
if new_idx == start_byte_idx || !grapheme.is_word_char() {
break;
}
start_byte_idx = new_idx;
}

let mut end_byte_idx = self.views[view_id].cursors[i].position;
loop {
let new_idx = self.rope.next_grapheme_boundary_byte(end_byte_idx);
let grapheme = self.rope.byte_slice(end_byte_idx..new_idx);
if new_idx == end_byte_idx || !grapheme.is_word_char() {
break;
}
end_byte_idx = new_idx;
}

self.views[view_id].cursors[i].position = end_byte_idx;
self.views[view_id].cursors[i].anchor = start_byte_idx;
self.select_word_raw(view_id, i);
}
}

Expand Down Expand Up @@ -1802,19 +1806,23 @@ impl Buffer {
}
}

fn select_line_raw(&mut self, view_id: ViewId, cursor_idx: usize) {
{
let line_idx = self.cursor_line_idx(view_id, cursor_idx);
let line_start = self.rope.line_to_byte(line_idx + 1);
self.views[view_id].cursors[cursor_idx].position = line_start;
}

{
let line_idx = self.anchor_line_idx(view_id, cursor_idx);
let line_start = self.rope.line_to_byte(line_idx);
self.views[view_id].cursors[cursor_idx].anchor = line_start;
}
}

pub fn select_line(&mut self, view_id: ViewId) {
for i in 0..self.views[view_id].cursors.len() {
{
let line_idx = self.cursor_line_idx(view_id, i);
let line_start = self.rope.line_to_byte(line_idx + 1);
self.views[view_id].cursors[i].position = line_start;
}

{
let line_idx = self.anchor_line_idx(view_id, i);
let line_start = self.rope.line_to_byte(line_idx);
self.views[view_id].cursors[i].anchor = line_start;
}
self.select_line_raw(view_id, i);
}

self.views[view_id].coalesce_cursors();
Expand Down Expand Up @@ -2090,21 +2098,34 @@ impl Buffer {
}
}

pub fn handle_click(&mut self, view_id: ViewId, col: usize, line: usize) {
self.views[view_id].cursors.clear();
self.set_cursor_pos(view_id, 0, col, line);
pub fn handle_click(&mut self, view_id: ViewId, spawn_cursor: bool, col: usize, line: usize) {
let cursor_idx = if spawn_cursor {
self.views[view_id].cursors.push(Cursor::default());
self.views[view_id].cursors.len() - 1
} else {
self.views[view_id].cursors.clear();
0
};
self.set_cursor_pos(view_id, cursor_idx, col, line);
self.views[view_id].cursors[cursor_idx].affinity =
self.cursor_grapheme_column(view_id, cursor_idx);

let click_point = Point::new(col, line);
let now = Instant::now();
if now.duration_since(self.views[view_id].last_click) < Duration::from_millis(500)
&& click_point == self.views[view_id].last_click_pos
{
self.views[view_id].clicks_in_a_row += 1;
if self.views[view_id].clicks_in_a_row == 1 {
self.select_word(view_id);
self.copy_selection_to_primary(view_id);
self.select_word_raw(view_id, cursor_idx);
if !spawn_cursor {
self.copy_selection_to_primary(view_id);
}
} else if self.views[view_id].clicks_in_a_row == 2 {
self.select_line(view_id);
self.copy_selection_to_primary(view_id);
self.select_line_raw(view_id, cursor_idx);
if !spawn_cursor {
self.copy_selection_to_primary(view_id);
}
} else {
self.views[view_id].clicks_in_a_row = 0;
}
Expand All @@ -2113,7 +2134,7 @@ impl Buffer {
}
self.views[view_id].last_click = now;
self.views[view_id].last_click_pos = click_point;
self.update_affinity(view_id);
self.views[view_id].coalesce_cursors();
}

pub fn set_cursor_pos(
Expand Down
4 changes: 3 additions & 1 deletion crates/ferrite-core/src/buffer/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ impl Buffer {
Tab { back } if !self.read_only => self.tab(view_id, back),
VerticalScroll(distance) => self.vertical_scroll(view_id, distance),
Escape => self.escape(view_id),
ClickCell(col, line) => self.handle_click(view_id, col, line),
ClickCell(spawn_cursor, col, line) => {
self.handle_click(view_id, spawn_cursor, col, line)
}
SelectArea { cursor, anchor } => self.select_area(view_id, cursor, anchor, true),
NextMatch => self.next_match(view_id),
PrevMatch => self.prev_match(view_id),
Expand Down
4 changes: 2 additions & 2 deletions crates/ferrite-core/src/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ pub enum Cmd {
BackspaceWord,
Delete,
DeleteWord,
ClickCell(usize, usize),
ClickCell(bool, usize, usize),
SelectArea {
cursor: Point<usize>,
anchor: Point<usize>,
Expand Down Expand Up @@ -178,7 +178,7 @@ impl Cmd {
BackspaceWord => "Backspace word",
Delete => "Delete",
DeleteWord => "Delete word",
ClickCell(_, _) => "Set cursor pos",
ClickCell(..) => "Set cursor pos",
SelectArea { .. } => "Select area",
PromptGoto => "Goto",
Home { .. } => "Home",
Expand Down
78 changes: 40 additions & 38 deletions crates/ferrite-gui/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use winit::{
dpi::PhysicalPosition,
event::{ElementState, Event, MouseButton, MouseScrollDelta, WindowEvent},
event_loop::{EventLoop, EventLoopBuilder, EventLoopWindowTarget},
keyboard::Key,
keyboard::{Key, ModifiersState, NamedKey},
window::{CursorIcon, Window, WindowBuilder},
};

Expand Down Expand Up @@ -291,53 +291,51 @@ impl GuiApp {
}
}
}
WindowEvent::ModifiersChanged(modifiers) => {
let modifiers = modifiers.state();
self.modifiers.set(
KeyModifiers::CONTROL,
modifiers.contains(ModifiersState::CONTROL),
);
self.modifiers
.set(KeyModifiers::ALT, modifiers.contains(ModifiersState::ALT));
self.modifiers.set(
KeyModifiers::SHIFT,
modifiers.contains(ModifiersState::SHIFT),
);
}
WindowEvent::KeyboardInput { event, .. } => {
tracing::trace!("{:?}", event);
let mut control_flow = self.control_flow;
if !event.state.is_pressed() {
if let Key::Named(key) = event.logical_key {
match key {
winit::keyboard::NamedKey::Control => {
self.modifiers.remove(KeyModifiers::CONTROL)
}
winit::keyboard::NamedKey::Alt => {
self.modifiers.remove(KeyModifiers::ALT)
}
winit::keyboard::NamedKey::Shift => {
self.modifiers.remove(KeyModifiers::SHIFT)
}
winit::keyboard::NamedKey::Super => {
self.modifiers.remove(KeyModifiers::SUPER)
}
winit::keyboard::NamedKey::Hyper => {
self.modifiers.remove(KeyModifiers::HYPER)
}
winit::keyboard::NamedKey::Meta => {
self.modifiers.remove(KeyModifiers::META)
}
_ => (),

if let Key::Named(key) = event.logical_key {
match key {
NamedKey::Super => {
self.modifiers
.set(KeyModifiers::SUPER, event.state.is_pressed());
return;
}
NamedKey::Hyper => {
self.modifiers
.set(KeyModifiers::HYPER, event.state.is_pressed());
return;
}
NamedKey::Meta => {
self.modifiers
.set(KeyModifiers::META, event.state.is_pressed());
return;
}
_ => (),
}
}

if !event.state.is_pressed() {
return;
}

let cmd = 'block: {
match event.logical_key {
Key::Named(key) => {
let modifier = match key {
winit::keyboard::NamedKey::Control => KeyModifiers::CONTROL,
winit::keyboard::NamedKey::Alt => KeyModifiers::ALT,
winit::keyboard::NamedKey::Shift => KeyModifiers::SHIFT,
winit::keyboard::NamedKey::Super => KeyModifiers::SUPER,
winit::keyboard::NamedKey::Hyper => KeyModifiers::HYPER,
winit::keyboard::NamedKey::Meta => KeyModifiers::META,
_ => KeyModifiers::NONE,
};
if !modifier.is_empty() {
self.modifiers |= modifier;
return;
}

if let Some(keycode) = convert_keycode(key) {
let cmd = keymap::get_command_from_input(
keycode,
Expand Down Expand Up @@ -492,7 +490,11 @@ impl GuiApp {
.saturating_sub(left_offset);
let line = (line as usize + buffer.line_pos(view_id))
.saturating_sub(pane_rect.y);
break 'block Some(Cmd::ClickCell(column, line));
break 'block Some(Cmd::ClickCell(
self.modifiers.contains(KeyModifiers::ALT),
column,
line,
));
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/ferrite-term/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ impl TermApp {
.saturating_sub(left_offset);
let line = (event.row as usize + buffer.line_pos(view_id))
.saturating_sub(pane_rect.y);
break 'block Some(Cmd::ClickCell(column, line));
break 'block Some(Cmd::ClickCell(false, column, line));
}
}
}
Expand Down

0 comments on commit d3ce5d8

Please sign in to comment.