wip(vscode-ide-companion): 实现 quick win 功能

- 将 WebView 调整到编辑器右侧
- 添加 ChatHeader 组件,实现会话下拉菜单
- 替换模态框为紧凑型下拉菜单
- 更新会话切换逻辑,显示当前标题
- 清理旧的会话选择器样式
基于 Claude Code v2.0.43 UI 分析实现。
This commit is contained in:
yiliang114
2025-11-19 00:16:45 +08:00
parent 729a3d0ab3
commit 732220e651
52 changed files with 16502 additions and 1420 deletions

448
WEBVIEW_PIN_FEATURE.md Normal file
View File

@@ -0,0 +1,448 @@
# WebView 固定功能实现说明
> **更新时间**: 2025-11-18
> **功能**: WebView 右侧固定 + Pin Tab 防止意外关闭
---
## ✅ 已实现的功能
### 1. WebView 固定在右侧 ✅
**位置**: `src/WebViewProvider.ts:82-85`
```typescript
this.panel = vscode.window.createWebviewPanel(
'qwenCode.chat',
'Qwen Code Chat',
{
viewColumn: vscode.ViewColumn.Beside, // 在编辑器右侧打开
preserveFocus: true, // 不抢夺编辑器焦点
},
// ...
);
```
**功能说明**:
-`viewColumn: vscode.ViewColumn.Beside` - WebView 始终在当前编辑器的右侧打开
-`preserveFocus: true` - 打开 WebView 时不会夺取焦点,用户可以继续编辑代码
**用户体验**:
- 打开 WebView 时,编辑器保持焦点
- WebView 在右侧独立列中打开
- 可以同时查看代码和聊天界面
---
### 2. WebView Tab 自动固定 ✅
**位置**: `src/WebViewProvider.ts:100-107`
```typescript
// Pin the webview tab to prevent accidental closure
// Note: This is done after panel creation to ensure it takes effect
setTimeout(() => {
if (this.panel) {
// Execute VSCode command to pin the active editor
vscode.commands.executeCommand('workbench.action.pinEditor');
}
}, 100);
```
**功能说明**:
- ✅ 创建 WebView 后自动执行 pin 命令
- ✅ 使用 100ms 延迟确保 panel 完全创建
- ✅ 防止用户意外关闭 WebView tab
**用户体验**:
- WebView tab 会显示 pin 图标(📌)
- 关闭其他 tab 时WebView 不会被关闭
- 需要明确点击关闭按钮才能关闭 WebView
---
### 3. WebView 重新打开时保持位置 ✅
**位置**: `src/WebViewProvider.ts:74-76`
```typescript
if (this.panel) {
this.panel.reveal(vscode.ViewColumn.Beside, true); // preserveFocus = true
return;
}
```
**功能说明**:
- ✅ 如果 WebView 已存在,调用 `reveal()` 显示
- ✅ 参数 `vscode.ViewColumn.Beside` 确保在右侧显示
- ✅ 参数 `true` (preserveFocus) 不夺取焦点
**用户体验**:
- 关闭后重新打开WebView 仍然在右侧
- 多次打开不会创建多个 WebView
- 保持用户的工作流程
---
## 🎯 与 Claude Code 的对比
| 功能 | Claude Code | 当前实现 | 状态 |
| ------------ | ----------- | -------- | -------- |
| **右侧打开** | ✅ | ✅ | 完全对标 |
| **不抢焦点** | ✅ | ✅ | 完全对标 |
| **Pin Tab** | ✅ | ✅ | 完全对标 |
| **记住位置** | ✅ | ✅ | 完全对标 |
---
## 📊 技术实现细节
### ViewColumn.Beside 的行为
```typescript
vscode.ViewColumn.Beside;
```
**说明**:
- 如果当前有活动编辑器,在其右侧创建新列
- 如果当前没有活动编辑器,在 ViewColumn.One 中打开
- 如果已经有多列,在最右侧列的右边打开
**实际效果**:
```
┌─────────────┬─────────────┐
│ │ │
│ Code │ WebView │
│ Editor │ (Pinned) │
│ (Focus) │ │
│ │ │
└─────────────┴─────────────┘
```
---
### preserveFocus 的作用
```typescript
{
viewColumn: vscode.ViewColumn.Beside,
preserveFocus: true // ← 关键参数
}
```
**功能**:
- `true`: 创建 WebView 时不夺取焦点,编辑器保持活动
- `false`: 创建 WebView 时自动切换焦点到 WebView
**用户场景**:
- ✅ 用户正在编辑代码时打开聊天,焦点仍在编辑器
- ✅ 用户可以继续输入代码,不会被打断
- ✅ 想要与 AI 交互时,手动点击 WebView 即可
---
### Pin Editor 命令的作用
```typescript
vscode.commands.executeCommand('workbench.action.pinEditor');
```
**功能**:
- 固定当前活动的 editor tab
- 防止被 `workbench.action.closeOtherEditors` 等命令关闭
- 在 tab 上显示 pin 图标
**VSCode 原生行为**:
- Pinned tab 会在非 pinned tab 的左侧显示
- 关闭"其他编辑器"时pinned 的不会被关闭
- Pinned tab 的颜色/样式可能有所不同(取决于主题)
---
## 🧪 测试建议
### 测试场景 1: 首次打开
**步骤**:
1. 打开一个代码文件
2. 执行命令 `qwenCode.openChat`
3. 观察 WebView 位置
**预期结果**:
- ✅ WebView 在右侧打开
- ✅ 代码编辑器保持焦点
- ✅ WebView tab 显示 pin 图标(📌)
---
### 测试场景 2: 关闭后重新打开
**步骤**:
1. 关闭 WebView tab
2. 再次执行命令 `qwenCode.openChat`
3. 观察 WebView 位置
**预期结果**:
- ✅ WebView 再次在右侧打开
- ✅ WebView 再次被 pin
- ✅ 代码编辑器保持焦点
---
### 测试场景 3: 关闭其他编辑器
**步骤**:
1. 打开多个代码文件和 WebView
2. 右键点击任意 tab
3. 选择 "关闭其他编辑器"
**预期结果**:
- ✅ 其他非 pinned tab 被关闭
- ✅ WebView (pinned) 保持打开
- ✅ 当前 tab 和 WebView 仍然可见
---
### 测试场景 4: 切换焦点
**步骤**:
1. WebView 打开后,焦点在编辑器
2. 点击 WebView 中的输入框
3. 输入一些文本
4. 按 Ctrl/Cmd + 1 切换回编辑器
**预期结果**:
- ✅ WebView 输入框获得焦点
- ✅ 可以正常输入
- ✅ 快捷键可以切换焦点
- ✅ WebView 保持在右侧
---
### 测试场景 5: 分屏编辑器
**步骤**:
1. 已经有左右分屏的编辑器
2. 焦点在左侧编辑器
3. 打开 WebView
**预期结果**:
- ✅ WebView 在右侧编辑器的右边打开(第三列)
- ✅ 左侧编辑器保持焦点
- ✅ WebView 被 pin
---
## 🔧 故障排查
### 问题 1: WebView 没有被 pin
**可能原因**:
- setTimeout 延迟不够
- panel 还未完全创建
**解决方案**:
```typescript
// 增加延迟到 200ms
setTimeout(() => {
if (this.panel) {
vscode.commands.executeCommand('workbench.action.pinEditor');
}
}, 200);
```
---
### 问题 2: WebView 不在右侧打开
**可能原因**:
- 没有活动编辑器
- ViewColumn 参数错误
**解决方案**:
确保使用正确的参数格式:
```typescript
{
viewColumn: vscode.ViewColumn.Beside, // ← 必须是对象属性
preserveFocus: true
}
```
---
### 问题 3: WebView 抢夺焦点
**可能原因**:
- `preserveFocus` 设置为 `false` 或未设置
- `reveal()` 方法没有传递 `preserveFocus` 参数
**解决方案**:
```typescript
// 创建时
{ viewColumn: ..., preserveFocus: true }
// 重新显示时
this.panel.reveal(vscode.ViewColumn.Beside, true);
// ↑
// preserveFocus
```
---
## 📝 代码改动总结
### 修改的文件
- `src/WebViewProvider.ts` (修改 ~30 行)
### 主要改动
1. **show() 方法** (line 73-107)
- 修改 `createWebviewPanel` 参数格式
- 添加 `preserveFocus: true`
- 添加自动 pin 逻辑
- 修改 `reveal()` 调用参数
2. **构造函数** (line 27-33)
- 修复 TypeScript 警告
-`private context` 改为普通参数
### 新增代码
- 添加 10 行pin 逻辑和注释)
---
## 🚀 后续优化建议
### 优先级 P2 - 可选增强
#### 1. 添加配置选项
**建议**:
```typescript
// 在 package.json 中添加配置
"qwenCode.webview.autoPin": {
"type": "boolean",
"default": true,
"description": "Automatically pin the WebView tab"
}
// 在代码中使用配置
const config = vscode.workspace.getConfiguration('qwenCode');
const autoPin = config.get<boolean>('webview.autoPin', true);
if (autoPin) {
setTimeout(() => {
vscode.commands.executeCommand('workbench.action.pinEditor');
}, 100);
}
```
**好处**:
- 用户可以选择是否自动 pin
- 更灵活的用户体验
---
#### 2. 记住 WebView 大小
**建议**:
```typescript
// 在 workspace state 中保存大小
context.workspaceState.update('webview.size', {
width: panel.viewColumn,
height: panel.visible,
});
// 恢复时使用保存的大小
const savedSize = context.workspaceState.get('webview.size');
```
**好处**:
- 用户调整的 WebView 大小会被记住
- 下次打开时恢复到相同大小
---
#### 3. 添加键盘快捷键
**建议**:
```json
// package.json
"keybindings": [
{
"command": "qwenCode.openChat",
"key": "ctrl+shift+q",
"mac": "cmd+shift+q"
},
{
"command": "qwenCode.focusChat",
"key": "ctrl+shift+c",
"mac": "cmd+shift+c"
}
]
```
**好处**:
- 快速打开/切换到 WebView
- 提高工作效率
---
## ✅ 验收标准
### 功能验收
- [x] WebView 在右侧打开
- [x] 不夺取编辑器焦点
- [x] Tab 自动被 pin
- [x] 重新打开时保持位置
- [x] 构建无错误
### 用户体验验收
- [ ] 符合用户预期
- [ ] 不干扰编码流程
- [ ] Pin 图标可见
- [ ] 关闭其他编辑器时不受影响
---
**文档版本**: v1.0
**创建时间**: 2025-11-18
**状态**: ✅ 实现完成,⏳ 等待测试