Skip to content

Commit 069d438

Browse files
authored
Merge pull request #115 from qianmoQ/dev-26.3.0
Refactor inline diff markers into useInlineDiff composable and add release notes
2 parents 70ae85f + e33ad84 commit 069d438

3 files changed

Lines changed: 167 additions & 42 deletions

File tree

docs/src/content/release/26.3.0.md

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
---
2+
title: 26.3.0
3+
---
4+
5+
CodeForge v26.3.0 是一次以**调试、AI、数据与工作区**为核心的大版本:把一套基于 DAP 的**可视化调试器**装进编辑器,覆盖 Python / Go / Rust / C / C++;扩展**选中代码的 AI 解释·重构·测试**与代码库上下文对话;带来**结果导出、ER 图、交互式事务**等数据库能力;引入**多根工作区**与大量编辑器生产力功能(.editorconfig、自动换行、缩进参考线、专注模式、置顶标签、文件树定位等)。
6+
7+
CodeForge v26.3.0 is a major release centered on **debugging, AI, data and workspaces**: a DAP-based **visual debugger** built into the editor for Python / Go / Rust / C / C++; expanded **AI explain·refactor·test** on selected code plus codebase-aware chat; richer database tooling (**result export, ER diagrams, interactive transactions**); and a new **multi-root workspace** alongside many editor productivity features (.editorconfig, word wrap, indent guides, Zen mode, pinned tabs, reveal-in-tree, and more).
8+
9+
---
10+
11+
## 📦 版本信息 | Release Information
12+
13+
- **项目地址 | Repository**https://github.com/devlive-community/codeforge
14+
- **官方网站 | Official Website**https://codeforge.devlive.org/
15+
- **版本号 | Version**:v26.3.0
16+
- **发布日期 | Release Date**:2026年6月29日 | June 29, 2026
17+
18+
---
19+
20+
## 🐞 可视化调试(DAP)| Visual Debugging
21+
22+
基于调试适配器协议(DAP)的**图形化调试**,无需切到命令行:
23+
A graphical debugger built on the Debug Adapter Protocol — no terminal needed:
24+
25+
- **断点**:行断点、**条件断点****异常断点**,执行行高亮
26+
- **调用栈 / 变量 / 监视 / 求值**面板,**调试控制台****悬停求值**
27+
- **会话控制**:继续 / 暂停 / 单步进入·跳过·跳出 / 重启 / 停止,调试工具栏
28+
- **支持语言**:Python(debugpy)、Go(delve)、Rust · C · C++(lldb-dap,先编译后调试)
29+
- **设置页一键安装调试适配器**,状态栏实时调试指示
30+
31+
Breakpoints (line / **conditional** / **exception**) with current-line highlight; call stack, variables, watch & evaluate panels, a **debug console** and **hover evaluation**; full session control and a debug toolbar; languages **Python (debugpy), Go (delve), Rust·C·C++ (lldb-dap, build-then-debug)**; one-click **adapter installation** from settings and a status-bar debug indicator.
32+
33+
---
34+
35+
## 🏃 运行 · 测试 · 任务 | Run, Test & Tasks
36+
37+
- **运行测试** - 自动识别项目类型并选用对应测试命令
38+
- **运行任务 / 构建预设** - 在集成终端中执行常用命令
39+
- **发送选区到终端** - 把选中代码片段一键送入终端运行
40+
41+
**Run tests** (auto-detecting project type), **run task / build presets** in the integrated terminal, and **send selection to terminal**.
42+
43+
---
44+
45+
## 🤖 AI 能力增强 | AI
46+
47+
- **选中代码 → AI 解释 / 重构 / 生成测试**,结果以差异预览确认后再应用
48+
- **AI 对话挂接代码库上下文**,回答更贴合当前项目
49+
- **AI 生成提交信息** - 基于**已暂存 diff** 生成,贴合本次实际提交内容
50+
51+
AI **explain / refactor / generate-tests** on a selection (applied via diff preview), **codebase-aware chat**, and **AI commit messages** generated from the **staged diff**.
52+
53+
---
54+
55+
## 🗄 数据库 · SQL | Database & SQL
56+
57+
- **查询结果导出** - 导出为 **JSON / Excel**
58+
- **ER 图** - 由 schema 自动生成实体关系图;MySQL 未选库时可**内联选择数据库**
59+
- **交互式事务** - SQLite / DuckDB / MySQL / Postgres 的 **BEGIN / COMMIT / ROLLBACK** 全程图形化
60+
- **执行历史收藏** - 常用执行记录可收藏、按收藏过滤
61+
62+
Export results to **JSON / Excel**, generate **ER diagrams** from schema (with inline DB picker for MySQL), **interactive transactions** (begin/commit/rollback) across SQLite·DuckDB·MySQL·Postgres, and **favorites** in execution history.
63+
64+
---
65+
66+
## 📁 多根工作区与导航 | Multi-root Workspace & Navigation
67+
68+
- **多根工作区** - 在主目录之外**挂载多个文件夹**,各根为可折叠分区、标题吸顶
69+
- **各根独立 Git 徽标**,根标题右键可**新建 / 移除**
70+
- **跨全部根的搜索 / 替换**,以及目录右键**在文件夹中搜索**
71+
- **在文件树中定位当前文件**(可选切换文件时自动定位)、**一键折叠所有文件夹**
72+
- **面包屑分段下拉** - 点击层级快速切换同级文件、钻入子目录
73+
74+
Mount **multiple folders** as collapsible, sticky-header roots; **per-root Git badges**; new-file / remove from a root's context menu; **search & replace across all roots** plus **find-in-folder**; **reveal active file in the tree** (with optional auto-reveal) and **collapse-all**; and a **breadcrumb dropdown** to jump between sibling files.
75+
76+
---
77+
78+
## ✍️ 编辑器体验 | Editor Experience
79+
80+
- **.editorconfig 支持** - 按文件应用缩进,保存时**去除行尾空白 / 补末尾换行**
81+
- **自动换行**(Alt+Z)、**缩进参考线****专注模式**(隐藏周边面板沉浸编辑)
82+
- **符号大纲** - 按层级缩进显示,打开即定位光标所在符号
83+
- **状态栏缩进指示** - 点击快速切换空格 / 制表符与缩进宽度
84+
- **文本命令** - 排序行、大小写转换、删除重复行、去除行尾空白、**复制为 Markdown 代码块**
85+
- **与剪贴板比较** - 把当前内容和剪贴板做差异对比
86+
87+
`.editorconfig` support (indent + trim-trailing / final-newline on save), **word wrap** (Alt+Z), **indent guides**, **Zen mode**, a hierarchical **symbol outline** that lands on the cursor's symbol, a clickable **indentation indicator**, text commands (sort / case / dedupe / trim / **copy as Markdown**), and **compare-with-clipboard**.
88+
89+
---
90+
91+
## 🗂 标签与 Git | Tabs & Git
92+
93+
- **重新打开已关闭标签**(Mod+Shift+T)、**置顶标签**
94+
- 标签右键 - 在文件树中定位 / 在文件管理器显示 / 复制路径与相对路径
95+
- **自定义 .gitignore 模板** - 设置页管理,独立存储
96+
- **远程永久链接** - 复制 / 在浏览器打开当前文件指定行的 GitHub·Gitee·GitLab 链接
97+
- **状态栏当前分支** - 点击直达 Git 面板
98+
99+
**Reopen closed tab** & **pin tab**, a richer tab context menu, custom **.gitignore templates**, **remote permalinks** (copy / open current line on GitHub·Gitee·GitLab), and a **status-bar branch** indicator.
100+
101+
---
102+
103+
## 📥 立即下载 | Download Now
104+
105+
[GitHub Releases](https://github.com/devlive-community/codeforge/releases) 下载最新版本,或访问[官方网站](https://codeforge.devlive.org/)了解更多信息。
106+
107+
Download the latest version from [GitHub Releases](https://github.com/devlive-community/codeforge/releases), or visit the [Official Website](https://codeforge.devlive.org/) for more information.

src/App.vue

Lines changed: 3 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,7 @@ import {useGitPermalink} from './composables/useGitPermalink'
545545
import {useRevealInTree} from './composables/useRevealInTree'
546546
import {useWorkspaceRoots} from './composables/useWorkspaceRoots'
547547
import {useGitStatus} from './composables/useGitStatus'
548+
import {useInlineDiff} from './composables/useInlineDiff'
548549
import {useSessionTabs} from './composables/useSessionTabs'
549550
import {useEditorContextMenu} from './composables/useEditorContextMenu'
550551
import {useRunConfig} from './composables/useRunConfig'
@@ -579,7 +580,6 @@ import {useDbConnections} from './composables/useDbConnections'
579580
import {useAiConfig} from './composables/useAiConfig'
580581
import {setGhost, clearGhostIn, ghostActive} from './editor/aiComplete'
581582
import {cursorInfo} from './editor/cursorInfo'
582-
import {computeDiffMarkers, setDiffMarkers} from './editor/diffGutter'
583583
import {setBreakpointData} from './editor/breakpointGutter'
584584
import {useDebug} from './composables/useDebug'
585585
import AiAssistant from './components/AiAssistant.vue'
@@ -1602,47 +1602,8 @@ const openGit = () => {
16021602
// 文件树 Git 徽标 + 当前分支(抽离到 useGitStatus);HEAD 变化时刷新差异基线
16031603
const {gitStatus, gitRepo, gitBranch, refreshGitStatus} = useGitStatus(rootDir, extraRoots, () => fetchBaseline())
16041604
1605-
// ===== 编辑器行内差异标记(vs HEAD)=====
1606-
// 当前文件在 HEAD 中的内容;null 表示无基线(新文件/非 git/未跟踪),不显示标记
1607-
const gitBaseline = ref<string | null>(null)
1608-
1609-
const fetchBaseline = async () => {
1610-
if (!rootDir.value || !currentFilePath.value || !currentFilePath.value.startsWith(rootDir.value)) {
1611-
gitBaseline.value = null
1612-
applyDiffMarkers()
1613-
return
1614-
}
1615-
const rel = currentFilePath.value.slice(rootDir.value.length + 1)
1616-
try {
1617-
const head = await invoke<{ exists: boolean, content: string }>('git_file_head', {
1618-
root: rootDir.value,
1619-
relPath: rel
1620-
})
1621-
gitBaseline.value = head.exists ? head.content : null
1622-
}
1623-
catch {
1624-
gitBaseline.value = null
1625-
}
1626-
applyDiffMarkers()
1627-
}
1628-
1629-
// 计算并派发标记到编辑器
1630-
const applyDiffMarkers = () => {
1631-
const view = editorView.value
1632-
if (!view) {
1633-
return
1634-
}
1635-
const markers = gitBaseline.value === null
1636-
? {changed: new Map(), deleted: new Set<number>()}
1637-
: computeDiffMarkers(gitBaseline.value, code.value)
1638-
view.dispatch({effects: setDiffMarkers.of(markers)})
1639-
}
1640-
const applyDiffMarkersDebounced = debounce(applyDiffMarkers, 250)
1641-
1642-
// 切换文件取新基线;编辑时重算;编辑器重挂时重新派发
1643-
watch(currentFilePath, () => fetchBaseline())
1644-
watch(code, () => applyDiffMarkersDebounced())
1645-
watch(editorView, () => applyDiffMarkers())
1605+
// ===== 编辑器行内差异标记(vs HEAD)抽离到 useInlineDiff =====
1606+
const {fetchBaseline} = useInlineDiff({editorView, code, rootDir, currentFilePath})
16461607
16471608
// ===== 断点(B1-P2):把当前文件的断点 + 执行行派发到编辑器 =====
16481609
const debug = useDebug()

src/composables/useInlineDiff.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// 编辑器行内差异标记(当前内容 vs HEAD 基线)。
2+
import {ref, watch, type Ref} from 'vue'
3+
import {invoke} from '@tauri-apps/api/core'
4+
import {debounce} from 'lodash-es'
5+
import {computeDiffMarkers, setDiffMarkers} from '../editor/diffGutter'
6+
7+
interface Deps {
8+
editorView: Ref<any>
9+
code: Ref<string>
10+
rootDir: Ref<string | null>
11+
currentFilePath: Ref<string | null>
12+
}
13+
14+
export function useInlineDiff({editorView, code, rootDir, currentFilePath}: Deps) {
15+
// 当前文件在 HEAD 中的内容;null 表示无基线(新文件/非 git/未跟踪),不显示标记
16+
const gitBaseline = ref<string | null>(null)
17+
18+
// 计算并派发标记到编辑器
19+
const applyDiffMarkers = () => {
20+
const view = editorView.value
21+
if (!view) {
22+
return
23+
}
24+
const markers = gitBaseline.value === null
25+
? {changed: new Map(), deleted: new Set<number>()}
26+
: computeDiffMarkers(gitBaseline.value, code.value)
27+
view.dispatch({effects: setDiffMarkers.of(markers)})
28+
}
29+
const applyDiffMarkersDebounced = debounce(applyDiffMarkers, 250)
30+
31+
const fetchBaseline = async () => {
32+
if (!rootDir.value || !currentFilePath.value || !currentFilePath.value.startsWith(rootDir.value)) {
33+
gitBaseline.value = null
34+
applyDiffMarkers()
35+
return
36+
}
37+
const rel = currentFilePath.value.slice(rootDir.value.length + 1)
38+
try {
39+
const head = await invoke<{ exists: boolean, content: string }>('git_file_head', {
40+
root: rootDir.value,
41+
relPath: rel
42+
})
43+
gitBaseline.value = head.exists ? head.content : null
44+
}
45+
catch {
46+
gitBaseline.value = null
47+
}
48+
applyDiffMarkers()
49+
}
50+
51+
// 切换文件取新基线;编辑时重算;编辑器重挂时重新派发
52+
watch(currentFilePath, () => fetchBaseline())
53+
watch(code, () => applyDiffMarkersDebounced())
54+
watch(editorView, () => applyDiffMarkers())
55+
56+
return {fetchBaseline}
57+
}

0 commit comments

Comments
 (0)