diff --git a/Cargo.lock b/Cargo.lock index d5765c8..35b9e08 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "aho-corasick" @@ -378,7 +378,7 @@ dependencies = [ [[package]] name = "python_ripgrep" -version = "0.0.9" +version = "0.1.0" dependencies = [ "anyhow", "bstr", diff --git a/README.md b/README.md index d81e5b4..e1eba89 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,10 @@ As of now, the library implements a subset of ripgrep's functionality. The main 3. `globs`: File patterns to include or exclude 4. `sort`: Sort mode for search results 5. `max_count`: Maximum number of matches to show +6. `case_sensitive`: Control case sensitivity +7. `smart_case`: Enable smart case matching +8. `no_ignore`: Disable gitignore/ignore file handling +9. `hidden`: Search hidden files and directories ## Implemented Flags @@ -89,6 +93,12 @@ The following is a checklist of ripgrep flags that have been implemented in this - [x] `separator_field_match`: (Optional) Separator between fields in matching lines - [x] `separator_context`: (Optional) Separator between context lines - [x] `-U, --multiline`: Enable matching across multiple lines +- [x] `-i, --ignore-case`: Case insensitive search (via `case_sensitive=False`) +- [x] `-s, --case-sensitive`: Case sensitive search (via `case_sensitive=True`) +- [x] `-S, --smart-case`: Smart case search (via `smart_case=True`) +- [x] `--no-ignore`: Don't respect ignore files (via `no_ignore=True`) +- [x] `--hidden`: Search hidden files and directories (via `hidden=True`) +- [x] `--json`: Output results in JSON Lines format (via `json=True`) The following flags from ripgrep are not yet implemented in this wrapper: @@ -99,13 +109,11 @@ The following flags from ripgrep are not yet implemented in this wrapper: - [ ] `--dfa-size-limit`: Limit for regex DFA size - [ ] `-E, --encoding`: Specify the text encoding of files to search - [ ] `-F, --fixed-strings`: Treat patterns as literal strings -- [ ] `-i, --ignore-case`: Case insensitive search - [ ] `-v, --invert-match`: Invert matching - [ ] `-n, --line-number`: Show line numbers - [ ] `-x, --line-regexp`: Only show matches surrounded by line boundaries - [ ] `-M, --max-columns`: Don't print lines longer than this limit - [ ] `--mmap`: Memory map searched files when possible -- [ ] `--no-ignore`: Don't respect ignore files - [ ] `--no-unicode`: Disable Unicode-aware search - [ ] `-0, --null`: Print NUL byte after file names - [ ] `-o, --only-matching`: Print only matched parts of a line @@ -113,8 +121,6 @@ The following flags from ripgrep are not yet implemented in this wrapper: - [ ] `-P, --pcre2`: Use the PCRE2 regex engine - [ ] `-p, --pretty`: Alias for --color=always --heading -n - [ ] `-r, --replace`: Replace matches with the given text -- [ ] `-S, --smart-case`: Smart case search -- [ ] `-s, --case-sensitive`: Case sensitive search - [ ] `--stats`: Print statistics about the search - [ ] `-a, --text`: Search binary files as if they were text - [ ] `-t, --type`: Only search files matching TYPE diff --git a/python_ripgrep/__init__.pyi b/python_ripgrep/__init__.pyi index e026063..78a50df 100644 --- a/python_ripgrep/__init__.pyi +++ b/python_ripgrep/__init__.pyi @@ -26,6 +26,11 @@ def search( max_count: int | None = None, line_number: bool | None = None, multiline: bool | None = None, + case_sensitive: bool | None = None, + smart_case: bool | None = None, + no_ignore: bool | None = None, + hidden: bool | None = None, + json: bool | None = None, ) -> list[str]: ... def files( patterns: list[str], @@ -41,4 +46,9 @@ def files( max_count: int | None = None, line_number: bool | None = None, multiline: bool | None = None, + case_sensitive: bool | None = None, + smart_case: bool | None = None, + no_ignore: bool | None = None, + hidden: bool | None = None, + json: bool | None = None, ) -> list[str]: ... diff --git a/src/ripgrep_core.rs b/src/ripgrep_core.rs index 5b421ff..6dab60d 100644 --- a/src/ripgrep_core.rs +++ b/src/ripgrep_core.rs @@ -1,16 +1,18 @@ -use std::{borrow::BorrowMut, ffi::{OsStr, OsString}}; use hiargs::HiArgs; -use pyo3::prelude::*; use pyo3::exceptions::PyValueError; +use pyo3::prelude::*; +use std::{ + borrow::BorrowMut, + ffi::{OsStr, OsString}, +}; -mod search; +mod haystack; mod hiargs; mod lowargs; -mod haystack; +mod search; #[macro_use] mod messages; - #[pyclass] pub struct PyArgs { pub patterns: Vec, @@ -26,29 +28,39 @@ pub struct PyArgs { pub max_count: Option, pub line_number: Option, pub multiline: Option, + pub case_sensitive: Option, + pub smart_case: Option, + pub no_ignore: Option, + pub hidden: Option, + pub json: Option, } #[pymethods] impl PyArgs { #[new] #[pyo3(signature = ( - patterns, - paths=None, - globs=None, - heading=None, + patterns, + paths=None, + globs=None, + heading=None, after_context=None, before_context=None, - separator_field_context=None, - separator_field_match=None, + separator_field_context=None, + separator_field_match=None, separator_context=None, sort=None, max_count=None, line_number=None, multiline=None, + case_sensitive=None, + smart_case=None, + no_ignore=None, + hidden=None, + json=None, ))] fn new( - patterns: Vec, - paths: Option>, + patterns: Vec, + paths: Option>, globs: Option>, heading: Option, after_context: Option, @@ -60,6 +72,11 @@ impl PyArgs { max_count: Option, line_number: Option, multiline: Option, + case_sensitive: Option, + smart_case: Option, + no_ignore: Option, + hidden: Option, + json: Option, ) -> Self { PyArgs { patterns, @@ -75,11 +92,15 @@ impl PyArgs { max_count, line_number, multiline, + case_sensitive, + smart_case, + no_ignore, + hidden, + json, } } } - #[pyclass(eq)] #[derive(PartialEq, Clone)] #[pyo3(get_all)] @@ -92,18 +113,11 @@ pub struct PySortMode { impl PySortMode { #[new] #[pyo3(signature = (kind, reverse=false))] - fn new( - kind: PySortModeKind, - reverse: bool, - ) -> Self { - PySortMode { - kind, - reverse, - } + fn new(kind: PySortModeKind, reverse: bool) -> Self { + PySortMode { kind, reverse } } } - #[pyclass(eq)] #[derive(PartialEq, Clone)] #[pyo3(get_all)] @@ -115,14 +129,16 @@ pub enum PySortModeKind { } fn build_patterns(patterns: Vec) -> Vec { - patterns.into_iter().map(|pattern| lowargs::PatternSource::Regexp(pattern)).collect() + patterns + .into_iter() + .map(|pattern| lowargs::PatternSource::Regexp(pattern)) + .collect() } fn build_paths(paths: Vec) -> Vec { paths.into_iter().map(|path| OsString::from(path)).collect() } - fn build_sort_mode_kind(kind: PySortModeKind) -> lowargs::SortModeKind { match kind { PySortModeKind::Path => lowargs::SortModeKind::Path, @@ -134,13 +150,19 @@ fn build_sort_mode_kind(kind: PySortModeKind) -> lowargs::SortModeKind { fn build_sort_mode(sort: Option) -> Option { if let Some(sort_mode) = sort { - Some(lowargs::SortMode { kind: build_sort_mode_kind(sort_mode.kind), reverse: sort_mode.reverse }) + Some(lowargs::SortMode { + kind: build_sort_mode_kind(sort_mode.kind), + reverse: sort_mode.reverse, + }) } else { None } } -fn build_context_mode(after_context: Option, before_context: Option) -> lowargs::ContextMode { +fn build_context_mode( + after_context: Option, + before_context: Option, +) -> lowargs::ContextMode { let mut context_mode = lowargs::ContextMode::default(); if let Some(after) = after_context { @@ -198,10 +220,32 @@ fn pyargs_to_hiargs(py_args: &PyArgs, mode: lowargs::Mode) -> anyhow::Result