EA4Z7VO73QB25PB5RMO7GIGQRWVYEZBZ2MT33K4C76JWXP2XWF5AC
3FTEGCMRMELPIJRUKNKRTA5TDBXEOTOOVRUTZJ7DWD27ZTKKMV3QC
VYAJZ7DE2LTJJRBPB4L64TN2HNYTM3PEH5B25TLHNIXB4CXF22AAC
ZSFJT4SFIAS7WBODRZOFKKG4SVYBC5PC6XY75WYN7CCQ3SMV7IUQC
CB7UPUQFOUH6M32KXQZL25EV4IH3XSK56RG3OYNRZBBFEABSNCXQC
IPU65ECUBBYBCAFUAOFZVL25IVBWEMHBZ6Q5XXLYTD5FZT6HNQOAC
U6TQX5Z2NF6GX3SRLUBQGCZ7WAXNYMWWZ2YMADUSG4EWVKNV2BIAC
IUGP6ZGBFLDRAKJOHFQNG67LZBDXUJ4QM25GOY3QT6GER3NVTHXQC
SXEYMYF7P4RZMZ46WPL4IZUTSQ2ATBWYZX7QNVMS3SGOYXYOHAGQC
I24UEJQLCH2SOXA4UHIYWTRDCHSOPU7AFTRUOTX7HZIAV4AZKYEQC
TFPETWTVADLG2DL7WERHJPGMJVOY4WOKCRWB3NZ3YOOQ4CVAUHBAC
5BB266P6HPUGYEVR7QNNOA62EFPYPUYJ3UMLE5J3LLYMSUWXANIQC
SLJ3OHD4F6GJGZ3SV2D7DMR3PXYHPSI64X77KZ3RJ24EGEX6ZNQAC
DO2Y5TY5JQISUHCVNPI2FXO7WWZVJQ3LGPWF4DNADMGZRIO6PT2QC
QL6K2ZM35B3NIXEMMCJWUSFXOBQHAGXRDMO7ID5DCKTJH4QJVY7QC
L4JXJHWXYNCL4QGJXNKKTOKKTAXKKXBJUUY7HFZGEUZ5A2V5H34QC
M5FK3ABTKBDG6HHW32G7UKRJEJQKD2U7BPXNZ3HVHBKULWVV6CTQC
3OW3YNZXF6DR2EI5XS7PDHUUZMARDU2JUJFJKIEWXQNSMCIBVAOQC
44BN7FWSIXKG75IJUTCXLJE7VANNQFPRHQXTPLQHFU7AKGLSPQRAC
IVLLXQ5ZWZDKHO4TNQG3TPXN34H6Y2WXPAGSO4PWCYNSKUZWOEJQC
A3RM526Y7LUXNYW4TL56YKQ5GVOK2R5D7JJVTSQ6TT5MEXIR6YAAC
GLRGFBCWZYQEP6BG2IXYMXVZ5ETPWKNA2YJSIRHBCAAOAHJYT2YQC
C4MJ7D7QCOFGIHQSDV3UC76DTSE5M7JSLGN5MROMSVKFVQRFSP5QC
pub tools: Option<Tools>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Tools {
pub pager: Option<Tool>,
pub editor: Option<Tool>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Tool {
pub path: String,
pub args: Option<Vec<String>>,
}
impl Tool {
pub fn to_os_string(&self) -> OsString {
let mut result = self.path.as_bytes().to_vec();
if let Some(args) = &self.args {
for arg in args {
result.extend_from_slice(" \"".as_bytes());
for c in arg.as_bytes() {
match c {
b'"' => result.extend_from_slice("\"\\\"\"".as_bytes()),
o => result.push(*o),
}
}
result.extend_from_slice("\"".as_bytes());
}
}
OsStr::from_bytes(&result[..]).to_os_string()
}
pub fn to_command(&self) -> Command {
match &self.args {
Some(args) => {
let mut cmd = Command::new(&self.path);
cmd.args(args);
cmd
}
None => Command::new(&self.path),
}
}
if let Some(crate::config::Choice::Never) = repo_config_pager {
return false;
} else if let Some(crate::config::Choice::Never) = crate::config::Global::load()
.ok()
.and_then(|(global, _)| global.pager)
{
return false;
} else if let Ok(pager_env_var) = std::env::var("PAGER") {
if !pager_env_var.is_empty() {
match pager_env_var.as_str() {
"less" => {
if let Ok(pager_output) = std::process::Command::new(pager_env_var)
.args(&["--version"])
.output()
let global_config = crate::config::Global::load().map(|(g, _)| g).ok();
let pager =
match repo_config_pager.or_else(|| global_config.as_ref().and_then(|v| v.pager.as_ref())) {
Some(crate::config::Choice::Never) => return false,
_ => match global_config
.as_ref()
.and_then(|g| g.tools.as_ref())
.and_then(|t| t.pager.as_ref())
{
Some(pager) => pager.to_os_string().to_string_lossy().into_owned(),
None => match std::env::var("PAGER").ok() {
Some(pager_env_var) if !pager_env_var.is_empty() => pager_env_var,
_ => return false,
},
},
};
match pager.as_str() {
"less" => {
if let Ok(pager_output) = std::process::Command::new(pager)
.args(&["--version"])
.output()
{
let regex = regex::bytes::Regex::new("less ([0-9]+)").unwrap();
if let Some(caps) = regex.captures(&pager_output.stdout) {
if std::str::from_utf8(&caps[1])
.unwrap()
.parse::<usize>()
.unwrap()
>= 530
let regex = regex::bytes::Regex::new("less ([0-9]+)").unwrap();
if let Some(caps) = regex.captures(&pager_output.stdout) {
if std::str::from_utf8(&caps[1])
.unwrap()
.parse::<usize>()
.unwrap()
>= 530
{
pager::Pager::with_pager("less -RF").setup();
return true;
} else {
pager::Pager::new().setup();
}
}
pager::Pager::with_pager(&"less -RF".to_string()).setup();
return true;
} else {
pager::Pager::new().setup();
}
pub fn edit(contents: impl AsRef<str>) -> std::io::Result<String> {
let temp_file = edit::Builder::new();
let mut file = temp_file.tempfile()?;
file.write_all(contents.as_ref().as_bytes())?;
edit_file(file.path())?;
file.seek(SeekFrom::Start(0))?;
let mut s = String::new();
file.read_to_string(&mut s)?;
Ok(s)
}
pub fn edit_bytes(contents: impl AsRef<[u8]>) -> std::io::Result<Vec<u8>> {
let temp_file = edit::Builder::new();
let mut file = temp_file.tempfile()?;
file.write_all(contents.as_ref())?;
edit_file(file.path())?;
file.seek(SeekFrom::Start(0))?;
let mut s = Vec::new();
file.read_to_end(&mut s)?;
Ok(s)
}
pub fn edit_file(path: impl AsRef<Path>) -> std::io::Result<()> {
let config = crate::config::Global::load().map(|(g, _)| g).ok();
match config
.as_ref()
.and_then(|f| f.tools.as_ref())
.and_then(|t| t.editor.as_ref())
{
Some(tool) => {
let status = tool
.to_command()
.arg(path.as_ref())
.stdin(Stdio::inherit())
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.output()?
.status;
if status.success() {
Ok(())
} else {
let full_command = format!(
"{} {}",
tool.to_os_string().to_string_lossy(),
path.as_ref().to_string_lossy()
);
Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!("editor '{}' exited with error: {}", full_command, status),
))
}
}
None => edit::edit_file(path),
}