mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-19 09:33:53 +00:00
feat(vscode-ide-companion/ui): add context toggle control to input form
This commit is contained in:
@@ -10,6 +10,7 @@ import {
|
|||||||
AutoEditIcon,
|
AutoEditIcon,
|
||||||
PlanModeIcon,
|
PlanModeIcon,
|
||||||
CodeBracketsIcon,
|
CodeBracketsIcon,
|
||||||
|
HideContextIcon,
|
||||||
ThinkingIcon,
|
ThinkingIcon,
|
||||||
SlashCommandIcon,
|
SlashCommandIcon,
|
||||||
LinkIcon,
|
LinkIcon,
|
||||||
@@ -33,6 +34,8 @@ interface InputFormProps {
|
|||||||
thinkingEnabled: boolean;
|
thinkingEnabled: boolean;
|
||||||
activeFileName: string | null;
|
activeFileName: string | null;
|
||||||
activeSelection: { startLine: number; endLine: number } | null;
|
activeSelection: { startLine: number; endLine: number } | null;
|
||||||
|
// Whether to auto-load the active editor selection/path into context
|
||||||
|
skipAutoActiveContext: boolean;
|
||||||
onInputChange: (text: string) => void;
|
onInputChange: (text: string) => void;
|
||||||
onCompositionStart: () => void;
|
onCompositionStart: () => void;
|
||||||
onCompositionEnd: () => void;
|
onCompositionEnd: () => void;
|
||||||
@@ -42,6 +45,7 @@ interface InputFormProps {
|
|||||||
onToggleEditMode: () => void;
|
onToggleEditMode: () => void;
|
||||||
onToggleThinking: () => void;
|
onToggleThinking: () => void;
|
||||||
onFocusActiveEditor: () => void;
|
onFocusActiveEditor: () => void;
|
||||||
|
onToggleSkipAutoActiveContext: () => void;
|
||||||
onShowCommandMenu: () => void;
|
onShowCommandMenu: () => void;
|
||||||
onAttachContext: () => void;
|
onAttachContext: () => void;
|
||||||
completionIsOpen: boolean;
|
completionIsOpen: boolean;
|
||||||
@@ -90,6 +94,7 @@ export const InputForm: React.FC<InputFormProps> = ({
|
|||||||
thinkingEnabled,
|
thinkingEnabled,
|
||||||
activeFileName,
|
activeFileName,
|
||||||
activeSelection,
|
activeSelection,
|
||||||
|
skipAutoActiveContext,
|
||||||
onInputChange,
|
onInputChange,
|
||||||
onCompositionStart,
|
onCompositionStart,
|
||||||
onCompositionEnd,
|
onCompositionEnd,
|
||||||
@@ -98,7 +103,7 @@ export const InputForm: React.FC<InputFormProps> = ({
|
|||||||
onCancel,
|
onCancel,
|
||||||
onToggleEditMode,
|
onToggleEditMode,
|
||||||
onToggleThinking,
|
onToggleThinking,
|
||||||
onFocusActiveEditor,
|
onToggleSkipAutoActiveContext,
|
||||||
onShowCommandMenu,
|
onShowCommandMenu,
|
||||||
onAttachContext,
|
onAttachContext,
|
||||||
completionIsOpen,
|
completionIsOpen,
|
||||||
@@ -128,6 +133,15 @@ export const InputForm: React.FC<InputFormProps> = ({
|
|||||||
onKeyDown(e);
|
onKeyDown(e);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Selection label like "6 lines selected" (Claude-style); no line numbers
|
||||||
|
const selectedLinesCount = activeSelection
|
||||||
|
? Math.max(1, activeSelection.endLine - activeSelection.startLine + 1)
|
||||||
|
: 0;
|
||||||
|
const selectedLinesText =
|
||||||
|
selectedLinesCount > 0
|
||||||
|
? `${selectedLinesCount} ${selectedLinesCount === 1 ? 'line' : 'lines'} selected`
|
||||||
|
: '';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="p-1 px-4 pb-4"
|
className="p-1 px-4 pb-4"
|
||||||
@@ -166,6 +180,9 @@ export const InputForm: React.FC<InputFormProps> = ({
|
|||||||
aria-label="Message input"
|
aria-label="Message input"
|
||||||
aria-multiline="true"
|
aria-multiline="true"
|
||||||
data-placeholder="Ask Qwen Code …"
|
data-placeholder="Ask Qwen Code …"
|
||||||
|
// Use a data flag so CSS can show placeholder even if the browser
|
||||||
|
// inserts an invisible <br> into contentEditable (so :empty no longer matches)
|
||||||
|
data-empty={inputText.trim().length === 0 ? 'true' : 'false'}
|
||||||
onInput={(e) => {
|
onInput={(e) => {
|
||||||
const target = e.target as HTMLDivElement;
|
const target = e.target as HTMLDivElement;
|
||||||
onInputChange(target.textContent || '');
|
onInputChange(target.textContent || '');
|
||||||
@@ -196,15 +213,26 @@ export const InputForm: React.FC<InputFormProps> = ({
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="btn-text-compact btn-text-compact--primary"
|
className="btn-text-compact btn-text-compact--primary"
|
||||||
title={`Showing Qwen Code your current file selection: ${activeFileName}${activeSelection ? `#${activeSelection.startLine}-${activeSelection.endLine}` : ''}`}
|
title={(() => {
|
||||||
onClick={onFocusActiveEditor}
|
if (skipAutoActiveContext) {
|
||||||
|
return selectedLinesText
|
||||||
|
? `Active selection will NOT be auto-loaded into context: ${selectedLinesText}`
|
||||||
|
: `Active file will NOT be auto-loaded into context: ${activeFileName}`;
|
||||||
|
}
|
||||||
|
return selectedLinesText
|
||||||
|
? `Showing Qwen Code your current selection: ${selectedLinesText}`
|
||||||
|
: `Showing Qwen Code your current file: ${activeFileName}`;
|
||||||
|
})()}
|
||||||
|
onClick={onToggleSkipAutoActiveContext}
|
||||||
>
|
>
|
||||||
<CodeBracketsIcon />
|
{skipAutoActiveContext ? (
|
||||||
|
<HideContextIcon />
|
||||||
|
) : (
|
||||||
|
<CodeBracketsIcon />
|
||||||
|
)}
|
||||||
{/* Truncate file path/selection; hide label on very small screens */}
|
{/* Truncate file path/selection; hide label on very small screens */}
|
||||||
<span className="hidden sm:inline">
|
<span className="hidden sm:inline">
|
||||||
{activeFileName}
|
{selectedLinesText || activeFileName}
|
||||||
{activeSelection &&
|
|
||||||
` #${activeSelection.startLine}${activeSelection.startLine !== activeSelection.endLine ? `-${activeSelection.endLine}` : ''}`}
|
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -109,6 +109,34 @@ export const CodeBracketsIcon: React.FC<IconProps> = ({
|
|||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hide context (eye slash) icon (20x20)
|
||||||
|
* Used to indicate the active selection will NOT be auto-loaded into context
|
||||||
|
*/
|
||||||
|
export const HideContextIcon: React.FC<IconProps> = ({
|
||||||
|
size = 20,
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}) => (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="currentColor"
|
||||||
|
width={size}
|
||||||
|
height={size}
|
||||||
|
className={className}
|
||||||
|
aria-hidden="true"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fillRule="evenodd"
|
||||||
|
d="M3.28 2.22a.75.75 0 0 0-1.06 1.06l14.5 14.5a.75.75 0 1 0 1.06-1.06l-1.745-1.745a10.029 10.029 0 0 0 3.3-4.38 1.651 1.651 0 0 0 0-1.185A10.004 10.004 0 0 0 9.999 3a9.956 9.956 0 0 0-4.744 1.194L3.28 2.22ZM7.752 6.69l1.092 1.092a2.5 2.5 0 0 1 3.374 3.373l1.091 1.092a4 4 0 0 0-5.557-5.557Z"
|
||||||
|
clipRule="evenodd"
|
||||||
|
/>
|
||||||
|
<path d="m10.748 13.93 2.523 2.523a9.987 9.987 0 0 1-3.27.547c-4.258 0-7.894-2.66-9.337-6.41a1.651 1.651 0 0 1 0-1.186A10.007 10.007 0 0 1 2.839 6.02L6.07 9.252a4 4 0 0 0 4.678 4.678Z" />
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Slash command icon (20x20)
|
* Slash command icon (20x20)
|
||||||
* Used for command menu button
|
* Used for command menu button
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ export {
|
|||||||
AutoEditIcon,
|
AutoEditIcon,
|
||||||
PlanModeIcon,
|
PlanModeIcon,
|
||||||
CodeBracketsIcon,
|
CodeBracketsIcon,
|
||||||
|
HideContextIcon,
|
||||||
SlashCommandIcon,
|
SlashCommandIcon,
|
||||||
LinkIcon,
|
LinkIcon,
|
||||||
OpenDiffIcon,
|
OpenDiffIcon,
|
||||||
|
|||||||
Reference in New Issue
Block a user