summaryrefslogtreecommitdiffstats
path: root/src/components/externaleditor.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/externaleditor.rs')
-rw-r--r--src/components/externaleditor.rs330
1 files changed, 165 insertions, 165 deletions
diff --git a/src/components/externaleditor.rs b/src/components/externaleditor.rs
index 94d3189f..e504690f 100644
--- a/src/components/externaleditor.rs
+++ b/src/components/externaleditor.rs
@@ -1,190 +1,190 @@
use crate::{
- components::{
- visibility_blocking, CommandBlocking, CommandInfo, Component,
- DrawableComponent, EventState,
- },
- keys::SharedKeyConfig,
- strings,
- ui::{self, style::SharedTheme},
+ components::{
+ visibility_blocking, CommandBlocking, CommandInfo, Component,
+ DrawableComponent, EventState,
+ },
+ keys::SharedKeyConfig,
+ strings,
+ ui::{self, style::SharedTheme},
};
use anyhow::{anyhow, bail, Result};
use asyncgit::{
- sync::{get_config_string, utils::repo_work_dir},
- CWD,
+ sync::{get_config_string, utils::repo_work_dir},
+ CWD,
};
use crossterm::{
- event::Event,
- terminal::{EnterAlternateScreen, LeaveAlternateScreen},
- ExecutableCommand,
+ event::Event,
+ terminal::{EnterAlternateScreen, LeaveAlternateScreen},
+ ExecutableCommand,
};
use scopeguard::defer;
use std::ffi::OsStr;
use std::{env, io, path::Path, process::Command};
use tui::{
- backend::Backend,
- layout::Rect,
- text::{Span, Spans},
- widgets::{Block, BorderType, Borders, Clear, Paragraph},
- Frame,
+ backend::Backend,
+ layout::Rect,
+ text::{Span, Spans},
+ widgets::{Block, BorderType, Borders, Clear, Paragraph},
+ Frame,
};
///
pub struct ExternalEditorComponent {
- visible: bool,
- theme: SharedTheme,
- key_config: SharedKeyConfig,
+ visible: bool,
+ theme: SharedTheme,
+ key_config: SharedKeyConfig,
}
impl ExternalEditorComponent {
- ///
- pub fn new(
- theme: SharedTheme,
- key_config: SharedKeyConfig,
- ) -> Self {
- Self {
- visible: false,
- theme,
- key_config,
- }
- }
-
- /// opens file at given `path` in an available editor
- pub fn open_file_in_editor(path: &Path) -> Result<()> {
- let work_dir = repo_work_dir(CWD)?;
-
- let path = if path.is_relative() {
- Path::new(&work_dir).join(path)
- } else {
- path.into()
- };
-
- if !path.exists() {
- bail!("file not found: {:?}", path);
- }
-
- io::stdout().execute(LeaveAlternateScreen)?;
- defer! {
- io::stdout().execute(EnterAlternateScreen).expect("reset terminal");
- }
-
- let environment_options = ["GIT_EDITOR", "VISUAL", "EDITOR"];
-
- let editor = env::var(environment_options[0])
- .ok()
- .or_else(|| get_config_string(CWD, "core.editor").ok()?)
- .or_else(|| env::var(environment_options[1]).ok())
- .or_else(|| env::var(environment_options[2]).ok())
- .unwrap_or_else(|| String::from("vi"));
-
- // TODO: proper handling arguments containing whitespaces
- // This does not do the right thing if the input is `editor --something "with spaces"`
-
- // deal with "editor name with spaces" p1 p2 p3
- // and with "editor_no_spaces" p1 p2 p3
- // does not address spaces in pn
- let mut echars = editor.chars().peekable();
-
- let first_char = *echars.peek().ok_or_else(|| {
- anyhow!(
- "editor env variable found empty: {}",
- environment_options.join(" or ")
- )
- })?;
- let command: String = if first_char == '\"' {
- echars
- .by_ref()
- .skip(1)
- .take_while(|c| *c != '\"')
- .collect()
- } else {
- echars.by_ref().take_while(|c| *c != ' ').collect()
- };
-
- let remainder_str = echars.collect::<String>();
- let remainder = remainder_str.split_whitespace();
-
- let mut args: Vec<&OsStr> =
- remainder.map(|s| OsStr::new(s)).collect();
-
- args.push(path.as_os_str());
-
- Command::new(command.clone())
- .current_dir(work_dir)
- .args(args)
- .status()
- .map_err(|e| anyhow!("\"{}\": {}", command, e))?;
-
- Ok(())
- }
+ ///
+ pub fn new(
+ theme: SharedTheme,
+ key_config: SharedKeyConfig,
+ ) -> Self {
+ Self {
+ visible: false,
+ theme,
+ key_config,
+ }
+ }
+
+ /// opens file at given `path` in an available editor
+ pub fn open_file_in_editor(path: &Path) -> Result<()> {
+ let work_dir = repo_work_dir(CWD)?;
+
+ let path = if path.is_relative() {
+ Path::new(&work_dir).join(path)
+ } else {
+ path.into()
+ };
+
+ if !path.exists() {
+ bail!("file not found: {:?}", path);
+ }
+
+ io::stdout().execute(LeaveAlternateScreen)?;
+ defer! {
+ io::stdout().execute(EnterAlternateScreen).expect("reset terminal");
+ }
+
+ let environment_options = ["GIT_EDITOR", "VISUAL", "EDITOR"];
+
+ let editor = env::var(environment_options[0])
+ .ok()
+ .or_else(|| get_config_string(CWD, "core.editor").ok()?)
+ .or_else(|| env::var(environment_options[1]).ok())
+ .or_else(|| env::var(environment_options[2]).ok())
+ .unwrap_or_else(|| String::from("vi"));
+
+ // TODO: proper handling arguments containing whitespaces
+ // This does not do the right thing if the input is `editor --something "with spaces"`
+
+ // deal with "editor name with spaces" p1 p2 p3
+ // and with "editor_no_spaces" p1 p2 p3
+ // does not address spaces in pn
+ let mut echars = editor.chars().peekable();
+
+ let first_char = *echars.peek().ok_or_else(|| {
+ anyhow!(
+ "editor env variable found empty: {}",
+ environment_options.join(" or ")
+ )
+ })?;
+ let command: String = if first_char == '\"' {
+ echars
+ .by_ref()
+ .skip(1)
+ .take_while(|c| *c != '\"')
+ .collect()
+ } else {
+ echars.by_ref().take_while(|c| *c != ' ').collect()
+ };
+
+ let remainder_str = echars.collect::<String>();
+ let remainder = remainder_str.split_whitespace();
+
+ let mut args: Vec<&OsStr> =
+ remainder.map(|s| OsStr::new(s)).collect();
+
+ args.push(path.as_os_str());
+
+ Command::new(command.clone())
+ .current_dir(work_dir)
+ .args(args)
+ .status()
+ .map_err(|e| anyhow!("\"{}\": {}", command, e))?;
+
+ Ok(())
+ }
}
impl DrawableComponent for ExternalEditorComponent {
- fn draw<B: Backend>(
- &self,
- f: &mut Frame<B>,
- _rect: Rect,
- ) -> Result<()> {
- if self.visible {
- let txt = Spans::from(
- strings::msg_opening_editor(&self.key_config)
- .split('\n')
- .map(|string| {
- Span::raw::<String>(string.to_string())
- })
- .collect::<Vec<Span>>(),
- );
-
- let area = ui::centered_rect_absolute(25, 3, f.size());
- f.render_widget(Clear, area);
- f.render_widget(
- Paragraph::new(txt)
- .block(
- Block::default()
- .borders(Borders::ALL)
- .border_type(BorderType::Thick)
- .border_style(self.theme.block(true)),
- )
- .style(self.theme.block(true)),
- area,
- );
- }
-
- Ok(())
- }
+ fn draw<B: Backend>(
+ &self,
+ f: &mut Frame<B>,
+ _rect: Rect,
+ ) -> Result<()> {
+ if self.visible {
+ let txt = Spans::from(
+ strings::msg_opening_editor(&self.key_config)
+ .split('\n')
+ .map(|string| {
+ Span::raw::<String>(string.to_string())
+ })
+ .collect::<Vec<Span>>(),
+ );
+
+ let area = ui::centered_rect_absolute(25, 3, f.size());
+ f.render_widget(Clear, area);
+ f.render_widget(
+ Paragraph::new(txt)
+ .block(
+ Block::default()
+ .borders(Borders::ALL)
+ .border_type(BorderType::Thick)
+ .border_style(self.theme.block(true)),
+ )
+ .style(self.theme.block(true)),
+ area,
+ );
+ }
+
+ Ok(())
+ }
}
impl Component for ExternalEditorComponent {
- fn commands(
- &self,
- out: &mut Vec<CommandInfo>,
- force_all: bool,
- ) -> CommandBlocking {
- if self.visible && !force_all {
- out.clear();
- }
-
- visibility_blocking(self)
- }
-
- fn event(&mut self, _ev: Event) -> Result<EventState> {
- if self.visible {
- return Ok(EventState::Consumed);
- }
-
- Ok(EventState::NotConsumed)
- }
-
- fn is_visible(&self) -> bool {
- self.visible
- }
-
- fn hide(&mut self) {
- self.visible = false;
- }
-
- fn show(&mut self) -> Result<()> {
- self.visible = true;
-
- Ok(())
- }
+ fn commands(
+ &self,
+ out: &mut Vec<CommandInfo>,
+ force_all: bool,
+ ) -> CommandBlocking {
+ if self.visible && !force_all {
+ out.clear();
+ }
+
+ visibility_blocking(self)
+ }
+
+ fn event(&mut self, _ev: Event) -> Result<EventState> {
+ if self.visible {
+ return Ok(EventState::Consumed);
+ }
+
+ Ok(EventState::NotConsumed)
+ }
+
+ fn is_visible(&self) -> bool {
+ self.visible
+ }
+
+ fn hide(&mut self) {
+ self.visible = false;
+ }
+
+ fn show(&mut self) -> Result<()> {
+ self.visible = true;
+
+ Ok(())
+ }
}