inspect selection
This commit is contained in:
Generated
+1163
-135
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -6,4 +6,4 @@ edition = "2024"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
crossterm = "0.29.0"
|
crossterm = "0.29.0"
|
||||||
itertools = "0.14.0"
|
itertools = "0.14.0"
|
||||||
ratatui = "0.29.0"
|
ratatui = "0.30.0"
|
||||||
|
|||||||
+132
-9
@@ -1,6 +1,6 @@
|
|||||||
use std::{cmp::min, collections::hash_set::Entry, convert::identity, fs::File, io::Write, iter, mem::{replace, swap}};
|
use std::{cmp::min, collections::hash_set::Entry, convert::identity, fs::File, io::Write, iter, mem::{replace, swap}};
|
||||||
use ratatui::{style::Stylize, text::Span};
|
use ratatui::{style::Stylize, text::Span};
|
||||||
use crate::{BYTES_OF_PADDING, BYTES_PER_LINE, LINES_OF_PADDING, app::WindowSize, buffer::{Buffer, Mode, PartialAction}, cursor::Cursor, edit_action::EditAction};
|
use crate::{BYTES_OF_PADDING, BYTES_PER_LINE, LINES_OF_PADDING, app::WindowSize, buffer::{Buffer, Mode, PartialAction, Popup}, cursor::Cursor, edit_action::EditAction};
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum Action {
|
pub enum Action {
|
||||||
@@ -88,6 +88,8 @@ pub enum BufferAction {
|
|||||||
ExtendToMark,
|
ExtendToMark,
|
||||||
ExtendToNull,
|
ExtendToNull,
|
||||||
ExtendToFF,
|
ExtendToFF,
|
||||||
|
|
||||||
|
InspectSelection,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<BufferAction> for Action {
|
impl From<BufferAction> for Action {
|
||||||
@@ -193,6 +195,8 @@ impl Buffer {
|
|||||||
BufferAction::ExtendToMark => self.extend_to_mark(window_size),
|
BufferAction::ExtendToMark => self.extend_to_mark(window_size),
|
||||||
BufferAction::ExtendToNull => self.extend_to_null(window_size),
|
BufferAction::ExtendToNull => self.extend_to_null(window_size),
|
||||||
BufferAction::ExtendToFF => self.extend_to_FF(window_size),
|
BufferAction::ExtendToFF => self.extend_to_FF(window_size),
|
||||||
|
|
||||||
|
BufferAction::InspectSelection => self.inspect_selection(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -550,6 +554,7 @@ impl Buffer {
|
|||||||
.chain(&self.cursors)
|
.chain(&self.cursors)
|
||||||
.all(|cursor| {
|
.all(|cursor| {
|
||||||
bytes_to_nat(&self.contents[cursor.range()])
|
bytes_to_nat(&self.contents[cursor.range()])
|
||||||
|
.map(|nat| nat as usize)
|
||||||
.is_some_and(|offset| offset < self.contents.len())
|
.is_some_and(|offset| offset < self.contents.len())
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
@@ -566,12 +571,12 @@ impl Buffer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.primary_cursor = Cursor::at(
|
self.primary_cursor = Cursor::at(
|
||||||
bytes_to_nat(&self.contents[self.primary_cursor.range()]).unwrap()
|
bytes_to_nat(&self.contents[self.primary_cursor.range()]).unwrap() as usize
|
||||||
);
|
);
|
||||||
|
|
||||||
for cursor in &mut self.cursors {
|
for cursor in &mut self.cursors {
|
||||||
*cursor = Cursor::at(
|
*cursor = Cursor::at(
|
||||||
bytes_to_nat(&self.contents[cursor.range()]).unwrap()
|
bytes_to_nat(&self.contents[cursor.range()]).unwrap() as usize
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -589,7 +594,7 @@ impl Buffer {
|
|||||||
.chain(&self.cursors)
|
.chain(&self.cursors)
|
||||||
.all(|cursor| {
|
.all(|cursor| {
|
||||||
bytes_to_nat(&self.contents[cursor.range()])
|
bytes_to_nat(&self.contents[cursor.range()])
|
||||||
.map(|offset| mark_before(cursor.lower_bound(), &sorted_marks) + offset)
|
.map(|offset| mark_before(cursor.lower_bound(), &sorted_marks) + offset as usize)
|
||||||
.is_some_and(|offset| offset < self.contents.len())
|
.is_some_and(|offset| offset < self.contents.len())
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
@@ -608,7 +613,7 @@ impl Buffer {
|
|||||||
self.primary_cursor = Cursor::at(
|
self.primary_cursor = Cursor::at(
|
||||||
bytes_to_nat(&self.contents[self.primary_cursor.range()])
|
bytes_to_nat(&self.contents[self.primary_cursor.range()])
|
||||||
.map(|offset| {
|
.map(|offset| {
|
||||||
mark_before(self.primary_cursor.lower_bound(), &sorted_marks) + offset
|
mark_before(self.primary_cursor.lower_bound(), &sorted_marks) + offset as usize
|
||||||
})
|
})
|
||||||
.unwrap()
|
.unwrap()
|
||||||
);
|
);
|
||||||
@@ -617,7 +622,7 @@ impl Buffer {
|
|||||||
*cursor = Cursor::at(
|
*cursor = Cursor::at(
|
||||||
bytes_to_nat(&self.contents[cursor.range()])
|
bytes_to_nat(&self.contents[cursor.range()])
|
||||||
.map(|offset| {
|
.map(|offset| {
|
||||||
mark_before(cursor.lower_bound(), &sorted_marks) + offset
|
mark_before(cursor.lower_bound(), &sorted_marks) + offset as usize
|
||||||
})
|
})
|
||||||
.unwrap()
|
.unwrap()
|
||||||
);
|
);
|
||||||
@@ -745,6 +750,101 @@ impl Buffer {
|
|||||||
|
|
||||||
self.clamp_screen_to_primary_cursor(window_size);
|
self.clamp_screen_to_primary_cursor(window_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn inspect_selection(&mut self) {
|
||||||
|
if self.inspecting_selection { return; }
|
||||||
|
|
||||||
|
self.inspecting_selection = true;
|
||||||
|
|
||||||
|
self.popups.extend(
|
||||||
|
iter::once(&self.primary_cursor)
|
||||||
|
.chain(&self.cursors)
|
||||||
|
.map(|cursor| {
|
||||||
|
let selection = &self.contents[cursor.range()];
|
||||||
|
|
||||||
|
let nat = bytes_to_nat(selection);
|
||||||
|
|
||||||
|
let int = nat.and_then(|nat| nat_to_int_if_different(nat, selection.len()));
|
||||||
|
|
||||||
|
let utf8 = str::from_utf8(selection).ok()
|
||||||
|
.and_then(|utf8| {
|
||||||
|
if utf8.contains(|char: char| char.is_ascii() && !char.is_ascii_graphic()) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(utf8)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(|utf8| utf8.replace('\0', "\\0"));
|
||||||
|
|
||||||
|
#[allow(clippy::cast_precision_loss)]
|
||||||
|
let fixedpoint2012 = nat
|
||||||
|
.and_then(|nat| (selection.len() == 4).then(|| nat as f64 / f64::from(1 << 12)))
|
||||||
|
.map(|fixedpoint2012| {
|
||||||
|
let two_decimals_is_enough = (fixedpoint2012 * 100.0).fract() == 0.0;
|
||||||
|
let approximate_symbol = if two_decimals_is_enough { "" } else { "~" };
|
||||||
|
|
||||||
|
format!("20.12: {approximate_symbol}{fixedpoint2012:.2}")
|
||||||
|
});
|
||||||
|
|
||||||
|
#[allow(clippy::cast_precision_loss)]
|
||||||
|
let fixedpoint1616 = nat
|
||||||
|
.and_then(|nat| (selection.len() == 4).then(|| nat as f64 / f64::from(1 << 16)))
|
||||||
|
.map(|fixedpoint1616| {
|
||||||
|
let two_decimals_is_enough = (fixedpoint1616 * 100.0).fract() == 0.0;
|
||||||
|
let approximate_symbol = if two_decimals_is_enough { "" } else { "~" };
|
||||||
|
|
||||||
|
format!("16.16: {approximate_symbol}{fixedpoint1616:.2}")
|
||||||
|
});
|
||||||
|
|
||||||
|
#[allow(clippy::cast_precision_loss)]
|
||||||
|
let fixedpoint124 = nat
|
||||||
|
.and_then(|nat| (selection.len() == 2).then(|| nat as f64 / f64::from(1 << 4)))
|
||||||
|
.map(|fixedpoint124| {
|
||||||
|
let two_decimals_is_enough = (fixedpoint124 * 100.0).fract() == 0.0;
|
||||||
|
let approximate_symbol = if two_decimals_is_enough { "" } else { "~" };
|
||||||
|
|
||||||
|
format!("12.4: {approximate_symbol}{fixedpoint124:.2}")
|
||||||
|
});
|
||||||
|
|
||||||
|
#[allow(clippy::cast_precision_loss)]
|
||||||
|
let fixedpoint88 = nat
|
||||||
|
.and_then(|nat| (selection.len() == 2).then(|| nat as f64 / f64::from(1 << 8)))
|
||||||
|
.map(|fixedpoint88| {
|
||||||
|
let two_decimals_is_enough = (fixedpoint88 * 100.0).fract() == 0.0;
|
||||||
|
let approximate_symbol = if two_decimals_is_enough { "" } else { "~" };
|
||||||
|
|
||||||
|
format!("8.8: {approximate_symbol}{fixedpoint88:.2}")
|
||||||
|
});
|
||||||
|
|
||||||
|
#[allow(clippy::cast_precision_loss)]
|
||||||
|
let fixedpoint412 = nat
|
||||||
|
.and_then(|nat| (selection.len() == 2).then(|| nat as f64 / f64::from(1 << 12)))
|
||||||
|
.map(|fixedpoint412| {
|
||||||
|
let two_decimals_is_enough = (fixedpoint412 * 100.0).fract() == 0.0;
|
||||||
|
let approximate_symbol = if two_decimals_is_enough { "" } else { "~" };
|
||||||
|
|
||||||
|
format!("4.12: {approximate_symbol}{fixedpoint412:.2}")
|
||||||
|
});
|
||||||
|
|
||||||
|
let color = (selection.len() == 3).then(|| [selection[0], selection[1], selection[2]]);
|
||||||
|
|
||||||
|
Popup::new(
|
||||||
|
cursor.lower_bound(),
|
||||||
|
int.map(|int| format!("{int}"))
|
||||||
|
.into_iter()
|
||||||
|
.chain(nat.map(|nat| format!("{nat}")))
|
||||||
|
.chain(utf8.map(|utf8| format!("\"{utf8}\"")))
|
||||||
|
.chain(fixedpoint2012)
|
||||||
|
.chain(fixedpoint1616)
|
||||||
|
.chain(fixedpoint124)
|
||||||
|
.chain(fixedpoint88)
|
||||||
|
.chain(fixedpoint412)
|
||||||
|
.collect(),
|
||||||
|
color
|
||||||
|
)
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// helpers
|
// helpers
|
||||||
@@ -758,16 +858,39 @@ impl Buffer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bytes_to_nat(bytes: &[u8]) -> Option<usize> {
|
pub fn bytes_to_nat(bytes: &[u8]) -> Option<u64> {
|
||||||
bytes
|
bytes
|
||||||
.iter()
|
.iter()
|
||||||
.rev() // little-endian
|
.rev() // little-endian
|
||||||
.skip_while(|&&byte| byte == 0)
|
.skip_while(|&&byte| byte == 0)
|
||||||
.try_fold(usize::default(), |result, &byte| {
|
.try_fold(u64::default(), |result, &byte| {
|
||||||
Some(result.shl_exact(8)? | (byte as usize))
|
Some(result.shl_exact(8)? | u64::from(byte))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fn nat_to_int_if_different(nat: u64, bytes: usize) -> Option<i64> {
|
||||||
|
match bytes {
|
||||||
|
1 if nat > i8::MAX as u64 => Some((nat as u8).cast_signed() as i64),
|
||||||
|
2 if nat > i16::MAX as u64 => Some((nat as u16).cast_signed() as i64),
|
||||||
|
4 if nat > i32::MAX as u64 => Some((nat as u32).cast_signed() as i64),
|
||||||
|
8 if nat > i64::MAX as u64 => Some(nat.cast_signed()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn nat_to_int_tests() {
|
||||||
|
assert_eq!(nat_to_int_if_different(0, 1), None);
|
||||||
|
assert_eq!(nat_to_int_if_different(i8::MAX as u64, 1), None);
|
||||||
|
assert_eq!(nat_to_int_if_different(i8::MAX as u64 + 1, 1), Some(i8::MIN as i64));
|
||||||
|
assert_eq!(nat_to_int_if_different(u8::MAX as u64, 1), Some(-1));
|
||||||
|
|
||||||
|
assert_eq!(nat_to_int_if_different(0, 2), None);
|
||||||
|
assert_eq!(nat_to_int_if_different(i16::MAX as u64, 2), None);
|
||||||
|
assert_eq!(nat_to_int_if_different(i16::MAX as u64 + 1, 2), Some(i16::MIN as i64));
|
||||||
|
assert_eq!(nat_to_int_if_different(u16::MAX as u64, 2), Some(-1));
|
||||||
|
}
|
||||||
|
|
||||||
// or 0 if no mark is before
|
// or 0 if no mark is before
|
||||||
fn mark_before(offset: usize, sorted_marks: &[usize]) -> usize {
|
fn mark_before(offset: usize, sorted_marks: &[usize]) -> usize {
|
||||||
match sorted_marks.binary_search(&offset) {
|
match sorted_marks.binary_search(&offset) {
|
||||||
|
|||||||
+69
-1
@@ -1,7 +1,7 @@
|
|||||||
use core::slice::GetDisjointMutIndex;
|
use core::slice::GetDisjointMutIndex;
|
||||||
use std::{collections::HashSet, fs::File, io::Read, path::PathBuf};
|
use std::{collections::HashSet, fs::File, io::Read, path::PathBuf};
|
||||||
use crossterm::event::KeyEvent;
|
use crossterm::event::KeyEvent;
|
||||||
use ratatui::{style::{Color, Stylize}, text::Span};
|
use ratatui::{layout::Rect, style::{Color, Stylize}, text::Span, widgets::Widget};
|
||||||
use crate::{BYTES_PER_LINE, action::{Action, AppAction, bytes_to_nat}, app::WindowSize, config::Config, cursor::Cursor, edit_action::EditAction};
|
use crate::{BYTES_PER_LINE, action::{Action, AppAction, bytes_to_nat}, app::WindowSize, config::Config, cursor::Cursor, edit_action::EditAction};
|
||||||
|
|
||||||
mod widget;
|
mod widget;
|
||||||
@@ -23,6 +23,9 @@ pub struct Buffer {
|
|||||||
pub partial_replace: Option<u8>,
|
pub partial_replace: Option<u8>,
|
||||||
|
|
||||||
pub alert_message: Span<'static>,
|
pub alert_message: Span<'static>,
|
||||||
|
pub popups: Vec<Popup>,
|
||||||
|
|
||||||
|
pub inspecting_selection: bool,
|
||||||
|
|
||||||
pub edit_history: Vec<EditAction>,
|
pub edit_history: Vec<EditAction>,
|
||||||
// the index *after* the latest edit action
|
// the index *after* the latest edit action
|
||||||
@@ -43,6 +46,14 @@ pub enum PartialAction {
|
|||||||
Goto, View, Replace, Space, Repeat, To
|
Goto, View, Replace, Space, Repeat, To
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Popup {
|
||||||
|
at: usize,
|
||||||
|
width: u16,
|
||||||
|
lines: Vec<String>,
|
||||||
|
color: Option<[u8; 3]>
|
||||||
|
}
|
||||||
|
|
||||||
impl Mode {
|
impl Mode {
|
||||||
pub const fn label(self) -> &'static str {
|
pub const fn label(self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
@@ -74,6 +85,53 @@ impl PartialAction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Popup {
|
||||||
|
pub fn new(at: usize, lines: Vec<String>, color: Option<[u8; 3]>) -> Self {
|
||||||
|
Self {
|
||||||
|
at,
|
||||||
|
width: lines
|
||||||
|
.iter()
|
||||||
|
.map(|line| line.len() as u16)
|
||||||
|
.chain(color.map(|_| 7))
|
||||||
|
.max()
|
||||||
|
.unwrap_or(0),
|
||||||
|
lines,
|
||||||
|
color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn area_at(&self, x: u16, y: u16) -> Rect {
|
||||||
|
Rect {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
width: self.width + 2,
|
||||||
|
height: self.lines.len() as u16 + u16::from(self.color.is_some())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Widget for Popup {
|
||||||
|
fn render(self, area: Rect, buf: &mut ratatui::prelude::Buffer) {
|
||||||
|
let width = self.width as usize;
|
||||||
|
|
||||||
|
for (line, area) in self.lines.iter().zip(area.rows()) {
|
||||||
|
Span::from(format!(" {line:^width$} "))
|
||||||
|
.white()
|
||||||
|
.on_dark_gray()
|
||||||
|
.render(area, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some([red, green, blue]) = self.color {
|
||||||
|
let color_code = format!("#{red:02X}{green:02X}{blue:02X}");
|
||||||
|
|
||||||
|
Span::from(format!(" {color_code:^width$} "))
|
||||||
|
.fg(Color::Rgb(red, green, blue))
|
||||||
|
.on_dark_gray()
|
||||||
|
.render(area.rows().next_back().unwrap(), buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Buffer {
|
impl Buffer {
|
||||||
pub fn new(file_path: PathBuf) -> Self {
|
pub fn new(file_path: PathBuf) -> Self {
|
||||||
let file = File::open(&file_path);
|
let file = File::open(&file_path);
|
||||||
@@ -97,6 +155,9 @@ impl Buffer {
|
|||||||
partial_replace: None,
|
partial_replace: None,
|
||||||
|
|
||||||
alert_message: "".into(),
|
alert_message: "".into(),
|
||||||
|
popups: Vec::new(),
|
||||||
|
|
||||||
|
inspecting_selection: false,
|
||||||
|
|
||||||
edit_history: Vec::new(),
|
edit_history: Vec::new(),
|
||||||
time_traveling: None,
|
time_traveling: None,
|
||||||
@@ -115,6 +176,9 @@ impl Buffer {
|
|||||||
window_size: WindowSize
|
window_size: WindowSize
|
||||||
) -> Option<AppAction> {
|
) -> Option<AppAction> {
|
||||||
self.alert_message = "".into();
|
self.alert_message = "".into();
|
||||||
|
self.popups.clear();
|
||||||
|
|
||||||
|
let was_inspecting_selection = self.inspecting_selection;
|
||||||
|
|
||||||
let app_action = match self.partial_action {
|
let app_action = match self.partial_action {
|
||||||
Some(PartialAction::Replace) => {
|
Some(PartialAction::Replace) => {
|
||||||
@@ -134,6 +198,10 @@ impl Buffer {
|
|||||||
_ => self.handle_other_modes(event, config, window_size),
|
_ => self.handle_other_modes(event, config, window_size),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if was_inspecting_selection {
|
||||||
|
self.inspecting_selection = false;
|
||||||
|
}
|
||||||
|
|
||||||
assert!(self.scroll_position.is_multiple_of(BYTES_PER_LINE));
|
assert!(self.scroll_position.is_multiple_of(BYTES_PER_LINE));
|
||||||
assert!(self.scroll_position < self.contents.len());
|
assert!(self.scroll_position < self.contents.len());
|
||||||
assert!(self.primary_cursor.head < self.contents.len());
|
assert!(self.primary_cursor.head < self.contents.len());
|
||||||
|
|||||||
@@ -43,6 +43,22 @@ impl Widget for &Buffer {
|
|||||||
.right_aligned()
|
.right_aligned()
|
||||||
.render(status_line_area, buf);
|
.render(status_line_area, buf);
|
||||||
|
|
||||||
|
for popup in &self.popups {
|
||||||
|
if self.scroll_position <= popup.at &&
|
||||||
|
popup.at < self.scroll_position + (hex_area.height.saturating_sub(1) as usize * BYTES_PER_LINE)
|
||||||
|
{
|
||||||
|
let position_on_screen = popup.at - self.scroll_position;
|
||||||
|
let hex_column = position_on_screen % BYTES_PER_LINE;
|
||||||
|
|
||||||
|
let popup_area = popup.area_at(
|
||||||
|
area.x + byte_column_to_screen_column(hex_column) as u16,
|
||||||
|
area.y + (position_on_screen / BYTES_PER_LINE) as u16 + 1
|
||||||
|
);
|
||||||
|
|
||||||
|
popup.clone().render(popup_area, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// if self.partial_action == Some(PartialAction::Space) {
|
// if self.partial_action == Some(PartialAction::Space) {
|
||||||
// let input_field_area = Rect::new(area.x, area.bottom() - 2, area.width, 1);
|
// let input_field_area = Rect::new(area.x, area.bottom() - 2, area.width, 1);
|
||||||
// Span::from("/0F673 ")
|
// Span::from("/0F673 ")
|
||||||
@@ -459,3 +475,29 @@ mod extra_statuses {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn byte_column_to_screen_column(byte_column: usize) -> usize {
|
||||||
|
match byte_column {
|
||||||
|
0 => 10,
|
||||||
|
1 => 13,
|
||||||
|
2 => 16,
|
||||||
|
3 => 19,
|
||||||
|
|
||||||
|
4 => 23,
|
||||||
|
5 => 26,
|
||||||
|
6 => 29,
|
||||||
|
7 => 32,
|
||||||
|
|
||||||
|
8 => 36,
|
||||||
|
9 => 39,
|
||||||
|
10 => 42,
|
||||||
|
11 => 45,
|
||||||
|
|
||||||
|
12 => 49,
|
||||||
|
13 => 52,
|
||||||
|
14 => 55,
|
||||||
|
15 => 58,
|
||||||
|
|
||||||
|
_ => panic!("byte column must be less than 16"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -167,6 +167,8 @@ impl Default for Config {
|
|||||||
("m".try_into().unwrap(), BufferAction::ToggleMark.into()),
|
("m".try_into().unwrap(), BufferAction::ToggleMark.into()),
|
||||||
|
|
||||||
("y".try_into().unwrap(), AppAction::Yank.into()),
|
("y".try_into().unwrap(), AppAction::Yank.into()),
|
||||||
|
|
||||||
|
("C- ".try_into().unwrap(), BufferAction::InspectSelection.into()),
|
||||||
].into()),
|
].into()),
|
||||||
(Some(PartialAction::Goto), [
|
(Some(PartialAction::Goto), [
|
||||||
("j".try_into().unwrap(), CursorAction::GotoLineStart.into()),
|
("j".try_into().unwrap(), CursorAction::GotoLineStart.into()),
|
||||||
@@ -281,6 +283,8 @@ impl Default for Config {
|
|||||||
("m".try_into().unwrap(), BufferAction::ToggleMark.into()),
|
("m".try_into().unwrap(), BufferAction::ToggleMark.into()),
|
||||||
|
|
||||||
("y".try_into().unwrap(), AppAction::Yank.into()),
|
("y".try_into().unwrap(), AppAction::Yank.into()),
|
||||||
|
|
||||||
|
("C- ".try_into().unwrap(), BufferAction::InspectSelection.into()),
|
||||||
].into()),
|
].into()),
|
||||||
(Some(PartialAction::View), [
|
(Some(PartialAction::View), [
|
||||||
("z".try_into().unwrap(), BufferAction::AlignViewCenter.into()),
|
("z".try_into().unwrap(), BufferAction::AlignViewCenter.into()),
|
||||||
|
|||||||
+4
-2
@@ -26,7 +26,9 @@ const LINES_OF_PADDING: usize = 5;
|
|||||||
const BYTES_OF_PADDING: usize = LINES_OF_PADDING * BYTES_PER_LINE;
|
const BYTES_OF_PADDING: usize = LINES_OF_PADDING * BYTES_PER_LINE;
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// - inspect selection
|
// - 4 with large selection crashes
|
||||||
|
// - also (/)
|
||||||
|
// - also C-F in excavate_defs
|
||||||
// - diffing
|
// - diffing
|
||||||
// - search
|
// - search
|
||||||
// - s/A-k/A-K
|
// - s/A-k/A-K
|
||||||
@@ -43,7 +45,7 @@ const BYTES_OF_PADDING: usize = LINES_OF_PADDING * BYTES_PER_LINE;
|
|||||||
// - if jump to panel, space?
|
// - if jump to panel, space?
|
||||||
// - visual gg/G
|
// - visual gg/G
|
||||||
// - jumplist
|
// - jumplist
|
||||||
// - y/p
|
// - p
|
||||||
// - [/] to cycle view offset?
|
// - [/] to cycle view offset?
|
||||||
// - gj jump to entered offset
|
// - gj jump to entered offset
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user