Added SelectToken action
This commit is contained in:
parent
3e3755c0b5
commit
8bd6a70968
4 changed files with 87 additions and 18 deletions
|
|
@ -32,6 +32,7 @@ pub enum Action {
|
||||||
OpenFile(PathBuf), // Open the file and switch the current pane to it
|
OpenFile(PathBuf), // Open the file and switch the current pane to it
|
||||||
CommandStart(&'static str), // Start a new command
|
CommandStart(&'static str), // Start a new command
|
||||||
GotoLine(isize), // Go to the specified file line
|
GotoLine(isize), // Go to the specified file line
|
||||||
|
SelectToken, // Fully select the token under the cursor
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -174,6 +175,22 @@ impl RawEvent {
|
||||||
Some(Action::Move(dir, page, retain_base))
|
Some(Action::Move(dir, page, retain_base))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_select_token(&self) -> Option<Action> {
|
||||||
|
if matches!(
|
||||||
|
&self.0,
|
||||||
|
TerminalEvent::Key(KeyEvent {
|
||||||
|
code: KeyCode::Char(' '),
|
||||||
|
modifiers: KeyModifiers::CONTROL,
|
||||||
|
kind: KeyEventKind::Press,
|
||||||
|
..
|
||||||
|
})
|
||||||
|
) {
|
||||||
|
Some(Action::SelectToken)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn to_open_prompt(&self) -> Option<Action> {
|
pub fn to_open_prompt(&self) -> Option<Action> {
|
||||||
if matches!(
|
if matches!(
|
||||||
&self.0,
|
&self.0,
|
||||||
|
|
|
||||||
|
|
@ -85,8 +85,12 @@ impl Highlighter {
|
||||||
|
|
||||||
pub fn rust() -> Self {
|
pub fn rust() -> Self {
|
||||||
Self::new_from_regex([
|
Self::new_from_regex([
|
||||||
(TokenKind::Doc, r"\/\/[\/!][^\n]*$"),
|
// Both kinds of comments match multiple lines
|
||||||
(TokenKind::Comment, r"\/\/[^$]*$"),
|
(
|
||||||
|
TokenKind::Doc,
|
||||||
|
r"\/\/[\/!][^\n]*$(\n[[:space:]]\/\/[\/!][^\n]*$)*",
|
||||||
|
),
|
||||||
|
(TokenKind::Comment, r"\/\/[^$]*$(\n[[:space:]]\/\/[^$]*$)*"),
|
||||||
// Multi-line comment
|
// Multi-line comment
|
||||||
(TokenKind::Comment, r"\/\*[^(\*\/)]*\*\/"),
|
(TokenKind::Comment, r"\/\*[^(\*\/)]*\*\/"),
|
||||||
(
|
(
|
||||||
|
|
@ -105,7 +109,7 @@ impl Highlighter {
|
||||||
// Primitives
|
// Primitives
|
||||||
(
|
(
|
||||||
TokenKind::Type,
|
TokenKind::Type,
|
||||||
r"\b[(u8)(u16)(u32)(u64)(u128)(i8)(i16)(i32)(i64)(i128)(usize)(isize)(bool)(str)(char)]\b",
|
r"\b[(u8)(u16)(u32)(u64)(u128)(i8)(i16)(i32)(i64)(i128)(usize)(isize)(bool)(str)(char)(f16)(f32)(f64)(f128)]\b",
|
||||||
),
|
),
|
||||||
// "foo" or b"foo" or r#"foo"#
|
// "foo" or b"foo" or r#"foo"#
|
||||||
(TokenKind::String, r#"b?r?(#*)@("[(\\")[^("~)]]*("~))"#),
|
(TokenKind::String, r#"b?r?(#*)@("[(\\")[^("~)]]*("~))"#),
|
||||||
|
|
@ -132,7 +136,7 @@ impl Highlighter {
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn highlight_str(&self, mut s: &[char]) -> Vec<(Range<usize>, TokenKind)> {
|
fn highlight_str(&self, mut s: &[char]) -> Vec<Token> {
|
||||||
let mut tokens = Vec::new();
|
let mut tokens = Vec::new();
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
loop {
|
loop {
|
||||||
|
|
@ -142,7 +146,10 @@ impl Highlighter {
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.find_map(|(i, r)| Some((i, r.matches(s)?)))
|
.find_map(|(i, r)| Some((i, r.matches(s)?)))
|
||||||
{
|
{
|
||||||
tokens.push((i..i + n, self.entries[idx]));
|
tokens.push(Token {
|
||||||
|
kind: self.entries[idx],
|
||||||
|
range: i..i + n,
|
||||||
|
});
|
||||||
n
|
n
|
||||||
} else if !s.is_empty() {
|
} else if !s.is_empty() {
|
||||||
1
|
1
|
||||||
|
|
@ -166,21 +173,31 @@ impl Highlighter {
|
||||||
|
|
||||||
pub struct Highlights {
|
pub struct Highlights {
|
||||||
pub highlighter: Highlighter,
|
pub highlighter: Highlighter,
|
||||||
tokens: Vec<(Range<usize>, TokenKind)>,
|
tokens: Vec<Token>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Token {
|
||||||
|
pub kind: TokenKind,
|
||||||
|
pub range: Range<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Highlights {
|
impl Highlights {
|
||||||
pub fn insert(&mut self, at: usize, s: &str) {}
|
pub fn insert(&mut self, at: usize, s: &str) {}
|
||||||
|
|
||||||
pub fn get_at(&self, pos: usize) -> Option<TokenKind> {
|
pub fn get_at(&self, pos: usize) -> Option<&Token> {
|
||||||
let idx = self.tokens
|
let idx = self.tokens
|
||||||
.binary_search_by_key(&pos, |(r, _)| r.start)
|
.binary_search_by_key(&pos, |tok| tok.range.start)
|
||||||
// .ok()?
|
// .ok()?
|
||||||
.unwrap_or_else(|p| p.saturating_sub(1))
|
.unwrap_or_else(|p| p.saturating_sub(1))
|
||||||
// .saturating_sub(1)
|
// .saturating_sub(1)
|
||||||
;
|
;
|
||||||
let (r, tok) = self.tokens.get(idx)?;
|
let tok = self.tokens.get(idx)?;
|
||||||
if r.contains(&pos) { Some(*tok) } else { None }
|
if tok.range.contains(&pos) {
|
||||||
|
Some(tok)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -279,16 +296,12 @@ impl State<'_> {
|
||||||
let mut times = 0;
|
let mut times = 0;
|
||||||
loop {
|
loop {
|
||||||
let pos = self.pos;
|
let pos = self.pos;
|
||||||
if times >= *at_most {
|
if times >= *at_most || self.attempt(x).is_none() {
|
||||||
break;
|
break (times >= *at_least).then_some(());
|
||||||
} else if self.attempt(x).is_none() {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
assert_ne!(pos, self.pos, "{x:?}");
|
assert_ne!(pos, self.pos, "{x:?}");
|
||||||
times += 1;
|
times += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if times >= *at_least { Some(()) } else { None }
|
|
||||||
}
|
}
|
||||||
Regex::Delim(d, r) => {
|
Regex::Delim(d, r) => {
|
||||||
let old_pos = self.pos;
|
let old_pos = self.pos;
|
||||||
|
|
|
||||||
30
src/state.rs
30
src/state.rs
|
|
@ -185,6 +185,36 @@ impl Buffer {
|
||||||
cursor.base = cursor.pos;
|
cursor.base = cursor.pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn select_token_cursor(&mut self, cursor_id: CursorId) {
|
||||||
|
let Some(cursor) = self.cursors.get_mut(cursor_id) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
if let Some(tok) = self
|
||||||
|
.highlights
|
||||||
|
.as_ref()
|
||||||
|
// Choose the longest token that the cursor is touching
|
||||||
|
.and_then(|hl| {
|
||||||
|
let a = hl.get_at(cursor.pos);
|
||||||
|
let b = hl.get_at(cursor.pos.saturating_sub(1));
|
||||||
|
a.zip(b)
|
||||||
|
.map(|(a, b)| {
|
||||||
|
if a.range.end - a.range.start > b.range.end - b.range.start {
|
||||||
|
a
|
||||||
|
} else {
|
||||||
|
b
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.or(a)
|
||||||
|
.or(b)
|
||||||
|
})
|
||||||
|
{
|
||||||
|
cursor.base = tok.range.start;
|
||||||
|
cursor.pos = tok.range.end;
|
||||||
|
} else {
|
||||||
|
// TODO: Bell
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn move_cursor(
|
pub fn move_cursor(
|
||||||
&mut self,
|
&mut self,
|
||||||
cursor_id: CursorId,
|
cursor_id: CursorId,
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,12 @@ impl Input {
|
||||||
cursor_id: CursorId,
|
cursor_id: CursorId,
|
||||||
event: Event,
|
event: Event,
|
||||||
) -> Result<Resp, Event> {
|
) -> Result<Resp, Event> {
|
||||||
match event.to_action(|e| e.to_char().map(Action::Char).or_else(|| e.to_move())) {
|
match event.to_action(|e| {
|
||||||
|
e.to_char()
|
||||||
|
.map(Action::Char)
|
||||||
|
.or_else(|| e.to_move())
|
||||||
|
.or_else(|| e.to_select_token())
|
||||||
|
}) {
|
||||||
Some(Action::Char(c)) => {
|
Some(Action::Char(c)) => {
|
||||||
if c == '\x08' {
|
if c == '\x08' {
|
||||||
buffer.backspace(cursor_id);
|
buffer.backspace(cursor_id);
|
||||||
|
|
@ -82,6 +87,10 @@ impl Input {
|
||||||
self.refocus(buffer, cursor_id);
|
self.refocus(buffer, cursor_id);
|
||||||
Ok(Resp::handled(None))
|
Ok(Resp::handled(None))
|
||||||
}
|
}
|
||||||
|
Some(Action::SelectToken) => {
|
||||||
|
buffer.select_token_cursor(cursor_id);
|
||||||
|
Ok(Resp::handled(None))
|
||||||
|
}
|
||||||
_ => Err(event),
|
_ => Err(event),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -165,7 +174,7 @@ impl Input {
|
||||||
.highlights
|
.highlights
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|hl| hl.get_at(pos))
|
.and_then(|hl| hl.get_at(pos))
|
||||||
.map(|tok| state.theme.token_color(tok))
|
.map(|tok| state.theme.token_color(tok.kind))
|
||||||
{
|
{
|
||||||
(fg, c)
|
(fg, c)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue