Files
qwen-code/packages/vscode-ide-companion/AUTO_LOCK_EDITOR_GROUP.md
yiliang114 732220e651 wip(vscode-ide-companion): 实现 quick win 功能
- 将 WebView 调整到编辑器右侧
- 添加 ChatHeader 组件,实现会话下拉菜单
- 替换模态框为紧凑型下拉菜单
- 更新会话切换逻辑,显示当前标题
- 清理旧的会话选择器样式
基于 Claude Code v2.0.43 UI 分析实现。
2025-11-19 00:16:45 +08:00

9.2 KiB
Raw Blame History

自动锁定编辑器组功能实现

概述

参考 Claude Code 的实现Qwen Code VSCode 扩展现在支持自动锁定编辑器组功能,确保 AI 助手界面保持稳定,不会被其他编辑器替换或意外关闭。

实现原理

1. VSCode 锁定组机制

VSCode 源码分析src/vs/workbench/browser/parts/editor/editor.contribution.ts:558-566

// Lock Group: only on auxiliary window and when group is unlocked
appendEditorToolItem(
  {
    id: LOCK_GROUP_COMMAND_ID,
    title: localize('lockEditorGroup', 'Lock Group'),
    icon: Codicon.unlock,
  },
  ContextKeyExpr.and(
    IsAuxiliaryEditorPartContext,
    ActiveEditorGroupLockedContext.toNegated(),
  ),
  CLOSE_ORDER - 1, // immediately to the left of close action
);

关键条件

  • IsAuxiliaryEditorPartContext: 当前是辅助窗口的编辑器组
  • ActiveEditorGroupLockedContext.toNegated(): 当前组未锁定

2. Claude Code 的实现方式

Claude Code 在创建 webview panel 时会检测是否在新列中打开:

context.subscriptions.push(
  vscode.commands.registerCommand(
    'claude-vscode.editor.open',
    async (param1, param2) => {
      context.globalState.update('lastClaudeLocation', 1);
      let { startedInNewColumn } = webviewProvider.createPanel(param1, param2);

      // 如果在新列中打开,则自动锁定编辑器组
      if (startedInNewColumn) {
        await vscode.commands.executeCommand(
          'workbench.action.lockEditorGroup',
        );
      }
    },
  ),
);

3. Qwen Code 的实现

文件位置: packages/vscode-ide-companion/src/WebViewProvider.ts:101-153

async show(): Promise<void> {
  // Track if we're creating a new panel in a new column
  let startedInNewColumn = false;

  if (this.panel) {
    // If panel already exists, just reveal it (no lock needed)
    this.revealPanelTab(true);
    this.capturePanelTab();
    return;
  }

  // Mark that we're creating a new panel
  startedInNewColumn = true;

  this.panel = vscode.window.createWebviewPanel(
    'qwenCode.chat',
    'Qwen Code Chat',
    {
      viewColumn: vscode.ViewColumn.Beside, // Open on right side of active editor
      preserveFocus: true, // Don't steal focus from editor
    },
    {
      enableScripts: true,
      retainContextWhenHidden: true,
      localResourceRoots: [vscode.Uri.joinPath(this.extensionUri, 'dist')],
    },
  );

  // Capture the Tab that corresponds to our WebviewPanel (Claude-style)
  this.capturePanelTab();

  // Auto-lock editor group when opened in new column (Claude Code style)
  if (startedInNewColumn) {
    console.log('[WebViewProvider] Auto-locking editor group for Qwen Code chat');
    try {
      // Reveal panel without preserving focus to make it the active group
      // This ensures the lock command targets the correct editor group
      this.revealPanelTab(false);

      await vscode.commands.executeCommand('workbench.action.lockEditorGroup');
      console.log('[WebViewProvider] Editor group locked successfully');
    } catch (error) {
      console.warn('[WebViewProvider] Failed to lock editor group:', error);
      // Non-fatal error, continue anyway
    }
  } else {
    // For existing panel, reveal with preserving focus
    this.revealPanelTab(true);
  }

  // Continue with panel setup...
}

关键修复preserveFocus 问题

问题发现

  • 最初实现中,createWebviewPanel 使用了 preserveFocus: true
  • 这导致焦点保留在左边的编辑器组,左边的组仍然是活动组activeGroup
  • 执行 workbench.action.lockEditorGroup 时,命令默认作用于活动组
  • 结果:错误地锁定了左边的编辑器组,而不是 webview 所在的组

错误的执行流程

1. createWebviewPanel() 创建新组
   └─> preserveFocus: true 保持焦点在左边
       └─> activeGroup 仍然是左边的编辑器组

2. executeCommand("workbench.action.lockEditorGroup")
   └─> resolveCommandsContext() 使用 activeGroup
       └─> activeGroup = 左边的编辑器组 ❌
           └─> 错误地锁定了左边的组

修复方案

  1. 在执行锁定命令之前,调用 this.revealPanelTab(false)
  2. 这会让 webview panel 获得焦点并成为活动组
  3. 然后执行锁定命令就会锁定正确的组

修复后的执行流程

1. createWebviewPanel() 创建新组
   └─> preserveFocus: true 保持焦点在左边

2. revealPanelTab(false) 激活 webview 组
   └─> webview 组成为 activeGroup

3. executeCommand("workbench.action.lockEditorGroup")
   └─> resolveCommandsContext() 使用 activeGroup
       └─> activeGroup = webview 所在的组 ✓
           └─> 正确锁定 webview 所在的组

执行流程

1. 用户打开 Qwen Code chat
   ↓
2. 调用 WebViewProvider.show()
   ↓
3. 检查是否已有 panel
   - 有:直接 reveal不执行锁定
   - 无:创建新 panel设置 startedInNewColumn = true
   ↓
4. 创建 webview panel
   - viewColumn: ViewColumn.Beside
   - preserveFocus: true (不抢夺焦点,保持在编辑器)
   ↓
5. 捕获 Tab 引用
   - 调用 capturePanelTab() 保存 Tab 对象
   ↓
6. 执行自动锁定startedInNewColumn === true
   - 调用 revealPanelTab(false) 激活 webview 组
   - webview 所在的组成为活动组activeGroup
   - 执行命令: workbench.action.lockEditorGroup
   - 命令作用于活动组,正确锁定 webview 组
   ↓
7. 编辑器组被锁定
   - ActiveEditorGroupLockedContext 变为 true
   - 工具栏显示"解锁组"按钮(锁定图标)
   - webview 保持在固定位置

功能效果

锁定前

  • 用户可以拖拽 Qwen Code panel 到其他位置
  • 其他编辑器可能替换 Qwen Code panel
  • 容易意外关闭整个编辑器组

锁定后

  • Qwen Code panel 保持在固定位置
  • 编辑器组不会被其他操作影响
  • 工具栏显示"锁定组"按钮,用户可以手动解锁
  • 类似侧边栏的稳定行为

设计优势

  1. 防止意外操作

    • 锁定后用户不能轻易拖拽或关闭 AI 助手界面
    • 减少误操作导致的工作流中断
  2. 保持固定位置

    • AI 助手界面始终在用户期望的位置
    • 符合"AI 助手作为辅助工具"的定位
  3. 用户可控

    • 自动锁定提供默认保护
    • 用户仍可以通过工具栏解锁按钮手动解锁
    • 平衡了便利性和灵活性
  4. 一致的用户体验

    • 与 Claude Code 保持一致的交互模式
    • 用户无需学习新的行为模式

错误处理

try {
  await vscode.commands.executeCommand('workbench.action.lockEditorGroup');
  console.log('[WebViewProvider] Editor group locked successfully');
} catch (error) {
  console.warn('[WebViewProvider] Failed to lock editor group:', error);
  // Non-fatal error, continue anyway
}

设计考虑

  • 锁定失败不影响 panel 的正常功能
  • 记录警告日志便于调试
  • 优雅降级,不中断用户工作流

配置选项(可选扩展)

如果需要让用户控制是否自动锁定,可以添加配置项:

// 在 package.json 中添加配置
"qwenCode.autoLockEditorGroup": {
  "type": "boolean",
  "default": true,
  "description": "Automatically lock the editor group when opening Qwen Code chat"
}

// 在代码中检查配置
const config = vscode.workspace.getConfiguration('qwenCode');
const autoLock = config.get<boolean>('autoLockEditorGroup', true);

if (startedInNewColumn && autoLock) {
  await vscode.commands.executeCommand('workbench.action.lockEditorGroup');
}

测试场景

场景 1: 首次打开 Qwen Code

  1. 打开 VSCode没有 Qwen Code panel
  2. 执行命令打开 Qwen Code chat
  3. 预期: Panel 在新列中打开,编辑器组自动锁定

场景 2: 已有 Qwen Code panel

  1. Qwen Code panel 已打开
  2. 切换到其他编辑器
  3. 再次打开 Qwen Code chat
  4. 预期: Panel 被 reveal不重复锁定

场景 3: 手动解锁后

  1. Qwen Code panel 已锁定
  2. 用户点击工具栏解锁按钮
  3. 编辑器组被解锁
  4. 预期: 用户可以自由操作编辑器组

场景 4: 关闭并重新打开

  1. Qwen Code panel 已打开并锁定
  2. 用户关闭 panel
  3. 再次打开 Qwen Code chat
  4. 预期: 新 panel 在新列打开,自动锁定

兼容性

  • VSCode 1.85+(支持 workbench.action.lockEditorGroup 命令)
  • 所有操作系统Windows, macOS, Linux
  • 不影响现有功能
  • 向后兼容旧版本 VSCode锁定失败时优雅降级

相关 VSCode 命令

命令 功能
workbench.action.lockEditorGroup 锁定当前编辑器组
workbench.action.unlockEditorGroup 解锁当前编辑器组
workbench.action.toggleEditorGroupLock 切换编辑器组锁定状态

总结

通过模仿 Claude Code 的实现Qwen Code 现在提供了:

  1. 自动锁定编辑器组功能
  2. 与 Claude Code 一致的用户体验
  3. 稳定的 AI 助手界面位置
  4. 优雅的错误处理

这个功能显著提升了用户体验,让 AI 助手界面更加稳定可靠!