Skip to content

Commit

Permalink
Move parent process query into a thread
Browse files Browse the repository at this point in the history
  • Loading branch information
th1000s committed Dec 23, 2021
1 parent 85a66cf commit f5e7a31
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 30 deletions.
4 changes: 1 addition & 3 deletions src/handlers/git_show_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ impl<'a> StateMachine<'a> {
self.painter.emit()?;
let mut handled_line = false;
if matches!(self.state, State::Unknown) {
if let Some(process::CallingProcess::GitShow(_, extension)) =
process::calling_process().as_deref()
{
if let process::CallingProcess::GitShow(_, extension) = &*process::calling_process() {
self.state = State::GitShowFile;
self.painter.set_syntax(extension.as_deref());
self.painter.set_highlighter();
Expand Down
11 changes: 5 additions & 6 deletions src/handlers/grep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,8 +246,8 @@ fn get_code_style_sections<'b>(
}

fn make_output_config() -> GrepOutputConfig {
match process::calling_process().as_deref() {
Some(process::CallingProcess::GitGrep(command_line))
match &*process::calling_process() {
process::CallingProcess::GitGrep(command_line)
if command_line.short_options.contains("-W")
|| command_line.long_options.contains("--function-context") =>
{
Expand All @@ -265,7 +265,7 @@ fn make_output_config() -> GrepOutputConfig {
pad_line_number: true,
}
}
Some(process::CallingProcess::GitGrep(command_line))
process::CallingProcess::GitGrep(command_line)
if command_line.short_options.contains("-p")
|| command_line.long_options.contains("--show-function") =>
{
Expand Down Expand Up @@ -380,9 +380,8 @@ pub fn parse_grep_line(line: &str) -> Option<GrepLine> {
if line.starts_with('{') {
ripgrep_json::parse_line(line)
} else {
match process::calling_process().as_deref() {
Some(process::CallingProcess::GitGrep(_))
| Some(process::CallingProcess::OtherGrep) => [
match &*process::calling_process() {
process::CallingProcess::GitGrep(_) | process::CallingProcess::OtherGrep => [
&*GREP_LINE_REGEX_ASSUMING_FILE_EXTENSION,
&*GREP_LINE_REGEX_ASSUMING_NO_INTERNAL_SEPARATOR_CHARS,
]
Expand Down
12 changes: 5 additions & 7 deletions src/handlers/hunk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,11 @@ lazy_static! {
}

fn compute_is_word_diff() -> bool {
match process::calling_process().as_deref() {
Some(
CallingProcess::GitDiff(cmd_line)
| CallingProcess::GitShow(cmd_line, _)
| CallingProcess::GitLog(cmd_line)
| CallingProcess::GitReflog(cmd_line),
) => {
match &*process::calling_process() {
CallingProcess::GitDiff(cmd_line)
| CallingProcess::GitShow(cmd_line, _)
| CallingProcess::GitLog(cmd_line)
| CallingProcess::GitReflog(cmd_line) => {
cmd_line.long_options.contains("--word-diff")
|| cmd_line.long_options.contains("--word-diff-regex")
|| cmd_line.long_options.contains("--color-words")
Expand Down
6 changes: 6 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ pub mod errors {

#[cfg(not(tarpaulin_include))]
fn main() -> std::io::Result<()> {
// Do this first because both parsing all the input in `run_app()` and
// listing all processes takes about 50ms on Linux.
// It also improves the chance that the calling process is still around when
// input is piped into delta (e.g. `git show --word-diff=color | delta`).
utils::process::start_determining_calling_process_in_thread();

// Ignore ctrl-c (SIGINT) to avoid leaving an orphaned pager process.
// See https://github.com/dandavison/delta/issues/681
ctrlc::set_handler(|| {})
Expand Down
55 changes: 41 additions & 14 deletions src/utils/process.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use std::borrow::Cow;
use std::collections::{HashMap, HashSet};
use std::path::Path;
use sysinfo::{Pid, Process, ProcessExt, ProcessRefreshKind, SystemExt};
use std::sync::{Arc, Condvar, Mutex, MutexGuard};

use lazy_static::lazy_static;
use sysinfo::{Pid, Process, ProcessExt, ProcessRefreshKind, SystemExt};

#[derive(Clone, Debug, PartialEq)]
pub enum CallingProcess {
Expand All @@ -13,6 +13,8 @@ pub enum CallingProcess {
GitReflog(CommandLine),
GitGrep(CommandLine),
OtherGrep, // rg, grep, ag, ack, etc
None, // no matching process could be found
Pending, // calling process is currently being determined
}
// TODO: Git blame is currently handled differently

Expand All @@ -23,23 +25,48 @@ pub struct CommandLine {
last_arg: Option<String>,
}

pub fn calling_process() -> Option<Cow<'static, CallingProcess>> {
#[cfg(not(test))]
{
CACHED_CALLING_PROCESS.as_ref().map(Cow::Borrowed)
}
#[cfg(test)]
{
determine_calling_process().map(Cow::Owned)
}
lazy_static! {
static ref CALLER: Arc<(Mutex<CallingProcess>, Condvar)> =
Arc::new((Mutex::new(CallingProcess::Pending), Condvar::new()));
}

lazy_static! {
static ref CACHED_CALLING_PROCESS: Option<CallingProcess> = determine_calling_process();
pub fn start_determining_calling_process_in_thread() {
// The handle is neither kept nor returned nor joined but dropped, so the main
// thread can exit early if it does not need to know its parent process.
std::thread::Builder::new()
.name("find_calling_process".into())
.spawn(move || {
let calling_process = determine_calling_process();

let (caller_mutex, determine_done) = &**CALLER;

let mut caller = caller_mutex.lock().unwrap();
*caller = calling_process;
determine_done.notify_all();
})
.unwrap();
}

#[cfg(not(test))]
pub fn calling_process() -> MutexGuard<'static, CallingProcess> {
let (caller_mutex, determine_done) = &**CALLER;
determine_done
.wait_while(caller_mutex.lock().unwrap(), |caller| {
*caller == CallingProcess::Pending
})
.unwrap()
}

// The return value is duck-typed to work in place of a MutexGuard when testing.
#[cfg(test)]
pub fn calling_process() -> Box<CallingProcess> {
type _UnusedImport = MutexGuard<'static, i8>;
Box::new(determine_calling_process())
}

fn determine_calling_process() -> Option<CallingProcess> {
fn determine_calling_process() -> CallingProcess {
calling_process_cmdline(ProcInfo::new(), describe_calling_process)
.unwrap_or(CallingProcess::None)
}

// Return value of `extract_args(args: &[String]) -> ProcessArgs<T>` function which is
Expand Down

0 comments on commit f5e7a31

Please sign in to comment.