Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
958999e
feat(lang): 新增 Dart 语言支持
qianmoQ Jun 17, 2026
6f98a64
docs: 在 README 支持语言中补充 Dart
qianmoQ Jun 17, 2026
d9c662d
feat(lang): 新增 Perl 语言支持
qianmoQ Jun 17, 2026
f222fe9
feat(lang): 新增 Julia 语言支持
qianmoQ Jun 17, 2026
dde516c
feat(lang): 新增 Vue 语言支持 (#85)
qianmoQ Jun 17, 2026
3ed40df
feat(chart): 中国地图支持点击下钻到省/市 (#96)
qianmoQ Jun 17, 2026
7449c47
feat(chart): 地图下钻 geojson 落盘缓存,支持离线复用 (#96)
qianmoQ Jun 17, 2026
3426b5a
feat(db): 数据库连接支持 SSL/TLS 与 SSH 隧道 (#93)
qianmoQ Jun 17, 2026
12c07e6
feat(lang): 新增 PowerShell 语言支持
qianmoQ Jun 17, 2026
d6bd18f
feat(lang): 新增 OCaml 语言支持
qianmoQ Jun 17, 2026
72a49e6
feat(lang): 新增 Tcl 语言支持
qianmoQ Jun 17, 2026
2466791
feat(lang): 新增 F# 语言支持
qianmoQ Jun 17, 2026
5b481ba
feat(lang): 新增 Crystal 语言支持
qianmoQ Jun 17, 2026
5c2cf7a
feat(lang): 新增 Erlang 语言支持
qianmoQ Jun 17, 2026
e2f056b
feat(lang): 新增 D 语言支持
qianmoQ Jun 17, 2026
e96db5f
feat(lang): 新增 Common Lisp / Scheme / Pascal 语言支持
qianmoQ Jun 17, 2026
70eb141
feat(git): Git 面板支持拉取与抓取 (#git)
qianmoQ Jun 17, 2026
4b60ec7
feat(git): 状态列文件可查看相对 HEAD 的改动 diff
qianmoQ Jun 17, 2026
a4f0d69
feat(git): 支持丢弃文件改动 discard
qianmoQ Jun 17, 2026
62fb39c
feat(git): 新增提交历史查看器 (log/show)
qianmoQ Jun 17, 2026
7e656fb
feat(git): 新增 Stash 储藏管理 (list/push/pop/drop)
qianmoQ Jun 17, 2026
6b4ccae
feat(git): 分支管理支持新建/删除/合并
qianmoQ Jun 17, 2026
1c9c138
feat(git): 提交支持修正上次提交 amend
qianmoQ Jun 17, 2026
9df062c
feat(git): 新增文件 Git Blame 逐行追溯
qianmoQ Jun 17, 2026
63bc683
feat(git): 提交历史支持还原与重置 (revert/reset)
qianmoQ Jun 17, 2026
cd21dff
feat(git): 新增标签管理 (创建/列出/删除)
qianmoQ Jun 17, 2026
756755c
feat(git): 新增远程管理与设置上游
qianmoQ Jun 17, 2026
c0880ff
feat(git): 识别冲突文件并支持标记已解决
qianmoQ Jun 17, 2026
d070da7
fix(i18n): 转义远程 URL 占位符中的 @,修复 vue-i18n 链接消息编译报错
qianmoQ Jun 17, 2026
f86a038
feat(git): 新增单文件提交历史
qianmoQ Jun 17, 2026
2c1a17c
feat(git): 文件树右键 Git 菜单(暂存/diff/丢弃/blame/历史/复制路径)
qianmoQ Jun 18, 2026
4bb066b
feat(git): 支持 git init 与加入 .gitignore
qianmoQ Jun 18, 2026
5ec7092
feat(git): 支持克隆远程仓库
qianmoQ Jun 18, 2026
1023793
fix(chart): 修复地图点击处理器类型导致 vue-tsc 构建失败
qianmoQ Jun 18, 2026
91f0356
feat(git): 支持重命名分支
qianmoQ Jun 18, 2026
d89b241
feat(git): 提交支持 -a 自动暂存与 -s sign-off
qianmoQ Jun 18, 2026
d68d0d9
feat(git): 支持清理未跟踪文件 (clean)
qianmoQ Jun 18, 2026
a34e298
feat(git): 储藏支持应用(保留)与查看补丁
qianmoQ Jun 18, 2026
3a9d128
feat(git): 新增 reflog 查看与误操作恢复
qianmoQ Jun 18, 2026
3f8fbfc
feat(git): 支持 cherry-pick 拣选其它分支的提交
qianmoQ Jun 18, 2026
f667251
feat(git): 进行中操作支持继续/中止/跳过
qianmoQ Jun 18, 2026
3bcb154
feat(git): 新增分支/提交对比
qianmoQ Jun 18, 2026
0ba4aa7
feat(git): 新增推送/拉取选项与删除远程分支
qianmoQ Jun 18, 2026
74a592b
feat(git): 文件历史支持恢复到某历史版本
qianmoQ Jun 18, 2026
1c1faf4
feat(git): 支持检出远程分支并建立跟踪
qianmoQ Jun 18, 2026
1293611
feat(git): 支持附注标签与检出标签
qianmoQ Jun 18, 2026
e07450a
feat(git): 新增仓库身份配置
qianmoQ Jun 18, 2026
848a905
feat(git): 支持分块暂存(hunk staging)
qianmoQ Jun 18, 2026
4eb09dc
feat(git): 新增分支图可视化
qianmoQ Jun 18, 2026
63e8ac4
feat(git): 新增子模块管理
qianmoQ Jun 18, 2026
51d5473
feat(git): 新增工作树(worktree)管理
qianmoQ Jun 18, 2026
165a143
feat(git): 新增二分定位(bisect)
qianmoQ Jun 18, 2026
12ca702
feat(git): 新增交互式变基(rebase -i)
qianmoQ Jun 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,25 +85,39 @@
<img src="public/icons/javascript-browser.svg" width="48" title="JavaScript (Browser)" />
<img src="public/icons/javascript-jquery.svg" width="48" title="JavaScript (jQuery)" />
<img src="public/icons/react.svg" width="48" title="React (JSX)" />
<img src="public/icons/vue.svg" width="48" title="Vue" />
<img src="public/icons/go.svg" width="48" title="Go" />
<img src="public/icons/rust.svg" width="48" title="Rust" />
<img src="public/icons/d.svg" width="48" title="D" />
<img src="public/icons/java.svg" width="48" title="Java" />
<img src="public/icons/kotlin.svg" width="48" title="Kotlin" />
<img src="public/icons/scala.svg" width="48" title="Scala" />
<img src="public/icons/fsharp.svg" width="48" title="F#" />
<img src="public/icons/groovy.svg" width="48" title="Groovy" />
<img src="public/icons/clojure.svg" width="48" title="Clojure" />
<img src="public/icons/commonlisp.svg" width="48" title="Common Lisp" />
<img src="public/icons/scheme.svg" width="48" title="Scheme" />
<img src="public/icons/c.svg" width="48" title="C" />
<img src="public/icons/cpp.svg" width="48" title="C++" />
<img src="public/icons/objective-c.svg" width="48" title="Objective-C" />
<img src="public/icons/objective-cpp.svg" width="48" title="Objective-C++" />
<img src="public/icons/pascal.svg" width="48" title="Pascal" />
<img src="public/icons/swift.svg" width="48" title="Swift" />
<img src="public/icons/dart.svg" width="48" title="Dart" />
<img src="public/icons/ruby.svg" width="48" title="Ruby" />
<img src="public/icons/crystal.svg" width="48" title="Crystal" />
<img src="public/icons/perl.svg" width="48" title="Perl" />
<img src="public/icons/php.svg" width="48" title="PHP" />
<img src="public/icons/r.svg" width="48" title="R" />
<img src="public/icons/julia.svg" width="48" title="Julia" />
<img src="public/icons/lua.svg" width="48" title="Lua" />
<img src="public/icons/haskell.svg" width="48" title="Haskell" />
<img src="public/icons/ocaml.svg" width="48" title="OCaml" />
<img src="public/icons/erlang.svg" width="48" title="Erlang" />
<img src="public/icons/tcl.svg" width="48" title="Tcl" />
<img src="public/icons/cangjie.svg" width="48" title="Cangjie" />
<img src="public/icons/shell.svg" width="48" title="Shell" />
<img src="public/icons/powershell.svg" width="48" title="PowerShell" />
<img src="public/icons/applescript.svg" width="48" title="AppleScript" />
<img src="public/icons/html.svg" width="48" title="HTML" />
<img src="public/icons/css.svg" width="48" title="CSS" />
Expand All @@ -122,7 +136,7 @@

<div align="center">

`Python` · `Node.js` · `TypeScript` · `JavaScript` · `React` · `Go` · `Rust` · `Java` · `Kotlin` · `Scala` · `Groovy` · `Clojure` · `C` · `C++` · `Objective-C/C++` · `Swift` · `Ruby` · `PHP` · `R` · `Lua` · `Haskell` · `Cangjie` · `Shell` · `AppleScript` · `SQL` · `HTML` · `CSS` · `Less` · `SVG` · `JSON` · `XML` · `YAML` · `Markdown` · `CSV` · `TSV` · `Excel` · `Text`
`Python` · `Node.js` · `TypeScript` · `JavaScript` · `React` · `Vue` · `Go` · `Rust` · `D` · `Java` · `Kotlin` · `Scala` · `F#` · `Groovy` · `Clojure` · `Common Lisp` · `Scheme` · `C` · `C++` · `Objective-C/C++` · `Pascal` · `Swift` · `Dart` · `Ruby` · `Crystal` · `Perl` · `PHP` · `R` · `Julia` · `Lua` · `Haskell` · `OCaml` · `Erlang` · `Tcl` · `Cangjie` · `Shell` · `PowerShell` · `AppleScript` · `SQL` · `HTML` · `CSS` · `Less` · `SVG` · `JSON` · `XML` · `YAML` · `Markdown` · `CSV` · `TSV` · `Excel` · `Text`

</div>

Expand Down
4 changes: 4 additions & 0 deletions public/icons/commonlisp.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions public/icons/crystal.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions public/icons/d.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions public/icons/dart.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions public/icons/erlang.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions public/icons/fsharp.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions public/icons/julia.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions public/icons/ocaml.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions public/icons/pascal.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions public/icons/perl.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions public/icons/powershell.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions public/icons/scheme.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions public/icons/tcl.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions public/icons/vue.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
47 changes: 30 additions & 17 deletions src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ tar = "0.4"
xz2 = "0.1"
zstd = "0.13"
notify = "6"
native-tls = "0.2.18"
postgres-native-tls = "0.5"

# DuckDB 走 bundled 编译,其 vendored C++(fmt) 在部分新版 MSVC 上编译失败,
# 故仅在非 Windows 平台启用;Windows 不提供 DuckDB 数据源。
Expand Down
28 changes: 21 additions & 7 deletions src-tauri/src/db/clickhouse.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::{DataSource, DbExecutor, SqlResultSet, SqlRunResult, split_sql};
use super::{DataSource, DbExecutor, SqlResultSet, SqlRunResult, resolve_endpoint, split_sql};
use serde_json::Value as JsonValue;

pub(crate) struct ClickhouseExecutor;
Expand All @@ -11,15 +11,29 @@ impl DbExecutor for ClickhouseExecutor {
fn run(&self, sql: &str, source: &DataSource) -> SqlRunResult {
let mut result = SqlRunResult::new();

let host = source.host.as_deref().unwrap_or("127.0.0.1");
let port = source.port.unwrap_or(8123);
// 解析端点:启用 SSH 时隧道转发到本地端口(隧道随 endpoint 在本函数结束时关闭)
let endpoint = match resolve_endpoint(source, 8123) {
Ok(e) => e,
Err(e) => {
result.error = Some(e);
return result;
}
};

let database = source.database.as_deref().unwrap_or("default");
let user = source.user.as_deref().unwrap_or("default");
// 走 HTTP 接口,SELECT 以 JSONCompact 返回,DDL/写入返回空体
// SSL 直连用 https;走 SSH 隧道时已由 ssh 加密,本地仍用 http
let scheme = if source.ssl.unwrap_or(false) && !source.ssh_enabled.unwrap_or(false) {
"https"
} else {
"http"
};
// 走 HTTP(S) 接口,SELECT 以 JSONCompact 返回,DDL/写入返回空体
let url = format!(
"http://{}:{}/?default_format=JSONCompact&database={}",
host,
port,
"{}://{}:{}/?default_format=JSONCompact&database={}",
scheme,
endpoint.host,
endpoint.port,
urlencode(database)
);

Expand Down
65 changes: 64 additions & 1 deletion src-tauri/src/db/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ mod duckdb;
mod mysql;
mod postgres;
mod sqlite;
mod tunnel;

use serde::{Deserialize, Serialize};
use serde_json::Value as JsonValue;
Expand Down Expand Up @@ -37,8 +38,9 @@ impl SqlRunResult {
}
}

/// 数据源描述:内存 / SQLite 文件 / MySQL(后续可扩展更多字段
/// 数据源描述:内存 / SQLite 文件 / 网络型数据库(含可选 SSL 与 SSH 隧道
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct DataSource {
pub kind: String,
#[serde(default)]
Expand All @@ -53,6 +55,67 @@ pub struct DataSource {
pub password: Option<String>,
#[serde(default)]
pub database: Option<String>,
// 直连 DB 时启用 TLS(pg/mysql 走加密连接,clickhouse 改 https)
#[serde(default)]
pub ssl: Option<bool>,
// SSH 隧道:经跳板机本地端口转发到目标 DB
#[serde(default)]
pub ssh_enabled: Option<bool>,
#[serde(default)]
pub ssh_host: Option<String>,
#[serde(default)]
pub ssh_port: Option<u16>,
#[serde(default)]
pub ssh_user: Option<String>,
#[serde(default)]
pub ssh_password: Option<String>,
#[serde(default)]
pub ssh_key_file: Option<String>,
}

/// 解析后的连接端点:直连时即原 host/port;启用 SSH 时为本地转发端口,
/// 并持有隧道句柄(随 Endpoint 释放而关闭 ssh 进程)。
pub(crate) struct Endpoint {
pub host: String,
pub port: u16,
_tunnel: Option<tunnel::SshTunnel>,
}

/// 按数据源解析实际连接端点:启用 SSH 隧道则开隧道并返回本地端口。
pub(crate) fn resolve_endpoint(source: &DataSource, default_port: u16) -> Result<Endpoint, String> {
let host = source
.host
.clone()
.unwrap_or_else(|| "127.0.0.1".to_string());
let port = source.port.unwrap_or(default_port);

if source.ssh_enabled.unwrap_or(false) {
let ssh_host = source.ssh_host.clone().unwrap_or_default();
let ssh_user = source.ssh_user.clone().unwrap_or_default();
if ssh_host.is_empty() || ssh_user.is_empty() {
return Err("SSH 隧道需填写跳板机主机与用户名".to_string());
}
let cfg = tunnel::SshConfig {
host: ssh_host,
port: source.ssh_port.unwrap_or(22),
user: ssh_user,
password: source.ssh_password.clone(),
key_file: source.ssh_key_file.clone(),
};
let t = tunnel::SshTunnel::open(&cfg, &host, port)?;
let local_port = t.local_port;
Ok(Endpoint {
host: "127.0.0.1".to_string(),
port: local_port,
_tunnel: Some(t),
})
} else {
Ok(Endpoint {
host,
port,
_tunnel: None,
})
}
}

/// 数据库执行器接口:新增数据库类型只需实现本 trait 并在 executors() 注册。
Expand Down
Loading
Loading