Compare commits

..
7 Commits
6 changed files with 268 additions and 85 deletions
+156
View File
@@ -0,0 +1,156 @@
name: Release
# Build native binaries for Windows / Linux / macOS.
# - Push a tag like `v0.2.3` -> builds all platforms and attaches the archives
# to a GitHub Release.
# - Run manually (workflow_dispatch) -> builds all platforms and uploads them as
# downloadable workflow artifacts (no release created).
on:
push:
tags: ["v*"]
workflow_dispatch:
permissions:
contents: write # needed to create / update the GitHub Release
jobs:
build:
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: windows-latest
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
target: x86_64-unknown-linux-gnu
name: linux-x86_64
bin: ashell
- 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)
target: x86_64-apple-darwin
name: macos-x86_64
bin: ashell
steps:
- uses: actions/checkout@v4
# GPUI needs these system libs on Linux to compile.
- name: Install Linux GUI dependencies
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
build-essential pkg-config cmake \
libfontconfig1-dev libfreetype6-dev \
libxcb1-dev libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev \
libxkbcommon-dev libxkbcommon-x11-dev libwayland-dev \
libgl1-mesa-dev libegl1-mesa-dev libgtk-3-dev \
libudev-dev
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Cache cargo build
uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.target }}
- name: Build (release)
run: cargo build --release --target ${{ matrix.target }}
- name: Package
shell: bash
run: |
set -eu
VERSION="${GITHUB_REF_NAME:-dev}"
STAGE="ashell-${VERSION}-${{ matrix.name }}"
if [ "${{ runner.os }}" = "macOS" ]; then
# ── Build a proper .app bundle ────────────────────────────────────
# 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"
cp "target/${{ matrix.target }}/release/ashell" "$CONTENTS/MacOS/"
VERSION_NUM="${VERSION#v}"
cat > "$CONTENTS/Info.plist" <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>ashell</string>
<key>CFBundleIdentifier</key>
<string>dev.ashell.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>ashell</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>${VERSION_NUM}</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string>12.0</string>
<key>NSHighResolutionCapable</key>
<true/>
</dict>
</plist>
EOF
printf 'APPL????' > "$CONTENTS/PkgInfo"
# Ad-hoc code-sign the assembled bundle.
codesign --force --deep --sign - "$APP"
codesign --verify --verbose "$APP"
# Package with ditto (Apple's tool) to preserve signature/metadata
ditto -c -k --keepParent "$APP" "${STAGE}.zip"
echo "ASSET=${STAGE}.zip" >> "$GITHUB_ENV"
elif [ "${{ runner.os }}" = "Windows" ]; then
mkdir "$STAGE"
cp "target/${{ matrix.target }}/release/${{ matrix.bin }}" "$STAGE/"
7z a "${STAGE}.zip" "$STAGE" >/dev/null
echo "ASSET=${STAGE}.zip" >> "$GITHUB_ENV"
else
# Linux
mkdir "$STAGE"
cp "target/${{ matrix.target }}/release/${{ matrix.bin }}" "$STAGE/"
tar -czf "${STAGE}.tar.gz" "$STAGE"
echo "ASSET=${STAGE}.tar.gz" >> "$GITHUB_ENV"
fi
- name: Upload workflow artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.name }}
path: ${{ env.ASSET }}
- name: Attach to GitHub Release
if: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v2
with:
files: ${{ env.ASSET }}
fail_on_unmatched_files: true
+47
View File
@@ -0,0 +1,47 @@
[中文](README.md) | [English](README.en.md)
# ashell
![Preview](preview.png)
`ashell` is a modern, GPUI Component-based desktop terminal client written in Rust.
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.
## Download
You can download the latest pre-compiled releases for macOS and Windows from the [GitHub Releases page](https://github.com/rust-kotlin/ashell/releases/latest).
## Features
The current version provides a fully-featured GPUI-native workspace:
- **Local & Remote Sessions:** Open local terminal tabs or connect to remote servers via SSH.
- **Advanced SSH Authentication:** Supports both password-based and key-based (file path or inline) SSH connections.
- **Session Management:** Easily save, reopen, edit, and remove your SSH sessions.
- **SFTP Integration:** Built-in SFTP file manager to browse, upload, download, and manage remote files.
- **Robust Terminal Emulator:** Parses terminal output with `alacritty_terminal`, supporting rich ANSI color spans, fast rendering, and complete keyboard input forwarding.
- **System Telemetry:** Real-time visualization of CPU, memory, swap, network, and disk metrics in the left cockpit sidebar.
- **Theming System:** Switch between multiple GPUI Component themes directly from the top toolbar.
- **Embedded Fonts:** Uses embedded Maple Mono NF CN fonts out-of-the-box for excellent CJK character and Nerd Font icon support.
## Run
To run the application locally:
```bash
cargo run --release
```
## Package macOS App
```bash
./scripts/package-macos-app.sh
open target/release/ashell.app
```
The packaging script creates a standard `.app` bundle. It does not attach an entitlements file, and after signing, it verifies that `com.apple.security.app-sandbox` is not present (meaning it runs non-sandboxed).
## License
This project is licensed under the [GPL-3.0-or-later License](LICENSE).
+25 -19
View File
@@ -1,41 +1,47 @@
[English](README.md) | [中文](README.zh-CN.md)
[中文](README.md) | [English](README.en.md)
# ashell
`ashell` is a modern, GPUI Component-based desktop terminal client written in Rust.
![Preview](preview.png)
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.
`ashell` 是一款现代化的、基于 GPUI Component 构建的 Rust 桌面终端客户端。
## Features
该项目旨在通过结合本地和远程环境,并内置丰富的核心功能,提供一个高性能且美观的 Shell 工作区。
The current version provides a fully-featured GPUI-native workspace:
## 下载
- **Local & Remote Sessions:** Open local terminal tabs or connect to remote servers via SSH.
- **Advanced SSH Authentication:** Supports both password-based and key-based (file path or inline) SSH connections.
- **Session Management:** Easily save, reopen, edit, and remove your SSH sessions.
- **SFTP Integration:** Built-in SFTP file manager to browse, upload, download, and manage remote files.
- **Robust Terminal Emulator:** Parses terminal output with `alacritty_terminal`, supporting rich ANSI color spans, fast rendering, and complete keyboard input forwarding.
- **System Telemetry:** Real-time visualization of CPU, memory, swap, network, and disk metrics in the left cockpit sidebar.
- **Theming System:** Switch between multiple GPUI Component themes directly from the top toolbar.
- **Embedded Fonts:** Uses embedded Maple Mono NF CN fonts out-of-the-box for excellent CJK character and Nerd Font icon support.
您可以从 [GitHub Releases 页面](https://github.com/rust-kotlin/ashell/releases/latest) 下载 macOS 和 Windows 版本的最新预编译程序。
## Run
## 功能特性
To run the application locally:
当前版本提供了一个功能完备的 GPUI 原生工作区:
- **本地与远程会话**:支持打开本地终端标签页或通过 SSH 连接到远程服务器。
- **高级 SSH 认证**:支持基于密码和基于密钥(文件路径或内联内容)的 SSH 连接方式。
- **会话管理**:可以轻松地保存、重新打开、编辑和删除您的 SSH 会话。
- **SFTP 集成**:内置 SFTP 文件管理器,可以浏览、上传、下载以及管理远程文件。
- **强大的终端模拟器**:使用 `alacritty_terminal` 解析终端输出,支持丰富的 ANSI 颜色代码、极速渲染和完整的键盘输入转发。
- **系统遥测**:在左侧边栏实时可视化显示 CPU、内存、Swap、网络和磁盘的使用指标。
- **主题系统**:支持直接从顶部工具栏切换多种 GPUI Component 颜色主题。
- **内置字体**:开箱即用,内置 Maple Mono NF CN 字体,提供卓越的中日韩(CJK)字符与 Nerd Font 图标支持。
## 运行
在本地运行该应用:
```bash
cargo run --release
```
## Package macOS App
## 打包 macOS 应用
```bash
./scripts/package-macos-app.sh
open target/release/ashell.app
```
The packaging script creates a standard `.app` bundle. It does not attach an entitlements file, and after signing, it verifies that `com.apple.security.app-sandbox` is not present (meaning it runs non-sandboxed).
该打包脚本会创建一个标准的 `.app` 应用程序包。它没有附加 entitlements 文件,并且在签名后会验证是否不存在 `com.apple.security.app-sandbox`(这意味着它在非沙盒模式下运行)。
## License
## 协议
This project is licensed under the [GPL-3.0-or-later License](LICENSE).
本项目采用 [GPL-3.0-or-later 协议](LICENSE) 开源。
-41
View File
@@ -1,41 +0,0 @@
[English](README.md) | [中文](README.zh-CN.md)
# ashell
`ashell` 是一款现代化的、基于 GPUI Component 构建的 Rust 桌面终端客户端。
该项目旨在通过结合本地和远程环境,并内置丰富的核心功能,提供一个高性能且美观的 Shell 工作区。
## 功能特性
当前版本提供了一个功能完备的 GPUI 原生工作区:
- **本地与远程会话**:支持打开本地终端标签页或通过 SSH 连接到远程服务器。
- **高级 SSH 认证**:支持基于密码和基于密钥(文件路径或内联内容)的 SSH 连接方式。
- **会话管理**:可以轻松地保存、重新打开、编辑和删除您的 SSH 会话。
- **SFTP 集成**:内置 SFTP 文件管理器,可以浏览、上传、下载以及管理远程文件。
- **强大的终端模拟器**:使用 `alacritty_terminal` 解析终端输出,支持丰富的 ANSI 颜色代码、极速渲染和完整的键盘输入转发。
- **系统遥测**:在左侧边栏实时可视化显示 CPU、内存、Swap、网络和磁盘的使用指标。
- **主题系统**:支持直接从顶部工具栏切换多种 GPUI Component 颜色主题。
- **内置字体**:开箱即用,内置 Maple Mono NF CN 字体,提供卓越的中日韩(CJK)字符与 Nerd Font 图标支持。
## 运行
在本地运行该应用:
```bash
cargo run --release
```
## 打包 macOS 应用
```bash
./scripts/package-macos-app.sh
open target/release/ashell.app
```
该打包脚本会创建一个标准的 `.app` 应用程序包。它没有附加 entitlements 文件,并且在签名后会验证是否不存在 `com.apple.security.app-sandbox`(这意味着它在非沙盒模式下运行)。
## 协议
本项目采用 [GPL-3.0-or-later 协议](LICENSE) 开源。
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 292 KiB

+40 -25
View File
@@ -1,3 +1,5 @@
#![windows_subsystem = "windows"]
use std::{
borrow::Cow,
cell::{Cell, RefCell},
@@ -13,14 +15,16 @@ use alacritty_terminal::index::Side;
use alacritty_terminal::selection::SelectionType;
use anyhow::{Context as _, Result};
use gpui::{
div, point, prelude::FluentBuilder as _, px, size, uniform_list, Anchor, App, AppContext as _,
Bounds, ClipboardItem, Context, Entity, FocusHandle, Focusable as _, FontWeight, Hsla,
InteractiveElement as _, IntoElement, KeyBinding, KeyDownEvent, MouseButton, MouseDownEvent,
MouseMoveEvent, MouseUpEvent, ParentElement as _, PathPromptOptions, Pixels, Point, QuitMode,
Render, ScrollDelta, ScrollWheelEvent, SharedString, Size, Styled as _,
UniformListScrollHandle, Window, WindowOptions,
Anchor, App, AppContext as _, Bounds, ClipboardItem, Context, Entity, FocusHandle,
Focusable as _, FontWeight, Hsla, InteractiveElement as _, IntoElement, KeyBinding,
KeyDownEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement as _,
PathPromptOptions, Pixels, Point, QuitMode, Render, ScrollDelta, ScrollWheelEvent,
SharedString, Size, Styled as _, UniformListScrollHandle, Window, WindowOptions, div, point,
prelude::FluentBuilder as _, px, size, uniform_list,
};
use gpui_component::{
ActiveTheme as _, ElementExt, IconName, Root, Sizable as _, Theme, ThemeMode, ThemeRegistry,
WindowExt as _,
button::{Button, ButtonVariants as _},
checkbox::Checkbox,
dialog::Dialog,
@@ -28,11 +32,10 @@ use gpui_component::{
input::{Input, InputEvent, InputState},
menu::{ContextMenuExt as _, DropdownMenu as _, PopupMenuItem},
progress::Progress,
resizable::{h_resizable, resizable_panel, v_resizable, ResizableState},
resizable::{ResizableState, h_resizable, resizable_panel, v_resizable},
scroll::{ScrollableElement as _, Scrollbar, ScrollbarHandle, ScrollbarShow},
tab::{Tab, TabBar},
v_flex, ActiveTheme as _, ElementExt, IconName, Root, Sizable as _, Theme, ThemeMode,
ThemeRegistry, WindowExt as _,
v_flex,
};
use gpui_component_assets::Assets;
use tokio::runtime::Runtime;
@@ -47,9 +50,9 @@ mod terminal;
mod terminal_element;
use config::{AuthMethod, ConfigStore, Session};
use sftp::{format_mtime, RemoteEntry, SftpHandle};
use system::{format_bytes, DiskSample, SystemSampler, SystemSnapshot};
use terminal::{encode_key, BackendCommand, BackendEvent, TabKind, TerminalTab};
use sftp::{RemoteEntry, SftpHandle, format_mtime};
use system::{DiskSample, SystemSampler, SystemSnapshot, format_bytes};
use terminal::{BackendCommand, BackendEvent, TabKind, TerminalTab, encode_key};
use terminal_element::TerminalElement;
const DEFAULT_COLS: u16 = 100;
@@ -166,6 +169,7 @@ struct Ashell {
system_sampler: SystemSampler,
system: SystemSnapshot,
last_system_sample: Instant,
last_theme_sync: Instant,
remote_sample_in_flight: bool,
runtime: Runtime,
events_rx: mpsc::Receiver<BackendEvent>,
@@ -293,6 +297,7 @@ impl Ashell {
system_sampler,
system,
last_system_sample: Instant::now(),
last_theme_sync: Instant::now(),
remote_sample_in_flight: false,
runtime: Runtime::new().expect("create tokio runtime"),
events_rx,
@@ -331,19 +336,22 @@ impl Ashell {
}
fn start_event_pump(&self, cx: &mut Context<Self>) {
cx.spawn(async move |this, cx| loop {
cx.background_executor()
.timer(Duration::from_millis(16))
.await;
if this
.update(cx, |this, cx| {
this.drain_backend_events();
this.sample_system_if_due();
cx.notify();
})
.is_err()
{
break;
cx.spawn(async move |this, cx| {
loop {
cx.background_executor()
.timer(Duration::from_millis(16))
.await;
if this
.update(cx, |this, cx| {
this.drain_backend_events();
this.sample_system_if_due();
this.sync_theme_if_due(cx);
cx.notify();
})
.is_err()
{
break;
}
}
})
.detach();
@@ -462,6 +470,13 @@ impl Ashell {
}
}
fn sync_theme_if_due(&mut self, cx: &mut Context<Self>) {
if self.follow_system_theme && self.last_theme_sync.elapsed() >= Duration::from_secs(1) {
Theme::sync_system_appearance(None, cx);
self.last_theme_sync = Instant::now();
}
}
fn request_active_system_snapshot(&mut self) {
if let Some((tab_id, session)) = self.active_ssh_session() {
if self.remote_sample_in_flight {