History

feat: add a `gix editor` command

<!-- agent --> Provide a small plumbing command that opens zero or more paths with `Repository::editor()`'s Git-compatible selection. Prepare editor definitions with command-aware argument splitting so PATH-resolved programs run directly while actual shell syntax still uses the shell, reject explicitly empty settings, and honor ':' as the no-op editor.

Byron committed 2 months ago

Commit d9306531 parent b76cc285 files · +60 −2Browse files

Unified · Split

5 files
  1. gitoxide-core/src/repository/editor.rs +21 −0
  2. gitoxide-core/src/repository/mod.rs +4 −2
  3. src/plumbing/main.rs +1 −0
  4. src/plumbing/options/mod.rs +5 −0
  5. tests/journey/gix.sh +29 −0
gitoxide-core/src/repository/editor.rs+21−0
@@ -0,0 +1,21 @@
1use std::path::PathBuf;
2
3use anyhow::{Context, Result, bail};
4
5pub fn function(repo: gix::Repository, paths: Vec<PathBuf>) -> Result<()> {
6 let editor = repo
7 .editor_command()
8 .context("Could not prepare editor")?
9 .context("No editor is configured and the terminal is not capable of running one")?;
10 let editor_display = editor.command.to_string_lossy().into_owned();
11 let status = editor
12 .args(paths)
13 .spawn()
14 .with_context(|| format!("Could not launch editor {editor_display}"))?
15 .wait()
16 .with_context(|| format!("Could not wait for editor {editor_display}"))?;
17 if !status.success() {
18 bail!("Editor {editor_display} exited with {status}");
19 }
20 Ok(())
21}
gitoxide-core/src/repository/mod.rs+4−2
@@ -17,11 +17,13 @@ pub use credential::function as credential; · 16 unmodified lines
17pub mod attributes;17pub mod attributes;
18#[cfg(feature = "clean")]18#[cfg(feature = "clean")]
19pub mod clean;19pub mod clean;
20#[cfg(feature = "clean")]
21pub use clean::function::clean;
20pub mod diff;22pub mod diff;
21pub mod dirty;23pub mod dirty;
22pub mod dirwalk;24pub mod dirwalk;
23#[cfg(feature = "clean")]25mod editor;
24pub use clean::function::clean;26pub use editor::function as editor;
25#[cfg(feature = "blocking-client")]27#[cfg(feature = "blocking-client")]
26pub mod clone;28pub mod clone;
27pub mod exclude;29pub mod exclude;
src/plumbing/main.rs+1−0
@@ -168,6 +168,7 @@ pub fn main() -> Result<()> { · 167 unmodified lines
168 None,168 None,
169 move |_progress, out, _err| core::env(out, format),169 move |_progress, out, _err| core::env(out, format),
170 ),170 ),
171 Subcommands::Editor { paths } => core::repository::editor(repository(Mode::Lenient)?, paths),
171 Subcommands::Merge(merge::Platform { cmd }) => match cmd {172 Subcommands::Merge(merge::Platform { cmd }) => match cmd {
172 merge::SubCommands::File {173 merge::SubCommands::File {
173 resolve_with,174 resolve_with,
src/plumbing/options/mod.rs+5−0
@@ -161,6 +161,11 @@ pub enum Subcommands { · 160 unmodified lines
161 Merge(merge::Platform),161 Merge(merge::Platform),
162 /// Print paths relevant to the Git installation.162 /// Print paths relevant to the Git installation.
163 Env,163 Env,
164 /// Open paths in the editor selected by Git's precedence rules.
165 Editor {
166 /// Paths to open, or none to start the editor without a file.
167 paths: Vec<PathBuf>,
168 },
164 Diff(diff::Platform),169 Diff(diff::Platform),
165 Log(log::Platform),170 Log(log::Platform),
166 /// Interactively browse commits and their graph.171 /// Interactively browse commits and their graph.
tests/journey/gix.sh+29−0
@@ -54,6 +54,35 @@ title "gix (with repository)" · 53 unmodified lines
54(with "a git repository"54(with "a git repository"
55 snapshot="$snapshot/repository"55 snapshot="$snapshot/repository"
56 56
57 title "gix editor"
58 (sandbox
59 git init -q
60 touch first second
61 printf '%s\n' '#!/bin/sh' \
62 'test "$#" = 2 && test "$1" = first && test "$2" = second' >check-editor
63 cp check-editor "check editor"
64 chmod +x "check editor"
65
66 it "launches the configured editor with all paths" && {
67 expect_run $SUCCESSFULLY "$exe_plumbing" --no-verbose -c "core.editor=sh check-editor" editor first second
68 }
69 it "preserves shell execution for editor command strings" && {
70 expect_run $SUCCESSFULLY env GIT_EDITOR='exec true' "$exe_plumbing" --no-verbose editor first second
71 }
72 it "launches an existing editor path with spaces directly" && {
73 expect_run $SUCCESSFULLY env GIT_EDITOR="$PWD/check editor" "$exe_plumbing" --no-verbose editor first second
74 }
75 it "launches a trusted relative editor path from the repository directly" && {
76 expect_run $SUCCESSFULLY env GIT_EDITOR='./check editor' "$exe_plumbing" --no-verbose editor first second
77 }
78 it "rejects an explicitly empty editor" && {
79 expect_run $WITH_FAILURE env GIT_EDITOR= "$exe_plumbing" --no-verbose editor
80 }
81 it "honors the whitespace-padded no-op editor" && {
82 expect_run $SUCCESSFULLY env 'GIT_EDITOR=: ' "$exe_plumbing" --no-verbose editor first second
83 }
84 )
85
57 title "gix index"86 title "gix index"
58 (with "the 'entries' sub-command"87 (with "the 'entries' sub-command"
59 snapshot="$snapshot/index/entries"88 snapshot="$snapshot/index/entries"

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t