From 50ad324e54eeeaeebc81428abe82c47d1de4708f Mon Sep 17 00:00:00 2001 From: qianmoQ Date: Mon, 29 Jun 2026 18:23:06 +0800 Subject: [PATCH 1/2] =?UTF-8?q?chore(release):=20=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E5=8F=B7=E5=8D=87=E8=87=B3=2026.4.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- src-tauri/Cargo.lock | 2 +- src-tauri/Cargo.toml | 2 +- src-tauri/tauri.conf.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 238a875e..0cc6a3fa 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "codeforge", "private": true, - "version": "26.3.0", + "version": "26.4.0", "type": "module", "scripts": { "dev": "vite", diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 247ed67b..ba99ea03 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -4,7 +4,7 @@ version = 4 [[package]] name = "CodeForge" -version = "26.3.0" +version = "26.4.0" dependencies = [ "async-trait", "chrono", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index f0eac932..3c263cd0 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "CodeForge" -version = "26.3.0" +version = "26.4.0" description = "CodeForge 是一款轻量级、高性能的桌面代码执行器,专为开发者、学生和编程爱好者设计。" authors = ["devlive-community"] edition = "2024" diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index eb07e4d7..da7bb972 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "CodeForge", - "version": "26.3.0", + "version": "26.4.0", "identifier": "org.devlive.codeforge", "build": { "beforeDevCommand": "pnpm dev", From c4f9f6f177da02da7c46725838fd4692e91f3ff5 Mon Sep 17 00:00:00 2001 From: qianmoQ Date: Mon, 29 Jun 2026 18:36:24 +0800 Subject: [PATCH 2/2] =?UTF-8?q?feat(editor):=20=E6=96=B0=E5=A2=9E=E3=80=8C?= =?UTF-8?q?=E8=BD=AC=E6=8D=A2=E7=BC=A9=E8=BF=9B=EF=BC=88=E7=A9=BA=E6=A0=BC?= =?UTF-8?q?=E2=86=94=E5=88=B6=E8=A1=A8=E7=AC=A6=EF=BC=89=E3=80=8D=E5=91=BD?= =?UTF-8?q?=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 命令面板「文本」分组:把整篇行首缩进在空格与制表符间转换,按 tab 宽度换算列数, 保留正文与光标位置;与状态栏缩进开关(改设置)互补。 --- src/App.vue | 34 ++++++++++++++++++++++++++++++++++ src/i18n/locales/en.json | 3 +++ src/i18n/locales/zh-CN.json | 3 +++ 3 files changed, 40 insertions(+) diff --git a/src/App.vue b/src/App.vue index e581971c..f02d49f9 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1136,6 +1136,38 @@ const copyAsMarkdown = async () => { } } +// 转换整篇的缩进:空格 ↔ 制表符(按 tab 宽度换算) +const convertIndentation = (toTabs: boolean) => { + const view = editorView.value + if (!view) { + return + } + const size = editorConfig.value?.tab_size ?? 2 + const original = view.state.doc.toString() + const out = original.split('\n').map((line: string) => { + const m = line.match(/^[ \t]+/) + if (!m) { + return line + } + // 把行首空白展开为列数(tab 计为 size 列) + let cols = 0 + for (const ch of m[0]) { + cols += ch === '\t' ? size : 1 + } + const rest = line.slice(m[0].length) + return toTabs + ? '\t'.repeat(Math.floor(cols / size)) + ' '.repeat(cols % size) + rest + : ' '.repeat(cols) + rest + }).join('\n') + if (out === original) { + return + } + const head = Math.min(view.state.selection.main.head, out.length) + view.dispatch({changes: {from: 0, to: view.state.doc.length, insert: out}, selection: {anchor: head}}) + view.focus() + toast.success(t('app.indentConverted')) +} + // AI 自然语言生成 / 选区改写 const showGenerate = ref(false) const generateSelection = ref('') @@ -2193,6 +2225,8 @@ const paletteCommands = computed(() => [ {id: 'removeDuplicateLines', label: t('command.removeDuplicateLines'), group: t('command.groupText'), icon: ListChecks, run: () => removeDuplicateLines()}, {id: 'trimTrailingWhitespace', label: t('command.trimTrailingWhitespace'), group: t('command.groupText'), icon: Eraser, run: () => trimTrailingWhitespace()}, {id: 'copyAsMarkdown', label: t('command.copyAsMarkdown'), group: t('command.groupText'), icon: Code2, run: () => copyAsMarkdown()}, + {id: 'indentToSpaces', label: t('command.indentToSpaces'), group: t('command.groupText'), icon: Eraser, run: () => convertIndentation(false)}, + {id: 'indentToTabs', label: t('command.indentToTabs'), group: t('command.groupText'), icon: Eraser, run: () => convertIndentation(true)}, {id: 'toggleAutoReveal', label: t('command.toggleAutoReveal'), icon: FolderOpen, run: () => toggleAutoReveal()}, {id: 'toggleSidebar', label: t('command.toggleSidebar'), icon: PanelLeft, hint: hintOf('toggleSidebar'), run: () => toggleSidebar()}, {id: 'toggleZen', label: t('command.toggleZen'), icon: Minimize2, run: () => toggleZen()}, diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 5f86652c..62fa370e 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -703,6 +703,8 @@ "removeDuplicateLines": "Remove duplicate lines", "trimTrailingWhitespace": "Trim trailing whitespace", "copyAsMarkdown": "Copy as Markdown code block", + "indentToSpaces": "Convert indentation to spaces", + "indentToTabs": "Convert indentation to tabs", "compareClipboard": "Compare with clipboard", "groupText": "Text", "toggleAutoReveal": "Toggle: auto-reveal active file", @@ -1324,6 +1326,7 @@ "multiEngine": "This type has multiple run engines; selected \"{name}\", switch manually in the dropdown", "pathCopied": "Path copied", "copiedMarkdown": "Copied as Markdown code block", + "indentConverted": "Indentation converted", "clipboardEmpty": "Clipboard is empty", "clipboardReadFailed": "Failed to read clipboard: ", "copyFailed": "Copy failed: ", diff --git a/src/i18n/locales/zh-CN.json b/src/i18n/locales/zh-CN.json index 34ee5c19..54ec2b32 100644 --- a/src/i18n/locales/zh-CN.json +++ b/src/i18n/locales/zh-CN.json @@ -703,6 +703,8 @@ "removeDuplicateLines": "删除重复行", "trimTrailingWhitespace": "去除行尾空白", "copyAsMarkdown": "复制为 Markdown 代码块", + "indentToSpaces": "转换缩进为空格", + "indentToTabs": "转换缩进为制表符", "compareClipboard": "与剪贴板比较", "groupText": "文本", "toggleAutoReveal": "切换:自动定位当前文件", @@ -1324,6 +1326,7 @@ "multiEngine": "该类型可用多个运行引擎,已选「{name}」,可在下拉手动切换", "pathCopied": "已复制路径", "copiedMarkdown": "已复制为 Markdown 代码块", + "indentConverted": "已转换缩进", "clipboardEmpty": "剪贴板为空", "clipboardReadFailed": "读取剪贴板失败: ", "copyFailed": "复制失败: ",