Merge pull request #755 from nicolasdanelon/new-tab-current-dir-with-config

feat: new tab on current dir with config
This commit is contained in:
Levi Portenier 2026-04-28 11:40:08 -06:00 committed by GitHub
commit b76a974cfb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 88 additions and 15 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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<ProfileId>,
#[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,

View file

@ -427,6 +427,7 @@ pub enum Message {
ShowHeaderBar(bool),
SyntaxTheme(ColorSchemeKind, usize),
SystemThemeChange,
TabNewInheritWorkingDirectory(bool),
TabActivate(segmented_button::Entity),
TabActivateJump(usize),
TabClose(Option<segmented_button::Entity>),
@ -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<PathBuf> {
let tab_model = self.pane_model.active()?;
let entity = tab_model.active();
let terminal = tab_model.data::<Mutex<Terminal>>(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<ProfileId>,
inherit_working_directory: bool,
) -> Task<Message> {
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() {

View file

@ -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<RegexSearch>,
search_value: String,
shell_pid: Option<u32>,
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<PathBuf> {
#[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<I: Into<Cow<'static, [u8]>>>(&self, input: I) {
self.input_no_scroll(input);
self.scroll(TerminalScroll::Bottom);