diff --git a/i18n/en/cosmic_term.ftl b/i18n/en/cosmic_term.ftl index 659021d..e2e459f 100644 --- a/i18n/en/cosmic_term.ftl +++ b/i18n/en/cosmic_term.ftl @@ -63,6 +63,8 @@ focus-follow-mouse = Typing focus follows mouse advanced = Advanced show-headerbar = Show header show-header-description = Reveal the header from the right-click menu +tab-new-inherit-working-directory = New tabs use current directory +tab-new-inherit-working-directory-description = Open new tabs in the active tab's working directory ### Keyboard shortcuts add-another-keybinding = Add another keybinding diff --git a/i18n/es-419/cosmic_term.ftl b/i18n/es-419/cosmic_term.ftl index d46447b..e4bdab1 100644 --- a/i18n/es-419/cosmic_term.ftl +++ b/i18n/es-419/cosmic_term.ftl @@ -68,6 +68,8 @@ focus-follow-mouse = El enfoque de escritura sigue al mouse advanced = Avanzado show-headerbar = Mostrar encabezado show-header-description = Mostrar el encabezado desde el menú contextual. +tab-new-inherit-working-directory = Las pestañas nuevas usan el directorio actual +tab-new-inherit-working-directory-description = Abrir pestañas nuevas en el directorio de trabajo de la pestaña activa # Find find-placeholder = Buscar... find-previous = Buscar anterior diff --git a/i18n/es-ES/cosmic_term.ftl b/i18n/es-ES/cosmic_term.ftl index e0ad38b..202761f 100644 --- a/i18n/es-ES/cosmic_term.ftl +++ b/i18n/es-ES/cosmic_term.ftl @@ -70,6 +70,8 @@ focus-follow-mouse = Enfoque del tecleo sigue el ratón advanced = Avanzado show-headerbar = Mostrar encabezado show-header-description = Mostrar encabezado desde el menú del clic secundario. +tab-new-inherit-working-directory = Las pestañas nuevas usan el directorio actual +tab-new-inherit-working-directory-description = Abrir pestañas nuevas en el directorio de trabajo de la pestaña activa # Find find-placeholder = Buscar... find-previous = Buscar previo diff --git a/i18n/it/cosmic_term.ftl b/i18n/it/cosmic_term.ftl index ba59cf0..59dac84 100644 --- a/i18n/it/cosmic_term.ftl +++ b/i18n/it/cosmic_term.ftl @@ -70,6 +70,8 @@ focus-follow-mouse = Il focus di scrittura segue il mouse advanced = Avanzate show-headerbar = Mostra intestazione show-header-description = Mostra intestazione dal menu click destro. +tab-new-inherit-working-directory = Le nuove schede usano la cartella corrente +tab-new-inherit-working-directory-description = Apri nuove schede nella directory di lavoro della scheda attiva # Find find-placeholder = Trova... find-previous = Trova precedente diff --git a/src/config.rs b/src/config.rs index 39e6568..49eb079 100644 --- a/src/config.rs +++ b/src/config.rs @@ -235,6 +235,8 @@ pub struct Config { pub syntax_theme_dark: String, pub syntax_theme_light: String, pub focus_follow_mouse: bool, + #[serde(default)] + pub tab_new_inherit_working_directory: bool, pub default_profile: Option, #[serde(default)] pub shortcuts_custom: Shortcuts, @@ -249,6 +251,7 @@ impl Default for Config { color_schemes_light: BTreeMap::new(), dim_font_weight: Weight::NORMAL.0, focus_follow_mouse: false, + tab_new_inherit_working_directory: false, font_name: "Noto Sans Mono".to_string(), font_size: 14, font_size_zoom_step_mul_100: 100, diff --git a/src/main.rs b/src/main.rs index 5199504..e8469d3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -427,6 +427,7 @@ pub enum Message { ShowHeaderBar(bool), SyntaxTheme(ColorSchemeKind, usize), SystemThemeChange, + TabNewInheritWorkingDirectory(bool), TabActivate(segmented_button::Entity), TabActivateJump(usize), TabClose(Option), @@ -1498,11 +1499,21 @@ impl App { .toggler(self.config.focus_follow_mouse, Message::FocusFollowMouse), ); - let advanced_section = widget::settings::section().title(fl!("advanced")).add( - widget::settings::item::builder(fl!("show-headerbar")) - .description(fl!("show-header-description")) - .toggler(self.config.show_headerbar, Message::ShowHeaderBar), - ); + let advanced_section = widget::settings::section() + .title(fl!("advanced")) + .add( + widget::settings::item::builder(fl!("show-headerbar")) + .description(fl!("show-header-description")) + .toggler(self.config.show_headerbar, Message::ShowHeaderBar), + ) + .add( + widget::settings::item::builder(fl!("tab-new-inherit-working-directory")) + .description(fl!("tab-new-inherit-working-directory-description")) + .toggler( + self.config.tab_new_inherit_working_directory, + Message::TabNewInheritWorkingDirectory, + ), + ); widget::settings::view_column(vec![ appearance_section.into(), @@ -1516,11 +1527,23 @@ impl App { self.config.default_profile } + fn active_terminal_working_directory(&self) -> Option { + let tab_model = self.pane_model.active()?; + let entity = tab_model.active(); + let terminal = tab_model.data::>(entity)?; + let terminal = terminal.lock().unwrap(); + terminal.working_directory() + } + fn create_and_focus_new_terminal( &mut self, pane: pane_grid::Pane, profile_id_opt: Option, + inherit_working_directory: bool, ) -> Task { + let inherited_working_directory = inherit_working_directory + .then(|| self.active_terminal_working_directory()) + .flatten(); self.pane_model.set_focus(pane); match &self.term_event_tx_opt { Some(term_event_tx) => { @@ -1557,12 +1580,13 @@ impl App { } None }), - working_directory: startup_options.working_directory.or_else( - || { + working_directory: startup_options + .working_directory + .or_else(|| inherited_working_directory.clone()) + .or_else(|| { (!profile.working_directory.is_empty()) .then(|| profile.working_directory.clone().into()) - }, - ), + }), drain_on_exit: startup_options.drain_on_exit || profile.drain_on_exit, ..startup_options @@ -1574,7 +1598,11 @@ impl App { }; (options, tab_title_override) } else { - (self.startup_options.take().unwrap_or_default(), None) + let mut options = self.startup_options.take().unwrap_or_default(); + if options.working_directory.is_none() { + options.working_directory = inherited_working_directory.clone(); + } + (options, None) }; let entity = tab_model @@ -2552,7 +2580,7 @@ impl Application for App { if let Some((pane, _)) = result { self.terminal_ids.insert(pane, widget::Id::unique()); let command = - self.create_and_focus_new_terminal(pane, self.get_default_profile()); + self.create_and_focus_new_terminal(pane, self.get_default_profile(), false); self.pane_model.panes_created += 1; return command; } @@ -2664,8 +2692,11 @@ impl Application for App { return self.save_profiles(); } Message::ProfileOpen(profile_id) => { - return self - .create_and_focus_new_terminal(self.pane_model.focused(), Some(profile_id)); + return self.create_and_focus_new_terminal( + self.pane_model.focused(), + Some(profile_id), + false, + ); } Message::ProfileRemove(profile_id) => { // Reset matching terminals to default profile @@ -2731,6 +2762,12 @@ impl Application for App { return self.update_config(); } } + Message::TabNewInheritWorkingDirectory(tab_new_inherit_working_directory) => { + config_set!( + tab_new_inherit_working_directory, + tab_new_inherit_working_directory + ); + } Message::UseBrightBold(use_bright_bold) => { if use_bright_bold != self.config.use_bright_bold { config_set!(use_bright_bold, use_bright_bold); @@ -2944,10 +2981,15 @@ impl Application for App { return self.create_and_focus_new_terminal( self.pane_model.focused(), self.get_default_profile(), + self.config.tab_new_inherit_working_directory, ); } Message::TabNewNoProfile => { - return self.create_and_focus_new_terminal(self.pane_model.focused(), None); + return self.create_and_focus_new_terminal( + self.pane_model.focused(), + None, + self.config.tab_new_inherit_working_directory, + ); } Message::TabNext => { if let Some(tab_model) = self.pane_model.active() { diff --git a/src/terminal.rs b/src/terminal.rs index 2dd8343..81b9f50 100644 --- a/src/terminal.rs +++ b/src/terminal.rs @@ -28,7 +28,8 @@ use indexmap::IndexSet; use std::{ borrow::Cow, collections::HashMap, - io, mem, + fs, io, mem, + path::PathBuf, sync::{ Arc, Mutex, Weak, atomic::{AtomicU32, Ordering}, @@ -257,6 +258,7 @@ pub struct Terminal { notifier: Notifier, search_regex_opt: Option, search_value: String, + shell_pid: Option, size: Size, use_bright_bold: bool, zoom_adj: i8, @@ -329,6 +331,10 @@ impl Terminal { let window_id = 0; let pty = tty::new(&options, size.into(), window_id)?; + #[cfg(not(windows))] + let shell_pid = Some(pty.child().id()); + #[cfg(windows)] + let shell_pid = pty.child_watcher().pid().map(|pid| pid.get()); let pty_event_loop = EventLoop::new(term.clone(), event_proxy, pty, options.drain_on_exit, false)?; @@ -353,6 +359,7 @@ impl Terminal { profile_id_opt, search_regex_opt: None, search_value: String::new(), + shell_pid, size, tab_title_override, term, @@ -408,6 +415,19 @@ impl Terminal { self.notifier.notify(input); } + pub fn working_directory(&self) -> Option { + #[cfg(target_os = "linux")] + { + let shell_pid = self.shell_pid?; + fs::read_link(format!("/proc/{shell_pid}/cwd")).ok() + } + + #[cfg(not(target_os = "linux"))] + { + None + } + } + pub fn input_scroll>>(&self, input: I) { self.input_no_scroll(input); self.scroll(TerminalScroll::Bottom);