Skip to content

Commit

Permalink
Fix #276: execute panic on zero results
Browse files Browse the repository at this point in the history
- If the command refers to items, it is forbidden on zero results
- otherwise the command is allowed to execute all the time
  • Loading branch information
lotabout committed Mar 1, 2020
1 parent 92bff22 commit e028df9
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 8 deletions.
2 changes: 1 addition & 1 deletion src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ fn main() {
std::process::exit(0)
}
std::process::exit(2)
},
}
}
}

Expand Down
20 changes: 18 additions & 2 deletions src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use crate::reader::{Reader, ReaderControl};
use crate::selection::Selection;
use crate::spinlock::SpinLock;
use crate::theme::ColorTheme;
use crate::util::{inject_command, margin_string_to_size, parse_margin, InjectContext};
use crate::util::{depends_on_items, inject_command, margin_string_to_size, parse_margin, InjectContext};
use crate::{FuzzyAlgorithm, MatchEngineFactory, SkimItem};

const REFRESH_DURATION: i64 = 100;
Expand Down Expand Up @@ -339,14 +339,30 @@ impl Model {
}

fn act_execute(&mut self, cmd: &str) {
let item = self.selection.get_current_item();
if depends_on_items(cmd) && item.is_none() {
debug!("act_execute: command refers to items and there is no item for now");
debug!("command to execute: [{}]", cmd);
return;
}

let _ = self.term.pause();
self.act_execute_silent(cmd);
let _ = self.term.restart();
}

fn act_execute_silent(&mut self, cmd: &str) {
let item = self.selection.get_current_item();
let current_selection = item.as_ref().map(|item| item.output()).unwrap();
if depends_on_items(cmd) && item.is_none() {
debug!("act_execute_silent: command refers to items and there is no item for now");
debug!("command to execute: [{}]", cmd);
return;
}

let current_selection = item
.as_ref()
.map(|item| item.output())
.unwrap_or_else(|| Cow::Borrowed(""));
let query = self.query.get_fz_query();
let cmd_query = self.query.get_cmd_query();

Expand Down
8 changes: 7 additions & 1 deletion src/previewer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::ansi::{ANSIParser, AnsiString};
use crate::event::{Event, EventHandler, UpdateScreen};
use crate::item::ItemWrapper;
use crate::spinlock::SpinLock;
use crate::util::{inject_command, InjectContext};
use crate::util::{depends_on_items, inject_command, InjectContext};
use crate::{ItemPreview, SkimItem};
use derive_builder::Builder;
use nix::libc;
Expand Down Expand Up @@ -142,6 +142,12 @@ impl Previewer {
ItemPreview::Text(_) | ItemPreview::AnsiText(_) => unreachable!(),
};

if depends_on_items(&cmd) && self.prev_item.is_none() {
debug!("the command for preview refers to items and currently there is no item");
debug!("command to execute: [{}]", cmd);
PreviewEvent::PreviewPlainText("no item matched".to_string());
}

let current_selection = self
.prev_item
.as_ref()
Expand Down
15 changes: 11 additions & 4 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@ use crate::field::get_string_by_range;
use crate::item::ItemWrapper;
use crate::SkimItem;

lazy_static! {
static ref RE_FIELDS: Regex = Regex::new(r"\\?(\{ *-?[0-9.,cq+]*? *})").unwrap();
}

pub fn escape_single_quote(text: &str) -> String {
text.replace("'", "'\\''")
}
Expand Down Expand Up @@ -301,6 +297,17 @@ pub struct InjectContext<'a> {
pub cmd_query: &'a str,
}

lazy_static! {
static ref RE_ITEMS: Regex = Regex::new(r"\\?(\{ *-?[0-9.+]*? *})").unwrap();
static ref RE_FIELDS: Regex = Regex::new(r"\\?(\{ *-?[0-9.,cq+]*? *})").unwrap();
}

/// Check if a command depends on item
/// e.g. contains `{}`, `{1..}`, `{+}`
pub fn depends_on_items(cmd: &str) -> bool {
RE_ITEMS.is_match(cmd)
}

/// inject the fields into commands
/// cmd: `echo {1..}`, text: `a,b,c`, delimiter: `,`
/// => `echo b,c`
Expand Down
19 changes: 19 additions & 0 deletions test/test_skim.py
Original file line number Diff line number Diff line change
Expand Up @@ -844,6 +844,25 @@ def test_cmd_history(self):
with open(history_file) as fp:
self.assertEqual('a\nb\nc\ncd', fp.read())

def test_execute_with_zero_result_ref(self):
"""execute should not panic with zero results #276"""
self.tmux.send_keys(f"""echo -n "" | {self.sk("--bind 'enter:execute(less {})'")}""", Key('Enter'))
self.tmux.until(lambda lines: lines.ready_with_lines(0))
self.tmux.send_keys(Key('Enter'))
self.tmux.send_keys(Key('q'))
self.tmux.until(lambda lines: lines.ready_with_lines(0))
self.tmux.until(lambda lines: lines[-1].startswith('> q')) # less is not executed at all
self.tmux.send_keys(Ctrl('g'))

def test_execute_with_zero_result_no_ref(self):
"""execute should not panic with zero results #276"""
self.tmux.send_keys(f"""echo -n "" | {self.sk("--bind 'enter:execute(less)'")}""", Key('Enter'))
self.tmux.until(lambda lines: lines.ready_with_lines(0))
self.tmux.send_keys(Key('Enter'))
self.tmux.send_keys(Key('q'))
self.tmux.until(lambda lines: lines.ready_with_lines(0))
self.tmux.send_keys(Ctrl('g'))

def find_prompt(lines, interactive=False, reverse=False):
linen = -1
prompt = ">"
Expand Down

0 comments on commit e028df9

Please sign in to comment.