diff options
Diffstat (limited to '')
| -rw-r--r-- | shell/src/lib.rs | 94 |
1 files changed, 21 insertions, 73 deletions
diff --git a/shell/src/lib.rs b/shell/src/lib.rs index 617e5a4..4640697 100644 --- a/shell/src/lib.rs +++ b/shell/src/lib.rs | |||
| @@ -515,7 +515,12 @@ impl Pipeline { | |||
| 515 | } | 515 | } |
| 516 | } | 516 | } |
| 517 | Filter::Pause => { | 517 | Filter::Pause => { |
| 518 | let StageState::Pause { shown, screen, cols } = st else { | 518 | let StageState::Pause { |
| 519 | shown, | ||
| 520 | screen, | ||
| 521 | cols, | ||
| 522 | } = st | ||
| 523 | else { | ||
| 519 | unreachable!("stage state does not match filter") | 524 | unreachable!("stage state does not match filter") |
| 520 | }; | 525 | }; |
| 521 | for l in cur.drain(..) { | 526 | for l in cur.drain(..) { |
| @@ -871,7 +876,7 @@ fn cmd_cat(p: &Parsed) { | |||
| 871 | if p.args.is_empty() { | 876 | if p.args.is_empty() { |
| 872 | // Path-less `cat` with no input keyword reads the keyboard | 877 | // Path-less `cat` with no input keyword reads the keyboard |
| 873 | // until ^D. | 878 | // until ^D. |
| 874 | cat_stdin(&mut pipe); | 879 | cat_stdin(&mut pipe, None); |
| 875 | } else { | 880 | } else { |
| 876 | for path in &p.args { | 881 | for path in &p.args { |
| 877 | if !cat_file(&mut pipe, path) { | 882 | if !cat_file(&mut pipe, path) { |
| @@ -885,7 +890,7 @@ fn cmd_cat(p: &Parsed) { | |||
| 885 | } | 890 | } |
| 886 | Input::Til(marker) => { | 891 | Input::Til(marker) => { |
| 887 | if p.args.is_empty() { | 892 | if p.args.is_empty() { |
| 888 | cat_stdin_until(&mut pipe, marker); | 893 | cat_stdin(&mut pipe, Some(marker)); |
| 889 | } else { | 894 | } else { |
| 890 | // `cat <path> TIL <marker>` — the paths are the input | 895 | // `cat <path> TIL <marker>` — the paths are the input |
| 891 | // source, truncated at the first marker line. | 896 | // source, truncated at the first marker line. |
| @@ -904,34 +909,21 @@ fn cmd_cat(p: &Parsed) { | |||
| 904 | pipe.end(); | 909 | pipe.end(); |
| 905 | } | 910 | } |
| 906 | 911 | ||
| 907 | fn cat_stdin(pipe: &mut Pipeline) -> bool { | 912 | /// Read lines from the tty until ^C/^D (or an exact marker line, when |
| 913 | /// `marker` is Some — the marker itself is not part of the input). | ||
| 914 | fn cat_stdin(pipe: &mut Pipeline, marker: Option<&str>) -> bool { | ||
| 908 | loop { | 915 | loop { |
| 909 | match tty::read_line() { | 916 | match tty::read_line() { |
| 910 | LineInput::Line(l) => { | 917 | LineInput::Line(l) => { |
| 911 | if !pipe.line(l.as_str()) { | 918 | if marker.is_some() && l.as_str() == marker.unwrap() { |
| 912 | return false; | ||
| 913 | } | ||
| 914 | } | ||
| 915 | LineInput::Interrupted => return false, // ^C aborts the stream | ||
| 916 | LineInput::Eof => return true, // ^D = EOF | ||
| 917 | } | ||
| 918 | } | ||
| 919 | } | ||
| 920 | |||
| 921 | fn cat_stdin_until(pipe: &mut Pipeline, marker: &str) -> bool { | ||
| 922 | loop { | ||
| 923 | match tty::read_line() { | ||
| 924 | LineInput::Line(l) => { | ||
| 925 | // Marker line is not part of the input. | ||
| 926 | if l.as_str() == marker { | ||
| 927 | return true; | 919 | return true; |
| 928 | } | 920 | } |
| 929 | if !pipe.line(l.as_str()) { | 921 | if !pipe.line(l.as_str()) { |
| 930 | return false; | 922 | return false; |
| 931 | } | 923 | } |
| 932 | } | 924 | } |
| 933 | LineInput::Interrupted => return false, | 925 | LineInput::Interrupted => return false, // ^C aborts the stream |
| 934 | LineInput::Eof => return true, | 926 | LineInput::Eof => return true, // ^D = EOF |
| 935 | } | 927 | } |
| 936 | } | 928 | } |
| 937 | } | 929 | } |
| @@ -1030,25 +1022,6 @@ struct HexCtx<'a> { | |||
| 1030 | alive: bool, | 1022 | alive: bool, |
| 1031 | } | 1023 | } |
| 1032 | 1024 | ||
| 1033 | fn format_row(addr: u64, row: &[u8; 16]) -> String { | ||
| 1034 | let mut out = String::new(); | ||
| 1035 | use core::fmt::Write as _; | ||
| 1036 | let _ = core::write!(out, "{:08x} ", addr); | ||
| 1037 | for &b in row { | ||
| 1038 | let _ = core::write!(out, "{:02x} ", b); | ||
| 1039 | } | ||
| 1040 | out.push_str(" |"); | ||
| 1041 | for &b in row { | ||
| 1042 | out.push(if b.is_ascii_graphic() || b == b' ' { | ||
| 1043 | b as char | ||
| 1044 | } else { | ||
| 1045 | '.' | ||
| 1046 | }); | ||
| 1047 | } | ||
| 1048 | out.push('|'); | ||
| 1049 | out | ||
| 1050 | } | ||
| 1051 | |||
| 1052 | fn format_partial(addr: u64, row: &[u8]) -> String { | 1025 | fn format_partial(addr: u64, row: &[u8]) -> String { |
| 1053 | let mut out = String::new(); | 1026 | let mut out = String::new(); |
| 1054 | use core::fmt::Write as _; | 1027 | use core::fmt::Write as _; |
| @@ -1081,7 +1054,7 @@ impl HexCtx<'_> { | |||
| 1081 | self.row[self.row_len] = b; | 1054 | self.row[self.row_len] = b; |
| 1082 | self.row_len += 1; | 1055 | self.row_len += 1; |
| 1083 | if self.row_len == 16 { | 1056 | if self.row_len == 16 { |
| 1084 | let line = format_row(self.pos, &self.row); | 1057 | let line = format_partial(self.pos, &self.row); |
| 1085 | self.alive = self.pipe.line(&line); | 1058 | self.alive = self.pipe.line(&line); |
| 1086 | self.pos += 16; | 1059 | self.pos += 16; |
| 1087 | self.row_len = 0; | 1060 | self.row_len = 0; |
| @@ -1106,7 +1079,7 @@ fn cmd_hexdump(p: &Parsed) { | |||
| 1106 | match &p.input { | 1079 | match &p.input { |
| 1107 | Input::None => { | 1080 | Input::None => { |
| 1108 | if p.args.is_empty() { | 1081 | if p.args.is_empty() { |
| 1109 | hexdump_stdin(&mut pipe); | 1082 | hexdump_stdin(&mut pipe, None); |
| 1110 | } else { | 1083 | } else { |
| 1111 | for path in &p.args { | 1084 | for path in &p.args { |
| 1112 | if !hexdump_file(&mut pipe, path) { | 1085 | if !hexdump_file(&mut pipe, path) { |
| @@ -1120,7 +1093,7 @@ fn cmd_hexdump(p: &Parsed) { | |||
| 1120 | } | 1093 | } |
| 1121 | Input::Til(marker) => { | 1094 | Input::Til(marker) => { |
| 1122 | if p.args.is_empty() { | 1095 | if p.args.is_empty() { |
| 1123 | hexdump_stdin_until(&mut pipe, marker); | 1096 | hexdump_stdin(&mut pipe, Some(marker)); |
| 1124 | } else { | 1097 | } else { |
| 1125 | // `hexdump <path> TIL <marker>` — the paths are the input | 1098 | // `hexdump <path> TIL <marker>` — the paths are the input |
| 1126 | // source, truncated at the first marker line. | 1099 | // source, truncated at the first marker line. |
| @@ -1176,34 +1149,9 @@ fn hexdump_file(pipe: &mut Pipeline, path: &str) -> bool { | |||
| 1176 | ctx.alive | 1149 | ctx.alive |
| 1177 | } | 1150 | } |
| 1178 | 1151 | ||
| 1179 | fn hexdump_stdin(pipe: &mut Pipeline) { | 1152 | /// Hex-dump lines from the tty until ^C/^D (or an exact marker line, |
| 1180 | let mut ctx = HexCtx { | 1153 | /// when `marker` is Some — the marker itself is not dumped). |
| 1181 | pipe, | 1154 | fn hexdump_stdin(pipe: &mut Pipeline, marker: Option<&str>) { |
| 1182 | pos: 0, | ||
| 1183 | row: [0u8; 16], | ||
| 1184 | row_len: 0, | ||
| 1185 | alive: true, | ||
| 1186 | }; | ||
| 1187 | loop { | ||
| 1188 | match tty::read_line() { | ||
| 1189 | LineInput::Line(l) => { | ||
| 1190 | ctx.feed(l.as_str().as_bytes()); | ||
| 1191 | if !ctx.alive { | ||
| 1192 | break; | ||
| 1193 | } | ||
| 1194 | ctx.feed(b"\n"); | ||
| 1195 | if !ctx.alive { | ||
| 1196 | break; | ||
| 1197 | } | ||
| 1198 | } | ||
| 1199 | LineInput::Interrupted => break, | ||
| 1200 | LineInput::Eof => break, | ||
| 1201 | } | ||
| 1202 | } | ||
| 1203 | ctx.flush(); | ||
| 1204 | } | ||
| 1205 | |||
| 1206 | fn hexdump_stdin_until(pipe: &mut Pipeline, marker: &str) { | ||
| 1207 | let mut ctx = HexCtx { | 1155 | let mut ctx = HexCtx { |
| 1208 | pipe, | 1156 | pipe, |
| 1209 | pos: 0, | 1157 | pos: 0, |
| @@ -1214,7 +1162,7 @@ fn hexdump_stdin_until(pipe: &mut Pipeline, marker: &str) { | |||
| 1214 | loop { | 1162 | loop { |
| 1215 | match tty::read_line() { | 1163 | match tty::read_line() { |
| 1216 | LineInput::Line(l) => { | 1164 | LineInput::Line(l) => { |
| 1217 | if l.as_str() == marker { | 1165 | if marker.is_some() && l.as_str() == marker.unwrap() { |
| 1218 | break; | 1166 | break; |
| 1219 | } | 1167 | } |
| 1220 | ctx.feed(l.as_str().as_bytes()); | 1168 | ctx.feed(l.as_str().as_bytes()); |
