aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/ansi/mod.rs54
-rw-r--r--src/cursor.rs20
-rw-r--r--src/lib.rs28
-rw-r--r--src/line/mod.rs35
-rw-r--r--src/syntax_highlighting.rs6
5 files changed, 99 insertions, 44 deletions
diff --git a/src/ansi/mod.rs b/src/ansi/mod.rs
index 96fb87a..4265b45 100644
--- a/src/ansi/mod.rs
+++ b/src/ansi/mod.rs
@@ -67,39 +67,55 @@ impl TerminalInput {
self.buf.pop_front()
}
- fn read_all_input(&mut self) {
- while {
- let buf_len = self.buf.len();
- self.read_internal();
- self.buf.len() != buf_len
- } {}
- }
-
pub fn query_cursor_position(&mut self) -> Option<CursorPos> {
- self.read_all_input();
-
// query to request cursor position
let mut stdout = std::io::stdout().lock();
stdout.write_all(b"\x1b[6n").ok()?;
stdout.flush().ok()?;
drop(stdout);
- loop {
+ self.read_internal();
+
+ while self
+ .buf
+ .back()
+ .map(|b| !b.as_bytes().ends_with(b"R"))
+ .unwrap_or(true)
+ {
let buf_len = self.buf.len();
self.read_internal();
// no new input, give up
if self.buf.len() <= buf_len {
- return None;
+ break;
}
+ }
- // buf.len() > buf_len >= 0, unwrap is safe.
- let input = self.buf.back().unwrap();
- if let Some(pos) = try_parse_cursor_position_message(input.as_bytes()) {
- self.buf.pop_back();
- return Some(pos);
- }
+ if self.buf.is_empty() {
+ return None;
+ }
+
+ if !self.buf.back().unwrap().as_bytes().ends_with(b"R") {
+ return None;
}
+
+ let i = self
+ .buf
+ .iter()
+ .enumerate()
+ .rev()
+ .find(|(_, x)| x.as_bytes().starts_with(b"\x1b"))
+ .map(|x| x.0)?;
+
+ let input = self.buf.iter().skip(i).fold(BString::new(), |mut acc, x| {
+ acc.push_all(x.as_bytes());
+ acc
+ });
+
+ let pos = try_parse_cursor_position_message(&input)?;
+ self.buf.truncate(i);
+
+ Some(pos)
}
}
@@ -193,7 +209,7 @@ pub struct Escape<'a> {
use terminfo_lean::parse::Terminfo;
-use crate::cursor::CursorPos;
+use crate::{BString, PushAll, cursor::CursorPos};
static TERMINFO: RwLock<Option<&'static Terminfo<'static>>> = RwLock::new(None);
static ESCAPE_TRIE: RwLock<Option<&'static EscapeTrie>> = RwLock::new(None);
diff --git a/src/cursor.rs b/src/cursor.rs
index 1ec23d5..959b15f 100644
--- a/src/cursor.rs
+++ b/src/cursor.rs
@@ -1,4 +1,4 @@
-use std::io::Write;
+use std::io::{self, Write};
#[derive(Debug, Clone, Copy)]
pub enum Direction {
@@ -41,3 +41,21 @@ pub struct CursorPos {
pub row: usize,
pub col: usize,
}
+
+impl Default for CursorPos {
+ fn default() -> Self {
+ Self { row: 1, col: 1 }
+ }
+}
+
+impl CursorPos {
+ pub fn f_go_to(&self, stdout: &mut dyn Write) -> std::io::Result<()> {
+ write!(stdout, "\x1b[{};{}H", self.row, self.col)
+ }
+
+ pub fn go_to(&self) {
+ let mut stdout = io::stdout().lock();
+ self.f_go_to(&mut stdout).unwrap();
+ stdout.flush().unwrap();
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 849ddea..93d9cb8 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -197,8 +197,11 @@ impl Session {
let prompt = this.lock().unwrap().prompt.prompt().to_vec();
io::stdout().write_all(&prompt).unwrap();
let mut this = this.lock().unwrap();
- this.line.display_pre();
- this.line.display_post(b"");
+ if let Some(ti) = this.terminal_input.as_mut()
+ && let Some(pos) = ti.query_cursor_position()
+ {
+ this.line.set_begin_of_line(pos);
+ }
this.line.mark_dirty();
this.cohere().unwrap();
}
@@ -212,8 +215,6 @@ impl Session {
.cmd
.clone()
};
- io::stdout().write_all(&new).unwrap();
- io::stdout().flush().unwrap();
self.line.set_content(new).unwrap();
}
@@ -299,7 +300,6 @@ impl Session {
Ok(p) => p,
Err(_) => {
se.line.type_byte(b'\n').unwrap();
- print!("\r\n> ");
return;
}
};
@@ -340,23 +340,7 @@ impl Session {
/// do cleanup actions after a bunch of mutations.
fn cohere(&mut self) -> io::Result<()> {
- if self.line.is_dirty() {
- self.line.mark_clean();
-
- // overwrite line in terminal with syntax-highlighted line.
- if self.highlighter.enabled {
- let buf = self.line.into_bytes();
- let mut parser = parse::Cursor::new(&buf, parse::ParseMode::Completion);
- let _res = parse::Ast::parse(&mut parser);
- let mut stdout = io::stdout().lock();
- cursor::fmove_cursor(cursor::Direction::Left, self.line.left_len(), &mut stdout)?;
- self.highlighter
- .pretty_print(&buf, parser.highlights, &mut stdout)?;
- cursor::fmove_cursor(cursor::Direction::Left, self.line.right_len(), &mut stdout)?;
- stdout.flush()?;
- }
- }
-
+ self.line.highlight_syntax(&mut self.highlighter)?;
Ok(())
}
}
diff --git a/src/line/mod.rs b/src/line/mod.rs
index 75a4508..c6c2f34 100644
--- a/src/line/mod.rs
+++ b/src/line/mod.rs
@@ -2,12 +2,16 @@ mod buf;
use std::io::{self, Write};
-use crate::cursor::{self, Direction};
+use crate::{
+ cursor::{self, CursorPos, Direction},
+ syntax_highlighting::Highlighter,
+};
pub use buf::LineBuf;
pub struct Line {
buf: LineBuf,
dirty: bool,
+ line_start: CursorPos,
}
impl std::ops::Deref for Line {
@@ -23,9 +27,38 @@ impl Line {
Self {
buf: LineBuf::new(),
dirty: false,
+ line_start: CursorPos::default(),
}
}
+ pub fn set_begin_of_line(&mut self, pos: CursorPos) {
+ self.line_start = pos;
+ }
+
+ pub fn highlight_syntax(&mut self, h: &mut Highlighter) -> std::io::Result<()> {
+ if !self.is_dirty() {
+ return Ok(());
+ }
+
+ self.mark_clean();
+
+ if !h.enabled {
+ return Ok(());
+ }
+
+ use crate::parse::{self, Parse};
+
+ let buf = self.into_bytes();
+ let mut parser = parse::Cursor::new(&buf, parse::ParseMode::Completion);
+ 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)?;
+ stdout.flush()?;
+
+ Ok(())
+ }
+
pub fn mark_clean(&mut self) {
self.dirty = false;
}
diff --git a/src/syntax_highlighting.rs b/src/syntax_highlighting.rs
index 1a6e626..043509a 100644
--- a/src/syntax_highlighting.rs
+++ b/src/syntax_highlighting.rs
@@ -124,7 +124,11 @@ impl Highlighter {
}
}
- stdout.write_all(&[x])?;
+ if x == b'\n' {
+ stdout.write_all(b"\r\n")?;
+ } else {
+ stdout.write_all(&[x])?;
+ }
}
stdout.write_all(self.color(HighlightKind::None))?;