aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs208
1 files changed, 47 insertions, 161 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 3931f5d..2a9a1ee 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -25,7 +25,7 @@ pub mod date;
pub mod defer;
pub mod export_fun;
pub mod history;
-pub mod linebuf;
+pub mod line;
pub mod panic;
pub mod parse;
pub mod raw;
@@ -33,15 +33,15 @@ pub mod reload;
pub mod run;
pub mod rw;
pub mod serialization;
+pub mod syntax_highlighting;
pub mod wait;
-use linebuf::LineBuf;
use raw::*;
use crate::completion::{PathCache, completion};
use crate::ctrlc::CtrlC;
-use crate::cursor::{Direction, move_cursor};
use crate::history::HistoryEntry;
+use crate::line::Line;
use crate::parse::{Block, ExpString, Parse, PostExpansion};
macro_rules! print {
@@ -93,7 +93,7 @@ impl PushAll for BString {
pub struct Session {
raw: Option<ScopedRawMode>,
- line: LineBuf,
+ line: Line,
history: Vec<HistoryEntry>,
prev_path: BString,
builtins: HashMap<BString, &'static dyn run::BuiltinClone>,
@@ -115,13 +115,15 @@ pub struct Session {
/// n before end of history.len()
/// 0 == not checking history
history_visit: usize,
+
+ highlighter: syntax_highlighting::Highlighter,
}
impl Session {
pub fn new_noninteractive() -> Self {
Self {
raw: None,
- line: LineBuf::new(),
+ line: Line::new(),
history: Vec::new(),
prev_path: b".".into(),
builtins: HashMap::new(),
@@ -136,6 +138,7 @@ impl Session {
debug_keystrokes: false,
loud: false,
history_visit: 0,
+ highlighter: syntax_highlighting::Highlighter::new(),
}
}
}
@@ -212,17 +215,8 @@ impl Session {
expanded
}
- fn clear_prompt(&mut self) {
- cursor::move_cursor(Direction::Right, self.line.distance_from_right_end());
- for _ in 0..self.line.len() {
- print!("\x08 \x08");
- }
- io::stdout().lock().flush().unwrap();
- self.line.clear();
- }
-
fn prompt_clear(&mut self) {
- self.clear_prompt();
+ self.line.clear_prompt().unwrap();
self.history_visit = 0;
}
@@ -234,7 +228,7 @@ impl Session {
}
fn display_historic_entry(&mut self) {
- self.clear_prompt();
+ self.line.clear_prompt().unwrap();
let new = if self.history_visit == 0 {
Vec::new()
} else {
@@ -244,7 +238,7 @@ impl Session {
};
io::stdout().write_all(&new).unwrap();
io::stdout().flush().unwrap();
- self.line.set_content(new);
+ self.line.set_content(new).unwrap();
}
fn history_up(&mut self) {
@@ -261,150 +255,26 @@ impl Session {
}
}
- fn type_bytes(&mut self, bs: &[u8]) {
- for b in bs.iter() {
- self.line.add(*b);
- }
- io::stdout().lock().write_all(&bs).unwrap();
- self.line.display_post(b"");
- }
-
- fn type_byte(&mut self, b: u8) {
- self.type_bytes(&[b]);
- }
-
- fn del_left(&mut self) {
- if self.line.del_left().is_some() {
- cursor::move_cursor(Direction::Left, 1);
- self.line.display_post(b" ");
- }
- }
-
- fn del_right(&mut self) {
- self.line.del_right();
- self.line.display_post(b" ");
- }
-
fn del_left_or_previous(&mut self) {
- if self.line.is_empty() && !self.line.is_dirty() && !self.history.is_empty() {
+ if self.line.is_empty() && !self.line.had_contents() && !self.history.is_empty() {
// take previous command for editing
let cmd = self.history[self.history.len() - 1].cmd.clone();
- self.type_bytes(&cmd);
+ self.line.type_bytes(&cmd).unwrap();
} else {
- self.del_left();
+ self.line.del_left().unwrap();
}
}
fn prompt_pipe_previous(&mut self) {
- if self.line.is_empty() && let Some(prev) = self.history.last() {
+ if self.line.is_empty()
+ && let Some(prev) = self.history.last()
+ {
let mut cmd = prev.cmd.clone();
cmd.push_all(b" | ");
- self.type_bytes(&cmd);
+ self.line.type_bytes(&cmd).unwrap();
} else {
- self.type_byte(b'|');
- }
- }
-
- fn move_to_begin(&mut self) {
- cursor::move_cursor(Direction::Left, self.line.all_left());
- io::stdout().flush().unwrap();
- }
-
- fn move_to_end(&mut self) {
- cursor::move_cursor(Direction::Right, self.line.all_right());
- io::stdout().flush().unwrap();
- }
-
- fn del_left_word(&mut self) {
- let mut del = 0;
- while let Some(x) = self.line.get_left()
- && x == b' '
- {
- self.line.del_left();
- del += 1;
- }
- while let Some(x) = self.line.get_left()
- && x != b' '
- {
- self.line.del_left();
- del += 1;
- }
- cursor::move_cursor(Direction::Left, del);
- self.line.display_post(&vec![b' '; del]);
- }
-
- fn del_right_word(&mut self) {
- let mut del = 0;
- while let Some(x) = self.line.get_right()
- && x == b' '
- {
- self.line.del_right();
- del += 1;
- }
- while let Some(x) = self.line.get_right()
- && x != b' '
- {
- self.line.del_right();
- del += 1;
- }
- self.line.display_post(&vec![b' '; del]);
- }
-
- fn cursor_left(&mut self) {
- if self.line.left() {
- move_cursor(Direction::Left, 1);
- io::stdout().lock().flush().unwrap();
- }
- }
-
- fn cursor_right(&mut self) {
- if self.line.right() {
- move_cursor(Direction::Right, 1);
- io::stdout().lock().flush().unwrap();
- }
- }
-
- // move to next
- fn cursor_left_word(&mut self) {
- let mut i = 0;
-
- // find word
- while let Some(b' ') = self.line.get_left() {
- self.line.left();
- i += 1;
- }
-
- // skip it
- while let Some(x) = self.line.get_left()
- && !x.is_ascii_whitespace()
- {
- self.line.left();
- i += 1;
- }
-
- cursor::move_cursor(Direction::Left, i);
- io::stdout().flush().unwrap();
- }
-
- fn cursor_right_word(&mut self) {
- let mut i = 0;
-
- // find word
- while let Some(b' ') = self.line.get_right() {
- self.line.right();
- i += 1;
+ self.line.type_byte(b'|').unwrap();
}
-
- // skip it
- while let Some(x) = self.line.get_right()
- && !x.is_ascii_whitespace()
- {
- self.line.right();
- i += 1;
- }
-
- cursor::move_cursor(Direction::Right, i);
- io::stdout().flush().unwrap();
}
fn complete(session: Arc<Mutex<Session>>) {
@@ -414,7 +284,7 @@ impl Session {
let mut se = session.lock().unwrap();
- se.type_bytes(&comp.shared_prefix);
+ se.line.type_bytes(&comp.shared_prefix).unwrap();
if comp.suggestions.len() > 1 {
print!("\r\n");
@@ -435,7 +305,7 @@ impl Session {
let parsed = match parse::do_parse(&line) {
Ok(p) => p,
Err(_) => {
- se.line.add(b'\n');
+ se.line.type_byte(b'\n').unwrap();
print!("\r\n> ");
return;
}
@@ -467,6 +337,27 @@ impl Session {
r.disable();
}
}
+
+ /// 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)?;
+ }
+ }
+
+ Ok(())
+ }
}
fn exec_rc_file(se: Arc<Mutex<Session>>) {
@@ -492,21 +383,14 @@ pub fn event_loop() {
let se = Session {
raw: Some(raw),
- line: LineBuf::new(),
- history: Vec::new(),
+ line: Line::new(),
builtins: run::builtin_map(),
prev_path: vec![b'.'],
history_visit: 0,
socket_running: None,
- vars: run::Vars::default(),
- funs: HashMap::new(),
- aliases: run::Aliases::new(),
path_cache: Default::default(),
ctrlc: Default::default(),
- debug_keystrokes: false,
- loud: false,
- ti_keybinds: HashMap::new(),
- ascii_keybinds: HashMap::new(),
+ ..Session::new_noninteractive()
};
let session = Arc::new(Mutex::new(se));
@@ -540,7 +424,7 @@ pub fn event_loop() {
}
match key {
- ansi::KbInput::Key([x]) => se.type_byte(x),
+ ansi::KbInput::Key([x]) => se.line.type_byte(x).unwrap(),
ansi::KbInput::Escape(escape) => {
for terminfo_key in escape.keys.iter() {
if let Some(cmd) = se.ti_keybinds.get(terminfo_key.as_bytes()) {
@@ -554,6 +438,8 @@ pub fn event_loop() {
}
ansi::KbInput::InvalidEscape(_) => continue,
}
+
+ se.cohere().unwrap();
}
session.lock().unwrap().raw_disable();