Skip to content

Commit

Permalink
Replace memchr::memchr by matches!
Browse files Browse the repository at this point in the history
  • Loading branch information
gwenn committed Jan 29, 2023
1 parent 45b9e3d commit c75f56d
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 43 deletions.
66 changes: 31 additions & 35 deletions src/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use std::path::{self, Path};

use crate::line_buffer::LineBuffer;
use crate::{Context, Result};
use memchr::memchr;

/// A completion candidate.
pub trait Candidate {
Expand Down Expand Up @@ -143,35 +142,35 @@ box_completer! { Box Rc Arc }

/// A `Completer` for file and folder names.
pub struct FilenameCompleter {
break_chars: &'static [u8],
double_quotes_special_chars: &'static [u8],
break_chars: fn(char) -> bool,
double_quotes_special_chars: fn(char) -> bool,
}

const DOUBLE_QUOTES_ESCAPE_CHAR: Option<char> = Some('\\');

cfg_if::cfg_if! {
if #[cfg(unix)] {
// rl_basic_word_break_characters, rl_completer_word_break_characters
const DEFAULT_BREAK_CHARS: [u8; 18] = [
b' ', b'\t', b'\n', b'"', b'\\', b'\'', b'`', b'@', b'$', b'>', b'<', b'=', b';', b'|', b'&',
b'{', b'(', b'\0',
];
const fn default_break_chars(c : char) -> bool {
matches!(c, ' ' | '\t' | '\n' | '"' | '\\' | '\'' | '`' | '@' | '$' | '>' | '<' | '=' | ';' | '|' | '&' |
'{' | '(' | '\0')
}
const ESCAPE_CHAR: Option<char> = Some('\\');
// In double quotes, not all break_chars need to be escaped
// https://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html
const DOUBLE_QUOTES_SPECIAL_CHARS: [u8; 4] = [b'"', b'$', b'\\', b'`'];
const fn double_quotes_special_chars(c: char) -> bool { matches!(c, '"' | '$' | '\\' | '`') }
} else if #[cfg(windows)] {
// Remove \ to make file completion works on windows
const DEFAULT_BREAK_CHARS: [u8; 17] = [
b' ', b'\t', b'\n', b'"', b'\'', b'`', b'@', b'$', b'>', b'<', b'=', b';', b'|', b'&', b'{',
b'(', b'\0',
];
const fn default_break_chars(c: char) -> bool {
matches!(c, ' ' | '\t' | '\n' | '"' | '\'' | '`' | '@' | '$' | '>' | '<' | '=' | ';' | '|' | '&' | '{' |
'(' | '\0')
}
const ESCAPE_CHAR: Option<char> = None;
const DOUBLE_QUOTES_SPECIAL_CHARS: [u8; 1] = [b'"']; // TODO Validate: only '"' ?
const fn double_quotes_special_chars(c: char) -> bool { c == '"' } // TODO Validate: only '"' ?
} else if #[cfg(target_arch = "wasm32")] {
const DEFAULT_BREAK_CHARS: [u8; 0] = [];
const fn default_break_chars(c: char) -> bool { false }
const ESCAPE_CHAR: Option<char> = None;
const DOUBLE_QUOTES_SPECIAL_CHARS: [u8; 0] = [];
const fn double_quotes_special_chars(c: char) -> bool { false }
}
}

Expand All @@ -191,8 +190,8 @@ impl FilenameCompleter {
#[must_use]
pub fn new() -> Self {
Self {
break_chars: &DEFAULT_BREAK_CHARS,
double_quotes_special_chars: &DOUBLE_QUOTES_SPECIAL_CHARS,
break_chars: default_break_chars,
double_quotes_special_chars,
}
}

Expand All @@ -208,22 +207,22 @@ impl FilenameCompleter {
start,
unescape(&line[start..pos], DOUBLE_QUOTES_ESCAPE_CHAR),
DOUBLE_QUOTES_ESCAPE_CHAR,
&self.double_quotes_special_chars,
self.double_quotes_special_chars,
quote,
)
} else {
(
start,
Borrowed(&line[start..pos]),
None,
&self.break_chars,
self.break_chars,
quote,
)
}
} else {
let (start, path) = extract_word(line, pos, ESCAPE_CHAR, self.break_chars);
let path = unescape(path, ESCAPE_CHAR);
(start, path, ESCAPE_CHAR, &self.break_chars, Quote::None)
(start, path, ESCAPE_CHAR, self.break_chars, Quote::None)
};
let mut matches = filename_complete(&path, esc_char, break_chars, quote);
#[allow(clippy::unnecessary_sort_by)]
Expand Down Expand Up @@ -284,16 +283,13 @@ pub fn unescape(input: &str, esc_char: Option<char>) -> Cow<'_, str> {
pub fn escape(
mut input: String,
esc_char: Option<char>,
break_chars: &[u8],
is_break_char: fn(char) -> bool,
quote: Quote,
) -> String {
if quote == Quote::Single {
return input; // no escape in single quotes
}
let n = input
.bytes()
.filter(|b| memchr(*b, break_chars).is_some())
.count();
let n = input.chars().filter(|c| is_break_char(*c)).count();
if n == 0 {
return input; // no need to escape
}
Expand All @@ -309,7 +305,7 @@ pub fn escape(
let mut result = String::with_capacity(input.len() + n);

for c in input.chars() {
if c.is_ascii() && memchr(c as u8, break_chars).is_some() {
if is_break_char(c) {
result.push(esc_char);
}
result.push(c);
Expand All @@ -320,7 +316,7 @@ pub fn escape(
fn filename_complete(
path: &str,
esc_char: Option<char>,
break_chars: &[u8],
is_break_char: fn(char) -> bool,
quote: Quote,
) -> Vec<Pair> {
#[cfg(feature = "with-dirs")]
Expand Down Expand Up @@ -383,7 +379,7 @@ fn filename_complete(
}
entries.push(Pair {
display: String::from(s),
replacement: escape(path, esc_char, break_chars, quote),
replacement: escape(path, esc_char, is_break_char, quote),
});
} // else ignore PermissionDenied
}
Expand All @@ -409,12 +405,12 @@ fn normalize(s: &str) -> Cow<str> {
/// Return (0, `line[..pos]`) if no break char has been found.
/// Return the word and its start position (idx, `line[idx..pos]`) otherwise.
#[must_use]
pub fn extract_word<'l>(
line: &'l str,
pub fn extract_word(
line: &str,
pos: usize,
esc_char: Option<char>,
break_chars: &[u8],
) -> (usize, &'l str) {
is_break_char: fn(char) -> bool,
) -> (usize, &str) {
let line = &line[..pos];
if line.is_empty() {
return (0, line);
Expand All @@ -429,7 +425,7 @@ pub fn extract_word<'l>(
}
break;
}
if c.is_ascii() && memchr(c as u8, break_chars).is_some() {
if is_break_char(c) {
start = Some(i + c.len_utf8());
if esc_char.is_none() {
break;
Expand Down Expand Up @@ -536,7 +532,7 @@ fn find_unclosed_quote(s: &str) -> Option<(usize, Quote)> {
mod tests {
#[test]
pub fn extract_word() {
let break_chars: &[u8] = &super::DEFAULT_BREAK_CHARS;
let break_chars = super::default_break_chars;
let line = "ls '/usr/local/b";
assert_eq!(
(4, "/usr/local/b"),
Expand Down Expand Up @@ -567,7 +563,7 @@ mod tests {

#[test]
pub fn escape() {
let break_chars: &[u8] = &super::DEFAULT_BREAK_CHARS;
let break_chars = super::default_break_chars;
let input = String::from("/usr/local/b");
assert_eq!(
input.clone(),
Expand Down
12 changes: 4 additions & 8 deletions src/highlight.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
//! Syntax highlighting
use crate::config::CompletionType;
use memchr::memchr;
use std::borrow::Cow::{self, Borrowed, Owned};
use std::cell::Cell;

Expand Down Expand Up @@ -91,9 +90,6 @@ impl<'r, H: ?Sized + Highlighter> Highlighter for &'r H {
}
}

const OPENS: &[u8; 3] = b"{[(";
const CLOSES: &[u8; 3] = b"}])";

// TODO versus https://python-prompt-toolkit.readthedocs.io/en/master/pages/reference.html?highlight=HighlightMatchingBracketProcessor#prompt_toolkit.layout.processors.HighlightMatchingBracketProcessor

/// Highlight matching bracket when typed or cursor moved on.
Expand Down Expand Up @@ -224,11 +220,11 @@ const fn matching_bracket(bracket: u8) -> u8 {
b => b,
}
}
fn is_open_bracket(bracket: u8) -> bool {
memchr(bracket, OPENS).is_some()
const fn is_open_bracket(bracket: u8) -> bool {
matches!(bracket, b'{' | b'[' | b'(')
}
fn is_close_bracket(bracket: u8) -> bool {
memchr(bracket, CLOSES).is_some()
const fn is_close_bracket(bracket: u8) -> bool {
matches!(bracket, b'}' | b']' | b')')
}

#[cfg(test)]
Expand Down

0 comments on commit c75f56d

Please sign in to comment.