Skip to content

Commit d691d7a

Browse files
committed
Add command to edit selected file in editor
Pressing `e` while looking at a file in the _Status_ view will launch an external editor with the current file opened. The editor chosen is determined by the default logic introduced in gitui-org#114. An improvement to this in the future could be launching at the specific line at which the _Diff_ view is focused, but that seems to require a change in `FileDiff` which is a change bigger than this PR. Fixes gitui-org#166
1 parent 4351b89 commit d691d7a

File tree

7 files changed

+76
-30
lines changed

7 files changed

+76
-30
lines changed

src/app.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use anyhow::{anyhow, Result};
1818
use asyncgit::{sync, AsyncNotification, CWD};
1919
use crossbeam_channel::Sender;
2020
use crossterm::event::{Event, KeyEvent};
21+
use std::path::PathBuf;
2122
use std::{cell::Cell, cell::RefCell, rc::Rc};
2223
use tui::{
2324
backend::Backend,
@@ -48,6 +49,7 @@ pub struct App {
4849

4950
// "Flags"
5051
requires_redraw: Cell<bool>,
52+
file_to_open: Option<Box<PathBuf>>,
5153
}
5254

5355
// public interface
@@ -96,6 +98,7 @@ impl App {
9698
queue,
9799
theme,
98100
requires_redraw: Cell::new(false),
101+
file_to_open: None,
99102
}
100103
}
101104

@@ -196,12 +199,18 @@ impl App {
196199
} else if let InputEvent::State(polling_state) = ev {
197200
self.external_editor_popup.hide();
198201
if let InputState::Paused = polling_state {
199-
if let Err(e) = self.commit.show_editor() {
202+
let result = match self.file_to_open.take() {
203+
Some(path) => crate::open_file_in_editor(&path),
204+
None => self.commit.show_editor(),
205+
};
206+
207+
if let Err(e) = result {
200208
let msg =
201209
format!("failed to launch editor:\n{}", e);
202210
log::error!("{}", msg.as_str());
203211
self.msg.show_msg(msg.as_str())?;
204212
}
213+
205214
self.requires_redraw.set(true);
206215
self.input.set_polling(true);
207216
}
@@ -408,9 +417,10 @@ impl App {
408417
self.inspect_commit_popup.open(id)?;
409418
flags.insert(NeedsUpdate::ALL | NeedsUpdate::COMMANDS)
410419
}
411-
InternalEvent::SuspendPolling => {
420+
InternalEvent::OpenExternalEditor(path) => {
412421
self.input.set_polling(false);
413422
self.external_editor_popup.show()?;
423+
self.file_to_open = path;
414424
flags.insert(NeedsUpdate::COMMANDS)
415425
}
416426
};

src/components/commit.rs

+5-24
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::{
88
strings::{self, commands},
99
ui::style::SharedTheme,
1010
};
11-
use anyhow::{anyhow, Result};
11+
use anyhow::Result;
1212
use asyncgit::{
1313
sync::{self, CommitId, HookResult},
1414
CWD,
@@ -20,11 +20,9 @@ use crossterm::{
2020
};
2121
use scopeguard::defer;
2222
use std::{
23-
env,
2423
fs::File,
2524
io::{self, Read, Write},
2625
path::PathBuf,
27-
process::Command,
2826
};
2927
use tui::{backend::Backend, layout::Rect, Frame};
3028

@@ -94,9 +92,9 @@ impl Component for CommitComponent {
9492
}
9593

9694
keys::OPEN_COMMIT_EDITOR => {
97-
self.queue
98-
.borrow_mut()
99-
.push_back(InternalEvent::SuspendPolling);
95+
self.queue.borrow_mut().push_back(
96+
InternalEvent::OpenExternalEditor(None),
97+
);
10098
self.hide();
10199
}
102100

@@ -159,29 +157,12 @@ impl CommitComponent {
159157
file.write_all(strings::COMMIT_EDITOR_MSG.as_bytes())?;
160158
}
161159

162-
let mut editor = env::var("GIT_EDTIOR")
163-
.ok()
164-
.or_else(|| env::var("VISUAL").ok())
165-
.or_else(|| env::var("EDITOR").ok())
166-
.unwrap_or_else(|| String::from("vi"));
167-
editor
168-
.push_str(&format!(" {}", config_path.to_string_lossy()));
169-
170-
let mut editor = editor.split_whitespace();
171-
172-
let command = editor.next().ok_or_else(|| {
173-
anyhow!("unable to read editor command")
174-
})?;
175-
176160
io::stdout().execute(LeaveAlternateScreen)?;
177161
defer! {
178162
io::stdout().execute(EnterAlternateScreen).expect("reset terminal");
179163
}
180164

181-
Command::new(command)
182-
.args(editor)
183-
.status()
184-
.map_err(|e| anyhow!("\"{}\": {}", command, e))?;
165+
crate::open_file_in_editor(&config_path)?;
185166

186167
let mut message = String::new();
187168

src/keys.rs

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ pub const SHIFT_UP: KeyEvent =
4848
pub const SHIFT_DOWN: KeyEvent =
4949
with_mod(KeyCode::Down, KeyModifiers::SHIFT);
5050
pub const ENTER: KeyEvent = no_mod(KeyCode::Enter);
51+
pub const EDIT_FILE: KeyEvent = no_mod(KeyCode::Char('e'));
5152
pub const STATUS_STAGE_FILE: KeyEvent = no_mod(KeyCode::Enter);
5253
pub const STATUS_STAGE_ALL: KeyEvent = no_mod(KeyCode::Char('a'));
5354
pub const STATUS_RESET_FILE: KeyEvent =

src/main.rs

+24-1
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,13 @@ use scopeguard::defer;
4545
use scopetime::scope_time;
4646
use simplelog::{Config, LevelFilter, WriteLogger};
4747
use spinner::Spinner;
48+
use std::process::Command;
4849
use std::{
4950
env, fs,
5051
fs::File,
5152
io::{self, Write},
5253
panic,
53-
path::PathBuf,
54+
path::{Path, PathBuf},
5455
process,
5556
time::{Duration, Instant},
5657
};
@@ -243,6 +244,28 @@ fn migrate_config() -> Result<()> {
243244
Ok(())
244245
}
245246

247+
fn open_file_in_editor(path: &Path) -> Result<()> {
248+
let mut editor = env::var("GIT_EDITOR")
249+
.ok()
250+
.or_else(|| env::var("VISUAL").ok())
251+
.or_else(|| env::var("EDITOR").ok())
252+
.unwrap_or_else(|| String::from("vi"));
253+
editor.push_str(&format!(" {}", path.to_string_lossy()));
254+
255+
let mut editor = editor.split_whitespace();
256+
257+
let command = editor
258+
.next()
259+
.ok_or_else(|| anyhow!("unable to read editor command"))?;
260+
261+
Command::new(command)
262+
.args(editor)
263+
.status()
264+
.map_err(|e| anyhow!("\"{}\": {}", command, e))?;
265+
266+
Ok(())
267+
}
268+
246269
fn get_app_cache_path() -> Result<PathBuf> {
247270
let mut path = dirs::cache_dir()
248271
.ok_or_else(|| anyhow!("failed to find os cache dir."))?;

src/queue.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::tabs::StashingOptions;
22
use asyncgit::sync::CommitId;
33
use bitflags::bitflags;
4+
use std::path::PathBuf;
45
use std::{cell::RefCell, collections::VecDeque, rc::Rc};
56

67
bitflags! {
@@ -49,9 +50,7 @@ pub enum InternalEvent {
4950
///
5051
InspectCommit(CommitId),
5152
///
52-
//TODO: make this a generic OpenExternalEditor to also use it for other places
53-
//(see https://github.com/extrawurst/gitui/issues/166)
54-
SuspendPolling,
53+
OpenExternalEditor(Option<Box<PathBuf>>),
5554
}
5655

5756
///

src/strings.rs

+6
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,12 @@ pub mod commands {
172172
CMD_GROUP_COMMIT,
173173
);
174174
///
175+
pub static EDIT_ITEM: CommandText = CommandText::new(
176+
"Edit Item [e]",
177+
"edit the currently selected file in an external editor",
178+
CMD_GROUP_CHANGES,
179+
);
180+
///
175181
pub static STAGE_ITEM: CommandText = CommandText::new(
176182
"Stage Item [enter]",
177183
"stage currently selected file or entire path",

src/tabs/status.rs

+26
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use asyncgit::{
1818
};
1919
use crossbeam_channel::Sender;
2020
use crossterm::event::Event;
21+
use std::path::PathBuf;
2122
use tui::layout::{Constraint, Direction, Layout};
2223

2324
///
@@ -312,6 +313,15 @@ impl Component for Status {
312313

313314
{
314315
let focus_on_diff = self.focus == Focus::Diff;
316+
out.push(CommandInfo::new(
317+
commands::EDIT_ITEM,
318+
if focus_on_diff {
319+
true
320+
} else {
321+
self.can_focus_diff()
322+
},
323+
self.visible || force_all,
324+
));
315325
out.push(CommandInfo::new(
316326
commands::DIFF_FOCUS_LEFT,
317327
true,
@@ -371,6 +381,22 @@ impl Component for Status {
371381
keys::FOCUS_STAGE => {
372382
self.switch_focus(Focus::Stage)
373383
}
384+
keys::EDIT_FILE
385+
if self.can_focus_diff()
386+
|| self.focus == Focus::Diff =>
387+
{
388+
if let Some((path, _)) = self.selected_path()
389+
{
390+
self.queue.borrow_mut().push_back(
391+
InternalEvent::OpenExternalEditor(
392+
Some(Box::new(PathBuf::from(
393+
path,
394+
))),
395+
),
396+
);
397+
}
398+
Ok(true)
399+
}
374400
keys::FOCUS_RIGHT if self.can_focus_diff() => {
375401
self.switch_focus(Focus::Diff)
376402
}

0 commit comments

Comments
 (0)