mirror of
https://github.com/lotabout/skim.git
synced 2026-09-10 07:16:23 -04:00
[keymap] add keys/actions to manipulate matched items.
This commit is contained in:
parent
d99d04dc52
commit
34de0879c3
|
|
@ -459,7 +459,7 @@ fn get_default_key_map() -> HashMap<Key, Event> {
|
|||
|
||||
ret.insert(Key::CtrlK, Event::EvActKillLine);
|
||||
ret.insert(Key::AltD, Event::EvActKillWord);
|
||||
ret.insert(Key::CtrlN, Event::EvActNextHistory);
|
||||
//ret.insert(Key::CtrlN, Event::EvActNextHistory);
|
||||
ret.insert(Key::PgDn, Event::EvActPageDown);
|
||||
ret.insert(Key::PgUp, Event::EvActPageUp);
|
||||
ret.insert(Key::CtrlP, Event::EvActPreviousHistory);
|
||||
|
|
|
|||
74
src/main.rs
74
src/main.rs
|
|
@ -160,51 +160,55 @@ fn main() {
|
|||
Event::EvActAbort => { break 'outer; }
|
||||
Event::EvActAccept => {
|
||||
// break out of the loop and output the selected item.
|
||||
if model.get_num_selected() <= 0 { model.act_toggle_select(Some(true)); }
|
||||
if model.get_num_selected() <= 0 { model.act_toggle(Some(true)); }
|
||||
break 'outer;
|
||||
}
|
||||
Event::EvActBackwardChar => { model.act_backward_char(); }
|
||||
Event::EvActBackwardDeleteChar => { model.act_backward_delete_char(); }
|
||||
Event::EvActBackwardKillWord => {model.act_backward_kill_word();}
|
||||
Event::EvActBackwardWord => {model.act_backward_word();}
|
||||
Event::EvActBeginningOfLine => {model.act_beginning_of_line();}
|
||||
Event::EvActCancel => {}
|
||||
Event::EvActClearScreen => {}
|
||||
Event::EvActDeleteChar => {model.act_delete_char();}
|
||||
Event::EvActDeleteCharEOF => {model.act_delete_char();}
|
||||
Event::EvActDeselectAll => {}
|
||||
Event::EvActDown => { model.act_move_line_cursor(1); }
|
||||
Event::EvActEndOfLine => {model.act_end_of_line();}
|
||||
Event::EvActForwardChar => {model.act_forward_char();}
|
||||
Event::EvActForwardWord => {model.act_forward_word();}
|
||||
Event::EvActIgnore => {}
|
||||
Event::EvActKillLine => {model.act_kill_line();}
|
||||
Event::EvActKillWord => {model.act_kill_word();}
|
||||
Event::EvActNextHistory => {}
|
||||
Event::EvActPageDown => {}
|
||||
Event::EvActPageUp => {}
|
||||
Event::EvActPreviousHistory => {}
|
||||
Event::EvActSelectAll => {}
|
||||
Event::EvActToggle => {}
|
||||
Event::EvActToggleAll => {}
|
||||
Event::EvActToggleDown => {
|
||||
model.act_toggle_select(None);
|
||||
Event::EvActBackwardChar => {model.act_backward_char();}
|
||||
Event::EvActBackwardDeleteChar => {model.act_backward_delete_char();}
|
||||
Event::EvActBackwardKillWord => {model.act_backward_kill_word();}
|
||||
Event::EvActBackwardWord => {model.act_backward_word();}
|
||||
Event::EvActBeginningOfLine => {model.act_beginning_of_line();}
|
||||
Event::EvActCancel => {}
|
||||
Event::EvActClearScreen => {model.refresh();}
|
||||
Event::EvActDeleteChar => {model.act_delete_char();}
|
||||
Event::EvActDeleteCharEOF => {model.act_delete_char();}
|
||||
Event::EvActDeselectAll => {model.act_deselect_all();}
|
||||
Event::EvActDown => {model.act_move_line_cursor(-1);}
|
||||
Event::EvActEndOfLine => {model.act_end_of_line();}
|
||||
Event::EvActForwardChar => {model.act_forward_char();}
|
||||
Event::EvActForwardWord => {model.act_forward_word();}
|
||||
Event::EvActIgnore => {}
|
||||
Event::EvActKillLine => {model.act_kill_line();}
|
||||
Event::EvActKillWord => {model.act_kill_word();}
|
||||
Event::EvActNextHistory => {}
|
||||
Event::EvActPageDown => {model.act_move_page(-1);}
|
||||
Event::EvActPageUp => {model.act_move_page(1);}
|
||||
Event::EvActPreviousHistory => {}
|
||||
Event::EvActSelectAll => {model.act_select_all();}
|
||||
Event::EvActToggle => {model.act_toggle(None);}
|
||||
Event::EvActToggleAll => {model.act_toggle_all();}
|
||||
Event::EvActToggleDown => {
|
||||
model.act_toggle(None);
|
||||
model.act_move_line_cursor(-1);
|
||||
}
|
||||
Event::EvActToggleIn => {}
|
||||
Event::EvActToggleOut => {}
|
||||
Event::EvActToggleSort => {}
|
||||
Event::EvActToggleUp => {
|
||||
model.act_toggle(None);
|
||||
model.act_move_line_cursor(1);
|
||||
}
|
||||
Event::EvActToggleIn => {}
|
||||
Event::EvActToggleOut => {}
|
||||
Event::EvActToggleSort => {}
|
||||
Event::EvActToggleUp => {}
|
||||
Event::EvActUnixLineDiscard => {model.act_line_discard();}
|
||||
Event::EvActUnixWordRubout => {model.act_backward_kill_word();}
|
||||
Event::EvActUp => { model.act_move_line_cursor(-1); }
|
||||
Event::EvActYank => {}
|
||||
Event::EvActUnixLineDiscard => {model.act_line_discard();}
|
||||
Event::EvActUnixWordRubout => {model.act_backward_kill_word();}
|
||||
Event::EvActUp => {model.act_move_line_cursor(1);}
|
||||
Event::EvActYank => {}
|
||||
|
||||
_ => {
|
||||
printw(format!("{}\n", e as i32).as_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
thread::sleep(Duration::from_millis(10));
|
||||
model.display();
|
||||
if need_refresh {
|
||||
|
|
|
|||
130
src/model.rs
130
src/model.rs
|
|
@ -13,6 +13,23 @@ use curses::*;
|
|||
use query::Query;
|
||||
use util::eventbox::EventBox;
|
||||
use event::Event;
|
||||
use std::mem;
|
||||
|
||||
// The whole screen is:
|
||||
//
|
||||
// +---------------------------------------|
|
||||
// | | | | 5
|
||||
// | | | ^ | 4
|
||||
// current cursor |>| | | | 3
|
||||
// | | | lines | | 2 cursor
|
||||
// selected | |>|-------------------------------- | 1
|
||||
// | | | | 0
|
||||
// +---------------------------------------+
|
||||
// spinner |/| | (matched/total) (per%) [selected] |
|
||||
// +---------------------------------------+
|
||||
// | prompt> query string |
|
||||
// +---------------------------------------+
|
||||
//
|
||||
|
||||
pub struct Model {
|
||||
eb: Arc<EventBox<Event>>,
|
||||
|
|
@ -27,9 +44,12 @@ pub struct Model {
|
|||
|
||||
item_cursor: usize, // the index of matched item currently highlighted.
|
||||
line_cursor: usize, // line No.
|
||||
item_start_pos: usize, // for screen scroll.
|
||||
hscroll_offset: usize,
|
||||
|
||||
max_y: i32,
|
||||
max_x: i32,
|
||||
width: usize,
|
||||
height: usize,
|
||||
|
||||
curses: Curses,
|
||||
}
|
||||
|
|
@ -48,10 +68,12 @@ impl Model {
|
|||
matched_items: RefCell::new(OrderedVec::new()),
|
||||
processed_percentage: 100,
|
||||
item_cursor: 0,
|
||||
line_cursor: (max_y - 3) as usize,
|
||||
item_start_pos: 0,
|
||||
line_cursor: 0,
|
||||
hscroll_offset: 0,
|
||||
max_y: max_y,
|
||||
max_x: max_x,
|
||||
width: (max_x - 2) as usize,
|
||||
height: (max_y - 2) as usize,
|
||||
curses: curses,
|
||||
}
|
||||
}
|
||||
|
|
@ -89,8 +111,9 @@ impl Model {
|
|||
|
||||
pub fn print_info(&self) {
|
||||
mv(self.max_y-2, 0);
|
||||
addstr(format!(" {}/{}{}", self.num_matched, self.num_total,
|
||||
if self.processed_percentage == 100 {"".to_string()} else {format!("({}%)", self.processed_percentage)}
|
||||
addstr(format!(" {}/{}{} [{}/{}/{}]", self.num_matched, self.num_total,
|
||||
if self.processed_percentage == 100 {"".to_string()} else {format!("({}%)", self.processed_percentage)},
|
||||
self.line_cursor, self.height, self.item_cursor
|
||||
).as_str());
|
||||
}
|
||||
|
||||
|
|
@ -147,23 +170,17 @@ impl Model {
|
|||
|
||||
pub fn print_items(&self) {
|
||||
let mut matched_items = self.matched_items.borrow_mut();
|
||||
let item_start_pos = self.item_cursor - self.line_cursor;
|
||||
|
||||
let mut y = self.max_y - 3;
|
||||
let mut i = self.item_start_pos;
|
||||
while let Some(matched) = matched_items.get(i) {
|
||||
i+=1;
|
||||
for i in 0..self.height {
|
||||
if let Some(matched) = matched_items.get(item_start_pos + i) {
|
||||
mv((self.height - i - 1) as i32, 0);
|
||||
|
||||
mv(y, 0);
|
||||
let is_current_line = y == self.line_cursor as i32;
|
||||
|
||||
let label = if is_current_line {">"} else {" "};
|
||||
|
||||
self.curses.cprint(COLOR_CURSOR, true, label);
|
||||
|
||||
self.print_item(matched, is_current_line);
|
||||
|
||||
y -= 1;
|
||||
if y < 0 {
|
||||
let is_current_line = i == self.line_cursor;
|
||||
let label = if is_current_line {">"} else {" "};
|
||||
self.curses.cprint(COLOR_CURSOR, true, label);
|
||||
self.print_item(matched, is_current_line);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -232,6 +249,10 @@ impl Model {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn act_deselect_all(&mut self) {
|
||||
self.selected_indics.clear();
|
||||
}
|
||||
|
||||
pub fn act_end_of_line(&mut self) {
|
||||
let _ = self.query.end_of_line();
|
||||
}
|
||||
|
|
@ -265,7 +286,24 @@ impl Model {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn act_toggle_select(&mut self, selected: Option<bool>) {
|
||||
pub fn act_select_all(&mut self) {
|
||||
let mut matched_items = self.matched_items.borrow_mut();
|
||||
for i in 0..matched_items.len() {
|
||||
self.selected_indics.insert(i);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn act_toggle_all(&mut self) {
|
||||
let mut matched_items = self.matched_items.borrow_mut();
|
||||
let selected = mem::replace(&mut self.selected_indics, HashSet::new());
|
||||
for i in 0..matched_items.len() {
|
||||
if !selected.contains(&i) {
|
||||
self.selected_indics.insert(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn act_toggle(&mut self, selected: Option<bool>) {
|
||||
let mut matched_items = self.matched_items.borrow_mut();
|
||||
let matched = matched_items.get(self.item_cursor);
|
||||
if matched == None {
|
||||
|
|
@ -295,32 +333,30 @@ impl Model {
|
|||
}
|
||||
|
||||
pub fn act_move_line_cursor(&mut self, diff: i32) {
|
||||
let total_item = self.matched_items.borrow().len() as i32;
|
||||
|
||||
let y = self.line_cursor as i32 + diff;
|
||||
let item_y = max(0, self.item_cursor as i32 - diff);
|
||||
let screen_height = (self.max_y - 3) as usize;
|
||||
self.line_cursor = if diff > 0 {
|
||||
let tmp = min(min(y, (self.height as i32) -1), total_item-1);
|
||||
if tmp < 0 {0} else {tmp as usize}
|
||||
} else {
|
||||
max(0, y) as usize
|
||||
};
|
||||
|
||||
match y {
|
||||
y if y < 0 => {
|
||||
self.line_cursor = 0;
|
||||
self.item_cursor = min(item_y as usize, self.matched_items.borrow().len()-1);
|
||||
self.item_start_pos = self.item_cursor - screen_height;
|
||||
}
|
||||
|
||||
y if y > screen_height as i32 => {
|
||||
self.line_cursor = screen_height;
|
||||
self.item_cursor = max(0, item_y as usize);
|
||||
self.item_start_pos = self.item_cursor;
|
||||
}
|
||||
|
||||
y => {
|
||||
self.line_cursor = y as usize;
|
||||
self.item_cursor = item_y as usize;
|
||||
}
|
||||
let item_y = self.item_cursor as i32 + diff;
|
||||
self.item_cursor = if diff > 0 {
|
||||
let tmp = min(item_y, total_item-1);
|
||||
if tmp < 0 {0} else {tmp as usize}
|
||||
} else {
|
||||
max(0, item_y) as usize
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn act_move_page(&mut self, pages: i32) {
|
||||
let lines = (self.height as i32) * pages;
|
||||
self.act_move_line_cursor(lines);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -334,31 +370,31 @@ fn display_width(text: &[char]) -> usize {
|
|||
}
|
||||
|
||||
|
||||
// calculate from left to right, stop when the width exceeds
|
||||
fn left_fixed(text: &[char], width: usize) -> usize {
|
||||
if width <= 0 {
|
||||
// calculate from left to right, stop when the max_x exceeds
|
||||
fn left_fixed(text: &[char], max_x: usize) -> usize {
|
||||
if max_x <= 0 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let mut w = 0;
|
||||
for (idx, &c) in text.iter().enumerate() {
|
||||
w += if c.len_utf8() > 1 {2} else {1};
|
||||
if w > width {
|
||||
if w > max_x {
|
||||
return idx-1;
|
||||
}
|
||||
}
|
||||
return text.len()-1;
|
||||
}
|
||||
|
||||
fn right_fixed(text: &[char], width: usize) -> usize {
|
||||
if width <= 0 {
|
||||
fn right_fixed(text: &[char], max_x: usize) -> usize {
|
||||
if max_x <= 0 {
|
||||
return text.len()-1;
|
||||
}
|
||||
|
||||
let mut w = 0;
|
||||
for (idx, &c) in text.iter().enumerate().rev() {
|
||||
w += if c.len_utf8() > 1 {2} else {1};
|
||||
if w > width {
|
||||
if w > max_x {
|
||||
return idx+1;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue