Skip to content

Commit 7f16744

Browse files
committed
Add history
1 parent 037802b commit 7f16744

File tree

4 files changed

+98
-2
lines changed

4 files changed

+98
-2
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ nix = { version = "0.28.0", features = ["fs", "process", "signal", "term", "user
1010
termion = "4.0.3"
1111
unicode-width = "0.1.11"
1212
signal-hook = "0.3.17"
13+
rev_lines = "0.3.0"

src/core.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
pub mod builtins;
55
pub mod data;
6+
pub mod history;
67
pub mod jobtable;
78

89
use self::data::Data;
@@ -21,6 +22,7 @@ use std::sync::atomic::Ordering::Relaxed;
2122

2223
pub struct ShellCore {
2324
pub data: Data,
25+
rewritten_history: HashMap<usize, String>,
2426
pub history: Vec<String>,
2527
pub builtins: HashMap<String, fn(&mut ShellCore, &mut Vec<String>) -> i32>,
2628
pub sigint: Arc<AtomicBool>,
@@ -51,7 +53,8 @@ impl ShellCore {
5153
pub fn new() -> ShellCore {
5254
let mut core = ShellCore{
5355
data: Data::new(),
54-
history: Vec::new(),
56+
rewritten_history: HashMap::new(),
57+
history: vec![],
5558
builtins: HashMap::new(),
5659
sigint: Arc::new(AtomicBool::new(false)),
5760
is_subshell: false,

src/core/history.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
//SPDXFileCopyrightText: 2024 Ryuichi Ueda ryuichiueda@gmail.com
2+
//SPDXLicense-Identifier: BSD-3-Clause
3+
4+
use crate::ShellCore;
5+
use rev_lines::RevLines;
6+
use std::fs::File;
7+
use std::io::{BufReader, BufWriter, Write};
8+
use std::fs::OpenOptions;
9+
10+
impl ShellCore {
11+
pub fn fetch_history(&mut self, pos: usize, prev: usize, prev_str: String) -> String {
12+
if prev < self.history.len() {
13+
self.history[prev] = prev_str;
14+
}else{
15+
self.rewritten_history.insert(prev + 1 - self.history.len(), prev_str);
16+
}
17+
18+
if pos < self.history.len() {
19+
self.history[pos].clone()
20+
}else{
21+
self.fetch_history_file(pos + 1 - self.history.len())
22+
}
23+
}
24+
25+
pub fn fetch_history_file(&mut self, pos: usize) -> String {
26+
if let Some(s) = self.rewritten_history.get(&pos) {
27+
return s.to_string();
28+
}
29+
if pos == 0 {
30+
return String::new();
31+
}
32+
33+
let mut file_line = pos - 1;
34+
if let Ok(n) = self.data.get_param("HISTFILESIZE").parse::<usize>() {
35+
file_line %= n;
36+
}
37+
38+
if let Ok(hist_file) = File::open(self.data.get_param("HISTFILE")){
39+
let mut rev_lines = RevLines::new(BufReader::new(hist_file));
40+
if let Some(Ok(s)) = rev_lines.nth(file_line) {
41+
return s;
42+
}
43+
}
44+
45+
String::new()
46+
}
47+
48+
pub fn write_history_to_file(&mut self) {
49+
if ! self.data.flags.contains('i') || self.is_subshell {
50+
return;
51+
}
52+
let filename = self.data.get_param("HISTFILE");
53+
if filename == "" {
54+
eprintln!("sush: HISTFILE is not set");
55+
return;
56+
}
57+
58+
let file = match OpenOptions::new().create(true)
59+
.write(true).append(true).open(&filename) {
60+
Ok(f) => f,
61+
_ => {
62+
eprintln!("sush: invalid history file");
63+
return;
64+
},
65+
};
66+
67+
let mut f = BufWriter::new(file);
68+
for h in self.history.iter().rev() {
69+
if h == "" {
70+
continue;
71+
}
72+
let _ = f.write(h.as_bytes());
73+
let _ = f.write(&vec![0x0A]);
74+
}
75+
let _ = f.flush();
76+
}
77+
}

src/main.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,18 @@ fn main() {
6262
main_loop(&mut core);
6363
}
6464

65+
fn set_history(core: &mut ShellCore, s: &str) {
66+
if core.history.len() == 0 {
67+
return;
68+
}
69+
70+
core.history[0] = s.trim_end().replace("\n", "↵ \0").to_string();
71+
if core.history[0].len() == 0
72+
|| (core.history.len() > 1 && core.history[0] == core.history[1]) {
73+
core.history.remove(0);
74+
}
75+
}
76+
6577
fn input_interrupt_check(feeder: &mut Feeder, core: &mut ShellCore) -> bool {
6678
if ! core.sigint.load(Relaxed) { //core.input_interrupt {
6779
return false;
@@ -89,7 +101,10 @@ fn main_loop(core: &mut ShellCore) {
89101
}
90102

91103
match Script::parse(&mut feeder, core){
92-
Some(mut s) => s.exec(core),
104+
Some(mut s) => {
105+
s.exec(core);
106+
set_history(core, &s.get_text());
107+
},
93108
None => {},
94109
}
95110
core.sigint.store(false, Relaxed);

0 commit comments

Comments
 (0)