Skip to content

Add command to edit selected file in editor #173

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use anyhow::{anyhow, Result};
use asyncgit::{sync, AsyncNotification, CWD};
use crossbeam_channel::Sender;
use crossterm::event::{Event, KeyEvent};
use std::path::PathBuf;
use std::{cell::Cell, cell::RefCell, rc::Rc};
use tui::{
backend::Backend,
Expand Down Expand Up @@ -48,6 +49,7 @@ pub struct App {

// "Flags"
requires_redraw: Cell<bool>,
file_to_open: Option<Box<PathBuf>>,
}

// public interface
Expand Down Expand Up @@ -96,6 +98,7 @@ impl App {
queue,
theme,
requires_redraw: Cell::new(false),
file_to_open: None,
}
}

Expand Down Expand Up @@ -196,12 +199,18 @@ impl App {
} else if let InputEvent::State(polling_state) = ev {
self.external_editor_popup.hide();
if let InputState::Paused = polling_state {
if let Err(e) = self.commit.show_editor() {
let result = match self.file_to_open.take() {
Some(path) => crate::open_file_in_editor(&path),
None => self.commit.show_editor(),
};

if let Err(e) = result {
let msg =
format!("failed to launch editor:\n{}", e);
log::error!("{}", msg.as_str());
self.msg.show_msg(msg.as_str())?;
}

self.requires_redraw.set(true);
self.input.set_polling(true);
}
Expand Down Expand Up @@ -408,9 +417,10 @@ impl App {
self.inspect_commit_popup.open(id)?;
flags.insert(NeedsUpdate::ALL | NeedsUpdate::COMMANDS)
}
InternalEvent::SuspendPolling => {
InternalEvent::OpenExternalEditor(path) => {
self.input.set_polling(false);
self.external_editor_popup.show()?;
self.file_to_open = path;
flags.insert(NeedsUpdate::COMMANDS)
}
};
Expand Down
29 changes: 5 additions & 24 deletions src/components/commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{
strings::{self, commands},
ui::style::SharedTheme,
};
use anyhow::{anyhow, Result};
use anyhow::Result;
use asyncgit::{
sync::{self, CommitId, HookResult},
CWD,
Expand All @@ -20,11 +20,9 @@ use crossterm::{
};
use scopeguard::defer;
use std::{
env,
fs::File,
io::{self, Read, Write},
path::PathBuf,
process::Command,
};
use tui::{backend::Backend, layout::Rect, Frame};

Expand Down Expand Up @@ -94,9 +92,9 @@ impl Component for CommitComponent {
}

keys::OPEN_COMMIT_EDITOR => {
self.queue
.borrow_mut()
.push_back(InternalEvent::SuspendPolling);
self.queue.borrow_mut().push_back(
InternalEvent::OpenExternalEditor(None),
);
self.hide();
}

Expand Down Expand Up @@ -159,29 +157,12 @@ impl CommitComponent {
file.write_all(strings::COMMIT_EDITOR_MSG.as_bytes())?;
}

let mut editor = env::var("GIT_EDTIOR")
.ok()
.or_else(|| env::var("VISUAL").ok())
.or_else(|| env::var("EDITOR").ok())
.unwrap_or_else(|| String::from("vi"));
editor
.push_str(&format!(" {}", config_path.to_string_lossy()));

let mut editor = editor.split_whitespace();

let command = editor.next().ok_or_else(|| {
anyhow!("unable to read editor command")
})?;

io::stdout().execute(LeaveAlternateScreen)?;
defer! {
io::stdout().execute(EnterAlternateScreen).expect("reset terminal");
}

Command::new(command)
.args(editor)
.status()
.map_err(|e| anyhow!("\"{}\": {}", command, e))?;
crate::open_file_in_editor(&config_path)?;

let mut message = String::new();

Expand Down
1 change: 1 addition & 0 deletions src/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ pub const SHIFT_UP: KeyEvent =
pub const SHIFT_DOWN: KeyEvent =
with_mod(KeyCode::Down, KeyModifiers::SHIFT);
pub const ENTER: KeyEvent = no_mod(KeyCode::Enter);
pub const EDIT_FILE: KeyEvent = no_mod(KeyCode::Char('e'));
pub const STATUS_STAGE_FILE: KeyEvent = no_mod(KeyCode::Enter);
pub const STATUS_STAGE_ALL: KeyEvent = no_mod(KeyCode::Char('a'));
pub const STATUS_RESET_FILE: KeyEvent =
Expand Down
25 changes: 24 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,13 @@ use scopeguard::defer;
use scopetime::scope_time;
use simplelog::{Config, LevelFilter, WriteLogger};
use spinner::Spinner;
use std::process::Command;
use std::{
env, fs,
fs::File,
io::{self, Write},
panic,
path::PathBuf,
path::{Path, PathBuf},
process,
time::{Duration, Instant},
};
Expand Down Expand Up @@ -243,6 +244,28 @@ fn migrate_config() -> Result<()> {
Ok(())
}

fn open_file_in_editor(path: &Path) -> Result<()> {
let mut editor = env::var("GIT_EDITOR")
.ok()
.or_else(|| env::var("VISUAL").ok())
.or_else(|| env::var("EDITOR").ok())
.unwrap_or_else(|| String::from("vi"));
editor.push_str(&format!(" {}", path.to_string_lossy()));

let mut editor = editor.split_whitespace();

let command = editor
.next()
.ok_or_else(|| anyhow!("unable to read editor command"))?;

Command::new(command)
.args(editor)
.status()
.map_err(|e| anyhow!("\"{}\": {}", command, e))?;

Ok(())
}

fn get_app_cache_path() -> Result<PathBuf> {
let mut path = dirs::cache_dir()
.ok_or_else(|| anyhow!("failed to find os cache dir."))?;
Expand Down
5 changes: 2 additions & 3 deletions src/queue.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::tabs::StashingOptions;
use asyncgit::sync::CommitId;
use bitflags::bitflags;
use std::path::PathBuf;
use std::{cell::RefCell, collections::VecDeque, rc::Rc};

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

///
Expand Down
6 changes: 6 additions & 0 deletions src/strings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,12 @@ pub mod commands {
CMD_GROUP_COMMIT,
);
///
pub static EDIT_ITEM: CommandText = CommandText::new(
"Edit Item [e]",
"edit the currently selected file in an external editor",
CMD_GROUP_CHANGES,
);
///
pub static STAGE_ITEM: CommandText = CommandText::new(
"Stage Item [enter]",
"stage currently selected file or entire path",
Expand Down
26 changes: 26 additions & 0 deletions src/tabs/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use asyncgit::{
};
use crossbeam_channel::Sender;
use crossterm::event::Event;
use std::path::PathBuf;
use tui::layout::{Constraint, Direction, Layout};

///
Expand Down Expand Up @@ -312,6 +313,15 @@ impl Component for Status {

{
let focus_on_diff = self.focus == Focus::Diff;
out.push(CommandInfo::new(
commands::EDIT_ITEM,
if focus_on_diff {
true
} else {
self.can_focus_diff()
},
self.visible || force_all,
));
out.push(CommandInfo::new(
commands::DIFF_FOCUS_LEFT,
true,
Expand Down Expand Up @@ -371,6 +381,22 @@ impl Component for Status {
keys::FOCUS_STAGE => {
self.switch_focus(Focus::Stage)
}
keys::EDIT_FILE
if self.can_focus_diff()
|| self.focus == Focus::Diff =>
{
if let Some((path, _)) = self.selected_path()
{
self.queue.borrow_mut().push_back(
InternalEvent::OpenExternalEditor(
Some(Box::new(PathBuf::from(
path,
))),
),
);
}
Ok(true)
}
keys::FOCUS_RIGHT if self.can_focus_diff() => {
self.switch_focus(Focus::Diff)
}
Expand Down