Skip to content

Commit

Permalink
Merge pull request #4 from ynqa/v0.1.2/main
Browse files Browse the repository at this point in the history
v0.1.2
  • Loading branch information
ynqa committed Jun 2, 2024
2 parents 62725ec + 0db6dda commit 629be95
Show file tree
Hide file tree
Showing 9 changed files with 269 additions and 55 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "sigrs"
version = "0.1.1"
version = "0.1.2"
authors = ["ynqa <[email protected]>"]
edition = "2021"
description = "Interactive grep (for streaming)"
Expand Down
40 changes: 39 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,16 @@ Interactive grep
- Interactive grep (for streaming)
- *sig* allows users to interactively search through (streaming) data,
updating results in real-time.
- Re-execute command
- If `--cmd` is specified instread of piping data to *sig*,
the command will be executed on initial and retries.
- This feature is designed to address the issue where data streams
past while the user is fine-tuning the search criteria.
In other words, even if the data has already passed,
executing the command again allows
the retrieval of the data for re-evaluation.
- Archived mode
- In Archived mode, since there is no seeking capability
- In archived mode, since there is no seeking capability
for streaming data received through a pipe,
it is not possible to search backwards without exiting the process.
Therefore, in *sig*, the latest N entries of streaming data are saved,
Expand Down Expand Up @@ -79,11 +87,28 @@ in
}
```

## Examples

```bash
stern --context kind-kind etcd |& sig
# or
sig --cmd "stern --context kind-kind etcd" # this is able to retry command by ctrl+r.
```

### Archived mode

```bash
cat README.md |& sig -a
# or
sig -a --cmd "cat README.md"
```

## Keymap

| Key | Action
| :- | :-
| <kbd>Ctrl + C</kbd> | Exit `sig`
| <kbd>Ctrl + R</kbd> | Retry command if `--cmd` is specified
| <kbd>Ctrl + F</kbd> | Enter Archived mode
| <kbd>←</kbd> | Move the cursor one character to the left
| <kbd>→</kbd> | Move the cursor one character to the right
Expand Down Expand Up @@ -111,6 +136,17 @@ Interactive grep (for streaming)

Usage: sig [OPTIONS]

Examples:

$ stern --context kind-kind etcd |& sig
Or the method to retry command by pressing ctrl+r:
$ sig --cmd "stern --context kind-kind etcd"

Archived mode:
$ cat README.md |& sig -a
Or
$ sig -a --cmd "cat README.md"

Options:
--retrieval-timeout <RETRIEVAL_TIMEOUT_MILLIS>
Timeout to read a next line from the stream in milliseconds. [default: 10]
Expand All @@ -122,6 +158,8 @@ Options:
Archived mode to grep through static data.
-i, --ignore-case
Case insensitive search.
--cmd <CMD>
Command to execute on initial and retries.
-h, --help
Print help (see more with '--help')
-V, --version
Expand Down
10 changes: 9 additions & 1 deletion src/archived.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ struct Archived {
lines: Snapshot<listbox::State>,
highlight_style: ContentStyle,
case_insensitive: bool,
cmd: Option<String>,
}

impl promkit::Finalizer for Archived {
Expand All @@ -39,7 +40,12 @@ impl promkit::Renderer for Archived {
}

fn evaluate(&mut self, event: &Event) -> anyhow::Result<PromptSignal> {
let signal = self.keymap.get()(event, &mut self.text_editor_snapshot, &mut self.lines);
let signal = self.keymap.get()(
event,
&mut self.text_editor_snapshot,
&mut self.lines,
self.cmd.clone(),
);
if self
.text_editor_snapshot
.after()
Expand Down Expand Up @@ -85,6 +91,7 @@ pub fn run(
lines: listbox::State,
highlight_style: ContentStyle,
case_insensitive: bool,
cmd: Option<String>,
) -> anyhow::Result<()> {
Prompt {
renderer: Archived {
Expand All @@ -93,6 +100,7 @@ pub fn run(
lines: Snapshot::new(lines),
highlight_style,
case_insensitive,
cmd,
},
}
.run()
Expand Down
16 changes: 16 additions & 0 deletions src/archived/keymap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,33 @@ pub type Keymap = fn(
&Event,
&mut Snapshot<text_editor::State>,
&mut Snapshot<listbox::State>,
Option<String>,
) -> anyhow::Result<PromptSignal>;

pub fn default(
event: &Event,
text_editor_snapshot: &mut Snapshot<text_editor::State>,
logs_snapshot: &mut Snapshot<listbox::State>,
cmd: Option<String>,
) -> anyhow::Result<PromptSignal> {
let text_editor_state = text_editor_snapshot.after_mut();
let logs_state = logs_snapshot.after_mut();

match event {
Event::Key(KeyEvent {
code: KeyCode::Char('r'),
modifiers: KeyModifiers::CONTROL,
kind: KeyEventKind::Press,
state: KeyEventState::NONE,
}) => {
if cmd.is_some() {
// Exiting archive mode here allows
// the caller to re-enter streaming mode,
// as it is running in an infinite loop.
return Ok(PromptSignal::Quit);
}
}

Event::Key(KeyEvent {
code: KeyCode::Char('c'),
modifiers: KeyModifiers::CONTROL,
Expand Down
54 changes: 54 additions & 0 deletions src/cmd.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
use std::process::Stdio;

use tokio::{
io::{AsyncBufReadExt, BufReader},
process::Command,
sync::mpsc,
time::{timeout, Duration},
};
use tokio_util::sync::CancellationToken;

pub async fn execute(
cmdstr: &str,
tx: mpsc::Sender<String>,
retrieval_timeout: Duration,
canceled: CancellationToken,
) -> anyhow::Result<()> {
let args: Vec<&str> = cmdstr.split_whitespace().collect();
let mut child = Command::new(args[0])
.args(&args[1..])
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?;

let stdout = child
.stdout
.take()
.ok_or_else(|| anyhow::anyhow!("stdout is not available"))?;
let stderr = child
.stderr
.take()
.ok_or_else(|| anyhow::anyhow!("stderr is not available"))?;
let mut stdout_reader = BufReader::new(stdout).lines();
let mut stderr_reader = BufReader::new(stderr).lines();

while !canceled.is_cancelled() {
tokio::select! {
stdout_res = timeout(retrieval_timeout, stdout_reader.next_line()) => {
if let Ok(Ok(Some(line))) = stdout_res {
let escaped = strip_ansi_escapes::strip_str(line.replace(['\n', '\t'], " "));
tx.send(escaped).await?;
}
},
stderr_res = timeout(retrieval_timeout, stderr_reader.next_line()) => {
if let Ok(Ok(Some(line))) = stderr_res {
let escaped = strip_ansi_escapes::strip_str(line.replace(['\n', '\t'], " "));
tx.send(escaped).await?;
}
}
}
}

child.kill().await?;
Ok(())
}
Loading

0 comments on commit 629be95

Please sign in to comment.