From db3da22972c5bd5dd19ff104f464ac95fc6ba17a Mon Sep 17 00:00:00 2001 From: qianmoQ Date: Fri, 5 Jun 2026 16:35:19 +0800 Subject: [PATCH 01/22] =?UTF-8?q?feat:=20=E4=BB=A3=E7=A0=81=E7=89=87?= =?UTF-8?q?=E6=AE=B5=20(snippets)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - useSnippets:localStorage 存储,前缀/语言/描述/内容,按语言匹配 - 编辑器 Tab 展开:光标前单词等于片段前缀时按 Tab 展开,$0/${0} 为光标落点,未匹配回落到默认缩进(Prec.highest) - SnippetManager 管理面板(增删改),接入命令面板 - 用 keymap 实现,无需新增 @codemirror/autocomplete 依赖,避免实例冲突 --- src/App.vue | 12 ++- src/components/SnippetManager.vue | 109 +++++++++++++++++++++++++ src/composables/useCodeMirrorEditor.ts | 41 ++++++++++ src/composables/useSnippets.ts | 60 ++++++++++++++ 4 files changed, 220 insertions(+), 2 deletions(-) create mode 100644 src/components/SnippetManager.vue create mode 100644 src/composables/useSnippets.ts diff --git a/src/App.vue b/src/App.vue index d750d3d..e9e143c 100644 --- a/src/App.vue +++ b/src/App.vue @@ -230,6 +230,9 @@ @go="gotoLine" @close="showOutline = false"/> + + + import {computed, nextTick, onMounted, onUnmounted, ref, watch} from 'vue' import {debounce} from 'lodash-es' -import {ChevronRight, CornerDownRight, Eye, FolderOpen, GitBranch, GitCompare, History, ListTree, Maximize2, Monitor, Moon, PanelBottom, PanelLeft, PanelRight, Play, Plus, Save, Search, Settings as SettingsIcon, Sparkles, Sun, X} from 'lucide-vue-next' +import {ChevronRight, Code2, CornerDownRight, Eye, FolderOpen, GitBranch, GitCompare, History, ListTree, Maximize2, Monitor, Moon, PanelBottom, PanelLeft, PanelRight, Play, Plus, Save, Search, Settings as SettingsIcon, Sparkles, Sun, X} from 'lucide-vue-next' import {ExecutionResult, LayoutMode, SplitDirection} from './types/app.ts' import AppHeader from './components/AppHeader.vue' import CodeEditor from './components/CodeEditor.vue' @@ -288,6 +291,7 @@ import PreviewPanel from './components/PreviewPanel.vue' import GitPanel from './components/GitPanel.vue' import GoToLine from './components/GoToLine.vue' import Outline from './components/Outline.vue' +import SnippetManager from './components/SnippetManager.vue' import {computeDiffMarkers, setDiffMarkers} from './editor/diffGutter' import AiAssistant from './components/AiAssistant.vue' import InlineGenerate from './components/InlineGenerate.vue' @@ -722,6 +726,9 @@ const openOutline = () => { showOutline.value = true } +// 代码片段管理 +const showSnippets = ref(false) + const openSearchResult = async (path: string, line: number) => { showSearch.value = false await smartOpen(path) @@ -1167,7 +1174,7 @@ const isOverlayOpen = () => showSettings.value || showAbout.value || showUpdate.value || showHistory.value || showViewer.value || showRunPrompt.value || showQuickOpen.value || showGenerate.value || showSearch.value - || showCommandPalette.value || showDiff.value || showGoToLine.value || showOutline.value + || showCommandPalette.value || showDiff.value || showGoToLine.value || showOutline.value || showSnippets.value // 全局快捷键(绑定可在设置中自定义) const {matchAction: matchShortcut, reload: reloadShortcuts, getBinding, formatCombo} = useShortcuts() @@ -1217,6 +1224,7 @@ const paletteCommands = computed(() => [ {id: 'quickOpen', label: '快速打开文件', icon: Search, hint: hintOf('quickOpen'), run: () => openQuickOpen()}, {id: 'gotoLine', label: '跳转到行', icon: CornerDownRight, hint: hintOf('gotoLine'), run: () => openGoToLine()}, {id: 'outline', label: '符号大纲', icon: ListTree, hint: hintOf('outline'), run: () => openOutline()}, + {id: 'snippets', label: '管理代码片段', icon: Code2, run: () => { showSnippets.value = true }}, {id: 'searchInFiles', label: '在文件夹内搜索', icon: Search, hint: hintOf('searchInFiles'), run: () => openSearch()}, {id: 'generate', label: 'AI 生成代码', icon: Sparkles, hint: hintOf('generate'), run: () => openGenerate()}, {id: 'showAi', label: 'AI 助手', icon: Sparkles, run: () => handleShowAi()}, diff --git a/src/components/SnippetManager.vue b/src/components/SnippetManager.vue new file mode 100644 index 0000000..8be8051 --- /dev/null +++ b/src/components/SnippetManager.vue @@ -0,0 +1,109 @@ +