From 81b160285dbe3e0dcb7cb0be4adb499e299e672d Mon Sep 17 00:00:00 2001 From: ancion Date: Sat, 13 Jun 2026 19:12:27 +0800 Subject: [PATCH] refactor: restructure project --- src/app/constants.rs | 7 + src/{ => app}/dialogs.rs | 2 +- src/{app.rs => app/mod.rs} | 14 +- src/app/startup.rs | 166 +++++++++++++ src/{ => app}/theme.rs | 30 ++- src/{ => app}/ui.rs | 10 +- src/{local_terminal.rs => backend/local.rs} | 0 src/backend/mod.rs | 2 + src/{ssh_terminal.rs => backend/ssh.rs} | 2 +- src/main.rs | 233 +----------------- src/{ => session}/config.rs | 0 src/{session.rs => session/mod.rs} | 23 +- src/{sftp.rs => sftp/mod.rs} | 6 +- src/{sftp_ops.rs => sftp/ops.rs} | 0 src/{system.rs => system/mod.rs} | 0 .../element.rs} | 0 src/{terminal_input.rs => terminal/input.rs} | 0 src/{terminal.rs => terminal/mod.rs} | 5 +- 18 files changed, 254 insertions(+), 246 deletions(-) create mode 100644 src/app/constants.rs rename src/{ => app}/dialogs.rs (99%) rename src/{app.rs => app/mod.rs} (99%) create mode 100644 src/app/startup.rs rename src/{ => app}/theme.rs (87%) rename src/{ => app}/ui.rs (99%) rename src/{local_terminal.rs => backend/local.rs} (100%) create mode 100644 src/backend/mod.rs rename src/{ssh_terminal.rs => backend/ssh.rs} (99%) rename src/{ => session}/config.rs (100%) rename src/{session.rs => session/mod.rs} (98%) rename src/{sftp.rs => sftp/mod.rs} (99%) rename src/{sftp_ops.rs => sftp/ops.rs} (100%) rename src/{system.rs => system/mod.rs} (100%) rename src/{terminal_element.rs => terminal/element.rs} (100%) rename src/{terminal_input.rs => terminal/input.rs} (100%) rename src/{terminal.rs => terminal/mod.rs} (99%) diff --git a/src/app/constants.rs b/src/app/constants.rs new file mode 100644 index 0000000..c34ce7e --- /dev/null +++ b/src/app/constants.rs @@ -0,0 +1,7 @@ +pub(crate) const DEFAULT_COLS: u16 = 100; +pub(crate) const DEFAULT_ROWS: u16 = 30; +pub(crate) const SIDEBAR_WIDTH: f32 = 306.0; +pub(crate) const TAB_BAR_HEIGHT: f32 = 52.0; +pub(crate) const TERMINAL_PADDING_X: f32 = 32.0; +pub(crate) const TERMINAL_PADDING_Y: f32 = 32.0; +pub(crate) const TERMINAL_KEY_CONTEXT: &str = "AshellTerminal"; diff --git a/src/dialogs.rs b/src/app/dialogs.rs similarity index 99% rename from src/dialogs.rs rename to src/app/dialogs.rs index dadc9f1..30dc59b 100644 --- a/src/dialogs.rs +++ b/src/app/dialogs.rs @@ -19,7 +19,7 @@ use rust_i18n::t; use crate::{ Ashell, - config::AuthMethod, + session::config::AuthMethod, system::format_bytes, }; diff --git a/src/app.rs b/src/app/mod.rs similarity index 99% rename from src/app.rs rename to src/app/mod.rs index b4421bb..dd32221 100644 --- a/src/app.rs +++ b/src/app/mod.rs @@ -1,3 +1,9 @@ +pub mod constants; +pub mod dialogs; +pub mod startup; +pub mod theme; +pub mod ui; + use std::{ cell::{Cell, RefCell}, collections::HashMap, @@ -22,11 +28,11 @@ use rust_i18n::t; use tokio::runtime::Runtime; use crate::{ - config::{AuthMethod, ConfigStore}, sftp::SftpHandle, + session::config::{AuthMethod, ConfigStore}, system::{SystemSampler, SystemSnapshot}, terminal::{self, BackendCommand, BackendEvent, TabKind, TerminalTab}, - ssh_terminal, + backend::ssh, }; #[derive(Clone, Debug)] @@ -638,6 +644,8 @@ impl Ashell { self.focused_pane_path = vec![]; self.active_tab = None; self.active_group = None; + self.tab_groups.clear(); + self.tabs.clear(); self.system_tab_id = None; self.cpu_history.clear(); self.net_rx_history.clear(); @@ -799,7 +807,7 @@ impl Ashell { let events = self.events_tx.clone(); let tab_id = tab_id.clone(); self.runtime.spawn(async move { - match ssh_terminal::sample_remote_system(session).await { + match ssh::sample_remote_system(session).await { Ok(snapshot) => { let _ = events.send(BackendEvent::RemoteSystem { tab_id, snapshot }); } diff --git a/src/app/startup.rs b/src/app/startup.rs new file mode 100644 index 0000000..9c5bd03 --- /dev/null +++ b/src/app/startup.rs @@ -0,0 +1,166 @@ +use gpui::{App, AppContext as _, Bounds, WindowOptions, point, px, size}; +use gpui_component::Root; + +use crate::session::config::ConfigStore; +use crate::Ashell; + +#[cfg(target_os = "macos")] +pub(crate) fn sync_macos_launch_environment() { + let shell = std::env::var("SHELL").unwrap_or_else(|_| "/bin/zsh".to_string()); + let Ok(output) = std::process::Command::new(&shell).args(["-l", "-c", "env -0"]).output() else { + return; + }; + if !output.status.success() { + return; + } + + for entry in output.stdout.split(|b| *b == 0) { + if entry.is_empty() { + continue; + } + let Some(eq) = entry.iter().position(|b| *b == b'=') else { + continue; + }; + let Ok(key) = std::str::from_utf8(&entry[..eq]) else { + continue; + }; + let Ok(value) = std::str::from_utf8(&entry[eq + 1..]) else { + continue; + }; + + let should_import = matches!( + key, + "PATH" + | "MANPATH" + | "INFOPATH" + | "LANG" + | "LC_ALL" + | "LC_CTYPE" + | "SHELL" + | "HOME" + | "HOMEBREW_PREFIX" + | "HOMEBREW_CELLAR" + | "HOMEBREW_REPOSITORY" + ) || key.starts_with("LC_"); + + if should_import { + unsafe { + std::env::set_var(key, value); + } + } + } +} + +#[cfg(not(target_os = "macos"))] +pub(crate) fn sync_macos_launch_environment() {} + +pub(crate) fn open_main_window(cx: &mut App) { + let mut window_options = WindowOptions::default(); + + #[cfg(not(target_os = "macos"))] + if let Ok(img) = image::load_from_memory(include_bytes!("../../assets/icons/ashell.png")) { + window_options.icon = Some(std::sync::Arc::new(img.into_rgba8())); + } + + let config = ConfigStore::load().unwrap_or_else(|_| ConfigStore::in_memory()); + if let Some(bounds) = config.window_bounds() { + window_options.window_bounds = Some(match bounds { + crate::session::config::SavedWindowBounds::Fullscreen { + x, + y, + width, + height, + } => gpui::WindowBounds::Fullscreen(Bounds::new( + point(px(*x), px(*y)), + size(px(*width), px(*height)), + )), + crate::session::config::SavedWindowBounds::Maximized { + x, + y, + width, + height, + } => gpui::WindowBounds::Maximized(Bounds::new( + point(px(*x), px(*y)), + size(px(*width), px(*height)), + )), + crate::session::config::SavedWindowBounds::Windowed { + x, + y, + width, + height, + } => gpui::WindowBounds::Windowed(Bounds::new( + point(px(*x), px(*y)), + size(px(*width), px(*height)), + )), + }); + } else if let Some(display) = cx.displays().first().cloned() { + let display_bounds = display.bounds(); + let width = display_bounds.size.width * 0.8; + let height = display_bounds.size.height * 0.9; + + let x = display_bounds.origin.x + (display_bounds.size.width - width) / 2.0; + + #[cfg(target_os = "macos")] + let y = display_bounds.origin.y; + #[cfg(not(target_os = "macos"))] + let y = display_bounds.origin.y + (display_bounds.size.height - height) / 2.0; + + window_options.window_bounds = Some(gpui::WindowBounds::Windowed(Bounds::new( + point(x, y), + size(width, height), + ))); + } + + cx.open_window(window_options, |window, cx| { + window.activate_window(); + window.set_window_title("ashell"); + gpui_component::Theme::sync_system_appearance(Some(window), cx); + let view = cx.new(|cx| Ashell::new(window, cx)); + + let workspace_panels_clone = view.read(cx).workspace_panels.clone(); + let body_panels_clone = view.read(cx).body_panels.clone(); + window.on_window_should_close(cx, move |window: &mut gpui::Window, cx: &mut gpui::App| { + let mut config = ConfigStore::load().unwrap_or_else(|_| ConfigStore::in_memory()); + let current_bounds = window.window_bounds(); + let saved_bounds = match current_bounds { + gpui::WindowBounds::Fullscreen(b) => crate::session::config::SavedWindowBounds::Fullscreen { + x: b.origin.x.into(), + y: b.origin.y.into(), + width: b.size.width.into(), + height: b.size.height.into(), + }, + gpui::WindowBounds::Maximized(b) => crate::session::config::SavedWindowBounds::Maximized { + x: b.origin.x.into(), + y: b.origin.y.into(), + width: b.size.width.into(), + height: b.size.height.into(), + }, + gpui::WindowBounds::Windowed(b) => crate::session::config::SavedWindowBounds::Windowed { + x: b.origin.x.into(), + y: b.origin.y.into(), + width: b.size.width.into(), + height: b.size.height.into(), + }, + }; + let workspace_sizes: Vec = workspace_panels_clone + .read(cx) + .sizes() + .iter() + .map(|s| s.into()) + .collect(); + let body_sizes: Vec = body_panels_clone + .read(cx) + .sizes() + .iter() + .map(|s| s.into()) + .collect(); + config.set_layout_state(Some(saved_bounds), Some(workspace_sizes), Some(body_sizes)); + let _ = config.save(); + true + }); + + cx.new(|cx| Root::new(view, window, cx)) + }) + .expect("failed to open window"); +} + diff --git a/src/theme.rs b/src/app/theme.rs similarity index 87% rename from src/theme.rs rename to src/app/theme.rs index 70c9a23..e189c86 100644 --- a/src/theme.rs +++ b/src/app/theme.rs @@ -1,4 +1,5 @@ -use gpui::{Anchor, Context, IntoElement, SharedString, Window, px}; +use anyhow::{Context as _, Result}; +use gpui::{Anchor, App, Context, IntoElement, SharedString, Window, px}; use gpui_component::{ ActiveTheme as _, IconName, Sizable as _, Theme, ThemeMode, ThemeRegistry, button::{Button, ButtonVariants as _}, @@ -8,6 +9,33 @@ use rust_i18n::t; use crate::Ashell; +pub(crate) const EMBEDDED_THEME_JSONS: &[&str] = &[ + include_str!("../../assets/themes/matrix.json"), + include_str!("../../assets/themes/tokyonight.json"), + include_str!("../../assets/themes/gruvbox.json"), + include_str!("../../assets/themes/solarized.json"), +]; + +pub(crate) fn load_fonts(cx: &mut App) -> Result<()> { + let regular = + std::borrow::Cow::Borrowed(include_bytes!("../../assets/fonts/MapleMono-NF-CN-Regular.ttf").as_slice()); + let bold = std::borrow::Cow::Borrowed(include_bytes!("../../assets/fonts/MapleMono-NF-CN-Bold.ttf").as_slice()); + cx.text_system() + .add_fonts(vec![regular, bold]) + .context("load Maple Mono NF CN fonts")?; + set_theme_font_names(cx.global_mut::(), ".SystemUIFont"); + Ok(()) +} + +pub(crate) fn load_embedded_themes(cx: &mut App) { + let registry = ThemeRegistry::global_mut(cx); + for theme_json in EMBEDDED_THEME_JSONS { + if let Err(err) = registry.load_themes_from_str(theme_json) { + tracing::warn!("failed to load embedded theme: {err:#}"); + } + } +} + pub(crate) fn set_theme_font_names(theme: &mut Theme, ui_font_family: &str) { theme.font_family = ui_font_family.into(); theme.mono_font_family = ui_font_family.into(); diff --git a/src/ui.rs b/src/app/ui.rs similarity index 99% rename from src/ui.rs rename to src/app/ui.rs index abc468b..ed915fb 100644 --- a/src/ui.rs +++ b/src/app/ui.rs @@ -22,12 +22,12 @@ use gpui_component::{ use rust_i18n::t; use crate::{ - Ashell, PaneLayout, SIDEBAR_WIDTH, TERMINAL_KEY_CONTEXT, - sftp_ops::is_editable_text_file, + Ashell, PaneLayout, + app::constants::{SIDEBAR_WIDTH, TERMINAL_KEY_CONTEXT}, + sftp::ops::is_editable_text_file, sftp::format_mtime, system::format_bytes, - terminal::{TabKind, TerminalTab}, - terminal_element, + terminal::{self, TabKind, TerminalTab}, }; impl Ashell { @@ -1574,7 +1574,7 @@ impl Ashell { this.focus_pane_with_id(tab_id_clone2.clone()); cx.notify(); })) - .child(terminal_element::TerminalElement::new( + .child(terminal::element::TerminalElement::new( cx.entity(), focus_handle, snapshot, diff --git a/src/local_terminal.rs b/src/backend/local.rs similarity index 100% rename from src/local_terminal.rs rename to src/backend/local.rs diff --git a/src/backend/mod.rs b/src/backend/mod.rs new file mode 100644 index 0000000..6d243a0 --- /dev/null +++ b/src/backend/mod.rs @@ -0,0 +1,2 @@ +pub mod local; +pub mod ssh; diff --git a/src/ssh_terminal.rs b/src/backend/ssh.rs similarity index 99% rename from src/ssh_terminal.rs rename to src/backend/ssh.rs index 382ad23..1f866d4 100644 --- a/src/ssh_terminal.rs +++ b/src/backend/ssh.rs @@ -14,7 +14,7 @@ use russh::{ use tokio::sync::mpsc; use crate::{ - config::{AuthMethod, Session}, + session::config::{AuthMethod, Session}, system::{SystemSnapshot, remote_snapshot_from_kv}, terminal::{BackendCommand, BackendEvent, BackendTx}, }; diff --git a/src/main.rs b/src/main.rs index b121143..05efc2e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,235 +1,25 @@ #![windows_subsystem = "windows"] - -use anyhow::{Context as _, Result}; -use gpui::{App, AppContext as _, Bounds, KeyBinding, WindowOptions, point, px, size}; -use gpui_component::{Root, Theme, ThemeRegistry}; +use gpui::{ KeyBinding }; use gpui_component_assets::Assets; -mod config; -mod local_terminal; +mod app; +mod backend; +mod session; mod sftp; -mod ssh_terminal; mod system; mod terminal; -mod terminal_element; -mod terminal_input; -mod app; -mod session; -mod sftp_ops; -mod theme; -mod dialogs; -mod ui; - -use config::ConfigStore; rust_i18n::i18n!("locales", fallback = "en"); -const DEFAULT_COLS: u16 = 100; -const DEFAULT_ROWS: u16 = 30; - -const SIDEBAR_WIDTH: f32 = 306.0; -const TAB_BAR_HEIGHT: f32 = 52.0; -const TERMINAL_PADDING_X: f32 = 32.0; -const TERMINAL_PADDING_Y: f32 = 32.0; -const TERMINAL_KEY_CONTEXT: &str = "AshellTerminal"; -const EMBEDDED_THEME_JSONS: &[&str] = &[ - include_str!("../assets/themes/matrix.json"), - include_str!("../assets/themes/tokyonight.json"), - include_str!("../assets/themes/gruvbox.json"), - include_str!("../assets/themes/solarized.json"), -]; - gpui::actions!(ashell_terminal, [TerminalTabKey, TerminalBacktabKey]); pub(crate) use app::{ Ashell, ConnectionProgress, PaneLayout, SelectorEntry, SftpContextMenuState, TabGroup, }; -fn load_fonts(cx: &mut App) -> Result<()> { - let regular = - std::borrow::Cow::Borrowed(include_bytes!("../assets/fonts/MapleMono-NF-CN-Regular.ttf").as_slice()); - let bold = std::borrow::Cow::Borrowed(include_bytes!("../assets/fonts/MapleMono-NF-CN-Bold.ttf").as_slice()); - cx.text_system() - .add_fonts(vec![regular, bold]) - .context("load Maple Mono NF CN fonts")?; - // At startup we don't have a config yet, so pass the default UI font family. - // It will be reapplied in Ashell::new() -> apply_theme_preferences. - theme::set_theme_font_names(cx.global_mut::(), ".SystemUIFont"); - Ok(()) -} - -fn load_embedded_themes(cx: &mut App) { - let registry = ThemeRegistry::global_mut(cx); - for theme_json in EMBEDDED_THEME_JSONS { - if let Err(err) = registry.load_themes_from_str(theme_json) { - tracing::warn!("failed to load embedded theme: {err:#}"); - } - } -} - -#[cfg(target_os = "macos")] -fn sync_macos_launch_environment() { - let shell = std::env::var("SHELL").unwrap_or_else(|_| "/bin/zsh".to_string()); - let Ok(output) = std::process::Command::new(&shell).args(["-l", "-c", "env -0"]).output() else { - return; - }; - if !output.status.success() { - return; - } - - for entry in output.stdout.split(|b| *b == 0) { - if entry.is_empty() { - continue; - } - let Some(eq) = entry.iter().position(|b| *b == b'=') else { - continue; - }; - let Ok(key) = std::str::from_utf8(&entry[..eq]) else { - continue; - }; - let Ok(value) = std::str::from_utf8(&entry[eq + 1..]) else { - continue; - }; - - let should_import = matches!( - key, - "PATH" - | "MANPATH" - | "INFOPATH" - | "LANG" - | "LC_ALL" - | "LC_CTYPE" - | "SHELL" - | "HOME" - | "HOMEBREW_PREFIX" - | "HOMEBREW_CELLAR" - | "HOMEBREW_REPOSITORY" - ) || key.starts_with("LC_"); - - if should_import { - unsafe { - std::env::set_var(key, value); - } - } - } -} - -#[cfg(not(target_os = "macos"))] -fn sync_macos_launch_environment() {} - -fn open_main_window(cx: &mut App) { - let mut window_options = WindowOptions::default(); - - #[cfg(not(target_os = "macos"))] - if let Ok(img) = image::load_from_memory(include_bytes!("../assets/icons/ashell.png")) { - window_options.icon = Some(std::sync::Arc::new(img.into_rgba8())); - } - - let config = ConfigStore::load().unwrap_or_else(|_| ConfigStore::in_memory()); - if let Some(bounds) = config.window_bounds() { - window_options.window_bounds = Some(match bounds { - crate::config::SavedWindowBounds::Fullscreen { - x, - y, - width, - height, - } => gpui::WindowBounds::Fullscreen(Bounds::new( - point(px(*x), px(*y)), - size(px(*width), px(*height)), - )), - crate::config::SavedWindowBounds::Maximized { - x, - y, - width, - height, - } => gpui::WindowBounds::Maximized(Bounds::new( - point(px(*x), px(*y)), - size(px(*width), px(*height)), - )), - crate::config::SavedWindowBounds::Windowed { - x, - y, - width, - height, - } => gpui::WindowBounds::Windowed(Bounds::new( - point(px(*x), px(*y)), - size(px(*width), px(*height)), - )), - }); - } else if let Some(display) = cx.displays().first().cloned() { - let display_bounds = display.bounds(); - let width = display_bounds.size.width * 0.8; - let height = display_bounds.size.height * 0.9; - - let x = display_bounds.origin.x + (display_bounds.size.width - width) / 2.0; - - #[cfg(target_os = "macos")] - let y = display_bounds.origin.y; - #[cfg(not(target_os = "macos"))] - let y = display_bounds.origin.y + (display_bounds.size.height - height) / 2.0; - - window_options.window_bounds = Some(gpui::WindowBounds::Windowed(Bounds::new( - point(x, y), - size(width, height), - ))); - } - - cx.open_window(window_options, |window, cx| { - window.activate_window(); - window.set_window_title("ashell"); - Theme::sync_system_appearance(Some(window), cx); - let view = cx.new(|cx| Ashell::new(window, cx)); - - let workspace_panels_clone = view.read(cx).workspace_panels.clone(); - let body_panels_clone = view.read(cx).body_panels.clone(); - window.on_window_should_close(cx, move |window: &mut gpui::Window, cx: &mut gpui::App| { - let mut config = ConfigStore::load().unwrap_or_else(|_| ConfigStore::in_memory()); - let current_bounds = window.window_bounds(); - let saved_bounds = match current_bounds { - gpui::WindowBounds::Fullscreen(b) => crate::config::SavedWindowBounds::Fullscreen { - x: b.origin.x.into(), - y: b.origin.y.into(), - width: b.size.width.into(), - height: b.size.height.into(), - }, - gpui::WindowBounds::Maximized(b) => crate::config::SavedWindowBounds::Maximized { - x: b.origin.x.into(), - y: b.origin.y.into(), - width: b.size.width.into(), - height: b.size.height.into(), - }, - gpui::WindowBounds::Windowed(b) => crate::config::SavedWindowBounds::Windowed { - x: b.origin.x.into(), - y: b.origin.y.into(), - width: b.size.width.into(), - height: b.size.height.into(), - }, - }; - let workspace_sizes: Vec = workspace_panels_clone - .read(cx) - .sizes() - .iter() - .map(|s| s.into()) - .collect(); - let body_sizes: Vec = body_panels_clone - .read(cx) - .sizes() - .iter() - .map(|s| s.into()) - .collect(); - config.set_layout_state(Some(saved_bounds), Some(workspace_sizes), Some(body_sizes)); - let _ = config.save(); - true - }); - - cx.new(|cx| Root::new(view, window, cx)) - }) - .expect("failed to open window"); -} - fn main() { - sync_macos_launch_environment(); + app::startup::sync_macos_launch_environment(); tracing_subscriber::fmt() .with_env_filter( tracing_subscriber::EnvFilter::try_from_default_env() @@ -246,20 +36,19 @@ fn main() { let app = gpui_platform::application().with_assets(Assets); app.on_reopen(|cx| { if cx.windows().is_empty() { - open_main_window(cx); + app::startup::open_main_window(cx); } }); app.run(move |cx| { gpui_component::init(cx); cx.bind_keys([ - KeyBinding::new("tab", TerminalTabKey, Some(TERMINAL_KEY_CONTEXT)), - KeyBinding::new("shift-tab", TerminalBacktabKey, Some(TERMINAL_KEY_CONTEXT)), + KeyBinding::new("tab", TerminalTabKey, Some(app::constants::TERMINAL_KEY_CONTEXT)), + KeyBinding::new("shift-tab", TerminalBacktabKey, Some(app::constants::TERMINAL_KEY_CONTEXT)), ]); - load_embedded_themes(cx); - if let Err(err) = load_fonts(cx) { + app::theme::load_embedded_themes(cx); + if let Err(err) = app::theme::load_fonts(cx) { tracing::warn!("failed to load embedded fonts: {err:#}"); } - open_main_window(cx); + app::startup::open_main_window(cx); }); } - diff --git a/src/config.rs b/src/session/config.rs similarity index 100% rename from src/config.rs rename to src/session/config.rs diff --git a/src/session.rs b/src/session/mod.rs similarity index 98% rename from src/session.rs rename to src/session/mod.rs index d16ce5a..9ebe998 100644 --- a/src/session.rs +++ b/src/session/mod.rs @@ -1,3 +1,5 @@ +pub mod config; + use gpui::{ App, AppContext as _, Context, Entity, KeyDownEvent, MouseButton, MouseDownEvent, MouseMoveEvent, SharedString, Window, px, @@ -9,21 +11,20 @@ use gpui_component::{ use rust_i18n::t; use uuid::Uuid; +use self::config::{AuthMethod, Session}; + use crate::{ Ashell, ConnectionProgress, PaneLayout, SelectorEntry, TabGroup, - config::{AuthMethod, Session}, - local_terminal, + backend::{local, ssh}, sftp, - ssh_terminal, terminal::{BackendCommand, RenderSnapshot, TabKind, TerminalTab}, - DEFAULT_COLS, DEFAULT_ROWS, SIDEBAR_WIDTH, TAB_BAR_HEIGHT, TERMINAL_PADDING_X, - TERMINAL_PADDING_Y, + app::constants::{DEFAULT_COLS, DEFAULT_ROWS, SIDEBAR_WIDTH, TAB_BAR_HEIGHT, TERMINAL_PADDING_X, TERMINAL_PADDING_Y}, }; impl Ashell { pub(crate) fn open_local(&mut self, cx: &mut Context) { let id = Uuid::new_v4().to_string(); - match local_terminal::spawn_local_terminal( + match local::spawn_local_terminal( id.clone(), DEFAULT_COLS, DEFAULT_ROWS, @@ -221,7 +222,7 @@ impl Ashell { if let Err(err) = self.config.save() { tracing::warn!("failed to save UI font family: {err:#}"); } - crate::theme::set_theme_font_names(Theme::global_mut(cx), &self.ui_font_family); + crate::app::theme::set_theme_font_names(Theme::global_mut(cx), &self.ui_font_family); cx.notify(); window.refresh(); } @@ -346,7 +347,7 @@ impl Ashell { pub(crate) fn open_ssh_session(&mut self, session: Session, cx: &mut Context) { let id = Uuid::new_v4().to_string(); - let backend = ssh_terminal::spawn_ssh_terminal( + let backend = ssh::spawn_ssh_terminal( self.runtime.handle(), id.clone(), session.clone(), @@ -528,6 +529,8 @@ impl Ashell { self.focused_pane_path = vec![]; self.active_tab = None; self.active_group = None; + self.tab_groups.clear(); + self.tabs.clear(); self.system_tab_id = None; self.cpu_history.clear(); self.net_rx_history.clear(); @@ -718,7 +721,7 @@ impl Ashell { let new_id = Uuid::new_v4().to_string(); let mut tab = match current_tab.kind { TabKind::Local => { - match local_terminal::spawn_local_terminal( + match local::spawn_local_terminal( new_id.clone(), DEFAULT_COLS, DEFAULT_ROWS, @@ -743,7 +746,7 @@ impl Ashell { cx.notify(); return; }; - let backend = ssh_terminal::spawn_ssh_terminal( + let backend = ssh::spawn_ssh_terminal( self.runtime.handle(), new_id.clone(), session.clone(), diff --git a/src/sftp.rs b/src/sftp/mod.rs similarity index 99% rename from src/sftp.rs rename to src/sftp/mod.rs index 07bfe4d..925a6dd 100644 --- a/src/sftp.rs +++ b/src/sftp/mod.rs @@ -1,3 +1,5 @@ +pub mod ops; + use std::{ fs, path::{Path, PathBuf}, @@ -27,7 +29,7 @@ use zip::read::ZipArchive; use rust_i18n::t; use crate::{ - config::{AuthMethod, Session}, + session::config::{AuthMethod, Session}, terminal::BackendEvent, }; @@ -496,7 +498,7 @@ async fn run_sftp( } SftpCommand::EditFile { remote_path } => { let id = uuid::Uuid::new_v4().to_string(); - let config = crate::config::ConfigStore::load().unwrap(); + let config = crate::session::config::ConfigStore::load().unwrap(); let tmp_dir = config.tmp_dir().unwrap_or_else(|| PathBuf::from("/tmp")); let base = base_name(&remote_path); let local_path = tmp_dir.join(format!("{}-{}", id, base)); diff --git a/src/sftp_ops.rs b/src/sftp/ops.rs similarity index 100% rename from src/sftp_ops.rs rename to src/sftp/ops.rs diff --git a/src/system.rs b/src/system/mod.rs similarity index 100% rename from src/system.rs rename to src/system/mod.rs diff --git a/src/terminal_element.rs b/src/terminal/element.rs similarity index 100% rename from src/terminal_element.rs rename to src/terminal/element.rs diff --git a/src/terminal_input.rs b/src/terminal/input.rs similarity index 100% rename from src/terminal_input.rs rename to src/terminal/input.rs diff --git a/src/terminal.rs b/src/terminal/mod.rs similarity index 99% rename from src/terminal.rs rename to src/terminal/mod.rs index 64e37a4..c84acbe 100644 --- a/src/terminal.rs +++ b/src/terminal/mod.rs @@ -1,3 +1,6 @@ +pub mod element; +pub mod input; + use std::sync::mpsc::Sender; use alacritty_terminal::{ @@ -10,7 +13,7 @@ use alacritty_terminal::{ }; use gpui::Keystroke; -use crate::config::Session; +use crate::session::config::Session; use crate::sftp::{PreviewData, RemoteEntry}; use crate::system::SystemSnapshot;