Skip to content

Commit c4f9f6f

Browse files
committed
feat(editor): 新增「转换缩进(空格↔制表符)」命令
命令面板「文本」分组:把整篇行首缩进在空格与制表符间转换,按 tab 宽度换算列数, 保留正文与光标位置;与状态栏缩进开关(改设置)互补。
1 parent 50ad324 commit c4f9f6f

3 files changed

Lines changed: 40 additions & 0 deletions

File tree

src/App.vue

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1136,6 +1136,38 @@ const copyAsMarkdown = async () => {
11361136
}
11371137
}
11381138
1139+
// 转换整篇的缩进:空格 ↔ 制表符(按 tab 宽度换算)
1140+
const convertIndentation = (toTabs: boolean) => {
1141+
const view = editorView.value
1142+
if (!view) {
1143+
return
1144+
}
1145+
const size = editorConfig.value?.tab_size ?? 2
1146+
const original = view.state.doc.toString()
1147+
const out = original.split('\n').map((line: string) => {
1148+
const m = line.match(/^[ \t]+/)
1149+
if (!m) {
1150+
return line
1151+
}
1152+
// 把行首空白展开为列数(tab 计为 size 列)
1153+
let cols = 0
1154+
for (const ch of m[0]) {
1155+
cols += ch === '\t' ? size : 1
1156+
}
1157+
const rest = line.slice(m[0].length)
1158+
return toTabs
1159+
? '\t'.repeat(Math.floor(cols / size)) + ' '.repeat(cols % size) + rest
1160+
: ' '.repeat(cols) + rest
1161+
}).join('\n')
1162+
if (out === original) {
1163+
return
1164+
}
1165+
const head = Math.min(view.state.selection.main.head, out.length)
1166+
view.dispatch({changes: {from: 0, to: view.state.doc.length, insert: out}, selection: {anchor: head}})
1167+
view.focus()
1168+
toast.success(t('app.indentConverted'))
1169+
}
1170+
11391171
// AI 自然语言生成 / 选区改写
11401172
const showGenerate = ref(false)
11411173
const generateSelection = ref('')
@@ -2193,6 +2225,8 @@ const paletteCommands = computed<PaletteCommand[]>(() => [
21932225
{id: 'removeDuplicateLines', label: t('command.removeDuplicateLines'), group: t('command.groupText'), icon: ListChecks, run: () => removeDuplicateLines()},
21942226
{id: 'trimTrailingWhitespace', label: t('command.trimTrailingWhitespace'), group: t('command.groupText'), icon: Eraser, run: () => trimTrailingWhitespace()},
21952227
{id: 'copyAsMarkdown', label: t('command.copyAsMarkdown'), group: t('command.groupText'), icon: Code2, run: () => copyAsMarkdown()},
2228+
{id: 'indentToSpaces', label: t('command.indentToSpaces'), group: t('command.groupText'), icon: Eraser, run: () => convertIndentation(false)},
2229+
{id: 'indentToTabs', label: t('command.indentToTabs'), group: t('command.groupText'), icon: Eraser, run: () => convertIndentation(true)},
21962230
{id: 'toggleAutoReveal', label: t('command.toggleAutoReveal'), icon: FolderOpen, run: () => toggleAutoReveal()},
21972231
{id: 'toggleSidebar', label: t('command.toggleSidebar'), icon: PanelLeft, hint: hintOf('toggleSidebar'), run: () => toggleSidebar()},
21982232
{id: 'toggleZen', label: t('command.toggleZen'), icon: Minimize2, run: () => toggleZen()},

src/i18n/locales/en.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,8 @@
703703
"removeDuplicateLines": "Remove duplicate lines",
704704
"trimTrailingWhitespace": "Trim trailing whitespace",
705705
"copyAsMarkdown": "Copy as Markdown code block",
706+
"indentToSpaces": "Convert indentation to spaces",
707+
"indentToTabs": "Convert indentation to tabs",
706708
"compareClipboard": "Compare with clipboard",
707709
"groupText": "Text",
708710
"toggleAutoReveal": "Toggle: auto-reveal active file",
@@ -1324,6 +1326,7 @@
13241326
"multiEngine": "This type has multiple run engines; selected \"{name}\", switch manually in the dropdown",
13251327
"pathCopied": "Path copied",
13261328
"copiedMarkdown": "Copied as Markdown code block",
1329+
"indentConverted": "Indentation converted",
13271330
"clipboardEmpty": "Clipboard is empty",
13281331
"clipboardReadFailed": "Failed to read clipboard: ",
13291332
"copyFailed": "Copy failed: ",

src/i18n/locales/zh-CN.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,8 @@
703703
"removeDuplicateLines": "删除重复行",
704704
"trimTrailingWhitespace": "去除行尾空白",
705705
"copyAsMarkdown": "复制为 Markdown 代码块",
706+
"indentToSpaces": "转换缩进为空格",
707+
"indentToTabs": "转换缩进为制表符",
706708
"compareClipboard": "与剪贴板比较",
707709
"groupText": "文本",
708710
"toggleAutoReveal": "切换:自动定位当前文件",
@@ -1324,6 +1326,7 @@
13241326
"multiEngine": "该类型可用多个运行引擎,已选「{name}」,可在下拉手动切换",
13251327
"pathCopied": "已复制路径",
13261328
"copiedMarkdown": "已复制为 Markdown 代码块",
1329+
"indentConverted": "已转换缩进",
13271330
"clipboardEmpty": "剪贴板为空",
13281331
"clipboardReadFailed": "读取剪贴板失败: ",
13291332
"copyFailed": "复制失败: ",

0 commit comments

Comments
 (0)