lib: move command variable interpolation from merge tools to generic location

This commit is contained in:
Danny Hooper 2024-05-24 22:13:34 -05:00
parent 1ece76d128
commit bbd9ba31df
2 changed files with 48 additions and 38 deletions

View file

@ -22,6 +22,7 @@ use std::{env, fmt, slice};
use config::Source;
use itertools::Itertools;
use jj_lib::settings::ConfigResultExt as _;
use regex::{Captures, Regex};
use thiserror::Error;
use tracing::instrument;
@ -661,12 +662,22 @@ impl CommandNameAndArgs {
/// Returns process builder configured with this.
pub fn to_command(&self) -> Command {
let empty: HashMap<&str, &str> = HashMap::new();
self.to_command_with_variables(&empty)
}
/// Returns process builder configured with this after interpolating
/// variables into the arguments.
pub fn to_command_with_variables<V: AsRef<str>>(
&self,
variables: &HashMap<&str, V>,
) -> Command {
let (name, args) = self.split_name_and_args();
let mut cmd = Command::new(name.as_ref());
if let CommandNameAndArgs::Structured { env, .. } = self {
cmd.envs(env);
}
cmd.args(args.as_ref());
cmd.args(interpolate_variables(&args, variables));
cmd
}
}
@ -693,6 +704,41 @@ impl fmt::Display for CommandNameAndArgs {
}
}
// Not interested in $UPPER_CASE_VARIABLES
static VARIABLE_REGEX: once_cell::sync::Lazy<Regex> =
once_cell::sync::Lazy::new(|| Regex::new(r"\$([a-z0-9_]+)\b").unwrap());
pub fn interpolate_variables<V: AsRef<str>>(
args: &[String],
variables: &HashMap<&str, V>,
) -> Vec<String> {
args.iter()
.map(|arg| {
VARIABLE_REGEX
.replace_all(arg, |caps: &Captures| {
let name = &caps[1];
if let Some(subst) = variables.get(name) {
subst.as_ref().to_owned()
} else {
caps[0].to_owned()
}
})
.into_owned()
})
.collect()
}
/// Return all variable names found in the args, without the dollar sign
pub fn find_all_variables(args: &[String]) -> impl Iterator<Item = &str> {
let regex = &*VARIABLE_REGEX;
args.iter()
.flat_map(|arg| regex.find_iter(arg))
.map(|single_match| {
let s = single_match.as_str();
&s[1..]
})
}
/// Wrapper to reject an array without command name.
// Based on https://github.com/serde-rs/serde/issues/939
#[derive(Clone, Debug, Eq, Hash, PartialEq, serde::Deserialize)]

View file

@ -12,14 +12,13 @@ use jj_lib::merge::{Merge, MergedTreeValue};
use jj_lib::merged_tree::{MergedTree, MergedTreeBuilder};
use jj_lib::repo_path::RepoPath;
use pollster::FutureExt;
use regex::{Captures, Regex};
use thiserror::Error;
use super::diff_working_copies::{
check_out_trees, new_utf8_temp_dir, set_readonly_recursively, DiffEditWorkingCopies, DiffSide,
};
use super::{ConflictResolveError, DiffEditError, DiffGenerateError};
use crate::config::CommandNameAndArgs;
use crate::config::{find_all_variables, interpolate_variables, CommandNameAndArgs};
use crate::ui::Ui;
/// Merge/diff tool loaded from the settings.
@ -220,41 +219,6 @@ pub fn run_mergetool_external(
Ok(new_tree)
}
// Not interested in $UPPER_CASE_VARIABLES
static VARIABLE_REGEX: once_cell::sync::Lazy<Regex> =
once_cell::sync::Lazy::new(|| Regex::new(r"\$([a-z0-9_]+)\b").unwrap());
fn interpolate_variables<V: AsRef<str>>(
args: &[String],
variables: &HashMap<&str, V>,
) -> Vec<String> {
args.iter()
.map(|arg| {
VARIABLE_REGEX
.replace_all(arg, |caps: &Captures| {
let name = &caps[1];
if let Some(subst) = variables.get(name) {
subst.as_ref().to_owned()
} else {
caps[0].to_owned()
}
})
.into_owned()
})
.collect()
}
/// Return all variable names found in the args, without the dollar sign
fn find_all_variables(args: &[String]) -> impl Iterator<Item = &str> {
let regex = &*VARIABLE_REGEX;
args.iter()
.flat_map(|arg| regex.find_iter(arg))
.map(|single_match| {
let s = single_match.as_str();
&s[1..]
})
}
pub fn edit_diff_external(
editor: &ExternalMergeTool,
left_tree: &MergedTree,