diff --git a/src/buffer/internal.rs b/src/buffer/internal.rs index edcc54c..eec00c9 100644 --- a/src/buffer/internal.rs +++ b/src/buffer/internal.rs @@ -35,6 +35,7 @@ fn count_chars(bytes: &[u8]) -> usize { let mut cur = 0; while cur < bytes.len() { + // SAFETY: we know we are in bounds and that we contain valid utf-8 data let ch = unsafe { decode_char_at(cur, bytes) }; cur += ch.len_utf8(); n_chars += 1; @@ -201,7 +202,7 @@ impl GapBuffer { v } - pub fn iter_lines(&self) -> impl Iterator { + pub fn iter_lines(&self) -> impl Iterator> { let mut line_idx = 0; std::iter::from_fn(move || { @@ -254,7 +255,7 @@ impl GapBuffer { pub fn char(&self, char_idx: usize) -> char { let byte_idx = self.char_to_raw_byte(char_idx); - // SAFTEY: we know that we have valid utf8 data internally + // SAFETY: we know that we have valid utf8 data internally unsafe { decode_char_at(byte_idx, &self.data) } } @@ -269,12 +270,12 @@ impl GapBuffer { #[inline] fn char_len(&self, byte_idx: usize) -> usize { - // SAFTEY: we know that we have valid utf8 data internally + // SAFETY: we know that we have valid utf8 data internally unsafe { decode_char_at(byte_idx, &self.data) }.len_utf8() } #[inline] - pub fn line(&self, line_idx: usize) -> Slice { + pub fn line(&self, line_idx: usize) -> Slice<'_> { if line_idx >= self.len_lines() { panic!( "line index was {line_idx} but buffer has {} lines", @@ -321,7 +322,7 @@ impl GapBuffer { } /// An exclusive range of characters from the buffer - pub fn slice(&self, char_from: usize, char_to: usize) -> Slice { + pub fn slice(&self, char_from: usize, char_to: usize) -> Slice<'_> { let from = self.char_to_raw_byte(char_from); let to = self.char_to_raw_byte(char_to); @@ -703,7 +704,7 @@ impl<'a> Slice<'a> { } pub fn as_strs(&self) -> (&str, &str) { - // SAFTEY: we know that we have valid utf8 data internally + // SAFETY: we know that we have valid utf8 data internally unsafe { ( std::str::from_utf8_unchecked(self.left), @@ -771,6 +772,7 @@ impl<'a> Iterator for Chars<'a> { } let (cur, data) = self.s.cur_and_data(self.cur); + // SAFETY: we know we are in bounds and that we contain valid utf-8 data let ch = unsafe { decode_char_at(cur, data) }; let len = ch.len_utf8(); self.cur += len; @@ -798,6 +800,7 @@ impl<'a> Iterator for IdxChars<'a> { if self.rev { let (cur, data) = self.s.cur_and_data(self.cur - 1); + // SAFETY: we know we are in bounds and that we contain valid utf-8 data let ch = unsafe { decode_char_ending_at(cur, data) }; let len = ch.len_utf8(); self.idx -= 1; @@ -805,6 +808,7 @@ impl<'a> Iterator for IdxChars<'a> { Some((self.idx, ch)) } else { let (cur, data) = self.s.cur_and_data(self.cur); + // SAFETY: we know we are in bounds and that we contain valid utf-8 data let ch = unsafe { decode_char_at(cur, data) }; let len = ch.len_utf8(); let res = Some((self.idx, ch)); diff --git a/src/buffer/mod.rs b/src/buffer/mod.rs index 7df4e3e..2aacbbb 100644 --- a/src/buffer/mod.rs +++ b/src/buffer/mod.rs @@ -409,7 +409,7 @@ impl Buffer { cx } - pub fn line(&self, y: usize) -> Option { + pub fn line(&self, y: usize) -> Option> { if y >= self.len_lines() { None } else { diff --git a/src/editor/input.rs b/src/editor/input.rs index 2d494ea..09048df 100644 --- a/src/editor/input.rs +++ b/src/editor/input.rs @@ -10,6 +10,7 @@ use std::{ thread::{spawn, JoinHandle}, }; +#[derive(Debug)] pub enum InputEvent { Message(Message), KeyPress(Key), diff --git a/src/editor/mod.rs b/src/editor/mod.rs index 65f76c4..0b0d768 100644 --- a/src/editor/mod.rs +++ b/src/editor/mod.rs @@ -41,6 +41,7 @@ pub enum EditorMode { Headless, } +#[derive(Debug)] pub struct Editor { screen_rows: usize, screen_cols: usize, @@ -164,7 +165,8 @@ impl Editor { enable_mouse_support(&mut self.stdout); enable_alternate_screen(&mut self.stdout); - register_signal_handler(); + // SAFETY: we only register our signal handler once + unsafe { register_signal_handler() }; self.update_window_size(); Input::new(tx).run_threaded(); } diff --git a/src/exec/addr.rs b/src/exec/addr.rs index 36a79ee..0834a89 100644 --- a/src/exec/addr.rs +++ b/src/exec/addr.rs @@ -52,7 +52,7 @@ impl Addr { } /// Attempt to parse a valid dot expression from a character stream - pub fn parse(it: &mut Peekable) -> Result { + pub fn parse(it: &mut Peekable>) -> Result { let start = match SimpleAddr::parse(it) { Ok(exp) => Some(exp), // If the following char is a ',' we substitute BOF for a missing start @@ -91,7 +91,7 @@ pub struct SimpleAddr { } impl SimpleAddr { - fn parse(it: &mut Peekable) -> Result { + fn parse(it: &mut Peekable>) -> Result { let base = AddrBase::parse(it)?; let mut suffix = String::with_capacity(2); @@ -159,7 +159,7 @@ enum Dir { } impl AddrBase { - pub(crate) fn parse(it: &mut Peekable) -> Result { + pub(crate) fn parse(it: &mut Peekable>) -> Result { let dir = match it.peek() { Some('-') => { it.next(); @@ -242,7 +242,7 @@ impl AddrBase { } } -fn parse_delimited_regex(it: &mut Peekable, dir: Dir) -> Result { +fn parse_delimited_regex(it: &mut Peekable>, dir: Dir) -> Result { let mut s = String::new(); let mut prev = '/'; diff --git a/src/exec/cached_stdin.rs b/src/exec/cached_stdin.rs index eac3dd2..e60029f 100644 --- a/src/exec/cached_stdin.rs +++ b/src/exec/cached_stdin.rs @@ -13,12 +13,14 @@ const LINE_BUF_LEN: usize = 100; /// A wrapper around stdin that buffers and caches input so that it can be manipulated /// like a Buffer +#[derive(Debug)] pub struct CachedStdin { inner: RefCell, buf: RefCell, gb: RefCell, } +#[derive(Debug)] struct CachedStdinInner { stdin: Stdin, closed: bool, @@ -132,6 +134,7 @@ impl Edit for CachedStdin { } } +#[derive(Debug)] pub struct CachedStdinIter<'a> { pub(super) inner: &'a CachedStdin, pub(super) from: usize, diff --git a/src/exec/char_iter.rs b/src/exec/char_iter.rs index 049d62f..23c7591 100644 --- a/src/exec/char_iter.rs +++ b/src/exec/char_iter.rs @@ -23,26 +23,27 @@ pub trait IterBoundedChars { } impl IterBoundedChars for GapBuffer { - fn iter_between(&self, from: usize, to: usize) -> CharIter { + fn iter_between(&self, from: usize, to: usize) -> CharIter<'_> { CharIter::Slice(self.slice(from, to).indexed_chars(from, false)) } - fn rev_iter_between(&self, from: usize, to: usize) -> CharIter { + fn rev_iter_between(&self, from: usize, to: usize) -> CharIter<'_> { CharIter::Slice(self.slice(to, from).indexed_chars(to, true)) } } impl IterBoundedChars for Buffer { - fn iter_between(&self, from: usize, to: usize) -> CharIter { + fn iter_between(&self, from: usize, to: usize) -> CharIter<'_> { CharIter::Slice(self.txt.slice(from, to).indexed_chars(from, false)) } - fn rev_iter_between(&self, from: usize, to: usize) -> CharIter { + fn rev_iter_between(&self, from: usize, to: usize) -> CharIter<'_> { CharIter::Slice(self.txt.slice(to, from).indexed_chars(to, true)) } } /// Supported iterator types that can be returned by an InterBoundedChars +#[derive(Debug)] pub enum CharIter<'a> { Slice(IdxChars<'a>), StdIn(CachedStdinIter<'a>), @@ -60,7 +61,7 @@ impl<'a> Iterator for CharIter<'a> { } impl IterBoundedChars for CachedStdin { - fn iter_between(&self, from: usize, to: usize) -> CharIter { + fn iter_between(&self, from: usize, to: usize) -> CharIter<'_> { CharIter::StdIn(CachedStdinIter { inner: self, from, @@ -69,7 +70,7 @@ impl IterBoundedChars for CachedStdin { } /// This will always return None - fn rev_iter_between(&self, from: usize, to: usize) -> CharIter { + fn rev_iter_between(&self, from: usize, to: usize) -> CharIter<'_> { CharIter::StdIn(CachedStdinIter { inner: self, from, diff --git a/src/exec/expr.rs b/src/exec/expr.rs index 67a9db7..2c2c9e7 100644 --- a/src/exec/expr.rs +++ b/src/exec/expr.rs @@ -27,7 +27,7 @@ pub(super) enum ParseOutput { } impl Expr { - pub(super) fn try_parse(it: &mut Peekable) -> Result { + pub(super) fn try_parse(it: &mut Peekable>) -> Result { use Expr::*; use ParseOutput::*; @@ -70,17 +70,21 @@ impl Expr { } } -fn parse_delimited_regex(it: &mut Peekable, kind: &'static str) -> Result { +fn parse_delimited_regex(it: &mut Peekable>, kind: &'static str) -> Result { let s = parse_delimited_str(it, kind)?; Ok(Regex::compile(&s)?) } -fn parse_delimited_str(it: &mut Peekable, kind: &'static str) -> Result { +fn parse_delimited_str(it: &mut Peekable>, kind: &'static str) -> Result { let delim = it.next().ok_or(Error::MissingDelimiter(kind))?; read_until(delim, it, kind) } -fn read_until(delim: char, it: &mut Peekable, kind: &'static str) -> Result { +fn read_until( + delim: char, + it: &mut Peekable>, + kind: &'static str, +) -> Result { let mut s = String::new(); let mut prev = delim; @@ -95,7 +99,7 @@ fn read_until(delim: char, it: &mut Peekable, kind: &'static str) -> Resu Err(Error::UnclosedDelimiter(kind, delim)) } -fn parse_sub(it: &mut Peekable) -> Result { +fn parse_sub(it: &mut Peekable>) -> Result { let delim = it.next().ok_or(Error::MissingDelimiter("s"))?; let re = Regex::compile(&read_until(delim, it, "s")?)?; let s = read_until(delim, it, "s")?; @@ -107,7 +111,7 @@ fn parse_sub(it: &mut Peekable) -> Result { } } -fn parse_group(it: &mut Peekable) -> Result>, Error> { +fn parse_group(it: &mut Peekable>) -> Result>, Error> { let mut group = Vec::new(); let mut branch = Vec::new(); loop { diff --git a/src/exec/mod.rs b/src/exec/mod.rs index c6af332..cf14946 100644 --- a/src/exec/mod.rs +++ b/src/exec/mod.rs @@ -361,7 +361,7 @@ impl Program { } } -fn consume_whitespace(it: &mut Peekable) { +fn consume_whitespace(it: &mut Peekable>) { loop { match it.peek() { Some(ch) if ch.is_whitespace() => { diff --git a/src/ftype/lex.rs b/src/ftype/lex.rs index 94d399a..048cd50 100644 --- a/src/ftype/lex.rs +++ b/src/ftype/lex.rs @@ -329,27 +329,27 @@ mod tests { use crate::ftype::RUST_SPEC; use simple_test_case::test_case; - fn t_def(s: &str) -> Token { + fn t_def(s: &str) -> Token<'_> { Token { ty: Default, s } } - fn t_com(s: &str) -> Token { + fn t_com(s: &str) -> Token<'_> { Token { ty: Comment, s } } - fn t_dot(s: &str) -> Token { + fn t_dot(s: &str) -> Token<'_> { Token { ty: Dot, s } } - fn t_dfn(s: &str) -> Token { + fn t_dfn(s: &str) -> Token<'_> { Token { ty: Definition, s } } - fn t_cfl(s: &str) -> Token { + fn t_cfl(s: &str) -> Token<'_> { Token { ty: ControlFlow, s } } - fn t_str(s: &str) -> Token { + fn t_str(s: &str) -> Token<'_> { Token { ty: String, s } } diff --git a/src/lib.rs b/src/lib.rs index 28fe935..a0797d3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,16 @@ //! ad :: the adaptable editor +#![warn( + clippy::complexity, + clippy::correctness, + clippy::style, + future_incompatible, + missing_debug_implementations, + // missing_docs, + rust_2018_idioms, + rustdoc::all, + clippy::undocumented_unsafe_blocks +)] + use libc::termios as Termios; use std::{ io::Stdout, diff --git a/src/mode/mod.rs b/src/mode/mod.rs index 971ae40..81a0a8a 100644 --- a/src/mode/mod.rs +++ b/src/mode/mod.rs @@ -16,6 +16,7 @@ pub(crate) fn modes() -> Vec { vec![normal::normal_mode(), insert::insert_mode()] } +#[derive(Debug)] pub struct Mode { pub(crate) name: String, pub(crate) cur_shape: CurShape, diff --git a/src/regex/ast.rs b/src/regex/ast.rs index ed811b1..0886806 100644 --- a/src/regex/ast.rs +++ b/src/regex/ast.rs @@ -380,7 +380,7 @@ enum ParseEnd { Eof, } -fn parse1(it: &mut Peekable, root: &mut Vec) -> Result, Error> { +fn parse1(it: &mut Peekable>, root: &mut Vec) -> Result, Error> { match next_char(it)? { Some((ch, true)) => handle_escaped(ch, root).map(|_| None), Some((ch, false)) => handle_char(ch, it, root), @@ -388,7 +388,7 @@ fn parse1(it: &mut Peekable, root: &mut Vec) -> Result, root: &mut Vec) -> Result { +fn parse_many(it: &mut Peekable>, root: &mut Vec) -> Result { loop { match parse1(it, root)? { Some(p) => return Ok(p), @@ -399,7 +399,7 @@ fn parse_many(it: &mut Peekable, root: &mut Vec) -> Result, + it: &mut Peekable>, root: &mut Vec, ) -> Result, Error> { match ch { @@ -438,7 +438,7 @@ fn handle_char( /// 3) "(?:...)" /// Non-capturing: allows for grouping and application of repetition / alternation /// of compund expressions without contributing to the captured sub-expressions. -fn handle_subexp(it: &mut Peekable, root: &mut Vec) -> Result<(), Error> { +fn handle_subexp(it: &mut Peekable>, root: &mut Vec) -> Result<(), Error> { let mut sub = Vec::new(); let kind = match it.peek() { Some('?') => { @@ -479,7 +479,7 @@ fn handle_subexp(it: &mut Peekable, root: &mut Vec) -> Result<(), Er Ok(()) } -fn handle_alt(it: &mut Peekable, root: &mut Vec) -> Result<(), Error> { +fn handle_alt(it: &mut Peekable>, root: &mut Vec) -> Result<(), Error> { if root.is_empty() { return Err(Error::UnbalancedAlt); } @@ -533,7 +533,7 @@ fn handle_escaped(ch: char, root: &mut Vec) -> Result<(), Error> { Ok(()) } -fn try_parse_counted_repetition(it: &mut Peekable) -> Result { +fn try_parse_counted_repetition(it: &mut Peekable>) -> Result { let (mut ch, _) = next_char(it)?.ok_or(Error::InvalidRepetition)?; if !ch.is_ascii_digit() { diff --git a/src/regex/matches.rs b/src/regex/matches.rs index b5107be..eec69e9 100644 --- a/src/regex/matches.rs +++ b/src/regex/matches.rs @@ -189,6 +189,7 @@ impl<'a> IndexedChars for &'a GapBuffer { /// An iterator over sequential, non overlapping matches of a Regex /// against a given input +#[derive(Debug)] pub struct MatchIter<'a, I> where I: IndexedChars, diff --git a/src/regex/mod.rs b/src/regex/mod.rs index dfb351f..713200a 100644 --- a/src/regex/mod.rs +++ b/src/regex/mod.rs @@ -63,7 +63,7 @@ struct CharClass { } impl CharClass { - fn try_parse(it: &mut Peekable) -> Result { + fn try_parse(it: &mut Peekable>) -> Result { let mut next = || next_char(it)?.ok_or(Error::InvalidClass); let (mut ch, _) = next()?; @@ -117,7 +117,7 @@ impl CharClass { } } -fn next_char(it: &mut Peekable) -> Result, Error> { +fn next_char(it: &mut Peekable>) -> Result, Error> { match it.next() { Some('\\') => (), Some(ch) => return Ok(Some((ch, false))), diff --git a/src/term.rs b/src/term.rs index 9ba68fb..9bb18f2 100644 --- a/src/term.rs +++ b/src/term.rs @@ -32,26 +32,26 @@ pub fn win_size_changed() -> bool { WIN_SIZE_CHANGED.swap(false, Ordering::Relaxed) } -pub fn register_signal_handler() { - unsafe { - let mut maybe_sa = mem::MaybeUninit::::uninit(); - if libc::sigemptyset(&mut (*maybe_sa.as_mut_ptr()).sa_mask) == -1 { - die!( - "Unable to register signal handler: {}", - io::Error::last_os_error() - ) - } +/// # Safety +/// must only be called once +pub unsafe fn register_signal_handler() { + let mut maybe_sa = mem::MaybeUninit::::uninit(); + if libc::sigemptyset(&mut (*maybe_sa.as_mut_ptr()).sa_mask) == -1 { + die!( + "Unable to register signal handler: {}", + io::Error::last_os_error() + ) + } - let mut sa_ptr = *maybe_sa.as_mut_ptr(); - sa_ptr.sa_sigaction = handle_win_size_change as sighandler_t; - sa_ptr.sa_flags = SA_SIGINFO; + let mut sa_ptr = *maybe_sa.as_mut_ptr(); + sa_ptr.sa_sigaction = handle_win_size_change as sighandler_t; + sa_ptr.sa_flags = SA_SIGINFO; - if libc::sigaction(SIGWINCH, &sa_ptr as *const _, ptr::null_mut()) == -1 { - die!( - "Unable to register signal handler: {}", - io::Error::last_os_error() - ) - } + if libc::sigaction(SIGWINCH, &sa_ptr as *const _, ptr::null_mut()) == -1 { + die!( + "Unable to register signal handler: {}", + io::Error::last_os_error() + ) } } @@ -174,9 +174,9 @@ pub(crate) fn get_termsize() -> (usize, usize) { x: 0, y: 0, }; - unsafe { - ioctl(STDOUT_FILENO, TIOCGWINSZ, &mut ts as *mut _); - } + + // SAFETY: ts is a valid termsize struct to pass as a pointer here + unsafe { ioctl(STDOUT_FILENO, TIOCGWINSZ, &mut ts as *mut _) }; (ts.r as usize, ts.c as usize) } @@ -238,12 +238,14 @@ pub(crate) fn enable_raw_mode(mut t: Termios) { } pub(crate) fn set_termios(t: Termios) { + // SAFETY: t is a valid termios struct to use as a pointer here if unsafe { tcsetattr(STDOUT_FILENO, TCSAFLUSH, &t) } == -1 { die!("tcsetattr"); } } pub(crate) fn get_termios() -> Termios { + // SAFETY: passing a null pointer here is valid unsafe { let mut t: Termios = mem::zeroed(); if tcgetattr(STDOUT_FILENO, &mut t as *mut _) == -1 { diff --git a/src/trie.rs b/src/trie.rs index 9e37c35..a008979 100644 --- a/src/trie.rs +++ b/src/trie.rs @@ -302,6 +302,7 @@ where pub type WildcardFn = fn(&K) -> bool; /// A wildcard node in a key sequence that can conditionally match a single key element. +#[derive(Debug)] pub enum WildCard { Lit(K), Wild(WildcardFn), diff --git a/src/util.rs b/src/util.rs index b531657..36995c8 100644 --- a/src/util.rs +++ b/src/util.rs @@ -128,7 +128,7 @@ pub(crate) fn relative_path_from(base: &Path, p: &Path) -> PathBuf { // returns the parsed number and following character if there was one. // initial must be a valid ascii digit -pub(crate) fn parse_num(initial: char, it: &mut Peekable) -> usize { +pub(crate) fn parse_num(initial: char, it: &mut Peekable>) -> usize { let mut s = String::from(initial); loop { match it.peek() {