mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-19 09:33:53 +00:00
chore(vscode-ide-companion): add qwen-code dependency to package files
This commit is contained in:
@@ -63,6 +63,10 @@
|
||||
{
|
||||
"command": "qwenCode.clearAuthCache",
|
||||
"title": "Qwen Code: Clear Authentication Cache"
|
||||
},
|
||||
{
|
||||
"command": "qwenCode.login",
|
||||
"title": "Qwen Code: Login"
|
||||
}
|
||||
],
|
||||
"configuration": {
|
||||
@@ -109,6 +113,10 @@
|
||||
{
|
||||
"command": "qwen.diff.cancel",
|
||||
"when": "qwen.diff.isVisible"
|
||||
},
|
||||
{
|
||||
"command": "qwenCode.login",
|
||||
"when": "false"
|
||||
}
|
||||
],
|
||||
"editor/title": [
|
||||
@@ -190,6 +198,7 @@
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/sdk": "^1.15.1",
|
||||
"@qwen-code/qwen-code-core": "file:../core",
|
||||
"@qwen-code/qwen-code": "file:../cli",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^5.1.0",
|
||||
"react": "^18.2.0",
|
||||
|
||||
@@ -43,7 +43,7 @@ export class WebViewProvider {
|
||||
(message) => this.sendMessageToWebView(message),
|
||||
);
|
||||
|
||||
// Set login handler for /login command - force re-login
|
||||
// Set login handler for /login command - direct force re-login
|
||||
this.messageHandler.setLoginHandler(async () => {
|
||||
await this.forceReLogin();
|
||||
});
|
||||
@@ -293,33 +293,13 @@ export class WebViewProvider {
|
||||
});
|
||||
}
|
||||
|
||||
// Check if we have valid auth cache and auto-reconnect
|
||||
// Don't auto-login; user must use /login command
|
||||
// Just initialize empty conversation for the UI
|
||||
if (!this.agentInitialized) {
|
||||
const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
|
||||
const workingDir = workspaceFolder?.uri.fsPath || process.cwd();
|
||||
const config = vscode.workspace.getConfiguration('qwenCode');
|
||||
const openaiApiKey = config.get<string>('openaiApiKey', '');
|
||||
// Use the same authMethod logic as qwenConnectionHandler
|
||||
const authMethod = openaiApiKey ? 'openai' : 'qwen-oauth';
|
||||
|
||||
// Check if we have valid cached auth
|
||||
const hasValidAuth = await this.authStateManager.hasValidAuth(
|
||||
workingDir,
|
||||
authMethod,
|
||||
console.log(
|
||||
'[WebViewProvider] Agent not initialized, waiting for /login command',
|
||||
);
|
||||
|
||||
if (hasValidAuth) {
|
||||
console.log(
|
||||
'[WebViewProvider] Found valid auth cache, auto-reconnecting...',
|
||||
);
|
||||
// Auto-reconnect using cached auth
|
||||
await this.initializeAgentConnection();
|
||||
} else {
|
||||
console.log(
|
||||
'[WebViewProvider] No valid auth cache, waiting for /login command',
|
||||
);
|
||||
await this.initializeEmptyConversation();
|
||||
}
|
||||
await this.initializeEmptyConversation();
|
||||
} else {
|
||||
console.log(
|
||||
'[WebViewProvider] Agent already initialized, reusing existing connection',
|
||||
@@ -447,6 +427,39 @@ export class WebViewProvider {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh connection without clearing auth cache
|
||||
* Called when restoring WebView after VSCode restart
|
||||
*/
|
||||
async refreshConnection(): Promise<void> {
|
||||
console.log('[WebViewProvider] Refresh connection requested');
|
||||
|
||||
// Disconnect existing connection if any
|
||||
if (this.agentInitialized) {
|
||||
try {
|
||||
this.agentManager.disconnect();
|
||||
console.log('[WebViewProvider] Existing connection disconnected');
|
||||
} catch (error) {
|
||||
console.log('[WebViewProvider] Error disconnecting:', error);
|
||||
}
|
||||
this.agentInitialized = false;
|
||||
}
|
||||
|
||||
// Wait a moment for cleanup to complete
|
||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||
|
||||
// Reinitialize connection (will use cached auth if available)
|
||||
try {
|
||||
await this.initializeAgentConnection();
|
||||
console.log(
|
||||
'[WebViewProvider] Connection refresh completed successfully',
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('[WebViewProvider] Connection refresh failed:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load messages from current Qwen session
|
||||
* Creates a new ACP session for immediate message sending
|
||||
@@ -540,7 +553,7 @@ export class WebViewProvider {
|
||||
* Restore an existing WebView panel (called during VSCode restart)
|
||||
* This sets up the panel with all event listeners
|
||||
*/
|
||||
restorePanel(panel: vscode.WebviewPanel): void {
|
||||
async restorePanel(panel: vscode.WebviewPanel): Promise<void> {
|
||||
console.log('[WebViewProvider] Restoring WebView panel');
|
||||
this.panelManager.setPanel(panel);
|
||||
|
||||
@@ -630,49 +643,25 @@ export class WebViewProvider {
|
||||
|
||||
console.log('[WebViewProvider] Panel restored successfully');
|
||||
|
||||
// Check if we have valid auth cache and auto-reconnect on restore
|
||||
if (!this.agentInitialized) {
|
||||
const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
|
||||
const workingDir = workspaceFolder?.uri.fsPath || process.cwd();
|
||||
const config = vscode.workspace.getConfiguration('qwenCode');
|
||||
const openaiApiKey = config.get<string>('openaiApiKey', '');
|
||||
// Use the same authMethod logic as qwenConnectionHandler
|
||||
const authMethod = openaiApiKey ? 'openai' : 'qwen-oauth';
|
||||
|
||||
// Check if we have valid cached auth
|
||||
this.authStateManager
|
||||
.hasValidAuth(workingDir, authMethod)
|
||||
.then(async (hasValidAuth) => {
|
||||
if (hasValidAuth) {
|
||||
console.log(
|
||||
'[WebViewProvider] Found valid auth cache on restore, auto-reconnecting...',
|
||||
);
|
||||
await this.initializeAgentConnection();
|
||||
} else {
|
||||
console.log(
|
||||
'[WebViewProvider] No valid auth cache after restore, waiting for /login command',
|
||||
);
|
||||
await this.initializeEmptyConversation();
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(
|
||||
'[WebViewProvider] Failed to check auth cache after restore:',
|
||||
error,
|
||||
);
|
||||
this.initializeEmptyConversation().catch(console.error);
|
||||
});
|
||||
// Refresh connection on restore (will use cached auth if available)
|
||||
if (this.agentInitialized) {
|
||||
console.log(
|
||||
'[WebViewProvider] Agent was initialized, refreshing connection...',
|
||||
);
|
||||
try {
|
||||
await this.refreshConnection();
|
||||
console.log('[WebViewProvider] Connection refreshed successfully');
|
||||
} catch (error) {
|
||||
console.error('[WebViewProvider] Failed to refresh connection:', error);
|
||||
// Fall back to empty conversation if refresh fails
|
||||
this.agentInitialized = false;
|
||||
await this.initializeEmptyConversation();
|
||||
}
|
||||
} else {
|
||||
console.log(
|
||||
'[WebViewProvider] Agent already initialized, loading current session...',
|
||||
'[WebViewProvider] Agent not initialized, waiting for /login command',
|
||||
);
|
||||
// Reload current session messages
|
||||
this.loadCurrentSessionMessages().catch((error) => {
|
||||
console.error(
|
||||
'[WebViewProvider] Failed to load session messages after restore:',
|
||||
error,
|
||||
);
|
||||
});
|
||||
await this.initializeEmptyConversation();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -231,6 +231,18 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
);
|
||||
log('Auth cache cleared by user');
|
||||
}),
|
||||
vscode.commands.registerCommand('qwenCode.login', async () => {
|
||||
// Get the current WebViewProvider instance - must already exist
|
||||
if (webViewProviders.length > 0) {
|
||||
const provider = webViewProviders[webViewProviders.length - 1];
|
||||
await provider.forceReLogin();
|
||||
} else {
|
||||
// No WebViewProvider exists, show a message to user
|
||||
vscode.window.showInformationMessage(
|
||||
'Please open Qwen Code chat first before logging in.',
|
||||
);
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
ideServer = new IDEServer(log, diffManager);
|
||||
|
||||
@@ -38,7 +38,7 @@ export const ThinkingIcon: React.FC<ThinkingIconProps> = ({
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M10.3927 6.81824C10.3927 7.14824 10.1767 7.42424 9.91668 7.42424H9.75968L9.30068 5.39324C9.47868 5.28524 9.71068 5.22424 9.91668 5.22424C10.1607 5.22424 10.3927 5.50824 10.3927 5.83624V6.81824ZM4.90268 5.19124C4.55468 5.14224 4.22568 5.42624 4.22568 5.83624V6.81824C4.22568 7.17324 4.51068 7.42424 4.80068 7.42424H4.90268V5.19124ZM4.90268 8.62224C4.90268 8.70424 4.89068 8.77724 4.86768 8.84524L4.72268 9.34024C4.64868 9.58424 4.45768 9.77224 4.22568 9.84624V8.62224C4.22568 8.25824 4.51068 8.01824 4.80068 8.01824H4.90268V8.62224ZM4.78068 10.4622C4.71468 10.6532 4.60968 10.8202 4.45768 10.9572L4.05568 11.3252C3.63768 11.7132 3.00268 11.6392 2.66968 11.1692C2.35768 10.7292 2.45668 10.1212 2.89268 9.79624L3.16868 9.59424C3.36768 9.44724 3.64068 9.51324 3.76268 9.74424L4.14268 10.4622H4.78068ZM5.50268 8.62224C5.50268 8.89724 5.70768 9.08624 5.96068 9.10124H6.15568V10.9802C6.15568 11.3402 5.88268 11.6132 5.56068 11.6132H5.02068C4.68868 11.6132 4.42668 11.3302 4.42668 10.9802V9.85824C4.42668 9.72024 4.55568 9.65324 4.68568 9.70524C4.93568 9.80324 5.17568 9.77924 5.36468 9.72324C5.43568 9.70224 5.50268 9.63324 5.50268 9.54824V8.62224ZM5.50268 7.42424H5.80868H6.07968V8.01824H5.80868C5.62068 8.01824 5.50268 8.25824 5.50268 8.62224V7.42424ZM6.72668 4.93024C6.60368 4.93024 6.49468 4.98624 6.42568 5.08124L6.07968 5.55924V4.79224C6.07968 4.60024 6.14768 4.41824 6.25568 4.26724C6.36368 4.11624 6.53468 4.00724 6.72668 4.00724H8.19668C8.41568 4.00724 8.60068 4.14024 8.69768 4.32424L9.08968 5.07524H9.91668C10.5367 5.07524 10.9927 5.52224 10.9927 6.08724V6.56924C10.9927 7.13824 10.5367 7.57724 9.91668 7.57724H9.60568L9.88968 8.80224C9.95068 9.06924 9.78268 9.33324 9.50668 9.37124C9.46268 9.37724 9.41668 9.37724 9.37168 9.37124L9.23368 9.34524L8.72668 11.2652C8.61668 11.6692 8.24568 11.9232 7.80868 11.9232C7.59668 11.9232 7.39468 11.8462 7.24068 11.7082L7.14068 11.6132H7.69168V10.0562H7.07168C6.79468 10.0562 6.56968 9.81524 6.56968 9.51424V9.10024L6.78468 8.77724C6.84768 8.68324 6.87968 8.57824 6.87968 8.46824C6.87968 8.24324 6.75268 8.01824 6.55768 8.01824H6.42668V5.89024L7.27568 5.18624C7.47468 5.02524 7.56068 4.98924 7.56068 4.93024C7.56068 4.86724 7.40568 4.78724 7.20668 4.85024L6.72668 5.00524V4.93024ZM8.38268 8.01824H8.73068L9.01568 9.24624L8.30868 9.09724L8.38268 8.72824V8.01824ZM8.11668 10.0552H8.00968V11.1032L8.26668 10.1322L8.11668 10.0552ZM9.07368 10.2272L8.52468 11.7662C8.47068 11.9092 8.34668 12.0082 8.20168 12.0362C8.14268 12.0482 8.08168 12.0482 8.02068 12.0362C7.86568 12.0062 7.73068 11.9042 7.66968 11.7552C7.61268 11.6142 7.58268 11.5622 7.55268 11.4912L7.41168 11.1662L7.36468 10.7362C7.35668 10.6562 7.40068 10.5822 7.47368 10.5482C7.56368 10.5082 7.61568 10.4402 7.64068 10.3502L7.69168 10.0562H8.00968L8.68268 10.4422L9.07368 10.2272ZM7.69168 7.27024V5.86524L7.62968 5.91624C7.43768 6.07324 7.15468 6.08424 6.95168 5.94724L6.87968 5.89724V7.42424H8.21368L8.00968 6.53424C7.96768 6.35324 8.06568 6.17024 8.22568 6.10524C8.27368 6.08724 8.32168 6.08524 8.37068 6.09524L9.02868 6.22224C9.15768 6.24724 9.22668 6.39524 9.17268 6.52424L9.09668 6.71024C9.08368 6.74324 9.06368 6.77124 9.04068 6.79624L8.21268 7.57724L7.95468 7.27024H7.69168ZM8.00968 9.26224C7.94168 9.30024 7.88368 9.34024 7.83068 9.38624C7.74368 9.46024 7.66768 9.54724 7.60968 9.65224L7.54668 9.76324C7.50868 9.83224 7.48468 9.90924 7.47468 9.99124L7.47268 10.0032V10.0562H6.72668V9.51124C6.72668 9.41924 6.77068 9.33424 6.84668 9.28024L7.05768 9.13024C7.12568 9.08224 7.16268 9.00424 7.16268 8.92024V8.01824H7.83068V8.77724H8.07368V8.81624C8.07368 8.94124 8.05168 9.06024 8.00968 9.17324V9.26224ZM6.72668 8.57324C6.72668 8.57024 6.72668 8.56524 6.72668 8.56224V8.01824H6.87968V8.46824C6.87968 8.50624 6.87568 8.54324 6.86868 8.57924L6.72668 8.57324Z"
|
||||
d="M8.00293 1.11523L8.35059 1.12402H8.35352C11.9915 1.30834 14.8848 4.31624 14.8848 8C14.8848 11.8025 11.8025 14.8848 8 14.8848C4.19752 14.8848 1.11523 11.8025 1.11523 8C1.11523 7.67691 1.37711 7.41504 1.7002 7.41504C2.02319 7.41514 2.28516 7.67698 2.28516 8C2.28516 11.1563 4.84369 13.7148 8 13.7148C11.1563 13.7148 13.7148 11.1563 13.7148 8C13.7148 4.94263 11.3141 2.4464 8.29492 2.29297V2.29199L7.99609 2.28516H7.9873V2.28418L7.89648 2.27539L7.88281 2.27441V2.27344C7.61596 2.21897 7.41513 1.98293 7.41504 1.7002C7.41504 1.37711 7.67691 1.11523 8 1.11523H8.00293ZM8 3.81543C8.32309 3.81543 8.58496 4.0773 8.58496 4.40039V7.6377L10.9619 8.82715C11.2505 8.97169 11.3678 9.32256 11.2236 9.61133C11.0972 9.86425 10.8117 9.98544 10.5488 9.91504L10.5352 9.91211V9.91016L10.4502 9.87891L10.4385 9.87402V9.87305L7.73828 8.52344C7.54007 8.42433 7.41504 8.22155 7.41504 8V4.40039C7.41504 4.0773 7.67691 3.81543 8 3.81543ZM2.44336 5.12695C2.77573 5.19517 3.02597 5.48929 3.02637 5.8418C3.02637 6.19456 2.7761 6.49022 2.44336 6.55859L2.2959 6.57324C1.89241 6.57324 1.56543 6.24529 1.56543 5.8418C1.56588 5.43853 1.89284 5.1123 2.2959 5.1123L2.44336 5.12695ZM3.46094 2.72949C3.86418 2.72984 4.19017 3.05712 4.19043 3.45996V3.46094C4.19009 3.86393 3.86392 4.19008 3.46094 4.19043H3.45996C3.05712 4.19017 2.72983 3.86419 2.72949 3.46094V3.45996C2.72976 3.05686 3.05686 2.72976 3.45996 2.72949H3.46094ZM5.98926 1.58008C6.32235 1.64818 6.57324 1.94276 6.57324 2.2959L6.55859 2.44336C6.49022 2.7761 6.19456 3.02637 5.8418 3.02637C5.43884 3.02591 5.11251 2.69895 5.1123 2.2959L5.12695 2.14844C5.19504 1.81591 5.48906 1.56583 5.8418 1.56543L5.98926 1.58008Z"
|
||||
strokeWidth="0.27"
|
||||
style={{
|
||||
stroke: enabled
|
||||
|
||||
@@ -13,7 +13,7 @@ interface WaitingMessageProps {
|
||||
export const WaitingMessage: React.FC<WaitingMessageProps> = ({
|
||||
loadingMessage,
|
||||
}) => (
|
||||
<div className="flex gap-0 items-start text-left py-2 flex-col relative opacity-85 animate-[fadeIn_0.2s_ease-in]">
|
||||
<div className="flex gap-0 items-start text-left py-2 flex-col opacity-85 animate-[fadeIn_0.2s_ease-in]">
|
||||
<div className="bg-transparent border-0 py-2 flex items-center gap-2">
|
||||
<span className="inline-flex items-center gap-1 mr-0">
|
||||
<span className="inline-block w-1.5 h-1.5 bg-[var(--app-secondary-foreground)] rounded-full mr-0 opacity-60 animate-[typingPulse_1.4s_infinite_ease-in-out] [animation-delay:0s]"></span>
|
||||
|
||||
@@ -47,14 +47,14 @@ export class AuthMessageHandler extends BaseMessageHandler {
|
||||
try {
|
||||
console.log('[AuthMessageHandler] Login requested');
|
||||
|
||||
// Direct login without additional confirmation
|
||||
if (this.loginHandler) {
|
||||
await this.loginHandler();
|
||||
} else {
|
||||
// Fallback: show message and use command
|
||||
vscode.window.showInformationMessage(
|
||||
'Please wait while we connect to Qwen Code...',
|
||||
);
|
||||
|
||||
// Fallback: trigger WebViewProvider's forceReLogin
|
||||
await vscode.commands.executeCommand('qwenCode.login');
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
@@ -150,6 +150,13 @@ export class MessageRouter {
|
||||
*/
|
||||
setLoginHandler(handler: () => Promise<void>): void {
|
||||
this.authHandler.setLoginHandler(handler);
|
||||
// Also set login handler for SessionMessageHandler
|
||||
if (
|
||||
this.sessionHandler &&
|
||||
typeof this.sessionHandler.setLoginHandler === 'function'
|
||||
) {
|
||||
this.sessionHandler.setLoginHandler(handler);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,6 +15,7 @@ import type { ChatMessage } from '../../agents/qwenAgentManager.js';
|
||||
export class SessionMessageHandler extends BaseMessageHandler {
|
||||
private currentStreamContent = '';
|
||||
private isSavingCheckpoint = false;
|
||||
private loginHandler: (() => Promise<void>) | null = null;
|
||||
|
||||
canHandle(messageType: string): boolean {
|
||||
return [
|
||||
@@ -27,6 +28,13 @@ export class SessionMessageHandler extends BaseMessageHandler {
|
||||
].includes(messageType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set login handler
|
||||
*/
|
||||
setLoginHandler(handler: () => Promise<void>): void {
|
||||
this.loginHandler = handler;
|
||||
}
|
||||
|
||||
async handle(message: { type: string; data?: unknown }): Promise<void> {
|
||||
const data = message.data as Record<string, unknown> | undefined;
|
||||
|
||||
@@ -231,13 +239,23 @@ export class SessionMessageHandler extends BaseMessageHandler {
|
||||
if (!this.agentManager.isConnected) {
|
||||
console.warn('[SessionMessageHandler] Agent not connected');
|
||||
|
||||
// Show non-modal notification with Login button
|
||||
const result = await vscode.window.showWarningMessage(
|
||||
'You need to login first to use Qwen Code.',
|
||||
'Login Now',
|
||||
);
|
||||
|
||||
if (result === 'Login Now') {
|
||||
vscode.commands.executeCommand('qwenCode.login');
|
||||
// Use login handler directly
|
||||
if (this.loginHandler) {
|
||||
await this.loginHandler();
|
||||
} else {
|
||||
// Fallback to command
|
||||
vscode.window.showInformationMessage(
|
||||
'Please wait while we connect to Qwen Code...',
|
||||
);
|
||||
await vscode.commands.executeCommand('qwenCode.login');
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -109,36 +109,12 @@ export function useCompletionTrigger(
|
||||
const handleInput = async () => {
|
||||
const text = inputElement.textContent || '';
|
||||
const selection = window.getSelection();
|
||||
|
||||
console.log(
|
||||
'[useCompletionTrigger] handleInput - text:',
|
||||
JSON.stringify(text),
|
||||
'length:',
|
||||
text.length,
|
||||
);
|
||||
|
||||
if (!selection || selection.rangeCount === 0) {
|
||||
console.log('[useCompletionTrigger] No selection or rangeCount === 0');
|
||||
return;
|
||||
}
|
||||
|
||||
const range = selection.getRangeAt(0);
|
||||
console.log(
|
||||
'[useCompletionTrigger] range.startContainer:',
|
||||
range.startContainer,
|
||||
'startOffset:',
|
||||
range.startOffset,
|
||||
);
|
||||
console.log(
|
||||
'[useCompletionTrigger] startContainer === inputElement:',
|
||||
range.startContainer === inputElement,
|
||||
);
|
||||
console.log(
|
||||
'[useCompletionTrigger] startContainer.nodeType:',
|
||||
range.startContainer.nodeType,
|
||||
'TEXT_NODE:',
|
||||
Node.TEXT_NODE,
|
||||
);
|
||||
|
||||
// Get cursor position more reliably
|
||||
// For contentEditable, we need to calculate the actual text offset
|
||||
@@ -157,14 +133,6 @@ export function useCompletionTrigger(
|
||||
offset += inputElement.childNodes[i].textContent?.length || 0;
|
||||
}
|
||||
cursorPosition = offset || text.length;
|
||||
console.log(
|
||||
'[useCompletionTrigger] Container mode - childIndex:',
|
||||
childIndex,
|
||||
'offset:',
|
||||
offset,
|
||||
'cursorPosition:',
|
||||
cursorPosition,
|
||||
);
|
||||
} else if (range.startContainer.nodeType === Node.TEXT_NODE) {
|
||||
// Cursor is in a text node - calculate offset from start of input
|
||||
const walker = document.createTreeWalker(
|
||||
@@ -187,40 +155,17 @@ export function useCompletionTrigger(
|
||||
}
|
||||
// If we found the node, use the calculated offset; otherwise use text length
|
||||
cursorPosition = found ? offset : text.length;
|
||||
console.log(
|
||||
'[useCompletionTrigger] Text node mode - found:',
|
||||
found,
|
||||
'offset:',
|
||||
offset,
|
||||
'cursorPosition:',
|
||||
cursorPosition,
|
||||
);
|
||||
}
|
||||
|
||||
// Find trigger character before cursor
|
||||
// Use text length if cursorPosition is 0 but we have text (edge case for first character)
|
||||
const effectiveCursorPosition =
|
||||
cursorPosition === 0 && text.length > 0 ? text.length : cursorPosition;
|
||||
console.log(
|
||||
'[useCompletionTrigger] cursorPosition:',
|
||||
cursorPosition,
|
||||
'effectiveCursorPosition:',
|
||||
effectiveCursorPosition,
|
||||
);
|
||||
|
||||
const textBeforeCursor = text.substring(0, effectiveCursorPosition);
|
||||
const lastAtMatch = textBeforeCursor.lastIndexOf('@');
|
||||
const lastSlashMatch = textBeforeCursor.lastIndexOf('/');
|
||||
|
||||
console.log(
|
||||
'[useCompletionTrigger] textBeforeCursor:',
|
||||
JSON.stringify(textBeforeCursor),
|
||||
'lastAtMatch:',
|
||||
lastAtMatch,
|
||||
'lastSlashMatch:',
|
||||
lastSlashMatch,
|
||||
);
|
||||
|
||||
// Check if we're in a trigger context
|
||||
let triggerPos = -1;
|
||||
let triggerChar: '@' | '/' | null = null;
|
||||
@@ -233,46 +178,19 @@ export function useCompletionTrigger(
|
||||
triggerChar = '/';
|
||||
}
|
||||
|
||||
console.log(
|
||||
'[useCompletionTrigger] triggerPos:',
|
||||
triggerPos,
|
||||
'triggerChar:',
|
||||
triggerChar,
|
||||
);
|
||||
|
||||
// Check if trigger is at word boundary (start of line or after space)
|
||||
if (triggerPos >= 0 && triggerChar) {
|
||||
const charBefore = triggerPos > 0 ? text[triggerPos - 1] : ' ';
|
||||
const isValidTrigger =
|
||||
charBefore === ' ' || charBefore === '\n' || triggerPos === 0;
|
||||
|
||||
console.log(
|
||||
'[useCompletionTrigger] charBefore:',
|
||||
JSON.stringify(charBefore),
|
||||
'isValidTrigger:',
|
||||
isValidTrigger,
|
||||
);
|
||||
|
||||
if (isValidTrigger) {
|
||||
const query = text.substring(triggerPos + 1, effectiveCursorPosition);
|
||||
|
||||
console.log(
|
||||
'[useCompletionTrigger] query:',
|
||||
JSON.stringify(query),
|
||||
'hasSpace:',
|
||||
query.includes(' '),
|
||||
'hasNewline:',
|
||||
query.includes('\n'),
|
||||
);
|
||||
|
||||
// Only show if query doesn't contain spaces (still typing the reference)
|
||||
if (!query.includes(' ') && !query.includes('\n')) {
|
||||
// Get precise cursor position for menu
|
||||
const cursorPos = getCursorPosition();
|
||||
console.log(
|
||||
'[useCompletionTrigger] Opening completion - cursorPos:',
|
||||
cursorPos,
|
||||
);
|
||||
if (cursorPos) {
|
||||
await openCompletion(triggerChar, query, cursorPos);
|
||||
return;
|
||||
@@ -282,10 +200,6 @@ export function useCompletionTrigger(
|
||||
}
|
||||
|
||||
// Close if no valid trigger
|
||||
console.log(
|
||||
'[useCompletionTrigger] No valid trigger, state.isOpen:',
|
||||
state.isOpen,
|
||||
);
|
||||
if (state.isOpen) {
|
||||
closeCompletion();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user