Skip to content

Commit

Permalink
fix #40, #48 support toggling regex mode dynamically.
Browse files Browse the repository at this point in the history
1. Change the default key binding for toggleing interactive mode to Ctrl-Q
2. Support toggling regex mode by Ctrl-R (rotate mode)
3. Update README
  • Loading branch information
lotabout committed Jan 19, 2017
1 parent 0507a02 commit 4f8e6ea
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 20 deletions.
35 changes: 29 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,17 @@ the ones you selected in vim.

## As Interactive Interface

`skim` can invoke other commands dynamically. Normally you would want to integrate it with
[ag](https://github.com/ggreer/the_silver_searcher) or [ack](https://github.com/petdance/ack2) for
searching contents in a project directory:
`skim` can invoke other commands dynamically. Normally you would want to
integrate it with [rg](https://github.com/BurntSushi/ripgrep)
[ag](https://github.com/ggreer/the_silver_searcher) or
[ack](https://github.com/petdance/ack2) for searching contents in a project
directory:

```
# work with ag
sk --ansi -i -c 'ag --color "{}"'
# or with rg
sk --ansi -c 'rg --color=always --line-number "{}"'
```

![interactive mode demo](https://cloud.githubusercontent.com/assets/1527040/21603930/655d859a-d1db-11e6-9fec-c25099d30a12.gif)
Expand All @@ -117,7 +122,7 @@ Some common used keybindings.

## Search Syntax

`skim` borrowed `fzf`'s syntax for matching items
`skim` borrowed `fzf`'s syntax for matching items:

| Token | Match type | Description |
|----------|----------------------------|-----------------------------------|
Expand All @@ -128,12 +133,24 @@ Some common used keybindings.
| `!fire` | inverse-exact-match | items that do not include `fire` |
| `!.mp3$` | inverse-suffix-exact-match | items that do not end with `.mp3` |

`skim` also support the combination of tokens.

- space has the meaning of `AND`. With the term `src main`, `skim` will search
for items that match **both** `src` and `main`.
- ` | ` means `OR` (note the spaces around `|`). With the term `.md$ |
.markdown$`, `skim` will search for items ends with either `.md` or
`.markdown`.
- `OR` have higher precedence. So `readme .md$ | .markdown$` is groupped into
`readme AND (.md$ OR .markdown$)`.

In case that you want to use regular expressions, `skim` provide `regex` mode:

```
sk --regex
```

You can switch to `regex` mode dynamically by pressing `Ctrl-R` (Rotate Mode).

## exit code

| Exit Code | Meaning |
Expand Down Expand Up @@ -183,7 +200,7 @@ Specify the bindings with comma seperated pairs(no space allowed), example:
| toggle | None |
| toggle-all | None |
| toggle-down | tab |
| toggle-in | None |
| toggle-interactive | ctrl-q |
| toggle-out | None |
| toggle-sort | None |
| toggle-up | shift-tab |
Expand Down Expand Up @@ -256,10 +273,16 @@ present the output to you. You can specify the command using the `-c` option:

`sk -i -c 'ag --color "{}"'`

In the above example, the replstr `{}` will be replaced with the query you
In the above example, the replace string `{}` will be replaced with the query you
type before invoking the command. Use `-I <replstr>` to change replstr if you
want.

For example, with the input "hello" in interactive mode, `skim` will replace
the above command with `ag --color "hello"` and invoke it.

If you want to further narrow down the result returned by the command, press
`Ctrl-Q` to toggle interactive mode.

## Fields support

Normally only plugin users need to understand this.
Expand Down
3 changes: 3 additions & 0 deletions src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub enum Event {
EvModelDrawInfo,
EvModelNewItem,
EvModelNotifyProcessed,
EvModelNotifyMatcherMode,
EvModelRestart,

EvReaderNewItem,
Expand Down Expand Up @@ -62,6 +63,7 @@ pub enum Event {
EvActToggleAll,
EvActToggleDown,
EvActToggleIn,
EvActToggleInteractive,
EvActToggleOut,
EvActToggleSort,
EvActToggleUp,
Expand Down Expand Up @@ -103,6 +105,7 @@ pub fn parse_action(action: &str) -> Option<Event> {
"toggle-all" => Some(Event::EvActToggleAll),
"toggle-down" => Some(Event::EvActToggleDown),
"toggle-in" => Some(Event::EvActToggleIn),
"toggle-interactive" => Some(Event::EvActToggleInteractive),
"toggle-out" => Some(Event::EvActToggleOut),
"toggle-sort" => Some(Event::EvActToggleSort),
"toggle-up" => Some(Event::EvActToggleUp),
Expand Down
1 change: 1 addition & 0 deletions src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,7 @@ fn get_default_key_map() -> HashMap<Key, (Event, Option<String>)> {
//ret.insert(Key::AltZ, (Event::EvActToggleAll, None));
ret.insert(Key::Tab, (Event::EvActToggleDown, None));
//ret.insert(Key::AltZ, (Event::EvActToggleIn, None));
ret.insert(Key::CtrlQ, (Event::EvActToggleInteractive, None));
//ret.insert(Key::AltZ, (Event::EvActToggleOut, None));
//ret.insert(Key::AltZ, (Event::EvActToggleSort, None));
ret.insert(Key::BTab, (Event::EvActToggleUp, None));
Expand Down
23 changes: 18 additions & 5 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ fn real_main() -> i32 {
// reader
let (tx_reader, rx_reader) = channel();
let (tx_item, rx_item) = sync_channel(128);
let mut reader = reader::Reader::new(rx_reader, tx_item);
let mut reader = reader::Reader::new(rx_reader, tx_item.clone());
reader.parse_options(&options);
thread::spawn(move || {
reader.run();
Expand Down Expand Up @@ -235,15 +235,22 @@ fn real_main() -> i32 {
// Helper functions

// light up the fire
let _ = tx_reader.send((EvReaderRestart, Box::new((query.get_cmd(), query.get_query()))));
let _ = tx_reader.send((EvReaderRestart, Box::new((query.get_cmd(), query.get_query(), false))));

let redraw_query = |query: &query::Query| {
let _ = tx_model.send((EvModelDrawQuery, Box::new(query.get_print_func())));
};

let on_query_change = |query: &query::Query| {
// restart the reader with new parameter
let _ = tx_reader.send((EvReaderRestart, Box::new((query.get_cmd(), query.get_query()))));
let _ = tx_reader.send((EvReaderRestart, Box::new((query.get_cmd(), query.get_query(), false))));
// send redraw event
redraw_query(query);
};

let on_query_force_update = |query: &query::Query| {
// restart the reader with new parameter
let _ = tx_reader.send((EvReaderRestart, Box::new((query.get_cmd(), query.get_query(), true))));
// send redraw event
redraw_query(query);
};
Expand Down Expand Up @@ -326,11 +333,17 @@ fn real_main() -> i32 {
on_query_change(&query);
}

EvActRotateMode => {
query.act_query_rotate_mode();
EvActToggleInteractive => {
query.act_query_toggle_interactive();
redraw_query(&query);
}

EvActRotateMode => {
// tell the matcher to switch mode
let _ = tx_item.send((EvActRotateMode, Box::new(false)));
on_query_force_update(&query);
}

EvActAccept => {
// sync with model to quit

Expand Down
32 changes: 26 additions & 6 deletions src/matcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ enum Algorithm {
#[derive(Clone, Copy, PartialEq)]
enum MatcherMode {
Regex,
Plain,
Fuzzy,
Exact,
}
Expand Down Expand Up @@ -104,6 +103,7 @@ impl Matcher {

let mut matcher_engine: Option<Box<MatchEngine>> = None;
let mut num_processed: usize = 0;
let mut matcher_mode = self.mode;
loop {

if matcher_restart.load(Ordering::Relaxed) {
Expand Down Expand Up @@ -147,7 +147,31 @@ impl Matcher {
// notifiy the model that the query had been changed
let _ = self.tx_result.send((Event::EvModelRestart, Box::new(true)));

matcher_engine = Some(EngineFactory::build(&query, self.mode));
let mode_string = match matcher_mode {
MatcherMode::Regex => "RE".to_string(),
MatcherMode::Exact => "EX".to_string(),
_ => "".to_string(),
};
let _ = self.tx_result.send((Event::EvModelNotifyMatcherMode, Box::new(mode_string)));

matcher_engine = Some(EngineFactory::build(&query, matcher_mode));
}

Event::EvActRotateMode => {
if self.mode == MatcherMode::Regex {
// sk started with regex mode.
matcher_mode = if matcher_mode == self.mode {
MatcherMode::Fuzzy
} else {
MatcherMode::Regex
};
} else {
matcher_mode = if matcher_mode == self.mode {
MatcherMode::Regex
} else {
self.mode
}
}
}

_ => {}
Expand Down Expand Up @@ -542,7 +566,6 @@ impl EngineFactory {
pub fn build(query: &str, mode: MatcherMode) -> Box<MatchEngine> {
match mode {
MatcherMode::Regex => Box::new(RegexEngine::builder(query).build()),
MatcherMode::Plain => Box::new(FuzzyEngine::builder(query).build()),
MatcherMode::Fuzzy | MatcherMode::Exact => {
if query.contains(" ") {
Box::new(AndEngine::builder(query, mode).build())
Expand Down Expand Up @@ -615,9 +638,6 @@ mod test {
let x1 = EngineFactory::build("'abc | def ^gh ij | kl mn", MatcherMode::Fuzzy);
assert_eq!(x1.display(), "(And: (Or: (Exact: abc), (Fuzzy: def)), (PrefixExact: gh), (Or: (Fuzzy: ij), (Fuzzy: kl)), (Fuzzy: mn))");

let x2 = EngineFactory::build("'abc | def ^gh ij | kl mn", MatcherMode::Plain);
assert_eq!(x2.display(), "(Fuzzy: 'abc | def ^gh ij | kl mn)");

let x3 = EngineFactory::build("'abc | def ^gh ij | kl mn", MatcherMode::Regex);
assert_eq!(x3.display(), "(Regex: 'abc | def ^gh ij | kl mn)");

Expand Down
11 changes: 11 additions & 0 deletions src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ pub struct Model {
matcher_stopped: bool,
num_read: usize,
num_processed: usize,
matcher_mode: String,
timer: Instant,
}

Expand All @@ -69,6 +70,7 @@ impl Model {
reader_stopped: false,
matcher_stopped: false,
timer: Instant::now(),
matcher_mode: "".to_string(),
theme: ColorTheme::new(),
}
}
Expand Down Expand Up @@ -142,6 +144,10 @@ impl Model {

}

Event::EvModelNotifyMatcherMode => {
self.matcher_mode = *arg.downcast().unwrap();
}

Event::EvMatcherStopped => {
self.matcher_stopped = true;
self.act_redraw_items_and_status(&curses);
Expand Down Expand Up @@ -332,6 +338,11 @@ impl Model {
// display matched/total number
curses.cprint(format!(" {}/{}", self.items.len(), self.num_read).as_ref(), COLOR_INFO, false);

// display the matcher mode
if !self.matcher_mode.is_empty() {
curses.cprint(format!("/{}", &self.matcher_mode).as_ref(), COLOR_INFO, false);
}

// display the percentage of the number of processed items
if self.num_processed < self.num_read {
curses.cprint(format!(" ({}%) ", self.num_processed*100 / self.num_read).as_ref(), COLOR_INFO, false)
Expand Down
2 changes: 1 addition & 1 deletion src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ impl Query {
//------------------------------------------------------------------------------
// Actions
//
pub fn act_query_rotate_mode(&mut self) {
pub fn act_query_toggle_interactive(&mut self) {
self.mode = match self.mode {
QueryMode::QUERY => QueryMode::CMD,
QueryMode::CMD => QueryMode::QUERY,
Expand Down
4 changes: 2 additions & 2 deletions src/reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,8 @@ impl Reader {
match ev {
Event::EvReaderRestart => {
// close existing command or file if exists
let (cmd, query) = *arg.downcast::<(String, String)>().unwrap();
if cmd == last_command && query == last_query { continue; }
let (cmd, query, force_update) = *arg.downcast::<(String, String, bool)>().unwrap();
if !force_update && cmd == last_command && query == last_query { continue; }

// restart command with new `command`
if cmd != last_command {
Expand Down

0 comments on commit 4f8e6ea

Please sign in to comment.