dsh-vscode-mode 0.14.1 → 0.14.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-vscode-mode",
3
- "version": "0.14.1",
3
+ "version": "0.14.2",
4
4
  "description": "DSH 上的类 VSCode 编码体验:Monaco 编辑器(文件页签/QuickOpen/状态栏,可驻 DSH 0.1.5+ 官方右侧 Sidebar 与对话同屏)+ 命令栏(Ctrl+Shift+P)与可扩展指令系统 + VS Code 兼容代码片段(.code-snippets 全局/项目,IntelliSense 展开)+ Agent 编辑差异审查(整文件差异/采纳/拒绝/归档/回滚)+ SVN 集成(侧栏变更面板/日志弹窗/并排差异)+ 语言服务器(LSP)智能(跳转定义/引用/hover/大纲 + VSIX 扩展市场安装),状态持久化到工作区旁车,界面状态(页签/光标/侧栏/编辑 Tab/导航历史)镜像到 DSH home 跨重启恢复",
5
5
  "icon": "assets/icon.svg",
6
6
  "keywords": [
@@ -26,6 +26,19 @@ export function splitGlobs(text) {
26
26
  return String(text ?? '').split(',').map((item) => item.trim()).filter(Boolean)
27
27
  }
28
28
 
29
+ /**
30
+ * 计算包含文件范围;仅当前文件已开启但无活动文件时返回 null,禁止退化为全工作区搜索。
31
+ * @author ddj 2026年09月29号
32
+ * @param onlyActive 是否仅搜索当前文件
33
+ * @param activePath 当前文件路径
34
+ * @param includeText 用户输入的包含模式
35
+ * @returns 包含 glob;null 表示当前搜索范围不可用
36
+ */
37
+ export function searchIncludes(onlyActive: boolean, activePath: string | null, includeText: string): string[] | null {
38
+ if (!onlyActive) return splitGlobs(includeText)
39
+ return activePath ? [activePath] : null
40
+ }
41
+
29
42
  /**
30
43
  * 读取按作用域持久化的搜索条件(损坏/缺失返回 null)。
31
44
  * 抽成函数而非内联:恢复 effect 内有两处消费者(填状态、同步 requestRef),
@@ -93,7 +106,7 @@ export function SearchPanel(props) {
93
106
  const requestRef = React.useRef({ matchCase, wholeWord, regex, include: [], exclude: [] })
94
107
  requestRef.current = {
95
108
  matchCase, wholeWord, regex,
96
- include: onlyActive ? (activePath ? [activePath] : []) : splitGlobs(includeText),
109
+ include: searchIncludes(onlyActive, activePath, includeText),
97
110
  exclude: excludeOn ? splitGlobs(excludeText) : [],
98
111
  }
99
112
 
@@ -117,9 +130,8 @@ export function SearchPanel(props) {
117
130
  matchCase: saved.matchCase === true,
118
131
  wholeWord: saved.wholeWord === true,
119
132
  regex: saved.regex === true,
120
- include: saved.onlyActive === true
121
- ? (activePathRef.current ? [activePathRef.current] : [])
122
- : splitGlobs(typeof saved.includeText === 'string' ? saved.includeText : ''),
133
+ include: searchIncludes(saved.onlyActive === true, activePathRef.current,
134
+ typeof saved.includeText === 'string' ? saved.includeText : ''),
123
135
  exclude: saved.excludeOn === true
124
136
  ? splitGlobs(typeof saved.excludeText === 'string' ? saved.excludeText : '')
125
137
  : [],
@@ -146,6 +158,14 @@ export function SearchPanel(props) {
146
158
  const clean = String(text ?? '').trim()
147
159
  if (clean.length < 2) { setMatches(null); setStatus('idle'); return }
148
160
  const req = requestRef.current
161
+ if (req.include === null) {
162
+ setMatches([])
163
+ setTruncated(false)
164
+ setError('')
165
+ setWarning('')
166
+ setStatus('done')
167
+ return
168
+ }
149
169
  setStatus('searching')
150
170
  setError('')
151
171
  setWarning('')
@@ -195,13 +215,13 @@ export function SearchPanel(props) {
195
215
  }
196
216
 
197
217
  /**
198
- * 立即重搜(查询 ≥2 字符时);先同步 ref 避免本次调用读到旧请求参数。
218
+ * 立即刷新搜索(短查询清空旧结果);先同步 ref 避免本次调用读到旧请求参数。
199
219
  * @param next 新的请求参数字段
200
220
  */
201
221
  const rerun = (next) => {
202
222
  requestRef.current = Object.assign({}, requestRef.current, next)
203
223
  if (timerRef.current) clearTimeout(timerRef.current)
204
- if (String(queryRef.current).trim().length >= 2) runSearch(queryRef.current)
224
+ runSearch(queryRef.current)
205
225
  }
206
226
 
207
227
  /** 选项开关切换(大小写/全词/正则/书本/设置):更新状态 + 立即重搜。 */
@@ -215,11 +235,19 @@ export function SearchPanel(props) {
215
235
  base[key] = value
216
236
  rerun({
217
237
  matchCase: base.matchCase, wholeWord: base.wholeWord, regex: base.regex,
218
- include: base.onlyActive ? (activePathRef.current ? [activePathRef.current] : []) : splitGlobs(includeText),
238
+ include: searchIncludes(base.onlyActive, activePathRef.current, includeText),
219
239
  exclude: base.excludeOn ? splitGlobs(excludeText) : [],
220
240
  })
221
241
  }
222
242
 
243
+ // 仅当前文件模式下切换/关闭活动文件,立即更新搜索范围并作废旧请求。
244
+ const previousPathRef = React.useRef(activePath)
245
+ React.useEffect(() => {
246
+ if (previousPathRef.current === activePath) return
247
+ previousPathRef.current = activePath
248
+ if (onlyActive) rerun({ include: searchIncludes(true, activePath, includeText) })
249
+ }, [activePath])
250
+
223
251
  /**
224
252
  * 取用一次性选区种子(需求 1:Ctrl+Shift+F 时把编辑器选中文本填入搜索框)。
225
253
  * 有种子即填入并立即搜索(不再等 250ms 防抖),同时全选便于直接改写;无种子为 no-op。
@@ -307,8 +335,8 @@ export function SearchPanel(props) {
307
335
  onChange: (e) => onChangeDebounced(setIncludeText, e.target.value),
308
336
  }),
309
337
  React.createElement('button', {
310
- className: 'edrv-search-toggle' + (onlyActive ? ' on' : ''), title: activePath ? '仅在当前打开的文件中搜索' : '无打开的文件(需先打开文件)',
311
- 'aria-pressed': onlyActive, disabled: !activePath,
338
+ className: 'edrv-search-toggle' + (onlyActive ? ' on' : ''), title: activePath ? '仅在当前打开的文件中搜索' : onlyActive ? '无打开的文件(点击退出仅当前文件)' : '无打开的文件(需先打开文件)',
339
+ 'aria-pressed': onlyActive, disabled: !activePath && !onlyActive,
312
340
  onClick: () => toggleOpt('onlyActive', !onlyActive),
313
341
  }, '📖')),
314
342
  React.createElement('div', { className: 'edrv-search-row' },
@@ -157,7 +157,7 @@ export function applyCaps(matches: ContentMatch[], maxMatches: number, maxFiles:
157
157
  */
158
158
  export function contentArgv(binary: string, root: string, input: ContentSearchInput): string[] {
159
159
  const argv = [binary, '--no-config', '--json', '--line-number', '--no-heading', '--color', 'never', '--hidden', '--no-ignore']
160
- if (input.matchCase === true) argv.push('--case-sensitive')
160
+ argv.push(input.matchCase === true ? '--case-sensitive' : '--ignore-case')
161
161
  if (input.wholeWord === true) argv.push('--word-regexp')
162
162
  if (input.regex !== true) argv.push('--fixed-strings')
163
163
  for (const excluded of EXCLUDES) argv.push('--glob', '!**/' + excluded + '/**')