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

Key remappings for mouse configuration #9469

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions helix-term/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ serde = { version = "1.0", features = ["derive"] }
grep-regex = "0.1.12"
grep-searcher = "0.1.13"

# macro type name concatenation
paste = "1.0.14"

[target.'cfg(not(windows))'.dependencies] # https://github.com/vorner/signal-hook/issues/100
signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] }
libc = "0.2.152"
Expand Down
9 changes: 8 additions & 1 deletion helix-term/src/application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use crate::{
handlers,
job::Jobs,
keymap::Keymaps,
mousemap::Mousemaps,
ui::{self, overlay::overlaid},
};

Expand Down Expand Up @@ -152,7 +153,13 @@ impl Application {
let keys = Box::new(Map::new(Arc::clone(&config), |config: &Config| {
&config.keys
}));
let editor_view = Box::new(ui::EditorView::new(Keymaps::new(keys)));
let mouse = Box::new(Map::new(Arc::clone(&config), |config: &Config| {
&config.mouse
}));
let editor_view = Box::new(ui::EditorView::new(
Keymaps::new(keys),
Mousemaps::new(mouse),
));
compositor.push(editor_view);

if args.load_tutor {
Expand Down
678 changes: 393 additions & 285 deletions helix-term/src/commands.rs

Large diffs are not rendered by default.

223 changes: 223 additions & 0 deletions helix-term/src/commands/mouse.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
use crate::ui::{
editor::{gutter_coords_and_view, pos_and_view},
EditorView,
};
use anyhow::anyhow;
use helix_core::{movement::Direction, Range, Selection};
use helix_view::{input::MouseEvent, Document, ViewId};

use super::{
move_next_long_word_end, move_next_word_end, move_prev_long_word_start, move_prev_word_start,
paste_primary_clipboard_before, yank_primary_selection_impl, Context,
};

#[derive(Eq, PartialEq, PartialOrd, Ord, Clone, Debug, Copy)]
pub struct StaticMouseCommand {
pub name: &'static str,
pub(crate) fun: fn(&mut Context, &MouseEvent, &mut EditorView),
pub doc: &'static str,
}

impl std::str::FromStr for StaticMouseCommand {
type Err = anyhow::Error;

fn from_str(s: &str) -> Result<Self, Self::Err> {
StaticMouseCommand::STATIC_COMMAND_LIST
.iter()
.find(|cmd| cmd.name() == s)
.cloned()
.ok_or_else(|| anyhow!("No command named '{}'", s))
}
}

impl StaticMouseCommand {
pub fn execute(&self, cx: &mut Context, event: &MouseEvent, editor_view: &mut EditorView) {
(self.fun)(cx, event, editor_view);
}

pub fn name(&self) -> &str {
self.name
}

pub fn doc(&self) -> &str {
self.doc
}
}

fn handle_selection_in_buffer(
cx: &mut Context,
evt: &MouseEvent,
ev: &mut EditorView,
callback: impl Fn(&mut Document, &ViewId, usize),
) -> bool {
let editor = &mut cx.editor;

if let Some((pos, view_id)) = pos_and_view(editor, evt.row, evt.column, true) {
let prev_view_id = view!(editor).id;
let doc = doc_mut!(editor, &view!(editor, view_id).doc);

callback(doc, &view_id, pos);

if view_id != prev_view_id {
ev.clear_completion(editor);
}

editor.focus(view_id);
editor.ensure_cursor_in_view(view_id);

return true;
}
false
}

pub fn handle_main_button_mouse(cx: &mut Context, evt: &MouseEvent, ev: &mut EditorView) {
if !handle_selection_in_buffer(
cx,
evt,
ev,
|doc: &mut Document, view_id: &ViewId, pos: usize| {
doc.set_selection(*view_id, Selection::point(pos));
},
) {
add_breakpoint_mouse(cx, evt, ev);
}
}

pub fn set_mouse_selection(cx: &mut Context, evt: &MouseEvent, ev: &mut EditorView) {
handle_selection_in_buffer(
cx,
evt,
ev,
|doc: &mut Document, view_id: &ViewId, pos: usize| {
doc.set_selection(*view_id, Selection::point(pos));
},
);
}

pub fn select_word_mouse(cx: &mut Context, _: &MouseEvent, _: &mut EditorView) {
move_prev_word_start(cx);
move_next_word_end(cx);
}

pub fn select_long_word_mouse(cx: &mut Context, _: &MouseEvent, _: &mut EditorView) {
move_prev_long_word_start(cx);
move_next_long_word_end(cx);
}

pub fn scroll_mouse_impl(cx: &mut Context, evt: &MouseEvent, dir: Direction, _: &mut EditorView) {
let current_view = cx.editor.tree.focus;

Choose a reason for hiding this comment

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

Should we check if a picker has the focus?

currently the mouse wheel does not scroll the code preview in the picker, but the code in the current buffer.

match pos_and_view(cx.editor, evt.row, evt.column, false) {
Some((_, view_id)) => cx.editor.tree.focus = view_id,
None => return,
}
super::scroll(cx, cx.editor.config().scroll_lines.unsigned_abs(), dir);
cx.editor.tree.focus = current_view;
cx.editor.ensure_cursor_in_view(current_view);
}

pub fn scroll_up_mouse(cx: &mut Context, evt: &MouseEvent, ev: &mut EditorView) {
scroll_mouse_impl(cx, evt, Direction::Backward, ev)
}

pub fn scroll_down_mouse(cx: &mut Context, evt: &MouseEvent, ev: &mut EditorView) {
scroll_mouse_impl(cx, evt, Direction::Forward, ev)
}

pub fn paste_primary_clipboard_before_mouse(
cx: &mut Context,
evt: &MouseEvent,
_: &mut EditorView,
) {
// if !config.middle_click_paste {
// return;
// }
let editor = &mut cx.editor;
if let Some((pos, view_id)) = pos_and_view(editor, evt.row, evt.column, true) {
let doc = doc_mut!(editor, &view!(editor, view_id).doc);
doc.set_selection(view_id, Selection::point(pos));
cx.editor.focus(view_id);
paste_primary_clipboard_before(cx)
}
}

pub fn yank_main_selection_to_primary_clipboard_mouse(
cx: &mut Context,
_: &MouseEvent,
_: &mut EditorView,
) {
let editor = &mut cx.editor;
let (view, doc) = current!(editor);
if doc
.selection(view.id)
.primary()
.slice(doc.text().slice(..))
.len_chars()
<= 1
{
return;
}

yank_primary_selection_impl(cx.editor, '*');
}

pub fn add_breakpoint_mouse(cx: &mut Context, evt: &MouseEvent, _: &mut EditorView) {
log::info!("called breakpoint adder");
let editor = &mut cx.editor;
if let Some((coords, view_id)) = gutter_coords_and_view(editor, evt.row, evt.column) {
editor.focus(view_id);

let (view, doc) = current!(cx.editor);

let path = match doc.path() {
Some(path) => path.clone(),
None => return,
};

if let Some(char_idx) =
view.pos_at_visual_coords(doc, coords.row as u16, coords.col as u16, true)
{
let line = doc.text().char_to_line(char_idx);
super::dap_toggle_breakpoint_impl(cx, path, line);
return;
}
}
}

pub fn add_selection_mouse(cx: &mut Context, evt: &MouseEvent, ev: &mut EditorView) {
handle_selection_in_buffer(
cx,
evt,
ev,
|doc: &mut Document, view_id: &ViewId, pos: usize| {
let selection = doc.selection(*view_id).clone();
doc.set_selection(*view_id, selection.push(Range::point(pos)));
},
);
}

fn dap_impl_mouse(cx: &mut Context, evt: &MouseEvent, callback: impl Fn(&mut Context)) {
let editor = &mut cx.editor;
if let Some((coords, view_id)) = gutter_coords_and_view(editor, evt.row, evt.column) {
editor.focus(view_id);

let (view, doc) = current!(editor);
if let Some(pos) =
view.pos_at_visual_coords(doc, coords.row as u16, coords.col as u16, true)
{
doc.set_selection(view_id, Selection::point(pos));
callback(cx);
}
}
}

pub fn dap_edit_condition_mouse(cx: &mut Context, evt: &MouseEvent, _: &mut EditorView) {
dap_impl_mouse(cx, evt, |cx| {
super::dap_edit_condition(cx);
})
}

pub fn dap_edit_log_mouse(cx: &mut Context, evt: &MouseEvent, _: &mut EditorView) {
dap_impl_mouse(cx, evt, |cx: &mut Context| {
super::dap_edit_log(cx);
})
}
Loading