= {
+ "X-User-ID": userId,
+};
+if (apiKey) headers["Authorization"] = `Bearer ${apiKey}`;
+
+const response = await fetch(`${serverUrl}/feedback/profile`, { headers });
+```
+
+**Endpoint:** `GET /feedback/profile`
+
+**Headers:**
+- `X-User-ID`: Hashed user identifier
+- `Authorization`: Bearer token (if configured)
+
+**Response:**
+```json
+{
+ "user_id": "e3b0c442",
+ "coding_style": {
+ "indent_size": 4,
+ "uses_tabs": false,
+ "total_samples": 42,
+ ...
+ },
+ "accept_rate": 0.85,
+ "avg_accept_time_ms": 450.0,
+ ...
+}
+```
+
+---
+
+#### Create Webview Panel
+
+```typescript
+const panel = vscode.window.createWebviewPanel(
+ 'btlProfile', // View type ID
+ 'My Coding Profile', // Panel title
+ vscode.ViewColumn.One, // Show in first column
+ {} // Options (empty)
+);
+```
+
+**Creates new tab** with HTML content
+
+---
+
+#### Webview HTML
+
+```typescript
+panel.webview.html = `
+
+
+
+
+
+
+ 🤖 Your Coding Profile
+ User ID: ${userId}
+ Total Samples: ${profile.coding_style?.total_samples || 0}
+ Indent: ${profile.coding_style?.uses_tabs ? 'Tabs' : profile.coding_style?.indent_size + ' spaces'}
+ Quotes: ${profile.coding_style?.prefer_double_quotes ? 'Double' : 'Single'}
+ Naming: ${profile.coding_style?.snake_case_ratio > 0.5 ? 'snake_case' : 'camelCase'}
+ Type Hints: ${(profile.coding_style?.type_hints_ratio * 100).toFixed(0)}%
+ Docstrings: ${(profile.coding_style?.docstring_ratio * 100).toFixed(0)}%
+ Accept Rate: ${(profile.accept_rate * 100).toFixed(1)}%
+ Avg Accept Time: ${profile.avg_accept_time_ms?.toFixed(0) || 'N/A'} ms
+
+
+`;
+```
+
+---
+
+### Phân tích Webview HTML
+
+**Profile display:**
+
+**User ID:**
+```typescript
+${userId}
+// → "e3b0c442f8a3b1d9"
+```
+
+**Total Samples:**
+```typescript
+${profile.coding_style?.total_samples || 0}
+// → "42"
+```
+
+**Indent Style:**
+```typescript
+${profile.coding_style?.uses_tabs ? 'Tabs' : profile.coding_style?.indent_size + ' spaces'}
+// → "4 spaces" or "Tabs"
+```
+
+**Quotes:**
+```typescript
+${profile.coding_style?.prefer_double_quotes ? 'Double' : 'Single'}
+// → "Single" or "Double"
+```
+
+**Naming Convention:**
+```typescript
+${profile.coding_style?.snake_case_ratio > 0.5 ? 'snake_case' : 'camelCase'}
+// If 60% snake_case → "snake_case"
+// If 30% snake_case → "camelCase"
+```
+
+**Type Hints:**
+```typescript
+${(profile.coding_style?.type_hints_ratio * 100).toFixed(0)}%
+// 0.75 → "75%"
+```
+
+**Docstrings:**
+```typescript
+${(profile.coding_style?.docstring_ratio * 100).toFixed(0)}%
+// 0.42 → "42%"
+```
+
+**Accept Rate:**
+```typescript
+${(profile.accept_rate * 100).toFixed(1)}%
+// 0.854 → "85.4%"
+```
+
+**Avg Accept Time:**
+```typescript
+${profile.avg_accept_time_ms?.toFixed(0) || 'N/A'} ms
+// 450.5 → "451 ms"
+// null → "N/A"
+```
+
+---
+
+#### Error Handling
+
+```typescript
+} catch (err) {
+ vscode.window.showErrorMessage(`Failed to load profile: ${err}`);
+}
+```
+
+**Shows popup** if fetch fails
+
+---
+
+### Step 9: Register Clear Profile Command
+
+```typescript
+// Clear coding profile
+context.subscriptions.push(
+ vscode.commands.registerCommand("btl.clearProfile", async () => {
+ const userId = (provider as any).userId;
+ if (!userId) {
+ vscode.window.showWarningMessage("Personalization is disabled");
+ return;
+ }
+
+ const confirm = await vscode.window.showWarningMessage(
+ "Delete your coding profile? This cannot be undone.",
+ { modal: true },
+ "Delete"
+ );
+
+ if (confirm !== "Delete") return;
+
+ try {
+ const headers: Record = {
+ "X-User-ID": userId,
+ };
+ if (apiKey) headers["Authorization"] = `Bearer ${apiKey}`;
+
+ const response = await fetch(`${serverUrl}/feedback/profile`, {
+ method: "DELETE",
+ headers
+ });
+
+ if (!response.ok) {
+ throw new Error(`HTTP ${response.status}`);
+ }
+
+ vscode.window.showInformationMessage("Coding profile deleted successfully");
+ } catch (err) {
+ vscode.window.showErrorMessage(`Failed to delete profile: ${err}`);
+ }
+ })
+);
+```
+
+---
+
+### Phân tích Clear Profile
+
+**Command ID:** `"btl.clearProfile"`
+
+**Purpose:** Delete user profile (GDPR compliance!)
+
+---
+
+#### Confirmation Dialog
+
+```typescript
+const confirm = await vscode.window.showWarningMessage(
+ "Delete your coding profile? This cannot be undone.",
+ { modal: true },
+ "Delete"
+);
+
+if (confirm !== "Delete") return;
+```
+
+**Modal dialog:**
+```
+⚠ Delete your coding profile? This cannot be undone.
+ [Cancel] [Delete]
+```
+
+**`modal: true`:**
+- Blocks VS Code UI
+- User must respond
+- Prevents accidental deletion
+
+**Return value:**
+- User clicks "Delete" → `confirm = "Delete"`
+- User clicks "Cancel" or ESC → `confirm = undefined`
+
+---
+
+#### Send DELETE Request
+
+```typescript
+const response = await fetch(`${serverUrl}/feedback/profile`, {
+ method: "DELETE",
+ headers
+});
+```
+
+**Endpoint:** `DELETE /feedback/profile`
+
+**Backend action:**
+- Deletes `data/user_profiles/{user_id}.json`
+- Returns 200 OK
+
+---
+
+#### Success Message
+
+```typescript
+vscode.window.showInformationMessage("Coding profile deleted successfully");
+```
+
+**Notification:**
+```
+ℹ Coding profile deleted successfully
+```
+
+---
+
+## 🔚 Function: `deactivate()`
+
+### Purpose
+**Called when extension is deactivated**
+
+### Code
+
+```typescript
+export function deactivate() {}
+```
+
+**Currently empty** - cleanup handled automatically by `context.subscriptions`
+
+**Could add:**
+- Save pending data
+- Close connections
+- Log deactivation
+
+---
+
+## 💡 Key Points cho thuyết trình
+
+### 1. Extension Activation Flow
+
+```
+VS Code starts
+ ↓
+Reads package.json
+ ↓
+Checks activationEvents: ["onLanguage:python", "onLanguage:cpp"]
+ ↓
+User opens Python/C++ file
+ ↓
+activate() called
+ ↓
+Load config → Create provider → Register commands
+ ↓
+Extension ready! 🎉
+```
+
+---
+
+### 2. Configuration Priority System
+
+**Three-tier fallback:**
+
+```typescript
+value = userSetting ?? envVariable ?? defaultValue
+```
+
+**Example:**
+
+| Source | Priority | Use Case |
+|--------|----------|----------|
+| VS Code Settings | 1 (highest) | User preference |
+| Environment Variable | 2 | CI/CD, Docker |
+| Default Value | 3 (fallback) | Out-of-box |
+
+**Benefits:**
+- ✅ Flexible deployment
+- ✅ User control
+- ✅ Works without config
+
+---
+
+### 3. Document Selector Design
+
+**Why explicit selectors?**
+
+```typescript
+[
+ { language: "python", scheme: "file" },
+ { language: "python", scheme: "untitled" },
+ ...
+]
+```
+
+**Alternatives (not used):**
+
+**Option 1: Wildcard (not supported)**
+```typescript
+{ language: "*", scheme: "*" } ❌
+```
+
+**Option 2: Array of languages (not supported)**
+```typescript
+{ language: ["python", "cpp"], scheme: "file" } ❌
+```
+
+**Current approach (correct):**
+```typescript
+[
+ { language: "python", scheme: "file" },
+ { language: "cpp", scheme: "file" },
+] ✅
+```
+
+---
+
+### 4. Command Registration Pattern
+
+**Standard pattern:**
+
+```typescript
+context.subscriptions.push(
+ vscode.commands.registerCommand("command.id", async (...args) => {
+ // Command logic
+ })
+);
+```
+
+**Benefits:**
+- Auto-cleanup on deactivation
+- Memory leak prevention
+- Proper lifecycle management
+
+**Our commands:**
+- `btl.trackAcceptance` - Feedback tracking
+- `btl.inlineSuggest` - Manual trigger
+- `btl.testCompletion` - Debug/test
+- `btl.viewProfile` - Show profile UI
+- `btl.clearProfile` - Delete data (GDPR)
+
+---
+
+### 5. Webview for Profile Display
+
+**Why webview?**
+
+**Alternatives:**
+
+**Option 1: QuickPick (limited)**
+```typescript
+vscode.window.showQuickPick([
+ "Indent: 4 spaces",
+ "Accept rate: 85%"
+])
+```
+❌ No styling, no layout
+
+**Option 2: Output Channel (ugly)**
+```typescript
+outputChannel.appendLine("Indent: 4 spaces")
+```
+❌ Plain text only
+
+**Option 3: Webview (chosen) ✅**
+```typescript
+panel.webview.html = `...`
+```
+✅ Full HTML/CSS
+✅ Rich formatting
+✅ Interactive (could add buttons)
+
+---
+
+### 6. Privacy & GDPR Compliance
+
+**Features:**
+
+**Anonymous User ID:**
+```typescript
+machineId → SHA256 → "e3b0c442..."
+```
+- Can't identify user
+- Persistent per machine
+- No personal data stored
+
+**Clear Profile Command:**
+```typescript
+vscode.commands.registerCommand("btl.clearProfile", ...)
+```
+- User can delete all data
+- Confirmation dialog
+- Complies with GDPR "right to erasure"
+
+**Opt-out Option:**
+```json
+// settings.json
+"btl.enablePersonalization": false
+```
+- Disables user tracking
+- No profile created
+- Privacy-first design
+
+---
+
+## 🧪 Test Cases
+
+### Test 1: Extension activates
+
+```typescript
+import * as vscode from 'vscode';
+import * as myExtension from '../extension';
+
+suite('Extension Test Suite', () => {
+ test('Extension should activate', async () => {
+ const ext = vscode.extensions.getExtension('your-publisher.btl-python');
+ assert.ok(ext);
+ await ext?.activate();
+ assert.strictEqual(ext?.isActive, true);
+ });
+});
+```
+
+---
+
+### Test 2: Configuration loading
+
+```typescript
+test('Should load configuration with defaults', () => {
+ const config = vscode.workspace.getConfiguration('btl');
+
+ // Should have default serverUrl if not configured
+ const serverUrl = config.get('serverUrl') ?? 'https://btl-python-r9kz.onrender.com';
+ assert.ok(serverUrl.startsWith('http'));
+
+ // Should have default timeout
+ const timeout = config.get('timeoutMs') ?? 15000;
+ assert.strictEqual(timeout >= 1000, true);
+});
+```
+
+---
+
+### Test 3: Commands registered
+
+```typescript
+test('Commands should be registered', async () => {
+ const commands = await vscode.commands.getCommands();
+
+ assert.ok(commands.includes('btl.trackAcceptance'));
+ assert.ok(commands.includes('btl.inlineSuggest'));
+ assert.ok(commands.includes('btl.testCompletion'));
+ assert.ok(commands.includes('btl.viewProfile'));
+ assert.ok(commands.includes('btl.clearProfile'));
+});
+```
+
+---
+
+### Test 4: Provider registration
+
+```typescript
+test('Inline completion provider should be registered', async () => {
+ const doc = await vscode.workspace.openTextDocument({
+ language: 'python',
+ content: 'def add('
+ });
+
+ const editor = await vscode.window.showTextDocument(doc);
+ const position = new vscode.Position(0, 8);
+
+ // Trigger completion
+ await vscode.commands.executeCommand('editor.action.inlineSuggest.trigger');
+
+ // Should have completions available (if server is running)
+ // Note: Hard to test without mocking server
+});
+```
+
+---
+
+### Test 5: View profile command
+
+```typescript
+test('View profile command should open webview', async () => {
+ // This test requires mocking fetch and provider
+ const originalFetch = global.fetch;
+
+ global.fetch = async () => ({
+ ok: true,
+ json: async () => ({
+ coding_style: {
+ indent_size: 4,
+ total_samples: 10
+ },
+ accept_rate: 0.8
+ })
+ }) as any;
+
+ try {
+ await vscode.commands.executeCommand('btl.viewProfile');
+ // Webview should be created
+ // Hard to assert without access to webview internals
+ } finally {
+ global.fetch = originalFetch;
+ }
+});
+```
+
+---
+
+### Test 6: Deactivation cleanup
+
+```typescript
+test('Extension should cleanup on deactivate', async () => {
+ const ext = vscode.extensions.getExtension('your-publisher.btl-python');
+ await ext?.activate();
+
+ const commandsBefore = await vscode.commands.getCommands();
+ assert.ok(commandsBefore.includes('btl.testCompletion'));
+
+ // Deactivate
+ if (ext?.exports?.deactivate) {
+ await ext.exports.deactivate();
+ }
+
+ // Commands should still be there (VS Code handles cleanup)
+ // But provider should be disposed
+});
+```
+
+---
+
+**File extension.ts hoàn tất!** ✅
+
+**Tiếp theo:** `inlineProvider.ts` - The CORE logic file (684 lines!) 🚀
+
+Tiếp tục không?
+
diff --git a/explaincode/src/02_inlineProvider.ts.md b/explaincode/src/02_inlineProvider.ts.md
new file mode 100644
index 0000000..2396766
--- /dev/null
+++ b/explaincode/src/02_inlineProvider.ts.md
@@ -0,0 +1,3008 @@
+# Giải thích chi tiết: `src/inlineProvider.ts`
+
+## 📋 Mục đích của file
+
+File này implement **InlineCompletionItemProvider** - CORE LOGIC:
+1. **Provide inline completions** khi user đang gõ code
+2. **Smart indentation** (tabs/spaces, auto-indent)
+3. **Comment-to-code generation** (từ comment → code)
+4. **Import detection** (detect missing imports)
+5. **Deduplication** (remove repeated code)
+6. **Feedback tracking** (acceptance/rejection)
+7. **Streaming support** (SSE for real-time)
+8. **User personalization** (SHA-256 hashed user ID)
+
+**Đây là FILE QUAN TRỌNG NHẤT** của extension! 🎯
+
+---
+
+## 🔍 Phân tích từng phần
+
+### Import statements
+
+```typescript
+import * as vscode from 'vscode';
+import * as crypto from 'crypto';
+```
+
+**Giải thích:**
+- `vscode`: VS Code Extension API
+- `crypto`: SHA-256 hashing for user ID
+
+---
+
+### Constants
+
+```typescript
+const DEFAULT_STOPS_PY = ["\n\n", "\n\n```", "\n\n##", "\n\n# ", "\n\n\"\"\"", "\n\n'''"];
+const DEFAULT_STOPS_CPP = ["\n\n", "\n\n```", "\n\n//", "\n\n/*", "\n\n#endif"];
+const DEFAULT_TEMPERATURE = 0.2; // Lower for more deterministic code
+const DEFAULT_MAX_TOKENS = 300; // Longer for multi-line completions
+const MAX_SIDE_CHARS = 8000; // More context
+```
+
+---
+
+### Phân tích Constants
+
+#### Stop Sequences (Python)
+
+```typescript
+const DEFAULT_STOPS_PY = ["\n\n", "\n\n```", "\n\n##", "\n\n# ", "\n\n\"\"\"", "\n\n'''"];
+```
+
+**Purpose:** Tell LLM when to stop generating
+
+**Each stop:**
+
+**`"\n\n"`** - Double newline
+```python
+def add(a, b):
+ return a + b
+
+← Stop here (function complete)
+```
+
+**`"\n\n```"`** - Markdown fence
+```python
+def add(a, b):
+ return a + b
+
+```← Stop (prevents markdown)
+```
+
+**`"\n\n##"`** - Markdown heading
+```python
+def add(a, b):
+ return a + b
+
+## ← Stop (prevents markdown heading)
+```
+
+**`"\n\n# "`** - Comment section
+```python
+def add(a, b):
+ return a + b
+
+# ← Stop (new section starts)
+```
+
+**`"\n\n\"\"\""`** - Docstring
+```python
+def add(a, b):
+ return a + b
+
+"""← Stop (new docstring)
+```
+
+**`"\n\n'''"`** - Alt docstring
+```python
+def add(a, b):
+ return a + b
+
+'''← Stop
+```
+
+---
+
+#### Stop Sequences (C++)
+
+```typescript
+const DEFAULT_STOPS_CPP = ["\n\n", "\n\n```", "\n\n//", "\n\n/*", "\n\n#endif"];
+```
+
+**C++-specific stops:**
+
+**`"\n\n//"`** - Single-line comment
+```cpp
+int add(int a, int b) {
+ return a + b;
+}
+
+// ← Stop (new section)
+```
+
+**`"\n\n/*"`** - Multi-line comment
+```cpp
+int add(int a, int b) {
+ return a + b;
+}
+
+/*← Stop
+```
+
+**`"\n\n#endif"`** - Preprocessor directive
+```cpp
+int add(int a, int b) {
+ return a + b;
+}
+
+#endif ← Stop (end of header guard)
+```
+
+---
+
+#### Temperature
+
+```typescript
+const DEFAULT_TEMPERATURE = 0.2;
+```
+
+**Low temperature for code:**
+- 0.0 = Completely deterministic (always same output)
+- 0.2 = Slight variation (good for code) ✅
+- 0.5 = Balanced
+- 1.0 = Very creative (bad for code)
+
+**Why 0.2?**
+- Code needs consistency
+- Math/logic should be deterministic
+- But allow some variation for variable names
+
+---
+
+#### Max Tokens
+
+```typescript
+const DEFAULT_MAX_TOKENS = 300;
+```
+
+**300 tokens ≈ 200-250 words**
+
+**Enough for:**
+- Multi-line functions (10-20 lines)
+- Class methods
+- Complex logic
+
+**Not enough for:**
+- Entire classes (would need 1000+)
+- Multiple functions (by design!)
+
+---
+
+#### Context Window
+
+```typescript
+const MAX_SIDE_CHARS = 8000;
+```
+
+**8000 chars ≈ 100-150 lines of code**
+
+**Split evenly:**
+- Prefix: 8000 chars max
+- Suffix: 8000 chars max
+- Total context: 16,000 chars
+
+**Why limit?**
+- LLM context window limits (4096-8192 tokens)
+- API payload size limits
+- Performance (less to process)
+
+---
+
+## 🆔 Function: `getUserId()`
+
+### Purpose
+**Generate anonymous user ID** from machine ID
+
+### Code
+
+```typescript
+function getUserId(): string {
+ const machineId = vscode.env.machineId;
+ const hash = crypto.createHash('sha256').update(machineId).digest('hex');
+ return hash.substring(0, 16); // Use first 16 chars for brevity
+}
+```
+
+---
+
+### Phân tích Step-by-Step
+
+#### Get Machine ID
+
+```typescript
+const machineId = vscode.env.machineId;
+```
+
+**VS Code provides unique machine ID:**
+- Persistent per installation
+- Same across VS Code restarts
+- Changes if reinstall VS Code
+- Example: `"550e8400-e29b-41d4-a716-446655440000"`
+
+---
+
+#### SHA-256 Hashing
+
+```typescript
+const hash = crypto.createHash('sha256').update(machineId).digest('hex');
+```
+
+**Process:**
+```
+machineId = "550e8400-e29b-41d4-a716-446655440000"
+ ↓
+SHA-256 hash
+ ↓
+hash = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+```
+
+**Properties:**
+- ✅ One-way (can't reverse)
+- ✅ Deterministic (same input → same output)
+- ✅ Unique (different inputs → different hashes)
+- ✅ Anonymous (can't identify user)
+
+---
+
+#### Truncate to 16 chars
+
+```typescript
+return hash.substring(0, 16);
+```
+
+**Result:**
+```
+"e3b0c44298fc1c14"
+```
+
+**Why 16 chars?**
+- Still very unique (2^64 combinations)
+- Shorter for logs
+- Easier to read
+- Saves bandwidth
+
+---
+
+## 📏 Function: `detectIndentation()`
+
+### Purpose
+**Detect editor's indent settings** (tabs vs spaces, size)
+
+### Code
+
+```typescript
+function detectIndentation(doc: vscode.TextDocument): { char: string, size: number } {
+ const config = vscode.workspace.getConfiguration('editor', doc.uri);
+ const insertSpaces = config.get('insertSpaces', true);
+ const tabSize = config.get('tabSize', 4);
+
+ if (insertSpaces) {
+ return { char: ' ', size: tabSize };
+ }
+ return { char: '\t', size: 1 };
+}
+```
+
+---
+
+### Phân tích
+
+#### Get Editor Config
+
+```typescript
+const config = vscode.workspace.getConfiguration('editor', doc.uri);
+```
+
+**Reads settings.json:**
+```json
+{
+ "editor.insertSpaces": true,
+ "editor.tabSize": 4
+}
+```
+
+**Per-document URI:**
+- Can have different settings per file
+- Respects `.editorconfig`
+- Language-specific overrides
+
+---
+
+#### Check Insert Spaces
+
+```typescript
+const insertSpaces = config.get('insertSpaces', true);
+```
+
+**Default:** `true` (use spaces)
+
+**Options:**
+- `true`: Tab key inserts spaces
+- `false`: Tab key inserts tab character
+
+---
+
+#### Get Tab Size
+
+```typescript
+const tabSize = config.get('tabSize', 4);
+```
+
+**Default:** 4 spaces
+
+**Common values:**
+- 2 spaces (JavaScript, Google style)
+- 4 spaces (Python PEP 8)
+- 8 spaces (Go, Linux kernel)
+
+---
+
+#### Return Indent Info
+
+```typescript
+if (insertSpaces) {
+ return { char: ' ', size: tabSize };
+}
+return { char: '\t', size: 1 };
+```
+
+**Examples:**
+
+**Spaces (insertSpaces=true, tabSize=4):**
+```typescript
+{ char: ' ', size: 4 }
+// One indent level = " " (4 spaces)
+```
+
+**Tabs (insertSpaces=false):**
+```typescript
+{ char: '\t', size: 1 }
+// One indent level = "\t" (1 tab char)
+```
+
+---
+
+## 📐 Function: `getIndentFromLine()`
+
+### Purpose
+**Extract indent string** from line start
+
+### Code
+
+```typescript
+function getIndentFromLine(line: string): string {
+ const match = line.match(/^(\s*)/);
+ return match ? match[1] : '';
+}
+```
+
+---
+
+### Phân tích
+
+#### Regex: `^(\s*)`
+
+**Breakdown:**
+- `^` - Start of string
+- `(\s*)` - Capture group: zero or more whitespace
+- Matches all leading whitespace
+
+**Examples:**
+
+```typescript
+getIndentFromLine(" return True")
+// → " " (4 spaces)
+
+getIndentFromLine("\t\treturn True")
+// → "\t\t" (2 tabs)
+
+getIndentFromLine("return True")
+// → "" (no indent)
+
+getIndentFromLine(" \t x = 10")
+// → " \t " (mixed spaces and tabs)
+```
+
+---
+
+## 🔢 Function: `getIndentLevel()`
+
+### Purpose
+**Calculate indent level** (number of indent units)
+
+### Code
+
+```typescript
+function getIndentLevel(indent: string, indentChar: string, indentSize: number): number {
+ if (indentChar === '\t') {
+ return indent.split('\t').length - 1;
+ }
+ return Math.floor(indent.length / indentSize);
+}
+```
+
+---
+
+### Phân tích
+
+#### Tab-based Indentation
+
+```typescript
+if (indentChar === '\t') {
+ return indent.split('\t').length - 1;
+}
+```
+
+**Examples:**
+
+```typescript
+// One tab:
+indent = "\t"
+indent.split('\t') = ["", ""]
+length = 2
+level = 2 - 1 = 1 ✅
+
+// Two tabs:
+indent = "\t\t"
+indent.split('\t') = ["", "", ""]
+length = 3
+level = 3 - 1 = 2 ✅
+
+// Three tabs:
+indent = "\t\t\t"
+indent.split('\t') = ["", "", "", ""]
+level = 4 - 1 = 3 ✅
+```
+
+---
+
+#### Space-based Indentation
+
+```typescript
+return Math.floor(indent.length / indentSize);
+```
+
+**Examples:**
+
+```typescript
+// 4 spaces, indent size = 4:
+indent = " "
+level = Math.floor(4 / 4) = 1 ✅
+
+// 8 spaces, indent size = 4:
+indent = " "
+level = Math.floor(8 / 4) = 2 ✅
+
+// 6 spaces, indent size = 4 (partial):
+indent = " "
+level = Math.floor(6 / 4) = 1 (not 2!)
+```
+
+**Math.floor()** handles incomplete indents:
+- 0-3 spaces = level 0
+- 4-7 spaces = level 1
+- 8-11 spaces = level 2
+
+---
+
+## 🔨 Function: `makeIndent()`
+
+### Purpose
+**Create indent string** from level
+
+### Code
+
+```typescript
+function makeIndent(level: number, indentChar: string, indentSize: number): string {
+ if (indentChar === '\t') {
+ return '\t'.repeat(level);
+ }
+ return ' '.repeat(level * indentSize);
+}
+```
+
+---
+
+### Phân tích
+
+**Inverse of `getIndentLevel()`**
+
+#### Tabs
+
+```typescript
+if (indentChar === '\t') {
+ return '\t'.repeat(level);
+}
+```
+
+**Examples:**
+```typescript
+makeIndent(0, '\t', 1) // → ""
+makeIndent(1, '\t', 1) // → "\t"
+makeIndent(2, '\t', 1) // → "\t\t"
+makeIndent(3, '\t', 1) // → "\t\t\t"
+```
+
+---
+
+#### Spaces
+
+```typescript
+return ' '.repeat(level * indentSize);
+```
+
+**Examples:**
+```typescript
+makeIndent(0, ' ', 4) // → ""
+makeIndent(1, ' ', 4) // → " " (4 spaces)
+makeIndent(2, ' ', 4) // → " " (8 spaces)
+makeIndent(3, ' ', 4) // → " " (12 spaces)
+```
+
+---
+
+## 💬 Function: `detectCommentIntent()`
+
+### Purpose
+**Detect comment-to-code generation** intent
+
+### Code (simplified)
+
+```typescript
+function detectCommentIntent(prefix: string, language: string): { isComment: boolean, instruction: string } {
+ const lines = prefix.split('\n');
+ const lastLine = lines[lines.length - 1] || '';
+ const prevLine = lines[lines.length - 2] || '';
+
+ // Python comments
+ if (language === 'python') {
+ // Single line: # TODO: implement this function
+ if (lastLine.trim().startsWith('#')) {
+ return { isComment: true, instruction: lastLine.trim().substring(1).trim() };
+ }
+ // Docstring: """Calculate sum of numbers"""
+ const docMatch = prefix.match(/"""([^"]+)"""\s*$/s) || prefix.match(/'''([^']+)'''\s*$/s);
+ if (docMatch) {
+ return { isComment: true, instruction: docMatch[1].trim() };
+ }
+ }
+
+ // C++ comments
+ if (language === 'cpp' || language === 'c') {
+ // Single line: // TODO: implement addition
+ if (lastLine.trim().startsWith('//')) {
+ return { isComment: true, instruction: lastLine.trim().substring(2).trim() };
+ }
+ // Multi-line: /* Calculate factorial */
+ const multiMatch = prefix.match(/\/\*([^*]+)\*\/\s*$/s);
+ if (multiMatch) {
+ return { isComment: true, instruction: multiMatch[1].trim() };
+ }
+ }
+
+ return { isComment: false, instruction: '' };
+}
+```
+
+---
+
+### Phân tích Comment Detection
+
+#### Python Single-Line Comment
+
+```typescript
+if (lastLine.trim().startsWith('#')) {
+ return { isComment: true, instruction: lastLine.trim().substring(1).trim() };
+}
+```
+
+**Example:**
+```python
+# Calculate factorial of n
+← Cursor here
+```
+
+**Detection:**
+```typescript
+lastLine = "# Calculate factorial of n"
+lastLine.trim() = "# Calculate factorial of n"
+startsWith('#') = true ✅
+
+instruction = lastLine.substring(1).trim()
+instruction = " Calculate factorial of n".trim()
+instruction = "Calculate factorial of n"
+
+return { isComment: true, instruction: "Calculate factorial of n" }
+```
+
+---
+
+#### Python Docstring
+
+```typescript
+const docMatch = prefix.match(/"""([^"]+)"""\s*$/s) || prefix.match(/'''([^']+)'''\s*$/s);
+if (docMatch) {
+ return { isComment: true, instruction: docMatch[1].trim() };
+}
+```
+
+**Example:**
+```python
+def calculate():
+ """Calculate sum of all numbers"""
+ ← Cursor here
+```
+
+**Detection:**
+```typescript
+prefix ends with: """Calculate sum of all numbers"""
+
+docMatch = /"""([^"]+)"""\s*$/s
+// Captures: "Calculate sum of all numbers"
+
+instruction = "Calculate sum of all numbers"
+return { isComment: true, instruction: "Calculate sum of all numbers" }
+```
+
+---
+
+#### C++ Single-Line Comment
+
+```typescript
+if (lastLine.trim().startsWith('//')) {
+ return { isComment: true, instruction: lastLine.trim().substring(2).trim() };
+}
+```
+
+**Example:**
+```cpp
+// Implement binary search
+← Cursor here
+```
+
+**Detection:**
+```typescript
+lastLine = "// Implement binary search"
+startsWith('//') = true ✅
+
+instruction = lastLine.substring(2).trim()
+instruction = " Implement binary search".trim()
+instruction = "Implement binary search"
+```
+
+---
+
+#### C++ Multi-Line Comment
+
+```typescript
+const multiMatch = prefix.match(/\/\*([^*]+)\*\/\s*$/s);
+if (multiMatch) {
+ return { isComment: true, instruction: multiMatch[1].trim() };
+}
+```
+
+**Example:**
+```cpp
+/* Calculate GCD of two numbers */
+← Cursor here
+```
+
+**Detection:**
+```typescript
+prefix ends with: /* Calculate GCD of two numbers */
+
+multiMatch = /\/\*([^*]+)\*\/\s*$/s
+// Captures: " Calculate GCD of two numbers "
+
+instruction = " Calculate GCD of two numbers ".trim()
+instruction = "Calculate GCD of two numbers"
+```
+
+---
+
+### Use Case: Comment-to-Code
+
+**Without detection:**
+```python
+# Calculate factorial
+← LLM generates: "# Calculate factorial" (repeats comment!)
+```
+
+**With detection:**
+```python
+# Calculate factorial
+← LLM generates actual implementation:
+def factorial(n):
+ if n <= 1:
+ return 1
+ return n * factorial(n - 1)
+```
+
+**Backend receives:**
+```json
+{
+ "comment_instruction": "Calculate factorial",
+ "prefix": "# Calculate factorial\n",
+ "suffix": ""
+}
+```
+
+---
+
+## 📦 Function: `detectMissingImports()`
+
+### Purpose
+**Detect missing imports** from generated code
+
+### Code (Python part)
+
+```typescript
+function detectMissingImports(completion: string, prefix: string, language: string): string[] {
+ const imports: string[] = [];
+
+ if (language === 'python') {
+ // Find usage patterns like: pd.DataFrame, np.array, os.path
+ const matches = completion.matchAll(/\b([a-z_]+)\.([A-Za-z_][A-Za-z0-9_]*)/g);
+ const usedModules = new Set();
+ for (const match of matches) {
+ usedModules.add(match[1]);
+ }
+
+ // Common module mappings
+ const commonImports: Record = {
+ 'pd': 'import pandas as pd',
+ 'np': 'import numpy as np',
+ 'plt': 'import matplotlib.pyplot as plt',
+ 'os': 'import os',
+ 'sys': 'import sys',
+ 'json': 'import json',
+ 're': 'import re',
+ 'datetime': 'import datetime',
+ 'math': 'import math',
+ };
+
+ // Check which imports are missing
+ for (const mod of usedModules) {
+ const importStatement = commonImports[mod];
+ if (importStatement && !prefix.includes(importStatement)) {
+ imports.push(importStatement);
+ }
+ }
+
+ // Check for direct function usage
+ if (/\bDataFrame\b/.test(completion) && !prefix.includes('pandas')) {
+ if (!imports.some(i => i.includes('pandas'))) {
+ imports.push('import pandas as pd');
+ }
+ }
+ }
+
+ // ... C++ detection ...
+
+ return imports;
+}
+```
+
+---
+
+### Phân tích Import Detection (Python)
+
+#### Pattern Matching
+
+```typescript
+const matches = completion.matchAll(/\b([a-z_]+)\.([A-Za-z_][A-Za-z0-9_]*)/g);
+```
+
+**Regex:** `\b([a-z_]+)\.([A-Za-z_][A-Za-z0-9_]*)`
+
+**Matches:**
+- `pd.DataFrame` → captures `"pd"`
+- `np.array` → captures `"np"`
+- `os.path.join` → captures `"os"`
+
+**Example:**
+```typescript
+completion = "df = pd.DataFrame(data)\narr = np.array([1, 2, 3])"
+
+matches:
+- match[0] = "pd.DataFrame", match[1] = "pd"
+- match[0] = "np.array", match[1] = "np"
+
+usedModules = Set(["pd", "np"])
+```
+
+---
+
+#### Common Module Mappings
+
+```typescript
+const commonImports: Record = {
+ 'pd': 'import pandas as pd',
+ 'np': 'import numpy as np',
+ 'plt': 'import matplotlib.pyplot as plt',
+ ...
+};
+```
+
+**Maps alias → import statement**
+
+**Why needed?**
+```python
+# User uses:
+df = pd.DataFrame(data)
+
+# Need to suggest:
+import pandas as pd ← Not just "import pd"!
+```
+
+---
+
+#### Check Missing Imports
+
+```typescript
+for (const mod of usedModules) {
+ const importStatement = commonImports[mod];
+ if (importStatement && !prefix.includes(importStatement)) {
+ imports.push(importStatement);
+ }
+}
+```
+
+**Logic:**
+1. For each used module (`pd`, `np`, etc.)
+2. Get import statement from mapping
+3. Check if already in prefix (file start)
+4. If not → add to suggestions
+
+**Example:**
+```typescript
+// Completion uses:
+completion = "df = pd.DataFrame(data)"
+
+// Prefix (existing code):
+prefix = "import numpy as np\n\n"
+
+// usedModules = ["pd"]
+// "import pandas as pd" not in prefix ✅
+// → imports = ["import pandas as pd"]
+```
+
+---
+
+#### Direct Class Detection
+
+```typescript
+if (/\bDataFrame\b/.test(completion) && !prefix.includes('pandas')) {
+ if (!imports.some(i => i.includes('pandas'))) {
+ imports.push('import pandas as pd');
+ }
+}
+```
+
+**Handles direct usage:**
+```python
+# Completion:
+df = DataFrame(data) ← No "pd." prefix!
+
+# Still detect pandas needed
+```
+
+---
+
+### C++ Import Detection
+
+```typescript
+if (language === 'cpp' || language === 'c') {
+ // Detect std:: usage
+ if (/std::(vector|string|map|set|cout|cin)/.test(completion)) {
+ if (!prefix.includes('#include ') && /std::(cout|cin|endl)/.test(completion)) {
+ imports.push('#include ');
+ }
+ if (!prefix.includes('#include ') && /std::vector/.test(completion)) {
+ imports.push('#include ');
+ }
+ if (!prefix.includes('#include ') && /std::string/.test(completion)) {
+ imports.push('#include ');
+ }
+ if (!prefix.includes('#include