Skip to content

Commit 1480980

Browse files
authored
Merge pull request #119 from qianmoQ/dev-26.4.0
Enhance editor features and improve branch deletion process
2 parents 812f6bd + d136a00 commit 1480980

19 files changed

Lines changed: 539 additions & 41 deletions

docs/src/content/blog/welcome.md renamed to docs/src/content/blog/tauri2-plugin-architecture-for-30-language-runner.md

File renamed without changes.

docs/src/i18n.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,14 @@ const messages = {
4444
open: '100%', openLabel: '开源免费'
4545
},
4646
releaseList: {title: '发布日志', intro: '每个版本的更新内容如下,点击查看详情。'},
47-
footer: {download: '下载', blog: '博客', releases: '发布日志'}
47+
footer: {download: '下载', blog: '博客', releases: '发布日志'},
48+
notFound: {
49+
title: '页面未找到',
50+
description: '抱歉,您访问的页面不存在或已被移动',
51+
goHome: '返回首页',
52+
goBack: '返回上页',
53+
quickLinks: '您可能想访问:'
54+
}
4855
},
4956
en: {
5057
nav: {download: 'Download', blog: 'Blog', releases: 'Releases'},
@@ -86,7 +93,14 @@ const messages = {
8693
open: '100%', openLabel: 'Open source'
8794
},
8895
releaseList: {title: 'Releases', intro: 'Update notes for each version. Click to view details.'},
89-
footer: {download: 'Download', blog: 'Blog', releases: 'Releases'}
96+
footer: {download: 'Download', blog: 'Blog', releases: 'Releases'},
97+
notFound: {
98+
title: 'Page Not Found',
99+
description: 'Sorry, the page you are looking for does not exist or has been moved',
100+
goHome: 'Go Home',
101+
goBack: 'Go Back',
102+
quickLinks: 'You might want to visit:'
103+
}
90104
}
91105
}
92106

docs/src/pages/NotFound.vue

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<template>
2+
<div class="min-h-[60vh] flex items-center justify-center px-5">
3+
<div class="text-center max-w-2xl">
4+
<!-- 404 大号文字 -->
5+
<div class="text-9xl font-extrabold text-transparent bg-clip-text bg-gradient-to-r from-brand-600 to-violet-600 mb-4">
6+
404
7+
</div>
8+
9+
<!-- 标题 -->
10+
<h1 class="text-3xl font-bold text-slate-900 dark:text-white mb-4">
11+
{{ t('notFound.title') }}
12+
</h1>
13+
14+
<!-- 描述 -->
15+
<p class="text-lg text-slate-600 dark:text-slate-400 mb-8">
16+
{{ t('notFound.description') }}
17+
</p>
18+
19+
<!-- 操作按钮 -->
20+
<div class="flex items-center justify-center gap-4">
21+
<RouterLink to="/"
22+
class="inline-flex items-center gap-2 px-6 py-3 rounded-xl bg-gradient-to-r from-brand-600 to-violet-600 text-white font-semibold hover:opacity-90 transition-opacity">
23+
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
24+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"/>
25+
</svg>
26+
{{ t('notFound.goHome') }}
27+
</RouterLink>
28+
29+
<button @click="goBack"
30+
class="inline-flex items-center gap-2 px-6 py-3 rounded-xl border-2 border-slate-200 dark:border-slate-800 text-slate-700 dark:text-slate-300 font-semibold hover:border-brand-400 dark:hover:border-brand-500 transition-colors">
31+
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
32+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"/>
33+
</svg>
34+
{{ t('notFound.goBack') }}
35+
</button>
36+
</div>
37+
38+
<!-- 快捷链接 -->
39+
<div class="mt-12 pt-8 border-t border-slate-200 dark:border-slate-800">
40+
<p class="text-sm text-slate-500 dark:text-slate-400 mb-4">{{ t('notFound.quickLinks') }}</p>
41+
<div class="flex items-center justify-center gap-6 text-sm">
42+
<RouterLink to="/download" class="text-brand-600 dark:text-brand-400 hover:underline">{{ t('nav.download') }}</RouterLink>
43+
<RouterLink to="/blog" class="text-brand-600 dark:text-brand-400 hover:underline">{{ t('nav.blog') }}</RouterLink>
44+
<RouterLink to="/release" class="text-brand-600 dark:text-brand-400 hover:underline">{{ t('nav.releases') }}</RouterLink>
45+
<a href="https://github.com/devlive-community/codeforge" target="_blank" rel="noopener" class="text-brand-600 dark:text-brand-400 hover:underline">GitHub</a>
46+
</div>
47+
</div>
48+
</div>
49+
</div>
50+
</template>
51+
52+
<script setup lang="ts">
53+
import {useRouter} from 'vue-router'
54+
import {useI18n} from 'vue-i18n'
55+
56+
const router = useRouter()
57+
const {t} = useI18n()
58+
59+
const goBack = () => {
60+
if (window.history.length > 1) {
61+
router.back()
62+
} else {
63+
router.push('/')
64+
}
65+
}
66+
</script>

docs/src/router.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import Home from './pages/Home.vue'
33
import Download from './pages/Download.vue'
44
import ReleaseList from './pages/ReleaseList.vue'
55
import BlogList from './pages/BlogList.vue'
6+
import NotFound from './pages/NotFound.vue'
67
import {releaseRoutes} from './content/releases'
78
import {blogRoutes} from './content/blogs'
89

@@ -12,5 +13,6 @@ export const routes: RouteRecordRaw[] = [
1213
{path: '/release', component: ReleaseList, meta: {title: '发布日志'}},
1314
{path: '/blog', component: BlogList, meta: {title: '技术博客'}},
1415
...releaseRoutes.map(r => ({...r, meta: {doc: true, docType: 'release'}})),
15-
...blogRoutes.map(r => ({...r, meta: {doc: true, docType: 'blog'}}))
16+
...blogRoutes.map(r => ({...r, meta: {doc: true, docType: 'blog'}})),
17+
{path: '/:pathMatch(.*)*', component: NotFound, meta: {title: '页面未找到'}}
1618
]

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"dependencies": {
1313
"@babel/runtime": "^7.28.2",
1414
"@codemirror/autocomplete": "6.20.3",
15+
"@codemirror/commands": "^6.10.4",
1516
"@codemirror/lang-cpp": "^6.0.3",
1617
"@codemirror/lang-css": "^6.3.1",
1718
"@codemirror/lang-go": "^6.0.1",
@@ -53,6 +54,7 @@
5354
"lodash-es": "^4.17.21",
5455
"lucide-vue-next": "^0.539.0",
5556
"markdown-it": "^14.2.0",
57+
"sql-formatter": "^15.8.2",
5658
"vscode-languageserver-protocol": "^3.18.0",
5759
"vue": "^3.5.13",
5860
"vue-codemirror": "^6.1.1",
@@ -77,7 +79,8 @@
7779
},
7880
"pnpm": {
7981
"overrides": {
80-
"@codemirror/autocomplete": "6.20.3"
82+
"@codemirror/autocomplete": "6.20.3",
83+
"@codemirror/state": "6.7.0"
8184
}
8285
}
8386
}

src-tauri/src/filesystem.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1304,10 +1304,12 @@ pub async fn git_branch_create(root: String, name: String) -> Result<String, Str
13041304

13051305
/// 删除分支(安全删除,未合并会失败)。
13061306
#[tauri::command]
1307-
pub async fn git_branch_delete(root: String, name: String) -> Result<String, String> {
1308-
tokio::task::spawn_blocking(move || run_git(&root, &["branch", "-d", &name]))
1309-
.await
1310-
.map_err(|e| format!("git 任务失败: {}", e))?
1307+
pub async fn git_branch_delete(root: String, name: String, force: bool) -> Result<String, String> {
1308+
tokio::task::spawn_blocking(move || {
1309+
run_git(&root, &["branch", if force { "-D" } else { "-d" }, &name])
1310+
})
1311+
.await
1312+
.map_err(|e| format!("git 任务失败: {}", e))?
13111313
}
13121314

13131315
/// 重命名分支。

src/App.vue

Lines changed: 99 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,8 @@
331331
<!-- 文件夹内全局搜索 -->
332332
<SearchPanel v-if="showSearch && rootDir" :root-dir="rootDir" :extra-roots="extraRoots" :scope="searchScope" @open="openSearchResult" @replaced="reloadAffectedFiles" @close="showSearch = false"/>
333333

334+
<WorkspaceManager v-if="showWorkspaces" :root-dir="rootDir" :extra-roots="extraRoots" @open="openWorkspace" @close="showWorkspaces = false"/>
335+
334336
<!-- 快速打开文件 -->
335337
<QuickOpen v-if="showQuickOpen && rootDir"
336338
:root-dir="rootDir"
@@ -354,6 +356,7 @@
354356
:code="code"
355357
:language="currentLanguage"
356358
:current-line="cursorInfo.line"
359+
:view="editorView"
357360
@go="gotoLine"
358361
@close="showOutline = false"/>
359362

@@ -463,6 +466,7 @@
463466
<button class="w-full text-left px-3 py-1.5 hover:bg-gray-100 dark:hover:bg-gray-700 cursor-pointer" @click="aiCodeAction('explain')">{{ t('aiCode.title.explain') }}</button>
464467
<button class="w-full text-left px-3 py-1.5 hover:bg-gray-100 dark:hover:bg-gray-700 cursor-pointer" @click="aiCodeAction('refactor')">{{ t('aiCode.title.refactor') }}</button>
465468
<button class="w-full text-left px-3 py-1.5 hover:bg-gray-100 dark:hover:bg-gray-700 cursor-pointer" @click="aiCodeAction('test')">{{ t('aiCode.title.test') }}</button>
469+
<button class="w-full text-left px-3 py-1.5 hover:bg-gray-100 dark:hover:bg-gray-700 cursor-pointer" @click="aiCodeAction('doc')">{{ t('aiCode.title.doc') }}</button>
466470
<button v-if="canBlame || editorCtx.lsp" class="w-full text-left px-3 py-1.5 hover:bg-gray-100 dark:hover:bg-gray-700 cursor-pointer" @click="aiFixDiagnostics">{{ t('aiCode.title.fix') }}</button>
467471
<div class="border-t border-gray-100 dark:border-gray-700 my-1"></div>
468472
<button class="w-full text-left px-3 py-1.5 hover:bg-gray-100 dark:hover:bg-gray-700 cursor-pointer" @click="sendToTerminal">
@@ -544,6 +548,8 @@ import {useWorkspace} from './composables/useWorkspace'
544548
import {useTextCommands} from './composables/useTextCommands'
545549
import {useBookmarks} from './composables/useBookmarks'
546550
import {foldAll, unfoldAll, matchBrackets} from '@codemirror/language'
551+
import {selectParentSyntax} from '@codemirror/commands'
552+
import {format as formatSql} from 'sql-formatter'
547553
import {diagnostics} from './editor/lspDiagnostics'
548554
import {useGitPermalink} from './composables/useGitPermalink'
549555
import {useRevealInTree} from './composables/useRevealInTree'
@@ -589,6 +595,7 @@ import {useDebug} from './composables/useDebug'
589595
import AiAssistant from './components/AiAssistant.vue'
590596
import InlineGenerate from './components/InlineGenerate.vue'
591597
import SearchPanel from './components/SearchPanel.vue'
598+
import WorkspaceManager from './components/WorkspaceManager.vue'
592599
import {useTheme, type AppTheme} from './composables/useTheme'
593600
import Modal from './ui/Modal.vue'
594601
import Button from './ui/Button.vue'
@@ -749,10 +756,18 @@ const handleCopyRelativePath = (path: string) => {
749756
const rootDir = ref<string | null>(null)
750757
751758
// 远程仓库永久链接(复制 / 在浏览器打开)
752-
const {copyPermalink, openPermalink} = useGitPermalink(rootDir, currentFilePath, cursorInfo)
759+
const {copyPermalink, openPermalink, openRepoOnWeb} = useGitPermalink(rootDir, currentFilePath, cursorInfo)
753760
754761
// 多根工作区:额外挂载的文件夹(Git/搜索仍走主根 rootDir)
755-
const {extraRoots, addWorkspaceFolder, removeWorkspaceFolder, resetExtraRoots} = useWorkspaceRoots(rootDir)
762+
const {extraRoots, addWorkspaceFolder, removeWorkspaceFolder, resetExtraRoots, setExtraRoots} = useWorkspaceRoots(rootDir)
763+
764+
// 命名工作区:保存/打开一组根
765+
const showWorkspaces = ref(false)
766+
const openWorkspace = (ws: {rootDir: string; extraRoots: string[]}) => {
767+
showWorkspaces.value = false
768+
openFolderPath(ws.rootDir) // 设主根并清空额外根
769+
setExtraRoots(ws.extraRoots) // 再恢复该工作区的额外根
770+
}
756771
const sidebarVisible = ref(kvGet('sidebar-visible') === 'true')
757772
// 专注模式:隐藏顶部工具栏/运行输入/侧栏/状态栏,沉浸编辑
758773
const zenMode = ref(false)
@@ -1175,6 +1190,65 @@ const convertIndentation = (toTabs: boolean) => {
11751190
toast.success(t('app.indentConverted'))
11761191
}
11771192
1193+
// 展开/收缩选区:按语法节点逐级扩选,收缩用选区栈回退
1194+
let expandStack: { anchor: number, head: number }[] = []
1195+
let expandLastKey = ''
1196+
const selKey = (view: any) => {
1197+
const s = view.state.selection.main
1198+
return s.anchor + ':' + s.head
1199+
}
1200+
const expandSelection = () => {
1201+
const view = editorView.value
1202+
if (!view) {
1203+
return
1204+
}
1205+
// 用户手动改过选区则重置栈
1206+
if (selKey(view) !== expandLastKey) {
1207+
expandStack = []
1208+
}
1209+
const s = view.state.selection.main
1210+
expandStack.push({anchor: s.anchor, head: s.head})
1211+
selectParentSyntax(view)
1212+
view.focus()
1213+
expandLastKey = selKey(view)
1214+
}
1215+
const shrinkSelection = () => {
1216+
const view = editorView.value
1217+
if (!view) {
1218+
return
1219+
}
1220+
const prev = expandStack.pop()
1221+
if (prev) {
1222+
view.dispatch({selection: {anchor: prev.anchor, head: prev.head}})
1223+
view.focus()
1224+
expandLastKey = selKey(view)
1225+
}
1226+
}
1227+
1228+
// 格式化 SQL(选区或全文)
1229+
const formatSqlDoc = () => {
1230+
const view = editorView.value
1231+
if (!view) {
1232+
return
1233+
}
1234+
if (currentLanguage.value !== 'sql') {
1235+
toast.info(t('app.sqlFormatOnlySql'))
1236+
return
1237+
}
1238+
const sel = view.state.selection.main
1239+
const from = sel.empty ? 0 : view.state.doc.lineAt(sel.from).from
1240+
const to = sel.empty ? view.state.doc.length : view.state.doc.lineAt(sel.to).to
1241+
try {
1242+
const out = formatSql(view.state.doc.sliceString(from, to), {language: 'sql', keywordCase: 'upper'})
1243+
view.dispatch({changes: {from, to, insert: out}, selection: {anchor: from}})
1244+
view.focus()
1245+
toast.success(t('app.sqlFormatted'))
1246+
}
1247+
catch (error) {
1248+
toast.error(t('app.sqlFormatFailed') + error)
1249+
}
1250+
}
1251+
11781252
// 转到匹配括号:取光标前后的括号,跳到其配对处
11791253
const goToMatchingBracket = () => {
11801254
const view = editorView.value
@@ -1422,7 +1496,7 @@ const runTests = async () => {
14221496
}
14231497
14241498
// C2:对选区(无选区则整篇)执行 AI 操作:解释 / 重构 / 生成测试
1425-
const aiCodeCtx = ref<{action: 'explain' | 'refactor' | 'test' | 'fix'; code: string; from: number; to: number; diagnostics?: string} | null>(null)
1499+
const aiCodeCtx = ref<{action: 'explain' | 'refactor' | 'test' | 'fix' | 'doc'; code: string; from: number; to: number; diagnostics?: string} | null>(null)
14261500
// AI 修复诊断:把当前文件的 LSP 诊断交给 AI 修复整篇
14271501
const aiFixDiagnostics = () => {
14281502
closeEditorCtx()
@@ -1437,7 +1511,7 @@ const aiFixDiagnostics = () => {
14371511
const diagText = diagnostics.value.map(d => `[${d.severity}] L${d.line}:${d.col} ${d.message}`).join('\n')
14381512
aiCodeCtx.value = {action: 'fix', code: view.state.doc.toString(), from: 0, to: view.state.doc.length, diagnostics: diagText}
14391513
}
1440-
const aiCodeAction = (action: 'explain' | 'refactor' | 'test') => {
1514+
const aiCodeAction = (action: 'explain' | 'refactor' | 'test' | 'doc') => {
14411515
closeEditorCtx()
14421516
const view = editorView.value
14431517
if (!view) {
@@ -1468,7 +1542,17 @@ const onAiReplace = (code: string) => {
14681542
const onAiInsert = (code: string) => {
14691543
const view = editorView.value
14701544
const ctx = aiCodeCtx.value
1471-
if (view && ctx) {
1545+
if (!view || !ctx) {
1546+
return
1547+
}
1548+
if (ctx.action === 'doc') {
1549+
// 文档注释插入到目标代码所在行之前,缩进对齐
1550+
const line = view.state.doc.lineAt(ctx.from)
1551+
const indent = line.text.match(/^\s*/)?.[0] ?? ''
1552+
const commented = code.trimEnd().split('\n').map(l => indent + l).join('\n')
1553+
view.dispatch({changes: {from: line.from, insert: `${commented}\n`}})
1554+
}
1555+
else {
14721556
view.dispatch({changes: {from: ctx.to, insert: `\n\n${code}\n`}})
14731557
}
14741558
}
@@ -2170,7 +2254,7 @@ const isOverlayOpen = () =>
21702254
|| showHistory.value || showViewer.value || showRunPrompt.value
21712255
|| showQuickOpen.value || showGenerate.value || showSearch.value
21722256
|| showCommandPalette.value || showDiff.value || showGoToLine.value || showOutline.value || showSnippets.value
2173-
|| applyPreview.value != null || clipboardDiff.value != null
2257+
|| applyPreview.value != null || clipboardDiff.value != null || showWorkspaces.value
21742258
21752259
// 全局快捷键(绑定可在设置中自定义)
21762260
const {matchAction: matchShortcut, reload: reloadShortcuts, getBinding, formatCombo} = useShortcuts()
@@ -2193,7 +2277,9 @@ const shortcutDispatch: Record<string, () => void> = {
21932277
toggleSidebar: () => toggleSidebar(),
21942278
toggleTerminal: () => toggleTerminal(),
21952279
toggleWordWrap: () => toggleWordWrap(),
2196-
toggleBookmark: () => toggleBookmark()
2280+
toggleBookmark: () => toggleBookmark(),
2281+
expandSelection: () => expandSelection(),
2282+
shrinkSelection: () => shrinkSelection()
21972283
}
21982284
21992285
// 切换自动换行(即时生效并随编辑器配置持久化)
@@ -2228,6 +2314,7 @@ const paletteCommands = computed<PaletteCommand[]>(() => [
22282314
{id: 'formatOnSave', label: formatOnSave.value ? t('command.formatOnSaveOff') : t('command.formatOnSaveOn'), icon: Save, run: () => toggleFormatOnSave()},
22292315
{id: 'open', label: t('command.open'), icon: FolderOpen, hint: hintOf('open'), run: () => handleOpenFileClick()},
22302316
{id: 'openFolder', label: t('command.openFolder'), icon: FolderOpen, run: () => openFolder()},
2317+
{id: 'workspaces', label: t('command.workspaces'), icon: FolderOpen, run: () => { showWorkspaces.value = true }},
22312318
{id: 'save', label: t('command.save'), icon: Save, hint: hintOf('save'), run: () => handleSave()},
22322319
{id: 'saveAs', label: t('command.saveAs'), icon: Save, hint: hintOf('saveAs'), run: () => saveFileAs()},
22332320
{id: 'newTab', label: t('command.newTab'), icon: Plus, hint: hintOf('newTab'), run: () => handleNewTab()},
@@ -2245,6 +2332,7 @@ const paletteCommands = computed<PaletteCommand[]>(() => [
22452332
{id: 'generateTests', label: t('command.generateTests'), icon: Sparkles, run: () => generateTests()},
22462333
{id: 'formatWithAi', label: t('command.formatWithAi'), icon: Sparkles, run: () => formatWithAi()},
22472334
{id: 'aiFixDiagnostics', label: t('command.aiFixDiagnostics'), icon: Sparkles, run: () => aiFixDiagnostics()},
2335+
{id: 'aiGenDoc', label: t('command.aiGenDoc'), icon: Sparkles, run: () => aiCodeAction('doc')},
22482336
{id: 'history', label: t('command.history'), icon: History, run: () => { showHistory.value = true }},
22492337
{id: 'diff', label: t('command.diff'), icon: GitCompare, run: () => openDiff()},
22502338
{id: 'compareClipboard', label: t('command.compareClipboard'), icon: GitCompare, run: () => compareWithClipboard()},
@@ -2258,6 +2346,7 @@ const paletteCommands = computed<PaletteCommand[]>(() => [
22582346
{id: 'revealInTree', label: t('command.revealInTree'), icon: FolderOpen, run: () => revealInTree()},
22592347
{id: 'copyPermalink', label: t('command.copyPermalink'), icon: GitBranch, run: () => copyPermalink()},
22602348
{id: 'openPermalink', label: t('command.openPermalink'), icon: GitBranch, run: () => openPermalink()},
2349+
{id: 'openRepoOnWeb', label: t('command.openRepoOnWeb'), icon: GitBranch, run: () => openRepoOnWeb()},
22612350
{id: 'sortLinesAsc', label: t('command.sortLinesAsc'), group: t('command.groupText'), icon: ArrowDownAZ, run: () => sortLines(false)},
22622351
{id: 'sortLinesDesc', label: t('command.sortLinesDesc'), group: t('command.groupText'), icon: ArrowUpAZ, run: () => sortLines(true)},
22632352
{id: 'toUpperCase', label: t('command.toUpperCase'), group: t('command.groupText'), icon: CaseUpper, run: () => transformSelectionOrLine(s => s.toUpperCase())},
@@ -2270,6 +2359,9 @@ const paletteCommands = computed<PaletteCommand[]>(() => [
22702359
{id: 'foldAll', label: t('command.foldAll'), group: t('command.groupCode'), icon: FoldVertical, run: () => { if (editorView.value) foldAll(editorView.value) }},
22712360
{id: 'unfoldAll', label: t('command.unfoldAll'), group: t('command.groupCode'), icon: UnfoldVertical, run: () => { if (editorView.value) unfoldAll(editorView.value) }},
22722361
{id: 'goToMatchingBracket', label: t('command.goToMatchingBracket'), group: t('command.groupCode'), icon: Code2, run: () => goToMatchingBracket()},
2362+
{id: 'formatSql', label: t('command.formatSql'), group: t('command.groupCode'), icon: Code2, run: () => formatSqlDoc()},
2363+
{id: 'expandSelection', label: t('command.expandSelection'), group: t('command.groupCode'), icon: Code2, hint: hintOf('expandSelection'), run: () => expandSelection()},
2364+
{id: 'shrinkSelection', label: t('command.shrinkSelection'), group: t('command.groupCode'), icon: Code2, hint: hintOf('shrinkSelection'), run: () => shrinkSelection()},
22732365
{id: 'toggleBookmark', label: t('command.toggleBookmark'), group: t('command.groupBookmark'), icon: Bookmark, hint: hintOf('toggleBookmark'), run: () => toggleBookmark()},
22742366
{id: 'nextBookmark', label: t('command.nextBookmark'), group: t('command.groupBookmark'), icon: Bookmark, run: () => nextBookmark()},
22752367
{id: 'prevBookmark', label: t('command.prevBookmark'), group: t('command.groupBookmark'), icon: Bookmark, run: () => prevBookmark()},

0 commit comments

Comments
 (0)