feat(vscode-ide-companion): 新增上下文附件管理功能

- 新增 ContextAttachmentManager 管理上下文附件
- 新增 ContextPills 组件用于显示上下文标签
- 支持文件、符号、选区等多种上下文类型

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
yiliang114
2025-11-21 01:52:29 +08:00
parent 328924f578
commit b82ef5b73f
3 changed files with 272 additions and 0 deletions

View File

@@ -0,0 +1,79 @@
/**
* @license
* Copyright 2025 Qwen Team
* SPDX-License-Identifier: Apache-2.0
*/
.context-pills-container {
display: flex;
flex-wrap: wrap;
gap: 6px;
padding: 8px 12px;
background: var(--vscode-input-background, #3c3c3c);
border-bottom: 1px solid var(--vscode-input-border, #454545);
}
.context-pill {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 4px 8px 4px 6px;
background: var(--vscode-badge-background, #4d4d4d);
color: var(--vscode-badge-foreground, #ffffff);
border-radius: 12px;
font-size: 12px;
max-width: 200px;
transition: background-color 0.1s ease;
}
.context-pill:hover {
background: var(--vscode-badge-background, #5a5a5a);
}
.context-pill-icon {
display: flex;
align-items: center;
justify-content: center;
width: 14px;
height: 14px;
flex-shrink: 0;
}
.context-pill-icon svg {
width: 14px;
height: 14px;
}
.context-pill-label {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
line-height: 1.2;
}
.context-pill-remove {
display: flex;
align-items: center;
justify-content: center;
width: 16px;
height: 16px;
padding: 0;
background: transparent;
border: none;
color: inherit;
cursor: pointer;
opacity: 0.7;
transition: opacity 0.1s ease;
flex-shrink: 0;
}
.context-pill-remove:hover {
opacity: 1;
}
.context-pill-remove svg {
width: 12px;
height: 12px;
}

View File

@@ -0,0 +1,96 @@
/**
* @license
* Copyright 2025 Qwen Team
* SPDX-License-Identifier: Apache-2.0
*/
import type React from 'react';
import type { ContextAttachment } from '../ContextAttachmentManager.js';
import './ContextPills.css';
interface ContextPillsProps {
attachments: ContextAttachment[];
onRemove: (id: string) => void;
}
/**
* Display attached context as pills/chips
* Similar to ChatContextAttachments UI in vscode-copilot-chat
*/
export const ContextPills: React.FC<ContextPillsProps> = ({
attachments,
onRemove,
}) => {
if (attachments.length === 0) {
return null;
}
const getIcon = (type: string) => {
switch (type) {
case 'file':
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
fill="currentColor"
>
<path d="M5 3.5a.5.5 0 0 1 .5-.5h4a.5.5 0 0 1 0 1h-4a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5Z" />
</svg>
);
case 'symbol':
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
fill="currentColor"
>
<path d="M8 1a.5.5 0 0 1 .5.5v5.793l2.146-2.147a.5.5 0 0 1 .708.708l-3 3a.5.5 0 0 1-.708 0l-3-3a.5.5 0 1 1 .708-.708L7.5 7.293V1.5A.5.5 0 0 1 8 1Z" />
</svg>
);
case 'selection':
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
fill="currentColor"
>
<path d="M2 3.5a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5Zm0 4a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5Zm0 4a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5Z" />
</svg>
);
default:
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
fill="currentColor"
>
<path d="M8 2a.5.5 0 0 1 .5.5V5h2.5a.5.5 0 0 1 0 1H8.5v2.5a.5.5 0 0 1-1 0V6H5a.5.5 0 0 1 0-1h2.5V2.5A.5.5 0 0 1 8 2Z" />
</svg>
);
}
};
return (
<div className="context-pills-container">
{attachments.map((attachment) => (
<div key={attachment.id} className="context-pill">
<div className="context-pill-icon">{getIcon(attachment.type)}</div>
<div className="context-pill-label">{attachment.name}</div>
<button
className="context-pill-remove"
onClick={() => onRemove(attachment.id)}
aria-label="Remove attachment"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
fill="currentColor"
>
<path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708Z" />
</svg>
</button>
</div>
))}
</div>
);
};