Compare commits

...
7 Commits
Author SHA1 Message Date
TomZz 7be0c420e1 chore: release v0.4.6 2026-06-18 08:20:33 +08:00
TomZz 62028c7921 feat: replace native title bar with custom TitleBar and integrate tab bar
This commit removes the native OS title bar and introduces a cross-platform custom title bar using gpui-component's TitleBar. To optimize vertical screen space, the tab bar has been relocated into the newly created custom title bar.

Fixes #37
2026-06-18 08:18:00 +08:00
TomZz 56a6ef98b7 feat: add tooltips for sidebar and tab bar buttons 2026-06-18 07:58:50 +08:00
TomZz caa8a58561 fix: correctly reset active_dialog in session selector and ssh dialog 2026-06-18 00:41:53 +08:00
TomZz 6150bd410b fix: correctly reset active_dialog when manually closing transfers dialog 2026-06-17 07:05:09 +08:00
TomZz f55c3a8470 chore: bump version to v0.4.5 and update documentation 2026-06-17 06:23:07 +08:00
TomZz 7ae44ab9a7 ci: automate homebrew cask release for macos 2026-06-17 05:59:05 +08:00
9 changed files with 170 additions and 19 deletions
+86 -5
View File
@@ -12,7 +12,7 @@ on:
workflow_dispatch:
permissions:
contents: write # needed to create / update the GitHub Release
contents: write # needed to create / update the GitHub Release
jobs:
build:
@@ -26,15 +26,15 @@ jobs:
target: x86_64-pc-windows-msvc
name: windows-x86_64
bin: ashell.exe
- os: ubuntu-22.04 # build on the oldest supported runner for broader glibc compatibility
- os: ubuntu-22.04 # build on the oldest supported runner for broader glibc compatibility
target: x86_64-unknown-linux-gnu
name: linux-x86_64
bin: ashell
- os: macos-14 # Apple Silicon
- os: macos-14 # Apple Silicon
target: aarch64-apple-darwin
name: macos-aarch64
bin: ashell
- os: macos-14 # Intel (cross-compiled from Apple Silicon to avoid queue delays)
- os: macos-14 # Intel (cross-compiled from Apple Silicon to avoid queue delays)
target: x86_64-apple-darwin
name: macos-x86_64
bin: ashell
@@ -80,7 +80,7 @@ jobs:
# Note: We build the bundle manually here rather than running
# scripts/package-macos-app.sh, because that script runs `cargo build`
# without respecting the `--target` flag from the matrix.
APP="ashell.app"
CONTENTS="$APP/Contents"
mkdir -p "$CONTENTS/MacOS" "$CONTENTS/Resources"
@@ -168,3 +168,84 @@ jobs:
files: dist/**/*
generate_release_notes: true
fail_on_unmatched_files: true
cask:
name: Update Homebrew Cask
needs: publish
if: startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
steps:
- name: Checkout Homebrew Tap
uses: actions/checkout@v4
with:
repository: rust-kotlin/homebrew-taps
token: ${{ secrets.TAP_GITHUB_TOKEN }}
path: tap
- name: Download all macOS artifacts
uses: actions/download-artifact@v4
with:
pattern: macos-*
path: dist
- name: Update Cask
run: |
VERSION=${GITHUB_REF#refs/tags/v}
SHA_ARM=$(sha256sum dist/macos-aarch64/*.zip | cut -d' ' -f1)
SHA_INTEL=$(sha256sum dist/macos-x86_64/*.zip | cut -d' ' -f1)
mkdir -p tap/Casks
CASK_FILE="tap/Casks/ashell.rb"
cat > "$CASK_FILE" <<EOF
cask "ashell" do
version "${VERSION}"
on_arm do
sha256 "${SHA_ARM}"
url "https://github.com/rust-kotlin/ashell/releases/download/v#{version}/ashell-v#{version}-macos-aarch64.zip"
end
on_intel do
sha256 "${SHA_INTEL}"
url "https://github.com/rust-kotlin/ashell/releases/download/v#{version}/ashell-v#{version}-macos-x86_64.zip"
end
name "ashell"
desc "ashell is a modern, fast, GPUI Component-based desktop terminal client written in Rust."
homepage "https://github.com/rust-kotlin/ashell"
app "ashell.app"
postflight do
puts "Removing quarantine flag from ashell.app..."
system_command "/usr/bin/xattr",
args: ["-rd", "com.apple.quarantine", "#{appdir}/ashell.app"],
sudo: true
end
caveats <<~EOS
ashell uses ad-hoc signing. The installation includes a postflight script
that removes the 'com.apple.quarantine' attribute from the application
to allow it to run. This will require your administrator password.
ashell 采用本地签名。安装程序包含一个后置脚本,用于移除应用程序的
'com.apple.quarantine' 属性以允许其运行。这需要您的管理员密码。
EOS
end
EOF
# Remove the 10 leading spaces added for YAML formatting
sed -i 's/^ //' "$CASK_FILE"
- name: Commit and Push
run: |
VERSION=${GITHUB_REF#refs/tags/v}
cd tap
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
if [[ -n $(git status -s) ]]; then
git add Casks/ashell.rb
git commit -m "chore: bump ashell to v${VERSION}"
git push
else
echo "No changes to commit"
fi
Generated
+1 -1
View File
@@ -303,7 +303,7 @@ dependencies = [
[[package]]
name = "ashell"
version = "0.4.4"
version = "0.4.6"
dependencies = [
"alacritty_terminal",
"anyhow",
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "ashell"
version = "0.4.4"
version = "0.4.6"
edition = "2024"
authors = ["ashell contributors"]
description = "A GPUI Component based SSH and local terminal client"
+22 -2
View File
@@ -24,8 +24,28 @@ You can download the latest pre-compiled releases for macOS, Windows, and Linux
## Mac Installation Guide
After downloading, please unzip the file and move `ashell.app` to your **Applications** folder.
Since the app uses ad-hoc signing, macOS may warn that the app is "damaged" upon first launch. If this happens, open Terminal and run the following command:
### Method 1: Homebrew (Recommended)
If you use [Homebrew](https://brew.sh/), you can install it quickly with:
```bash
brew install rust-kotlin/taps/ashell --cask
```
To update the app:
```bash
brew update
brew upgrade ashell --cask
```
> **Note**: Since the app uses ad-hoc signing, the Homebrew installation or update includes a postflight script to automatically handle the quarantine flag. This will require you to enter your administrator password for authorization.
### Method 2: Manual Download
1. Download and unzip from the [Releases page](https://github.com/rust-kotlin/ashell/releases/latest).
2. Move `ashell.app` to your **Applications** folder.
3. Since the app uses ad-hoc signing, macOS may warn that the app is "damaged" upon first launch. If this happens, open Terminal and run:
```bash
sudo xattr -cr /Applications/ashell.app
+22 -2
View File
@@ -24,8 +24,28 @@ v0.4 在 v0.3 打下的基础上,重点带来了更完整的工作区操作能
## Mac 安装指南
下载并解压后,请先将 `ashell.app` 拖入或移动到 **应用程序 (Applications)** 目录。
由于应用采用本地签名,初次启动时如果系统提示“App 已损坏,无法打开”,请打开终端(Terminal)并执行以下命令:
### 方法 1: Homebrew 安装 (推荐)
如果您使用 [Homebrew](https://brew.sh/),可以通过以下命令快速安装:
```bash
brew install rust-kotlin/taps/ashell --cask
```
更新应用:
```bash
brew update
brew upgrade ashell --cask
```
> **注意**: 由于应用采用本地签名,Homebrew 在安装或更新过程中会执行一个后置脚本来自动处理隔离属性(quarantine flag),这需要您输入管理员密码以授权。
### 方法 2: 手动下载
1. 从 [Releases 页面](https://github.com/rust-kotlin/ashell/releases/latest) 下载并解压。
2. 将 `ashell.app` 拖入或移动到 **应用程序 (Applications)** 目录。
3. 由于应用采用本地签名,初次启动时如果系统提示“App 已损坏,无法打开”,请打开终端(Terminal)并执行以下命令:
```bash
sudo xattr -cr /Applications/ashell.app
+15 -3
View File
@@ -160,7 +160,11 @@ impl Ashell {
.child(
Button::new("connect-ssh-cancel")
.label(t!("cancel").to_string())
.on_click(|_, window, cx| window.close_dialog(cx)),
.on_click(window.listener_for(&view, |this, _, window, cx| {
this.active_dialog = None;
window.close_dialog(cx);
cx.notify();
})),
)
.child(
Button::new("connect-ssh-confirm")
@@ -259,8 +263,10 @@ impl Ashell {
.on_mouse_down(
MouseButton::Left,
window.listener_for(&view, |this, _, window, cx| {
this.active_dialog = None;
this.open_local(cx);
window.close_dialog(cx);
cx.notify();
}),
)
.child(
@@ -301,8 +307,10 @@ impl Ashell {
.on_mouse_down(
MouseButton::Left,
window.listener_for(&view, |this, _, window, cx| {
this.active_dialog = None;
window.close_dialog(cx);
this.open_new_ssh_dialog(window, cx);
cx.notify();
}),
)
.child(
@@ -370,11 +378,13 @@ impl Ashell {
window.listener_for(
&view,
move |this, _, window, cx| {
this.active_dialog = None;
this.connect_saved_session(
connect_id.clone(),
cx,
);
window.close_dialog(cx);
cx.notify();
},
),
)
@@ -513,9 +523,11 @@ impl Ashell {
.small()
.ghost()
.icon(IconName::Close)
.on_click(|_, window, cx| {
.on_click(window.listener_for(&view, |this, _, window, cx| {
this.active_dialog = None;
window.close_dialog(cx);
}),
cx.notify();
})),
),
);
+4 -1
View File
@@ -176,7 +176,10 @@ pub(crate) fn sync_macos_launch_environment() {
pub(crate) fn sync_macos_launch_environment() {}
pub(crate) fn open_main_window(cx: &mut App) {
let mut window_options = WindowOptions::default();
let mut window_options = WindowOptions {
titlebar: Some(gpui_component::TitleBar::title_bar_options()),
..Default::default()
};
#[cfg(not(target_os = "macos"))]
if let Ok(img) = image::load_from_memory(include_bytes!("../../assets/icons/ashell.png")) {
+15 -4
View File
@@ -1541,6 +1541,7 @@ impl Ashell {
Button::new("sidebar-collapse-toggle")
.ghost()
.icon(IconName::PanelLeftClose)
.tooltip(t!("settings_toggle_sidebar").to_string())
.on_click(cx.listener(|this, _, _, cx| {
this.sidebar_collapsed = true;
this.config.set_sidebar_collapsed(true);
@@ -1552,6 +1553,7 @@ impl Ashell {
Button::new("sidebar-settings")
.ghost()
.icon(IconName::Settings)
.tooltip(t!("settings_open_settings").to_string())
.on_click(cx.listener(|this, _, window, cx| {
this.show_settings_dialog(window, cx)
})),
@@ -1772,6 +1774,7 @@ impl Ashell {
Button::new("sidebar-expand-toggle")
.ghost()
.icon(IconName::PanelLeftOpen)
.tooltip(t!("settings_toggle_sidebar").to_string())
.on_click(cx.listener(|this, _, _, cx| {
this.sidebar_collapsed = false;
this.config.set_sidebar_collapsed(false);
@@ -2029,6 +2032,7 @@ impl Ashell {
.small()
.rounded(px(999.))
.icon(IconName::Plus)
.tooltip(t!("settings_open_session").to_string())
.on_click(cx.listener(|this, _, window, cx| {
this.show_selector_dialog(window, cx)
})),
@@ -2039,6 +2043,7 @@ impl Ashell {
.small()
.rounded(px(999.))
.icon(IconName::PanelBottom)
.tooltip(t!("settings_split_pane_down").to_string())
.on_click(cx.listener(|this, _, window, cx| {
window.prevent_default();
cx.stop_propagation();
@@ -2051,6 +2056,7 @@ impl Ashell {
.small()
.rounded(px(999.))
.icon(IconName::PanelRight)
.tooltip(t!("settings_split_pane_right").to_string())
.on_click(cx.listener(|this, _, window, cx| {
window.prevent_default();
cx.stop_propagation();
@@ -2425,7 +2431,6 @@ impl Render for Ashell {
.size_full()
.relative()
.overflow_hidden()
.child(self.render_tab_bar(cx))
.child(body_panel),
),
)
@@ -2446,7 +2451,6 @@ impl Render for Ashell {
.size_full()
.relative()
.overflow_hidden()
.child(self.render_tab_bar(cx))
.child(body_panel),
);
@@ -2457,7 +2461,7 @@ impl Render for Ashell {
.into_any_element()
};
div()
v_flex()
.id("ashell-root")
.size_full()
.bg(cx.theme().background)
@@ -2489,7 +2493,14 @@ impl Render for Ashell {
this.close_tab(active_id, cx);
}
}))
.child(workspace)
.child(
gpui_component::TitleBar::new().child(
div().flex().items_center().w_full().child(self.render_tab_bar(cx)),
),
)
.child(
div().flex_1().min_h_0().child(workspace),
)
.children(Root::render_dialog_layer(window, cx))
.children(Root::render_sheet_layer(window, cx))
.when_some(self.sftp_context_menu.clone(), |this, menu| {
+4
View File
@@ -113,7 +113,9 @@ impl Ashell {
self.open_ssh_session(session, cx);
self.editing_session_id = None;
self.active_dialog = None;
window.close_dialog(cx);
cx.notify();
}
pub(crate) fn set_input_value(
@@ -368,6 +370,7 @@ impl Ashell {
return;
};
self.active_dialog = None;
match entry {
SelectorEntry::Local => {
self.open_local(cx);
@@ -382,6 +385,7 @@ impl Ashell {
window.close_dialog(cx);
}
}
cx.notify();
}
pub(crate) fn on_selector_key_down(