aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJonas Maier <>2026-05-24 19:25:45 +0200
committerJonas Maier <>2026-05-24 19:25:45 +0200
commit76ce59936d6d1c03ea291e6631db26339d310c19 (patch)
treeb0cbff9bf3fac0bb3b9ad9580f6e83bcc51b0056 /src
parent01a198b8ad42680c9333039c75317d1787120c78 (diff)
downloadpish-76ce59936d6d1c03ea291e6631db26339d310c19.tar.gz
less broken multiline editing
Diffstat (limited to 'src')
-rw-r--r--src/cursor.rs12
-rw-r--r--src/lib.rs1
-rw-r--r--src/line/mod.rs45
-rw-r--r--src/syntax_highlighting.rs19
4 files changed, 42 insertions, 35 deletions
diff --git a/src/cursor.rs b/src/cursor.rs
index 959b15f..e6f99f1 100644
--- a/src/cursor.rs
+++ b/src/cursor.rs
@@ -27,12 +27,20 @@ pub fn move_cursor(direction: Direction, n: usize) {
fmove_cursor(direction, n, &mut std::io::stdout()).unwrap()
}
+pub fn f_save(stdout: &mut dyn Write) -> std::io::Result<()> {
+ stdout.write_all(b"\x1b[s")
+}
+
+pub fn f_restore(stdout: &mut dyn Write) -> std::io::Result<()> {
+ stdout.write_all(b"\x1b[u")
+}
+
pub fn save() {
- std::io::stdout().lock().write_all(b"\x1b[s").unwrap();
+ f_save(&mut std::io::stdout().lock()).unwrap();
}
pub fn restore() {
- std::io::stdout().lock().write_all(b"\x1b[u").unwrap();
+ f_restore(&mut std::io::stdout().lock()).unwrap();
}
/// Represents a cursor position
diff --git a/src/lib.rs b/src/lib.rs
index 93d9cb8..314f12c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -431,6 +431,7 @@ pub fn event_loop() {
drop(se);
// not sure if/how to report this error - would be strange to print something to console every time a keybind command returns nonzero exit code.
let _ = run::run_quiet(session.clone(), cmd);
+ session.lock().unwrap().cohere().unwrap();
continue 'repl;
}
}
diff --git a/src/line/mod.rs b/src/line/mod.rs
index c6c2f34..510c480 100644
--- a/src/line/mod.rs
+++ b/src/line/mod.rs
@@ -36,15 +36,15 @@ impl Line {
}
pub fn highlight_syntax(&mut self, h: &mut Highlighter) -> std::io::Result<()> {
- if !self.is_dirty() {
+ if !self.dirty {
return Ok(());
}
+ self.dirty = false;
- self.mark_clean();
-
- if !h.enabled {
- return Ok(());
- }
+ // TODO this is currently needed to reprint the prompt upon modification so we can't skip it.
+ // if !h.enabled {
+ // return Ok(());
+ // }
use crate::parse::{self, Parse};
@@ -53,7 +53,7 @@ impl Line {
let _ = parse::Ast::parse(&mut parser);
let mut stdout = io::stdout().lock();
self.line_start.f_go_to(&mut stdout)?;
- h.pretty_print(&buf, parser.highlights, &mut stdout)?;
+ h.pretty_print(&buf, self.left_len(), parser.highlights, &mut stdout)?;
stdout.flush()?;
Ok(())
@@ -159,8 +159,9 @@ macro_rules! mutating_impls {
($(pub fn $fun:ident(&mut $self:ident $($arg:tt)*) -> $ty:ty $body:block )*) => {
impl Line {$(
pub fn $fun(&mut $self $($arg)*) -> $ty {
+ let result = $body;
$self.dirty = true;
- $body
+ result
}
)*}
};
@@ -168,25 +169,14 @@ macro_rules! mutating_impls {
mutating_impls! {
pub fn clear_prompt(&mut self) -> io::Result<()> {
- let mut stdout = io::stdout().lock();
- cursor::fmove_cursor(
- Direction::Right,
- self.buf.distance_from_right_end(),
- &mut stdout,
- )?;
- for _ in 0..self.buf.len() {
- stdout.write_all(b"\x08 \x08")?;
- }
self.buf.clear();
- stdout.flush()
+ Ok(())
}
pub fn type_bytes(&mut self, bs: &[u8]) -> io::Result<()> {
for b in bs.iter() {
self.buf.add(*b);
}
- io::stdout().lock().write_all(&bs)?;
- self.buf.display_post(b"");
Ok(())
}
@@ -196,52 +186,43 @@ mutating_impls! {
pub fn del_left(&mut self) -> io::Result<()> {
if self.buf.del_left().is_some() {
- cursor::fmove_cursor(Direction::Left, 1, &mut io::stdout())?;
- self.buf.display_post(b" ");
+ let mut stdout = io::stdout().lock();
+ cursor::fmove_cursor(Direction::Left, 1, &mut stdout)?;
+ stdout.flush()?;
}
Ok(())
}
pub fn del_right(&mut self) -> io::Result<()> {
self.buf.del_right();
- self.buf.display_post(b" ");
Ok(())
}
pub fn del_left_word(&mut self) -> io::Result<()> {
- let mut del = 0;
while let Some(x) = self.buf.get_left()
&& x == b' '
{
self.buf.del_left();
- del += 1;
}
while let Some(x) = self.buf.get_left()
&& x != b' '
{
self.buf.del_left();
- del += 1;
}
- cursor::fmove_cursor(Direction::Left, del, &mut io::stdout())?;
- self.buf.display_post(&vec![b' '; del]);
Ok(())
}
pub fn del_right_word(&mut self) -> io::Result<()> {
- let mut del = 0;
while let Some(x) = self.buf.get_right()
&& x == b' '
{
self.buf.del_right();
- del += 1;
}
while let Some(x) = self.buf.get_right()
&& x != b' '
{
self.buf.del_right();
- del += 1;
}
- self.buf.display_post(&vec![b' '; del]);
Ok(())
}
diff --git a/src/syntax_highlighting.rs b/src/syntax_highlighting.rs
index 043509a..19f44ab 100644
--- a/src/syntax_highlighting.rs
+++ b/src/syntax_highlighting.rs
@@ -1,7 +1,7 @@
use std::collections::HashMap;
use crate::{
- BString, ansi, bstr,
+ BString, ansi, bstr, cursor,
parse::{Highlight, HighlightKind},
};
@@ -15,6 +15,8 @@ pub enum SetColorError {
NoSuchKeyword,
}
+const CLEAR_TO_END: &bstr = b"\x1b[K";
+
impl Highlighter {
pub fn new() -> Self {
let mut this = Self {
@@ -51,6 +53,7 @@ impl Highlighter {
pub fn pretty_print(
&self,
bytes: &[u8],
+ cursor_offset: usize,
colors: Vec<Highlight>,
stdout: &mut dyn std::io::Write,
) -> std::io::Result<()> {
@@ -104,7 +107,16 @@ impl Highlighter {
let mut current_color = self.color(HighlightKind::None);
+ let mut saved_pos = false;
+
+ stdout.write_all(CLEAR_TO_END)?;
+
for (i, x) in bytes.iter().cloned().enumerate() {
+ if i == cursor_offset {
+ cursor::f_save(stdout)?;
+ saved_pos = true;
+ }
+
while let Some(color_boundary) = coloring.first().cloned()
&& color_boundary.loc <= i
{
@@ -126,6 +138,7 @@ impl Highlighter {
if x == b'\n' {
stdout.write_all(b"\r\n")?;
+ stdout.write_all(CLEAR_TO_END)?;
} else {
stdout.write_all(&[x])?;
}
@@ -133,6 +146,10 @@ impl Highlighter {
stdout.write_all(self.color(HighlightKind::None))?;
+ if saved_pos {
+ cursor::f_restore(stdout)?;
+ }
+
Ok(())
}
}