Compare commits

...
7 Commits
Author SHA1 Message Date
TomZz 58fd03386a Feat: Implement intelligent right-click copy/paste and add missing translations 2026-06-12 02:27:09 +08:00
TomZz 890ce85cfc Docs: Update preview image 2026-06-12 01:42:20 +08:00
TomZz d5fb956161 Docs: Update README with v0.3 release highlights 2026-06-12 01:31:07 +08:00
TomZz 4bad75e522 UI: Optimize font selection layout and prioritize built-in font
- Align UI font and Terminal font label widths (180px -> 240px) to match other settings
- Pin 'Maple Mono NF CN' to the top of font dropdown menus
- Add localized '(Built-in)' / '(软件内置)' suffix to the built-in font
- Add a visual separator below the built-in font in the dropdown menu
- Add 'software_builtin' translation keys in en.yml and zh-CN.yml
2026-06-12 01:03:47 +08:00
TomZz 9e28e78319 Merge pull request #6 from ancion/ashell
- Resolves conflicts in src/main.rs with SFTP header layout, font sizing, and resizable panel configs.
2026-06-12 00:50:10 +08:00
ancion 0cfd3a2fc2 chore: Increased maximum height for the SFTP section; clicking a file toggles its selection state. 2026-06-11 17:30:26 +08:00
ancion 6dfa199dcb feat: add UI font config and font scale and change real time 2026-06-11 16:55:14 +08:00
8 changed files with 527 additions and 72 deletions
+10
View File
@@ -8,6 +8,16 @@
This project focuses on providing a high-performance and visually appealing shell workspace by combining local and remote environments with a rich set of built-in features.
## 🚀 v0.3 Massive Update!
The brand-new v0.3 introduces comprehensive upgrades to both architecture and user experience:
- ✨ **Global Real-Time Font Sizing** (Thanks to [@ancion](https://github.com/ancion) for [PR #6](https://github.com/rust-kotlin/ashell/pull/6)): Customize your global UI fonts and terminal rendering fonts independently. Adjust text size with real-time scaling and automatic persistence.
- ✨ **Concurrent SFTP Transfers**: A dedicated Transfers dialog now supports highly optimized, concurrent file uploads and downloads with precise progress, speed, and ETA calculations.
- ✨ **Persistent Workspace State**: Your sidebar width adjustments, terminal themes, font settings, and file visibility preferences are completely restored upon your next launch!
- ✨ **Intelligent SSH Disconnect/Reconnect**: Greatly enhanced SSH connection resilience. Provides a beautiful and localized overlay for one-click re-connection on unexpected disconnections.
- ✨ **Hot-Swappable i18n System**: Deeply optimized internationalization. Switch instantly between English and Simplified Chinese without restarting the application.
- ✨ **Smart Right-Click Actions**: Added intelligent right-click copy and paste for the terminal, featuring a dedicated settings toggle and OS-native keyboard shortcut hints.
## Download
You can download the latest pre-compiled releases for macOS, Windows, and Linux from the [GitHub Releases page](https://github.com/rust-kotlin/ashell/releases/latest).
+10
View File
@@ -8,6 +8,16 @@
该项目旨在通过结合本地和远程环境,并内置丰富的核心功能,提供一个高性能且美观的 Shell 工作区。
## 🚀 v0.3 版本重磅更新!
全新发布的 v0.3 迎来了架构和体验的全面升级:
- ✨ **全局实时字体设置与无级缩放**(感谢 [@ancion](https://github.com/ancion) 提供的 [PR #6](https://github.com/rust-kotlin/ashell/pull/6)):支持自定义全局 UI 字体和终端渲染字体,支持实时字号调节缩放并自动记忆。
- ✨ **SFTP 多任务并发传输队列**:引入全新的独立传输对话框,支持多文件并发上传下载,提供精准的进度条、速率和剩余时间显示。
- ✨ **持久化工作区记忆**:您对侧边栏的尺寸拖拽、终端主题、字体、隐藏文件开关等一切设置都会在下次启动时原样恢复!
- ✨ **智能断线重连与状态感知**:全面增强的 SSH 网络异常处理机制,断线后直接提供美观的覆盖层用于一键重连或关闭。
- ✨ **多语言热切换增强**:深度优化的 i18n 系统,包含中文与英文在内的所有界面文案现在均支持热切换。
- ✨ **智能右键快捷操作**:新增终端右键智能复制与粘贴功能,提供专属设置项自由控制开关,并支持根据不同操作系统自适应显示原生快捷键提示。
## 下载
您可以从 [GitHub Releases 页面](https://github.com/rust-kotlin/ashell/releases/latest) 下载 macOS、Windows 和 Linux 版本的最新预编译程序。
+9
View File
@@ -51,7 +51,11 @@ add_ssh: "+ ssh"
open_local_or_ssh: "Open a local terminal or pick an SSH session."
open_session: "Open Session"
settings: "Settings"
ui_font_size: "UI Font Size"
terminal_font_size: "Terminal Font Size"
system_default: "System Default"
ui_font_family: "UI Font"
terminal_font_family: "Terminal Font"
theme_management_hint: "Theme mode and light/dark theme families are managed from the top-bar theme button."
local_host: "local host"
local_terminal_opened: "local terminal opened"
@@ -86,3 +90,8 @@ completed: "Completed"
failed: "Failed"
cancelled: "Cancelled"
session: "Session"
software_builtin: "Built-in"
retry: "Retry"
right_click_copy_paste: "Right-click Copy/Paste"
copy_paste_hint: "Tip: Regardless of this switch, you can always use %{key} + C/V to copy/paste."
+9
View File
@@ -51,7 +51,11 @@ add_ssh: "+ SSH"
open_local_or_ssh: "打开本地终端或选择一个 SSH 会话。"
open_session: "打开会话"
settings: "设置"
ui_font_size: "界面字体大小"
terminal_font_size: "终端字体大小"
system_default: "系统默认"
ui_font_family: "界面字体"
terminal_font_family: "终端字体"
theme_management_hint: "主题模式和亮/暗主题系列可通过顶栏的主题按钮管理。"
local_host: "本地主机"
local_terminal_opened: "已打开本地终端"
@@ -86,3 +90,8 @@ completed: "已完成"
failed: "失败"
cancelled: "已取消"
session: "会话"
software_builtin: "软件内置"
retry: "重试"
right_click_copy_paste: "右键复制/粘贴"
copy_paste_hint: "提示:不管是否开启此开关,都可以使用 %{key} + C/V 快捷键进行复制和粘贴。"
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 292 KiB

After

Width:  |  Height:  |  Size: 279 KiB

+66
View File
@@ -107,6 +107,14 @@ pub struct ConfigFile {
pub locale: String,
#[serde(default = "default_terminal_font_size")]
pub terminal_font_size: f32,
#[serde(default = "default_ui_font_size")]
pub ui_font_size: f32,
#[serde(default)]
pub right_click_copy_paste: bool,
#[serde(default = "default_ui_font_family")]
pub ui_font_family: String,
#[serde(default = "default_terminal_font_family")]
pub terminal_font_family: String,
#[serde(default)]
pub sessions: Vec<Session>,
#[serde(default)]
@@ -127,6 +135,20 @@ fn default_terminal_font_size() -> f32 {
13.0
}
fn default_ui_font_size() -> f32 {
12.0
}
pub fn default_ui_font_family() -> String {
// ".SystemUIFont" is a GPUI sentinel that resolves to the platform system UI font.
// This matches gpui-component's own Theme default.
".SystemUIFont".to_string()
}
fn default_terminal_font_family() -> String {
"Maple Mono NF CN".to_string()
}
pub struct ConfigStore {
path: PathBuf,
cache: ConfigFile,
@@ -258,6 +280,50 @@ impl ConfigStore {
self.cache.terminal_font_size = terminal_font_size.max(10.0);
}
pub fn ui_font_size(&self) -> f32 {
if self.cache.ui_font_size <= 0.0 {
default_ui_font_size()
} else {
self.cache.ui_font_size
}
}
pub fn set_ui_font_size(&mut self, ui_font_size: f32) {
self.cache.ui_font_size = ui_font_size.max(8.0);
}
pub fn ui_font_family(&self) -> &str {
if self.cache.ui_font_family.is_empty() {
".SystemUIFont"
} else {
&self.cache.ui_font_family
}
}
pub fn set_ui_font_family(&mut self, family: &str) {
self.cache.ui_font_family = family.to_string();
}
pub fn right_click_copy_paste(&self) -> bool {
self.cache.right_click_copy_paste
}
pub fn set_right_click_copy_paste(&mut self, val: bool) {
self.cache.right_click_copy_paste = val;
}
pub fn terminal_font_family(&self) -> &str {
if self.cache.terminal_font_family.is_empty() {
"Maple Mono NF CN"
} else {
&self.cache.terminal_font_family
}
}
pub fn set_terminal_font_family(&mut self, family: &str) {
self.cache.terminal_font_family = family.to_string();
}
pub fn get(&self, id: &str) -> Option<&Session> {
self.cache.sessions.iter().find(|s| s.id == id)
}
+417 -66
View File
@@ -19,13 +19,14 @@ use gpui::{
KeyDownEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement as _,
PathPromptOptions, Pixels, Point, QuitMode, Render, ScrollDelta, ScrollWheelEvent,
SharedString, Size, StatefulInteractiveElement, Styled as _, UniformListScrollHandle, Window, WindowOptions, div, point,
prelude::FluentBuilder as _, px, size, uniform_list,
prelude::FluentBuilder as _, px, rems, size, uniform_list,
};
use gpui_component::{
ActiveTheme as _, Disableable, ElementExt, IconName, Root, Sizable as _, Theme, ThemeMode,
ThemeRegistry, WindowExt as _,
button::{Button, ButtonVariants as _},
checkbox::Checkbox,
switch::Switch,
dialog::Dialog,
h_flex,
input::{Input, InputEvent, InputState},
@@ -59,7 +60,7 @@ rust_i18n::i18n!("locales", fallback = "en");
const DEFAULT_COLS: u16 = 100;
const DEFAULT_ROWS: u16 = 30;
const APP_FONT_FAMILY: &str = "Maple Mono NF CN";
const SIDEBAR_WIDTH: f32 = 306.0;
const TAB_BAR_HEIGHT: f32 = 52.0;
const TERMINAL_PADDING_X: f32 = 32.0;
@@ -152,7 +153,10 @@ struct Ashell {
theme_mode: ThemeMode,
light_theme_name: SharedString,
dark_theme_name: SharedString,
ui_font_size: f32,
terminal_font_size: f32,
ui_font_family: SharedString,
terminal_font_family: SharedString,
tabs: Vec<TerminalTab>,
sftp_handles: HashMap<String, SftpHandle>,
active_tab: Option<String>,
@@ -285,6 +289,8 @@ impl Ashell {
}
rust_i18n::set_locale(&active_locale);
gpui_component::set_locale(&active_locale);
let ui_font_family: SharedString = config.ui_font_family().into();
let terminal_font_family: SharedString = config.terminal_font_family().into();
let mut this = Self {
focus_handle: cx.focus_handle(),
selector_focus_handle: cx.focus_handle(),
@@ -302,7 +308,10 @@ impl Ashell {
theme_mode,
light_theme_name,
dark_theme_name,
ui_font_size: config.ui_font_size(),
terminal_font_size: config.terminal_font_size(),
ui_font_family,
terminal_font_family,
tabs: Vec::new(),
sftp_handles: HashMap::new(),
active_tab: None,
@@ -771,6 +780,42 @@ impl Ashell {
cx.notify();
}
fn change_ui_font_size(&mut self, delta: f32, cx: &mut Context<Self>) {
self.ui_font_size = (self.ui_font_size + delta).clamp(8.0, 24.0);
self.config.set_ui_font_size(self.ui_font_size);
if let Err(err) = self.config.save() {
tracing::warn!("failed to save UI font size: {err:#}");
}
Theme::global_mut(cx).font_size = px(self.ui_font_size);
self.status = format!("UI font size: {:.0}px", self.ui_font_size).into();
cx.notify();
}
fn change_ui_font_family(
&mut self,
family: &str,
window: &mut Window,
cx: &mut Context<Self>,
) {
self.ui_font_family = family.into();
self.config.set_ui_font_family(family);
if let Err(err) = self.config.save() {
tracing::warn!("failed to save UI font family: {err:#}");
}
set_theme_font_names(Theme::global_mut(cx), &self.ui_font_family);
cx.notify();
window.refresh();
}
fn change_terminal_font_family(&mut self, family: &str, cx: &mut Context<Self>) {
self.terminal_font_family = family.into();
self.config.set_terminal_font_family(family);
if let Err(err) = self.config.save() {
tracing::warn!("failed to save terminal font family: {err:#}");
}
cx.notify();
}
fn show_ssh_dialog(&mut self, window: &mut Window, cx: &mut Context<Self>) {
let view = cx.entity();
let session_name_input = self.session_name_input.clone();
@@ -895,7 +940,7 @@ impl Ashell {
self.selector_selection = self.default_selector_index();
window.open_dialog(cx, move |dialog: Dialog, _window, _| {
dialog
.title("Open Session")
.title(t!("open_session").to_string())
.w(px(520.))
.on_ok({
let view = view.clone();
@@ -953,13 +998,13 @@ impl Ashell {
.gap_1()
.child(
div()
.text_size(px(12.))
.text_size(rems(1.0))
.font_weight(FontWeight::SEMIBOLD)
.child(t!("local_terminal")),
)
.child(
div()
.text_size(px(11.))
.text_size(rems(0.917))
.text_color(_cx.theme().muted_foreground)
.child(t!("open_local_shell_tab")),
),
@@ -995,13 +1040,13 @@ impl Ashell {
.gap_1()
.child(
div()
.text_size(px(12.))
.text_size(rems(1.0))
.font_weight(FontWeight::SEMIBOLD)
.child(t!("new_ssh_connection")),
)
.child(
div()
.text_size(px(11.))
.text_size(rems(0.917))
.text_color(_cx.theme().muted_foreground)
.child(t!("create_or_edit_ssh_session")),
),
@@ -1057,7 +1102,7 @@ impl Ashell {
.gap_1()
.child(
div()
.text_size(px(12.))
.text_size(rems(1.0))
.font_weight(
FontWeight::SEMIBOLD,
)
@@ -1065,7 +1110,7 @@ impl Ashell {
)
.child(
div()
.text_size(px(11.))
.text_size(rems(0.917))
.text_color(
_cx.theme()
.muted_foreground,
@@ -1316,6 +1361,40 @@ impl Ashell {
content.child(
v_flex()
.gap_3()
.child(
h_flex()
.items_center()
.gap_3()
.child(
div()
.w(px(240.))
.child(t!("ui_font_size").to_string()),
)
.child(
Button::new("ui-font-size-down")
.label("-")
.on_click(window.listener_for(
&view,
|this, _, _, cx| {
this.change_ui_font_size(-1.0, cx)
},
)),
)
.child(div().min_w(px(64.)).text_center().child(format!(
"{:.0}px",
view.read(cx).ui_font_size
)))
.child(
Button::new("ui-font-size-up")
.label("+")
.on_click(window.listener_for(
&view,
|this, _, _, cx| {
this.change_ui_font_size(1.0, cx)
},
)),
),
)
.child(
h_flex()
.items_center()
@@ -1325,20 +1404,246 @@ impl Ashell {
.w(px(240.))
.child(t!("terminal_font_size").to_string()),
)
.child(Button::new("font-size-down").label("-").on_click(
window.listener_for(&view, |this, _, _, cx| {
this.change_terminal_font_size(-1.0, cx)
}),
))
.child(
Button::new("font-size-down")
.label("-")
.on_click(window.listener_for(
&view,
|this, _, _, cx| {
this.change_terminal_font_size(-1.0, cx)
},
)),
)
.child(div().min_w(px(64.)).text_center().child(format!(
"{:.0}px",
view.read(cx).terminal_font_size
)))
.child(Button::new("font-size-up").label("+").on_click(
window.listener_for(&view, |this, _, _, cx| {
this.change_terminal_font_size(1.0, cx)
}),
)),
.child(
Button::new("font-size-up")
.label("+")
.on_click(window.listener_for(
&view,
|this, _, _, cx| {
this.change_terminal_font_size(1.0, cx)
},
)),
),
)
.child(
h_flex()
.items_center()
.gap_3()
.child(
div()
.w(px(240.))
.child(t!("ui_font_family").to_string()),
)
.child(
Button::new("ui-font-dropdown")
.small()
.icon(IconName::ChevronsUpDown)
.label({
let current = view
.read(cx)
.ui_font_family
.to_string();
let names = cx.text_system().all_font_names();
if current == *".SystemUIFont"
|| current.is_empty()
|| !names.contains(&current)
{
t!("system_default").to_string()
} else if current == "Maple Mono NF CN" {
format!("Maple Mono NF CN ({})", t!("software_builtin"))
} else {
current
}
})
.dropdown_menu_with_anchor(
Anchor::BottomRight,
{
let view = view.clone();
move |mut menu, window, cx| {
let current = view
.read(cx)
.ui_font_family
.to_string();
let mut names =
cx.text_system().all_font_names();
menu = menu.min_w(200.).max_h(
px(320.),
).scrollable(true);
// "System Default" entry
menu = menu.item(
PopupMenuItem::new(
t!(
"system_default"
)
.to_string(),
)
.checked(
current == *".SystemUIFont"
|| current
.is_empty(),
)
.on_click(window
.listener_for(
&view,
move |this, _, window,
cx| {
this.change_ui_font_family(
".SystemUIFont",
window,
cx,
);
},
)),
);
let maple_font = "Maple Mono NF CN".to_string();
if names.contains(&maple_font) {
names.retain(|n| n != &maple_font);
menu = menu.item(
PopupMenuItem::new(format!("{} ({})", maple_font, t!("software_builtin")))
.checked(current == maple_font)
.on_click(window.listener_for(&view, move |this, _, window, cx| {
this.change_ui_font_family("Maple Mono NF CN", window, cx);
}))
).separator();
}
for name in names {
let checked =
name == current;
menu = menu.item(
PopupMenuItem::new(
name.clone(),
)
.checked(checked)
.on_click(window
.listener_for(
&view,
move |this, _,
window, cx| {
this
.change_ui_font_family(
&name,
window,
cx,
);
},
)),
);
}
menu
}
},
),
),
)
.child(
h_flex()
.items_center()
.gap_3()
.child(
div()
.w(px(240.))
.child(t!("terminal_font_family").to_string()),
)
.child(
Button::new("terminal-font-dropdown")
.small()
.icon(IconName::ChevronsUpDown)
.label({
let current = view.read(cx).terminal_font_family.to_string();
if current == "Maple Mono NF CN" {
format!("Maple Mono NF CN ({})", t!("software_builtin"))
} else {
current
}
})
.dropdown_menu_with_anchor(
Anchor::BottomRight,
{
let view = view.clone();
move |mut menu, window, cx| {
let current = view
.read(cx)
.terminal_font_family
.to_string();
let mut names =
cx.text_system().all_font_names();
menu = menu.min_w(200.).max_h(
px(320.),
).scrollable(true);
let maple_font = "Maple Mono NF CN".to_string();
if names.contains(&maple_font) {
names.retain(|n| n != &maple_font);
menu = menu.item(
PopupMenuItem::new(format!("{} ({})", maple_font, t!("software_builtin")))
.checked(current == maple_font)
.on_click(window.listener_for(&view, move |this, _, _window, cx| {
this.change_terminal_font_family("Maple Mono NF CN", cx);
}))
).separator();
}
for name in names {
let checked =
name == current;
menu = menu.item(
PopupMenuItem::new(
name.clone(),
)
.checked(checked)
.on_click(window
.listener_for(
&view,
move |this, _,
_window, cx| {
this
.change_terminal_font_family(
&name,
cx,
);
},
)),
);
}
menu
}
},
),
),
)
.child(
v_flex()
.gap_1()
.child(
h_flex()
.items_center()
.gap_3()
.child(div().w(px(240.)).child(t!("right_click_copy_paste").to_string()))
.child(
Switch::new("right-click-copy-paste")
.checked(view.read(cx).config.right_click_copy_paste())
.on_click(window.listener_for(
&view,
|this, checked, _, cx| {
this.config.set_right_click_copy_paste(*checked);
let _ = this.config.save();
cx.notify();
},
)),
)
)
.child(
div()
.text_size(rems(0.85))
.text_color(cx.theme().muted_foreground)
.child(t!("copy_paste_hint", key = if cfg!(target_os = "macos") { "Command" } else { "Ctrl" }).to_string())
)
)
.child(
h_flex()
@@ -1438,7 +1743,7 @@ impl Ashell {
)
.child(
div()
.text_size(px(12.))
.text_size(rems(1.0))
.text_color(cx.theme().muted_foreground)
.child(t!("theme_management_hint")),
),
@@ -1718,6 +2023,11 @@ impl Ashell {
return;
}
self.mark_sftp_entry_selected(&entry.full_path, cx);
if let Some(sftp) = self.active_sftp_mut() {
if !sftp.selected_entries.remove(&entry.full_path) {
sftp.selected_entries.insert(entry.full_path);
}
}
}
fn mark_sftp_entry_selected(&mut self, path: &str, cx: &mut Context<Self>) {
@@ -1969,7 +2279,8 @@ impl Ashell {
let theme = Theme::global_mut(cx);
theme.light_theme = light_theme;
theme.dark_theme = dark_theme;
set_theme_font_names(theme);
theme.font_size = px(self.ui_font_size);
set_theme_font_names(theme, &self.ui_font_family);
if self.follow_system_theme {
Theme::sync_system_appearance(Some(window), cx);
@@ -2217,6 +2528,43 @@ impl Ashell {
cx.notify();
}
fn on_terminal_right_click(
&mut self,
_event: &MouseDownEvent,
window: &mut Window,
cx: &mut Context<Self>,
) {
if !self.config.right_click_copy_paste() {
return;
}
let mut handled = false;
if let Some(text) = self.active_terminal_selection_text() {
if !text.is_empty() {
cx.write_to_clipboard(gpui::ClipboardItem::new_string(text));
let active_id = self.active_tab.clone();
if let Some(active_id) = active_id {
if let Some(tab) = self.tabs.iter_mut().find(|tab| tab.id == active_id) {
tab.clear_selection();
}
}
cx.notify();
handled = true;
}
}
if !handled {
if let Some(clipboard_item) = cx.read_from_clipboard() {
if let Some(text) = clipboard_item.text() {
if !text.is_empty() {
self.paste_into_terminal(&text, window, cx);
}
}
}
}
}
fn begin_terminal_selection(&mut self, event: &MouseDownEvent, cx: &mut Context<Self>) {
let click_count = event.click_count.max(1);
let selection_type = match click_count {
@@ -2337,13 +2685,13 @@ impl Ashell {
.gap_4()
.child(
div()
.text_size(px(28.))
.text_size(rems(2.333))
.font_weight(FontWeight::BOLD)
.child("ashell"),
)
.child(
div()
.text_size(px(13.))
.text_size(rems(1.083))
.text_color(cx.theme().muted_foreground)
.child(t!("open_local_or_ssh")),
)
@@ -2484,7 +2832,7 @@ impl Ashell {
.gap_2()
.child(
div()
.text_size(px(11.))
.text_size(rems(0.917))
.font_weight(FontWeight::SEMIBOLD)
.text_color(fill)
.child(label.clone()),
@@ -2492,7 +2840,7 @@ impl Ashell {
.child(div().flex_1())
.child(
div()
.text_size(px(11.))
.text_size(rems(0.917))
.text_color(cx.theme().muted_foreground)
.flex_none()
.child(format!("{:.0}%", percent * 100.0)),
@@ -2510,7 +2858,7 @@ impl Ashell {
.w_full()
.min_w(px(0.))
.overflow_hidden()
.text_size(px(11.))
.text_size(rems(0.917))
.text_color(cx.theme().muted_foreground)
.child(detail),
)
@@ -2530,7 +2878,7 @@ impl Ashell {
.gap_2()
.child(
div()
.text_size(px(12.))
.text_size(rems(1.0))
.font_weight(FontWeight::SEMIBOLD)
.text_color(cx.theme().chart_4)
.child(t!("net")),
@@ -2538,7 +2886,7 @@ impl Ashell {
.child(div().flex_1())
.child(
div()
.text_size(px(11.))
.text_size(rems(0.917))
.text_color(cx.theme().muted_foreground)
.child(t!("live")),
),
@@ -2554,11 +2902,11 @@ impl Ashell {
.child(
div()
.flex_none()
.text_size(px(12.))
.text_size(rems(1.0))
.text_color(cx.theme().chart_4)
.child("↓"),
)
.child(div().text_size(px(12.)).child(self.system.net_rx.clone())),
.child(div().text_size(rems(1.0)).child(self.system.net_rx.clone())),
)
.child(
h_flex()
@@ -2568,11 +2916,11 @@ impl Ashell {
.child(
div()
.flex_none()
.text_size(px(12.))
.text_size(rems(1.0))
.text_color(cx.theme().chart_5)
.child("↑"),
)
.child(div().text_size(px(12.)).child(self.system.net_tx.clone())),
.child(div().text_size(rems(1.0)).child(self.system.net_tx.clone())),
),
)
}
@@ -2598,14 +2946,14 @@ impl Ashell {
.flex_1()
.min_w(px(0.))
.overflow_hidden()
.text_size(px(11.))
.text_size(rems(0.917))
.text_color(cx.theme().foreground)
.child(mount.clone()),
)
.child(
div()
.flex_none()
.text_size(px(11.))
.text_size(rems(0.917))
.text_color(cx.theme().muted_foreground)
.child(format!("{:.0}%", percent * 100.0)),
),
@@ -2621,7 +2969,7 @@ impl Ashell {
div()
.min_w(px(0.))
.overflow_hidden()
.text_size(px(11.))
.text_size(rems(0.917))
.text_color(cx.theme().muted_foreground)
.child(format!(
"{}/{}",
@@ -2821,7 +3169,7 @@ impl Ashell {
.bg(cx.theme().tab_bar)
.child(
div()
.text_size(px(12.))
.text_size(rems(1.0))
.font_weight(FontWeight::SEMIBOLD)
.text_color(cx.theme().primary)
.child(t!("remote_files")),
@@ -2910,7 +3258,7 @@ impl Ashell {
.p_3()
.child(
div()
.text_size(px(12.))
.text_size(rems(1.0))
.text_color(cx.theme().muted_foreground)
.child(t!("open_ssh_tab_sftp")),
),
@@ -3007,7 +3355,7 @@ impl Ashell {
.child(
div()
.flex_1()
.text_size(px(11.))
.text_size(rems(0.917))
.text_color(cx.theme().muted_foreground)
.child(t!("name")),
),
@@ -3016,7 +3364,7 @@ impl Ashell {
div()
.w(size_col_width)
.flex_none()
.text_size(px(11.))
.text_size(rems(0.917))
.text_color(cx.theme().muted_foreground)
.child(t!("size")),
)
@@ -3024,7 +3372,7 @@ impl Ashell {
div()
.w(modified_col_width)
.flex_none()
.text_size(px(11.))
.text_size(rems(0.917))
.text_color(cx.theme().muted_foreground)
.child(t!("modified")),
)
@@ -3148,7 +3496,7 @@ impl Ashell {
div()
.w(icon_col_width)
.flex_none()
.text_size(px(12.))
.text_size(rems(1.0))
.text_color(name_color)
.child(if entry.is_dir {
"📁"
@@ -3161,7 +3509,7 @@ impl Ashell {
.flex_1()
.min_w(px(0.))
.overflow_hidden()
.text_size(px(12.))
.text_size(rems(1.0))
.text_color(name_color)
.child(entry.name),
),
@@ -3170,7 +3518,7 @@ impl Ashell {
div()
.w(size_col_width)
.flex_none()
.text_size(px(11.))
.text_size(rems(0.917))
.text_color(cx.theme().muted_foreground)
.child(if entry.is_dir {
"-".to_string()
@@ -3182,7 +3530,7 @@ impl Ashell {
div()
.w(modified_col_width)
.flex_none()
.text_size(px(11.))
.text_size(rems(0.917))
.text_color(cx.theme().muted_foreground)
.child(format_mtime(entry.modified)),
)
@@ -3221,7 +3569,7 @@ impl Ashell {
div()
.min_w(px(0.))
.overflow_hidden()
.text_size(px(11.))
.text_size(rems(0.917))
.text_color(cx.theme().muted_foreground)
.child(status),
),
@@ -3261,13 +3609,13 @@ impl Ashell {
.child(
div()
.font_weight(FontWeight::BOLD)
.text_size(px(20.))
.text_size(rems(1.667))
.text_color(cx.theme().primary)
.child("ashell"),
)
.child(
div()
.text_size(px(11.))
.text_size(rems(0.917))
.text_color(cx.theme().muted_foreground)
.child({
if let Some(kind) = self.active_kind() {
@@ -3291,7 +3639,7 @@ impl Ashell {
.items_center()
.child(
div()
.text_size(px(12.))
.text_size(rems(1.0))
.font_weight(FontWeight::SEMIBOLD)
.text_color(cx.theme().primary)
.child(t!("system")),
@@ -3299,7 +3647,7 @@ impl Ashell {
.child(div().flex_1())
.child(
div()
.text_size(px(11.))
.text_size(rems(0.917))
.text_color(cx.theme().muted_foreground)
.child(self.system_target_label()),
),
@@ -3307,7 +3655,7 @@ impl Ashell {
.when_some(self.system_status.clone(), |this, text| {
this.child(
div()
.text_size(px(11.))
.text_size(rems(0.917))
.text_color(cx.theme().muted_foreground)
.child(text),
)
@@ -3344,7 +3692,7 @@ impl Ashell {
.bg(cx.theme().muted)
.child(
div()
.text_size(px(11.))
.text_size(rems(0.917))
.text_color(cx.theme().chart_5)
.child(t!("disk")),
)
@@ -3370,7 +3718,7 @@ impl Ashell {
.gap_2()
.child(
div()
.text_size(px(12.))
.text_size(rems(1.0))
.font_weight(FontWeight::SEMIBOLD)
.text_color(cx.theme().primary)
.child(t!("saved")),
@@ -3449,13 +3797,13 @@ impl Ashell {
.gap_1()
.child(
div()
.text_size(px(12.))
.text_size(rems(1.0))
.font_weight(FontWeight::SEMIBOLD)
.child(name),
)
.child(
div()
.text_size(px(11.))
.text_size(rems(0.917))
.text_color(cx.theme().muted_foreground)
.child(detail),
),
@@ -3514,7 +3862,7 @@ impl Render for Ashell {
.size_full()
.bg(cx.theme().background)
.text_color(cx.theme().foreground)
.font_family(APP_FONT_FAMILY)
.font_family(self.ui_font_family.clone())
.child(
h_resizable("ashell-workspace")
.with_state(&self.workspace_panels)
@@ -3624,13 +3972,14 @@ impl Render for Ashell {
.p_4()
.bg(cx.theme().background)
.text_color(cx.theme().foreground)
.font_family(APP_FONT_FAMILY)
.text_size(px(13.))
.font_family(self.ui_font_family.clone())
.text_size(rems(1.083))
.line_height(px(18.))
.overflow_hidden()
.track_focus(&self.focus_handle)
.key_context(TERMINAL_KEY_CONTEXT)
.on_mouse_down(MouseButton::Left, cx.listener(Self::focus_terminal))
.on_mouse_down(MouseButton::Right, cx.listener(Self::on_terminal_right_click))
.on_mouse_move(cx.listener(Self::on_terminal_mouse_move))
.on_mouse_up(MouseButton::Left, cx.listener(Self::on_terminal_mouse_up))
.on_key_down(cx.listener(Self::on_terminal_key_down))
@@ -3660,7 +4009,7 @@ impl Render for Ashell {
self.focus_handle.clone(),
snapshot,
self.terminal_marked_text.clone(),
APP_FONT_FAMILY,
self.terminal_font_family.clone(),
px(self.terminal_font_size),
px(self.terminal_line_height()),
px(self.terminal_cell_width()),
@@ -3676,7 +4025,7 @@ impl Render for Ashell {
.child(
resizable_panel()
.size(px(self.config.body_panels().and_then(|s| s.get(1).copied()).unwrap_or(248.0)))
.size_range(px(180.)..px(420.))
.size_range(px(180.)..px(1000.))
.child(self.render_sftp_panel(window, cx)),
),
),
@@ -3782,7 +4131,7 @@ impl Render for Ashell {
.gap_2()
.children(progress.lines.iter().cloned().map(|line| {
div()
.text_size(px(12.))
.text_size(rems(1.0))
.text_color(if progress.failed {
cx.theme().danger
} else {
@@ -3800,14 +4149,14 @@ impl Render for Ashell {
.child(
Button::new("ssh-connect-progress-retry")
.primary()
.label("retry")
.label(t!("retry").to_string())
.on_click(cx.listener(|this, _, _, cx| {
this.retry_connection_progress(cx)
})),
)
.child(
Button::new("ssh-connect-progress-close")
.label("cancel")
.label(t!("cancel").to_string())
.on_click(cx.listener(|this, _, _, cx| {
this.cancel_connection_progress(cx)
})),
@@ -3827,7 +4176,9 @@ fn load_fonts(cx: &mut App) -> Result<()> {
cx.text_system()
.add_fonts(vec![regular, bold])
.context("load Maple Mono NF CN fonts")?;
set_theme_font_names(cx.global_mut::<Theme>());
// 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.
set_theme_font_names(cx.global_mut::<Theme>(), ".SystemUIFont");
Ok(())
}
@@ -3840,9 +4191,9 @@ fn load_embedded_themes(cx: &mut App) {
}
}
fn set_theme_font_names(theme: &mut Theme) {
theme.font_family = APP_FONT_FAMILY.into();
theme.mono_font_family = APP_FONT_FAMILY.into();
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();
}
#[cfg(target_os = "macos")]
+6 -6
View File
@@ -4,7 +4,7 @@ use alacritty_terminal::{
};
use gpui::{
App, Bounds, Element, ElementId, Entity, FocusHandle, Font, FontStyle, FontWeight,
GlobalElementId, Hsla, InputHandler, IntoElement, LayoutId, Pixels, Point, Rgba,
GlobalElementId, Hsla, InputHandler, IntoElement, LayoutId, Pixels, Point, Rgba, SharedString,
StrikethroughStyle, TextRun, TextStyle, UTF16Selection, UnderlineStyle, Window, fill, point,
px, relative, rgb,
};
@@ -127,7 +127,7 @@ pub struct TerminalElement {
focus_handle: FocusHandle,
snapshot: RenderSnapshot,
marked_text: Option<String>,
font_family: &'static str,
font_family: SharedString,
font_size: Pixels,
line_height: Pixels,
cell_width: Pixels,
@@ -250,7 +250,7 @@ impl TerminalElement {
focus_handle: FocusHandle,
snapshot: RenderSnapshot,
marked_text: Option<String>,
font_family: &'static str,
font_family: SharedString,
font_size: Pixels,
line_height: Pixels,
cell_width: Pixels,
@@ -270,7 +270,7 @@ impl TerminalElement {
fn base_text_style(&self, cx: &App) -> TextStyle {
TextStyle {
color: cx.theme().foreground,
font_family: self.font_family.into(),
font_family: self.font_family.clone(),
font_size: self.font_size.into(),
line_height: self.line_height.into(),
..Default::default()
@@ -319,7 +319,7 @@ impl TerminalElement {
color: fg,
background_color: None,
font: Font {
family: self.font_family.into(),
family: self.font_family.clone(),
weight,
style,
..Font::default()
@@ -514,7 +514,7 @@ impl Element for TerminalElement {
&[TextRun {
len: marked_text.len(),
font: Font {
family: self.font_family.into(),
family: self.font_family.clone(),
..Font::default()
},
color: base_style.color,