diff --git a/.gitignore b/.gitignore index 4f5cf1b..8cfa132 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,6 @@ out *.vsix .DS_Store coverage -.nyc_output \ No newline at end of file +.nyc_output +.claude +.vscode \ No newline at end of file diff --git a/.vscodeignore b/.vscodeignore index 7824559..c67421d 100644 --- a/.vscodeignore +++ b/.vscodeignore @@ -41,16 +41,12 @@ scripts/** web/** app/** -# Documentation (keep only essential) -docs/TODO.md -docs/ARCHITECTURE.md -docs/TESTING*.md -docs/DOCUMENTATION_SUMMARY.md -docs/MARKETPLACE_PREP.md -docs/RELEASE_CHECKLIST.md +# Documentation +docs # Git files .gitignore +.github # Build artifacts *.vsix diff --git a/CHANGELOG.md b/CHANGELOG.md index c16af7c..543a6d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,51 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Note templates - Tags and categories +## [0.1.5] - 2025-10-19 + +### Added +- **Auto-collapse all other notes when working on one** - When opening, editing, or viewing a note, ALL other comment threads are automatically collapsed to improve focus and reduce visual clutter + - Only one note is visible at a time for better concentration + - All other notes (both expanded and already collapsed) are ensured to be collapsed + - Temporary threads (new notes being created) are disposed completely + - Editing threads are disposed when switching to another note + - Applies to all interaction methods: keyboard shortcuts, CodeLens, and edit buttons + - Creates a cleaner, more focused editing experience + +### Fixed +- **Keyboard shortcuts now use modern comment UI** (Bug #9) + - `Ctrl+Alt+N` (Add Note) now opens the comment editor instead of a simple input box + - `Ctrl+Alt+H` (View History) now shows history inline in the comment thread instead of opening a separate document + - Provides better UX with markdown support, formatting shortcuts, and Save/Cancel buttons + - Consistent experience across all interaction methods + +- **+ icon comment editor now saves notes** (Bug #10) + - Fixed issue where clicking the + icon in the editor gutter would open a comment editor but Save wouldn't work + - `handleSaveNewNote()` now handles threads created by both our code and VSCode's native + icon + - Falls back to finding the document by URI matching if custom properties aren't set + - Provides clear error messages if document cannot be found + +- **Test coverage configuration** (Bug #8) + - Fixed nyc coverage tool reporting 0% coverage after esbuild migration + - Removed dependency on missing `@istanbuljs/nyc-config-typescript` package + - Updated include path from `out/src/**/*.js` to `out/**/*.js` + - All 41 unit tests continue to pass + +### Changed +- Improved comment thread lifecycle management with better editor state tracking +- Enhanced user experience by preventing multiple simultaneous comment editors +- Updated internal methods: `openCommentEditor()`, `enableEditMode()`, and `focusNoteThread()` to auto-close other editors +- **Improved labels with more relevant information** + - New note editor: "Add your note" (clearer action) + - View/Edit notes: Shows "Last updated [date]" if modified, or "Created [date]" if new + - History entries: Shows action with full timestamp (e.g., "Updated on 10/19/2025 at 2:30:00 PM") + +### Technical +- New `closeAllCommentEditors()` helper method in CommentController +- Better detection of temporary vs. editing vs. viewing thread states +- Improved handling of VSCode's native + icon thread creation +- Continued compatibility with esbuild bundling + ## [0.1.4] - 2025-10-17 ### Changed - ES Module Migration diff --git a/docs/COMMENT_EDITOR_ANALYSIS.md b/docs/COMMENT_EDITOR_ANALYSIS.md new file mode 100644 index 0000000..46873ca --- /dev/null +++ b/docs/COMMENT_EDITOR_ANALYSIS.md @@ -0,0 +1,757 @@ +# Comment Editor Lifecycle Management Analysis + +**Document Date:** October 19, 2025 +**Analysis Scope:** Comment editor creation, tracking, and lifecycle management +**Status:** Complete analysis of current architecture + +--- + +## Executive Summary + +The Code Context Notes extension uses VSCode's native comment thread API for the comment editor UI. The current architecture manages comment editor lifecycle through a combination of: + +1. **Direct thread creation** via `CommentController.openCommentEditor()` +2. **VSCode-managed thread creation** via the + icon in the editor gutter +3. **Temporary thread tracking** using custom properties on thread objects +4. **Cleanup on note save/cancel** via explicit disposal + +There is **no centralized tracking mechanism** for open comment editors. Threads are created on-demand and managed contextually based on how they were created. + +--- + +## Section 1: Comment Editor Creation Points + +### 1.1 Add Note Command (Keyboard Shortcut: Ctrl+Alt+N / Cmd+Alt+N) + +**File:** `/Users/nahian/Projects/code-notes/src/extension.ts` (lines 167-196) + +```typescript +const addNoteCommand = vscode.commands.registerCommand( + 'codeContextNotes.addNote', + async () => { + // ... validation ... + const selection = editor.selection; + const range = new vscode.Range(selection.start.line, 0, selection.end.line, 0); + // Opens comment editor + await commentController.openCommentEditor(editor.document, range); + } +); +``` + +**Triggering Conditions:** +- User has text editor focused: `editorTextFocus` +- User has text selected: `editorHasSelection` +- User presses Ctrl+Alt+N (Windows/Linux) or Cmd+Alt+N (Mac) + +**Flow:** +``` +User presses Ctrl+Alt+N + ↓ +Validates: Has selection + ↓ +Calls: commentController.openCommentEditor(document, range) + ↓ +Comment thread created in expanded state +``` + +--- + +### 1.2 Add Note via CodeLens Command + +**File:** `/Users/nahian/Projects/code-notes/src/extension.ts` (lines 199-213) + +```typescript +const addNoteViaCodeLensCommand = vscode.commands.registerCommand( + 'codeContextNotes.addNoteViaCodeLens', + async (document: vscode.TextDocument, selection: vscode.Selection) => { + const range = new vscode.Range(selection.start.line, 0, selection.end.line, 0); + await commentController.openCommentEditor(document, range); + } +); +``` + +**Triggering Conditions:** +- CodeLens "➕ Add Note" is visible (shown when selection exists and no existing note) +- User clicks on the CodeLens item + +**Flow:** +``` +User clicks "➕ Add Note" CodeLens + ↓ +CodeLens command invoked with document and selection + ↓ +Calls: commentController.openCommentEditor() + ↓ +Comment thread created in expanded state +``` + +--- + +### 1.3 VSCode Native + Icon Comment Creation + +**File:** Not in extension code - managed by VSCode + +**Triggering Conditions:** +- User clicks the + icon in the editor gutter (left margin) +- + icon appears when clicking in the comment range + +**Flow:** +``` +User clicks + icon in gutter + ↓ +VSCode creates new comment thread automatically + ↓ +Thread is created WITHOUT our custom properties (tempId, sourceDocument) + ↓ +Our saveNewNote command is called when user hits Save +``` + +**Important:** This is outside our direct control. The extension must handle threads created this way. + +--- + +### 1.4 View Note Command (Expands Existing Note) + +**File:** `/Users/nahian/Projects/code-notes/src/extension.ts` (lines 216-230) + +```typescript +const viewNoteCommand = vscode.commands.registerCommand( + 'codeContextNotes.viewNote', + async (noteId: string, filePath: string) => { + await commentController.focusNoteThread(noteId, filePath); + } +); +``` + +**Triggering Conditions:** +- User clicks CodeLens above a note +- User clicks "View Note" CodeLens + +**Flow:** +``` +User clicks CodeLens + ↓ +viewNote command called with noteId and filePath + ↓ +Calls: commentController.focusNoteThread() + ↓ +Existing thread is found by note ID + ↓ +Thread expanded and scrolled into view +``` + +**Note:** This doesn't create a new editor - it focuses an existing thread. + +--- + +### 1.5 Edit Note Command + +**File:** `/Users/nahian/Projects/code-notes/src/extension.ts` (lines 341-361) + +```typescript +const editNoteCommand = vscode.commands.registerCommand( + 'codeContextNotes.editNote', + async (comment: vscode.Comment) => { + const noteId = comment.contextValue; + await commentController.enableEditMode(noteId, editor.document.uri.fsPath); + } +); +``` + +**Triggering Conditions:** +- User clicks "Edit" button on a comment +- Button visible in comment thread title menu + +**Flow:** +``` +User clicks Edit button + ↓ +editNote command called with comment object + ↓ +Calls: commentController.enableEditMode() + ↓ +Existing thread switched to edit mode (editable text) + ↓ +Same comment thread, different mode +``` + +**Note:** This modifies the existing thread, doesn't create a new editor. + +--- + +## Section 2: Comment Editor Tracking Mechanism + +### 2.1 Thread Tracking Architecture + +**File:** `/Users/nahian/Projects/code-notes/src/commentController.ts` (lines 14-21) + +```typescript +export class CommentController { + private commentController: vscode.CommentController; + private noteManager: NoteManager; + private commentThreads: Map; // noteId -> CommentThread + + constructor(noteManager: NoteManager, context: vscode.ExtensionContext) { + this.noteManager = noteManager; + this.commentThreads = new Map(); + // ... + } +} +``` + +**Tracking Map Structure:** +- **Key:** Note ID (UUID string) or temporary ID for new notes +- **Value:** VSCode CommentThread object +- **Purpose:** Map notes to their comment threads for quick lookup + +**Map Usage:** +```typescript +// Store after creating thread +this.commentThreads.set(note.id, thread); + +// Retrieve when needed +const thread = this.commentThreads.get(noteId); + +// Delete when note is deleted +this.commentThreads.delete(noteId); +``` + +--- + +### 2.2 Temporary Thread Tracking for New Notes + +**File:** `/Users/nahian/Projects/code-notes/src/commentController.ts` (lines 207-235) + +```typescript +async openCommentEditor( + document: vscode.TextDocument, + range: vscode.Range +): Promise { + const thread = this.commentController.createCommentThread( + document.uri, + range, + [] + ); + + thread.collapsibleState = vscode.CommentThreadCollapsibleState.Expanded; + thread.canReply = true; + thread.label = 'New Note'; + + // Store thread temporarily with special properties + const tempId = `temp-${Date.now()}`; + (thread as any).tempId = tempId; // Custom property 1 + (thread as any).sourceDocument = document; // Custom property 2 + this.commentThreads.set(tempId, thread); + + return thread; +} +``` + +**Custom Properties Added:** + +| Property | Type | Purpose | +|----------|------|---------| +| `tempId` | string | Temporary identifier for the thread before it's saved | +| `sourceDocument` | vscode.TextDocument | Reference to the source document for new note creation | + +**Why Needed:** +- When a new note is created via keyboard shortcut or CodeLens, we need to track the document +- Comment editor input creates a temporary virtual document in VSCode's memory +- We need to remember the original source document to save the note in the correct file + +--- + +### 2.3 Permanent Thread Tracking After Note Creation + +**File:** `/Users/nahian/Projects/code-notes/src/commentController.ts` (lines 290-308) + +```typescript +async handleSaveNewNote( + thread: vscode.CommentThread, + content: string +): Promise { + // ... get document ... + + // Create the actual note + const note = await this.noteManager.createNote({ + filePath: document.uri.fsPath, + lineRange, + content + }, document); + + // Remove temporary thread + thread.dispose(); + if (tempId) { + this.commentThreads.delete(tempId); + } + + // Create the real comment thread for the saved note + this.createCommentThread(document, note); +} +``` + +**Lifecycle Transition:** +``` +temp-{timestamp} → note.id (UUID) +├─ When created: tracked as temp-{timestamp} +├─ When saved: new note gets UUID +├─ Old temporary thread disposed +└─ New permanent thread created with UUID as key +``` + +--- + +## Section 3: Comment Editor Lifecycle - Detailed Flow + +### 3.1 New Note Creation Lifecycle + +``` +START: User presses Ctrl+Alt+N + ↓ +1. openCommentEditor() called + - Creates empty thread + - Sets canReply = true, collapsibleState = Expanded + - Adds custom properties: tempId, sourceDocument + - Stores in commentThreads map as temp-{timestamp} + ↓ +2. VSCode displays empty comment input box + - User types note content + - User clicks Save button + ↓ +3. saveNewNote command triggered + - Gets content from input + - Calls handleSaveNewNote(thread, content) + ↓ +4. handleSaveNewNote() executes + - Retrieves document (from custom property or workspace lookup) + - Creates note via NoteManager.createNote() + - Note gets permanent UUID + - Disposes temporary thread + - Removes temp-{timestamp} from commentThreads map + - Creates new permanent thread with UUID as key + ↓ +5. State: Permanent comment thread now visible in preview mode +END: Note saved and comment thread displayed +``` + +--- + +### 3.2 Edit Existing Note Lifecycle + +``` +START: User clicks Edit button on comment + ↓ +1. editNote command triggered + - Gets noteId from comment.contextValue + - Calls enableEditMode(noteId, filePath) + ↓ +2. enableEditMode() executes + - Looks up thread by noteId in commentThreads map + - Switches comment mode to vscode.CommentMode.Editing + - Sets body to plain text (not markdown preview) + - Updates thread.comments array + ↓ +3. VSCode displays editable text field + - User modifies note content + - User clicks Save or Cancel + ↓ +4. IF User clicks Save: + - saveNote command triggered + - Gets noteId and new content + - Calls saveEditedNoteById(noteId, newContent) + ↓ +5. saveEditedNoteById() executes + - Looks up thread by noteId in commentThreads map + - Gets document URI from thread.uri + - Opens document + - Calls NoteManager.updateNote() + - Calls updateCommentThread() to switch back to preview mode + ↓ +6. State: Comment thread back in preview mode with updated content +END: Note edited and comment thread updated + +OR IF User clicks Cancel: + - cancelEditNote command triggered + - Calls refreshCommentsForDocument() + - Reloads note from storage + - Thread reverts to original content in preview mode +END: Edit cancelled, thread reverted +``` + +--- + +### 3.3 View History Lifecycle + +``` +START: User clicks View History button + ↓ +1. viewNoteHistory command triggered + - Gets noteId from comment.contextValue + - Calls showHistoryInThread(noteId, filePath) + ↓ +2. showHistoryInThread() executes + - Looks up thread by noteId in commentThreads map + - Retrieves note with history from NoteManager + - Constructs history comments: + * Main comment: current note content + * Reply comments: one for each history entry + - Sets thread.comments array to [main + all history] + - Expands thread + - Calls focusNoteThread() + ↓ +3. focusNoteThread() executes + - Opens document if not already open + - Displays document in editor + - Sets cursor to note location + - Scrolls view to show thread + ↓ +4. State: Comment thread visible with full history as replies +END: History displayed in comment thread +``` + +--- + +### 3.4 Delete Note Lifecycle + +``` +START: User clicks Delete button on comment + ↓ +1. deleteNoteFromComment command triggered + - Gets noteId from comment.contextValue + - Shows confirmation dialog + ↓ +2. IF confirmed: + - Calls commentController.handleDeleteNote(noteId, filePath) + ↓ +3. handleDeleteNote() executes + - Calls NoteManager.deleteNote() + - Calls deleteCommentThread(noteId) + ↓ +4. deleteCommentThread() executes + - Looks up thread by noteId in commentThreads map + - Calls thread.dispose() + - Removes noteId from commentThreads map + ↓ +5. State: Thread disposed, no longer visible, removed from tracking +END: Note deleted and comment thread removed +``` + +--- + +## Section 4: Tracking vs. Lifecycle Management + +### 4.1 What IS Currently Tracked + +The extension tracks comment threads in two ways: + +**1. By Note ID (Permanent Storage)** +```typescript +this.commentThreads.set(note.id, thread); // For saved notes +``` + +**2. By Temporary ID (Transient Storage)** +```typescript +this.commentThreads.set(`temp-${Date.now()}`, thread); // For new notes being edited +``` + +**Tracking Map Contents at Any Time:** +- `note-uuid-1` → Permanent thread for saved note 1 +- `note-uuid-2` → Permanent thread for saved note 2 +- `temp-1698835200000` → Temporary thread for note currently being created +- etc. + +--- + +### 4.2 What IS NOT Currently Tracked + +The extension does **NOT** track: + +1. **Open comment editors by document** + - No map like `Map` + - Cannot query "how many editors are open in file X" + +2. **Edit state of threads** + - Cannot query "which threads are in edit mode" + - Edit state is implicit in thread.comments[0].mode + +3. **Hierarchy of thread creation** + - Cannot determine if thread was created via keyboard, CodeLens, or + icon + - (We store tempId only for ones we created) + +4. **Disposal/Cleanup events** + - No listeners for when threads are disposed + - Cannot detect if user clicks X to close a thread + +--- + +### 4.3 Current Cleanup Mechanisms + +**Automatic Cleanup on Save:** +```typescript +// When saving a new note +thread.dispose(); +this.commentThreads.delete(tempId); +``` + +**Automatic Cleanup on Delete:** +```typescript +// When deleting a note +thread.dispose(); +this.commentThreads.delete(noteId); +``` + +**Automatic Cleanup on File Close/Reload:** +```typescript +// In refreshCommentsForDocument() +this.clearThreadsForDocument(uri); // Disposes all old threads +// Then loads fresh threads from storage +``` + +**Manual Cleanup on Extension Deactivation:** +```typescript +// In dispose() +for (const thread of this.commentThreads.values()) { + thread.dispose(); +} +this.commentThreads.clear(); +``` + +--- + +## Section 5: Handling VSCode Native + Icon Threads + +### 5.1 The Problem + +When a user clicks the **+ icon in the editor gutter**, VSCode creates a comment thread automatically. This thread: +- Is NOT created by our `openCommentEditor()` method +- Does NOT have our custom properties (`tempId`, `sourceDocument`) +- Is NOT in our `commentThreads` map until the user saves + +**File:** `/Users/nahian/Projects/code-notes/src/commentController.ts` (lines 240-298) + +### 5.2 The Solution + +The `handleSaveNewNote()` method detects and handles both types of threads: + +```typescript +async handleSaveNewNote( + thread: vscode.CommentThread, + content: string +): Promise { + const tempId = (thread as any).tempId; + + // CASE 1: Thread created by our code + // These have sourceDocument property + let document: vscode.TextDocument | undefined = + (thread as any).sourceDocument as vscode.TextDocument; + + // CASE 2: Thread created by VSCode's + icon + // Find the document by matching URI + if (!document) { + const docs = vscode.workspace.textDocuments; + document = docs.find(d => d.uri.toString() === thread.uri.toString()); + + if (!document) { + // Last resort: try to open the document + try { + document = await vscode.workspace.openTextDocument(thread.uri); + } catch (error) { + vscode.window.showErrorMessage('Could not find the document for this note'); + thread.dispose(); + return; + } + } + } + + // ... rest of note creation ... +} +``` + +**Flow for + Icon Creation:** +``` +User clicks + icon + ↓ +VSCode creates thread + - URI set correctly to source file + - NO tempId property + - NO sourceDocument property + ↓ +User types and clicks Save + ↓ +saveNewNote command called + ↓ +handleSaveNewNote() detects missing sourceDocument + ↓ +Searches vscode.workspace.textDocuments for matching URI + ↓ +Finds document and creates note + ↓ +Note saved successfully +``` + +--- + +## Section 6: Current Architecture Limitations + +### 6.1 No Global Registry of Open Editors + +**Current State:** +```typescript +private commentThreads: Map; +``` + +**Limitation:** This only tracks threads that are currently loaded. If: +- Document is closed and reopened: threads are disposed and recreated +- Multiple files open with notes: threads only exist if document is active +- User has multiple windows: each window has separate threads + +**Why This is Acceptable:** +- VSCode manages comment threads per-document +- Threads are automatically recreated when document opens +- Memory efficient - doesn't hold references to disposed threads + +--- + +### 6.2 No Edit State Tracking + +**Current State:** Edit state is implicit in `thread.comments[0].mode` + +**Limitation:** Cannot query "what threads are currently in edit mode" + +**Workaround:** +```typescript +// To check if thread is in edit mode: +if (thread.comments[0].mode === vscode.CommentMode.Editing) { + // It's in edit mode +} +``` + +--- + +### 6.3 No Disposal Event Hooks + +**Current State:** No way to detect when user clicks X to close a thread + +**Why:** VSCode doesn't provide thread disposal events + +**Workaround:** Use `CommentController.dispose()` which is called when extension deactivates + +--- + +## Section 7: Key Code Locations Reference + +| Functionality | File | Lines | +|---------------|------|-------| +| Thread creation | `commentController.ts` | 62-98 | +| New note editor | `commentController.ts` | 207-235 | +| Saving new note | `commentController.ts` | 240-308 | +| Updating thread | `commentController.ts` | 127-147 | +| Deleting thread | `commentController.ts` | 152-158 | +| Clearing threads | `commentController.ts` | 191-202 | +| Edit mode | `commentController.ts` | 457-480 | +| Save edited note | `commentController.ts` | 485-508 | +| Edit command | `extension.ts` | 341-361 | +| Save command | `extension.ts` | 364-385 | +| Cancel command | `extension.ts` | 388-408 | +| Add note command | `extension.ts` | 167-196 | +| Add note via CodeLens | `extension.ts` | 199-213 | +| Save new note command | `extension.ts` | 411-425 | +| Cancel new note command | `extension.ts` | 428-439 | + +--- + +## Section 8: Summary + +### Thread Lifecycle States + +``` +Creation Phase: + ├─ Via keyboard: temp-{timestamp} → UUID (on save) + ├─ Via CodeLens: temp-{timestamp} → UUID (on save) + └─ Via + icon: NOT tracked until save → UUID (on save) + +Active Phase: + ├─ Preview mode: thread.comments[0].mode = Preview + ├─ Edit mode: thread.comments[0].mode = Editing + └─ History mode: thread.comments[0+history] = Multiple comments + +Disposal Phase: + ├─ On note delete: dispose() + remove from map + ├─ On file close: dispose() + remove from map + ├─ On document change: dispose() + remove + recreate + └─ On extension deactivate: dispose all + clear map +``` + +### Key Design Principles + +1. **Lazy Creation:** Threads created only when needed +2. **On-Demand Loading:** Notes loaded from disk, threads recreated as needed +3. **Explicit Cleanup:** Threads disposed when no longer needed +4. **Handle All Cases:** Works whether editor created via keyboard, CodeLens, or VSCode + icon +5. **Stateless Fallback:** Even if tracking loses a thread, we can recreate it from storage + +--- + +## Section 9: Design Rationale + +### Why No Global Registry? + +VSCode's comment system is designed to be lightweight and stateless. Benefits: + +1. **Memory Efficient:** Don't keep references to disposed threads +2. **Resilient:** Can recover from crashes by reloading from disk +3. **Per-Document:** Aligns with VSCode's document-centric architecture +4. **Clean Separation:** UI layer (VSCode) separate from data layer (NoteManager) + +### Why Temporary IDs? + +Using `temp-{timestamp}` for new notes allows: + +1. **Safe Cleanup:** Can delete from map without affecting note ID +2. **Recovery:** If user cancels, temp thread is discarded without saving +3. **Clear Intent:** Code clearly shows "this is not yet saved" +4. **Prevention:** Doesn't interfere with searching by permanent note ID + +### Why Custom Properties? + +Using TypeScript `as any` to add `tempId` and `sourceDocument` because: + +1. VSCode CommentThread interface doesn't provide these properties +2. Need to track context that VSCode doesn't provide +3. Only used internally - doesn't affect VSCode API +4. Cleaned up immediately after use + +--- + +## Appendix: Future Enhancement Possibilities + +If keybinding issues arise, consider: + +1. **Global Editor Registry** + ```typescript + // Track all open editors by document + private openEditors: Map; + ``` + +2. **Edit State Tracking** + ```typescript + // Track which threads are in edit mode + private editingThreads: Set; + ``` + +3. **Disposal Event System** + ```typescript + // Listen for thread disposal + thread.onDidDispose(() => { + this.commentThreads.delete(noteId); + }); + ``` + +4. **Centralized Save Handler** + ```typescript + // Single handler for all save events + this.commentController.onSave((event) => { + this.handleSaveNewNote(event.thread, event.content); + }); + ``` + diff --git a/docs/COMMENT_EDITOR_CODE_REFERENCE.md b/docs/COMMENT_EDITOR_CODE_REFERENCE.md new file mode 100644 index 0000000..b872f85 --- /dev/null +++ b/docs/COMMENT_EDITOR_CODE_REFERENCE.md @@ -0,0 +1,595 @@ +# Comment Editor - Detailed Code Reference + +## 1. Thread Creation: `openCommentEditor()` + +**File:** `/Users/nahian/Projects/code-notes/src/commentController.ts` +**Lines:** 207-235 + +**Creates:** Empty comment thread in expanded state +**Called by:** +- `codeContextNotes.addNote` command (keyboard shortcut) +- `codeContextNotes.addNoteViaCodeLens` command + +**Key Details:** +- Sets `canReply = true` - allows user input +- Sets `collapsibleState = Expanded` - shows empty text field immediately +- Adds custom properties `tempId` and `sourceDocument` +- Stores in tracking map with temporary ID + +```typescript +async openCommentEditor( + document: vscode.TextDocument, + range: vscode.Range +): Promise { + // Create empty thread + const thread = this.commentController.createCommentThread( + document.uri, + range, + [] // Empty comments array + ); + + // Configure for input + thread.collapsibleState = vscode.CommentThreadCollapsibleState.Expanded; + thread.canReply = true; + thread.label = 'New Note'; + + // Store with custom metadata + const tempId = `temp-${Date.now()}`; + (thread as any).tempId = tempId; + (thread as any).sourceDocument = document; + this.commentThreads.set(tempId, thread); + + return thread; +} +``` + +--- + +## 2. Saving New Note: `handleSaveNewNote()` + +**File:** `/Users/nahian/Projects/code-notes/src/commentController.ts` +**Lines:** 240-308 + +**Called by:** `codeContextNotes.saveNewNote` command +**Input:** `thread` (from VSCode) + `content` (user typed text) +**Output:** Saves note, updates thread + +**Critical Code Path:** + +```typescript +async handleSaveNewNote( + thread: vscode.CommentThread, + content: string +): Promise { + const tempId = (thread as any).tempId; + + // CASE 1: Our thread (has sourceDocument) + let document: vscode.TextDocument | undefined = + (thread as any).sourceDocument as vscode.TextDocument; + + // CASE 2: VSCode + icon thread (no sourceDocument) + if (!document) { + const docs = vscode.workspace.textDocuments; + document = docs.find(d => d.uri.toString() === thread.uri.toString()); + + if (!document) { + try { + document = await vscode.workspace.openTextDocument(thread.uri); + } catch (error) { + vscode.window.showErrorMessage('Could not find the document for this note'); + thread.dispose(); + return; + } + } + } + + // Validate + if (!document) { + vscode.window.showErrorMessage('Could not find the document for this note'); + thread.dispose(); + if (tempId) { + this.commentThreads.delete(tempId); + } + return; + } + + if (!content || !thread.range) { + thread.dispose(); + if (tempId) { + this.commentThreads.delete(tempId); + } + return; + } + + // Create note in NoteManager + const lineRange: LineRange = { + start: thread.range.start.line, + end: thread.range.end.line + }; + + const note = await this.noteManager.createNote( + { + filePath: document.uri.fsPath, + lineRange, + content + }, + document + ); + + // Clean up temporary thread + thread.dispose(); + if (tempId) { + this.commentThreads.delete(tempId); + } + + // Create permanent thread with saved note + this.createCommentThread(document, note); +} +``` + +**Key Points:** +1. Line 244-247: Try to get document from custom property +2. Line 250-264: Fallback for VSCode + icon threads +3. Line 267-276: Validation +4. Line 290-298: Create permanent thread with UUID +5. Thread replacement: `temp-xxx` → `note-uuid` + +--- + +## 3. Permanent Thread Creation: `createCommentThread()` + +**File:** `/Users/nahian/Projects/code-notes/src/commentController.ts` +**Lines:** 62-98 + +**Called by:** +- `handleSaveNewNote()` - after saving new note +- `loadCommentsForDocument()` - when file opens +- `refreshCommentsForDocument()` - when refreshing + +**Creates:** Thread with note content in preview mode + +```typescript +createCommentThread( + document: vscode.TextDocument, + note: Note +): vscode.CommentThread { + // Check if thread already exists + const existingThread = this.commentThreads.get(note.id); + if (existingThread) { + return existingThread; + } + + // Create range from note's line range + const range = new vscode.Range( + note.lineRange.start, + 0, + note.lineRange.end, + document.lineAt(note.lineRange.end).text.length + ); + + // Create thread with note content + const thread = this.commentController.createCommentThread( + document.uri, + range, + [] + ); + + thread.collapsibleState = vscode.CommentThreadCollapsibleState.Collapsed; + thread.canReply = false; // No inline replies, use Edit button instead + + // Create comment from note + const comment = this.createComment(note); + thread.comments = [comment]; + + // Store with permanent ID + this.commentThreads.set(note.id, thread); + + return thread; +} +``` + +**Key Differences from `openCommentEditor()`:** +- `canReply = false` - no inline replies +- `collapsibleState = Collapsed` - not expanded by default +- Uses note.id (UUID) instead of tempId +- Creates comment with note.content + +--- + +## 4. Edit Mode: `enableEditMode()` + +**File:** `/Users/nahian/Projects/code-notes/src/commentController.ts` +**Lines:** 457-480 + +**Called by:** `codeContextNotes.editNote` command + +**Switches:** Thread from Preview to Editing + +```typescript +async enableEditMode(noteId: string, filePath: string): Promise { + const note = await this.noteManager.getNoteById(noteId, filePath); + if (!note) { + vscode.window.showErrorMessage('Note not found'); + return; + } + + const thread = this.commentThreads.get(noteId); + if (!thread) { + return; + } + + // Switch comment to edit mode + if (thread.comments.length > 0) { + const comment = thread.comments[0]; + const editableComment: vscode.Comment = { + ...comment, + mode: vscode.CommentMode.Editing, // KEY CHANGE + body: note.content // Plain text for editing + }; + thread.comments = [editableComment]; + } +} +``` + +**Mode Transitions:** +``` +Preview (default) + ↓ User clicks Edit +Editing (text field) + ↓ User clicks Save or Cancel +Preview (or reverted) +``` + +--- + +## 5. Saving Edited Note: `saveEditedNoteById()` + +**File:** `/Users/nahian/Projects/code-notes/src/commentController.ts` +**Lines:** 485-508 + +**Called by:** `codeContextNotes.saveNote` command + +**Updates:** Note content and thread display + +```typescript +async saveEditedNoteById(noteId: string, newContent: string): Promise { + // Get thread to find file + const thread = this.commentThreads.get(noteId); + if (!thread) { + vscode.window.showErrorMessage('Note thread not found'); + return false; + } + + const filePath = thread.uri.fsPath; + + // Open document + const document = await vscode.workspace.openTextDocument(filePath); + + // Update note + const updatedNote = await this.noteManager.updateNote( + { id: noteId, content: newContent }, + document + ); + + // Update thread back to preview mode + this.updateCommentThread(updatedNote, document); + + return true; +} +``` + +**Key Points:** +1. Line 487: Looks up thread by note ID +2. Line 493: Gets file path from thread.uri +3. Line 496-501: Updates note in storage +4. Line 504: Updates thread (switches back to preview) + +--- + +## 6. Thread Updates: `updateCommentThread()` + +**File:** `/Users/nahian/Projects/code-notes/src/commentController.ts` +**Lines:** 127-147 + +**Updates:** Thread range and comment content + +**Called by:** +- `saveEditedNoteById()` - after saving edits +- `handleDocumentChange()` - when code moves +- Command handlers + +```typescript +updateCommentThread(note: Note, document: vscode.TextDocument): void { + const thread = this.commentThreads.get(note.id); + if (!thread) { + // Create new thread if it doesn't exist + this.createCommentThread(document, note); + return; + } + + // Update range (if code moved) + const range = new vscode.Range( + note.lineRange.start, + 0, + note.lineRange.end, + document.lineAt(note.lineRange.end).text.length + ); + thread.range = range; + + // Update comment (refreshes display) + const comment = this.createComment(note); + thread.comments = [comment]; +} +``` + +--- + +## 7. Thread Deletion: `deleteCommentThread()` + +**File:** `/Users/nahian/Projects/code-notes/src/commentController.ts` +**Lines:** 152-158 + +**Called by:** `handleDeleteNote()` command + +```typescript +deleteCommentThread(noteId: string): void { + const thread = this.commentThreads.get(noteId); + if (thread) { + thread.dispose(); // Dispose VSCode thread + this.commentThreads.delete(noteId); // Remove from tracking map + } +} +``` + +**Cleans up:** +1. VSCode thread disposal +2. Map entry removal +3. UI refresh (automatic) + +--- + +## 8. Thread Lookup: `getNoteIdFromThread()` + +**File:** `/Users/nahian/Projects/code-notes/src/commentController.ts` +**Lines:** 373-380 + +**Purpose:** Reverse lookup - find note ID from thread + +```typescript +getNoteIdFromThread(thread: vscode.CommentThread): string | undefined { + for (const [noteId, commentThread] of this.commentThreads.entries()) { + if (commentThread === thread) { + return noteId; + } + } + return undefined; +} +``` + +--- + +## 9. Thread Focus: `focusNoteThread()` + +**File:** `/Users/nahian/Projects/code-notes/src/commentController.ts` +**Lines:** 385-405 + +**Called by:** +- `codeContextNotes.viewNote` command +- `showHistoryInThread()` command + +**Action:** Opens document, expands thread, scrolls to view + +```typescript +async focusNoteThread(noteId: string, filePath: string): Promise { + const thread = this.commentThreads.get(noteId); + if (!thread) { + vscode.window.showErrorMessage('Note thread not found'); + return; + } + + // Open the document + const document = await vscode.workspace.openTextDocument(filePath); + const editor = await vscode.window.showTextDocument(document); + + // Expand the thread + thread.collapsibleState = vscode.CommentThreadCollapsibleState.Expanded; + + // Move cursor and scroll + if (thread.range) { + const position = new vscode.Position(thread.range.start.line, 0); + editor.selection = new vscode.Selection(position, position); + editor.revealRange(thread.range, vscode.TextEditorRevealType.InCenter); + } +} +``` + +--- + +## 10. History Display: `showHistoryInThread()` + +**File:** `/Users/nahian/Projects/code-notes/src/commentController.ts` +**Lines:** 410-452 + +**Converts:** Note history to comment replies + +```typescript +async showHistoryInThread(noteId: string, filePath: string): Promise { + const thread = this.commentThreads.get(noteId); + if (!thread) { + vscode.window.showErrorMessage('Note thread not found'); + return; + } + + const note = await this.noteManager.getNoteById(noteId, filePath); + if (!note) { + vscode.window.showErrorMessage('Note not found'); + return; + } + + // Main comment: current content + const mainComment = this.createComment(note); + + // History comments: one per history entry + const historyComments: vscode.Comment[] = [mainComment]; + + if (note.history && note.history.length > 0) { + for (const entry of note.history) { + const historyComment: vscode.Comment = { + body: new vscode.MarkdownString( + `**${entry.action}**\n\n${entry.content || '*(no content)*'}` + ), + mode: vscode.CommentMode.Preview, + author: { + name: entry.author + }, + label: new Date(entry.timestamp).toLocaleString() + }; + historyComments.push(historyComment); + } + } + + // Update thread with all comments + thread.comments = historyComments; + thread.collapsibleState = vscode.CommentThreadCollapsibleState.Expanded; + + // Focus on the thread + await this.focusNoteThread(noteId, filePath); +} +``` + +**Result:** Main comment + replies for each history entry + +--- + +## 11. Document-Level Operations + +### Load Comments: `loadCommentsForDocument()` + +**File:** `/Users/nahian/Projects/code-notes/src/commentController.ts` +**Lines:** 163-173 + +```typescript +async loadCommentsForDocument(document: vscode.TextDocument): Promise { + const filePath = document.uri.fsPath; + + // Get all notes for this file + const notes = await this.noteManager.getNotesForFile(filePath); + + // Create comment threads for each note + for (const note of notes) { + this.createCommentThread(document, note); + } +} +``` + +### Refresh Comments: `refreshCommentsForDocument()` + +**File:** `/Users/nahian/Projects/code-notes/src/commentController.ts` +**Lines:** 178-186 + +```typescript +async refreshCommentsForDocument(document: vscode.TextDocument): Promise { + const filePath = document.uri.fsPath; + + // Clear existing threads + this.clearThreadsForDocument(document.uri); + + // Reload comments + await this.loadCommentsForDocument(document); +} +``` + +### Clear Threads: `clearThreadsForDocument()` + +**File:** `/Users/nahian/Projects/code-notes/src/commentController.ts` +**Lines:** 191-202 + +```typescript +private clearThreadsForDocument(uri: vscode.Uri): void { + const threadsToDelete: string[] = []; + + for (const [noteId, thread] of this.commentThreads.entries()) { + if (thread.uri.fsPath === uri.fsPath) { + thread.dispose(); + threadsToDelete.push(noteId); + } + } + + threadsToDelete.forEach(id => this.commentThreads.delete(id)); +} +``` + +--- + +## 12. Extension Integration Points + +### Command Registration + +**File:** `/Users/nahian/Projects/code-notes/src/extension.ts` + +| Command | Lines | Handler | +|---------|-------|---------| +| `codeContextNotes.addNote` | 167-196 | Keyboard shortcut | +| `codeContextNotes.addNoteViaCodeLens` | 199-213 | CodeLens click | +| `codeContextNotes.editNote` | 341-361 | Edit button | +| `codeContextNotes.saveNote` | 364-385 | Save button | +| `codeContextNotes.cancelEditNote` | 388-408 | Cancel button | +| `codeContextNotes.saveNewNote` | 411-425 | Save new | +| `codeContextNotes.cancelNewNote` | 428-439 | Cancel new | + +### Keyboard Shortcuts + +**File:** `package.json` +**Lines:** 140-195 + +```json +{ + "command": "codeContextNotes.addNote", + "key": "ctrl+alt+n", + "mac": "cmd+alt+n", + "when": "editorTextFocus && editorHasSelection" +} +``` + +--- + +## 13. Quick Trace: User Presses Ctrl+Alt+N + +``` +1. VSCode triggers: codeContextNotes.addNote command + Location: extension.ts:167 + +2. Handler executes: + - Validates: Has editor, has selection + - Extracts: selection range + - Calls: commentController.openCommentEditor() + Location: extension.ts:167-196 + +3. openCommentEditor() executes: + - Creates: VSCode comment thread + - Sets: tempId, sourceDocument + - Stores: in commentThreads map + Location: commentController.ts:207-235 + +4. VSCode renders: + - Empty text field appears + - Focus in input field + +5. User types content and clicks Save + +6. VSCode triggers: codeContextNotes.saveNewNote command + Location: extension.ts:411 + +7. Handler calls: commentController.handleSaveNewNote() + Location: extension.ts:411-425 + +8. handleSaveNewNote() executes: + - Gets: document from sourceDocument property + - Creates: note via NoteManager + - Disposes: temporary thread + - Creates: permanent thread + Location: commentController.ts:240-308 + +9. Thread now visible with content in preview mode +``` + diff --git a/docs/COMMENT_EDITOR_INDEX.md b/docs/COMMENT_EDITOR_INDEX.md new file mode 100644 index 0000000..46437b8 --- /dev/null +++ b/docs/COMMENT_EDITOR_INDEX.md @@ -0,0 +1,421 @@ +# Comment Editor Management - Complete Documentation Index + +**Created:** October 19, 2025 +**Purpose:** Understand comment editor lifecycle for keybinding issue investigation +**Branch:** `fix/keybindings-not-opening-the-comment-editor` + +--- + +## Document Guide + +### For Quick Understanding +**Start here:** [`COMMENT_EDITOR_SUMMARY.md`](./COMMENT_EDITOR_SUMMARY.md) +- Quick overview of opening methods +- Tracking mechanism explained simply +- Lifecycle phases at a glance +- Potential keybinding issues listed + +### For Complete Architecture Knowledge +**Read:** [`COMMENT_EDITOR_ANALYSIS.md`](./COMMENT_EDITOR_ANALYSIS.md) +- 9 major sections covering all aspects +- Detailed flow diagrams for each operation +- Tracking vs lifecycle management clarification +- Design rationale and philosophy +- Future enhancement possibilities + +### For Specific Code Details +**Reference:** [`COMMENT_EDITOR_CODE_REFERENCE.md`](./COMMENT_EDITOR_CODE_REFERENCE.md) +- 13 detailed method breakdowns +- Full code examples with line numbers +- Call chain documentation +- Integration point mapping +- Complete execution trace example + +--- + +## Quick Facts + +**Tracking Data Structure:** +```typescript +private commentThreads: Map; +``` + +**Keys:** +- Temporary: `temp-{timestamp}` (for new notes being created) +- Permanent: `note-id` (UUID for saved notes) + +**Main Methods:** +- **Create:** `openCommentEditor()` (commentController.ts:207-235) +- **Save:** `handleSaveNewNote()` (commentController.ts:240-308) +- **Edit:** `enableEditMode()` (commentController.ts:457-480) +- **Delete:** `deleteCommentThread()` (commentController.ts:152-158) + +**Opening Methods:** +1. Keyboard: `Ctrl+Alt+N` → `codeContextNotes.addNote` → `openCommentEditor()` +2. CodeLens: Click "➕ Add Note" → `codeContextNotes.addNoteViaCodeLens` → `openCommentEditor()` +3. VSCode + icon: Click + in gutter → VSCode native → `handleSaveNewNote()` +4. Edit button: Click Edit → `codeContextNotes.editNote` → `enableEditMode()` + +--- + +## Investigation Path for Keybinding Issues + +### Issue: Keyboard shortcut not opening comment editor + +**Check List:** +1. Command registered? + - File: `extension.ts` line 168 + - Command: `codeContextNotes.addNote` + +2. Keybinding configured? + - File: `package.json` lines 141-146 + - Key: `ctrl+alt+n` / `cmd+alt+n` + - When: `editorTextFocus && editorHasSelection` + +3. openCommentEditor() working? + - File: `commentController.ts` lines 207-235 + - Creates thread? Check return value + - Sets tempId? Check custom properties + - Stores in map? Check commentThreads + +4. VSCode rendering? + - Thread has correct document.uri? Check thread.uri + - Thread has correct range? Check thread.range + - Thread has empty comments? Check thread.comments + +### Issue: Comment editor not saving + +**Check List:** +1. Save command registered? + - File: `extension.ts` line 365 + - Command: `codeContextNotes.saveNewNote` + +2. handleSaveNewNote() called? + - File: `commentController.ts` lines 240-308 + - Gets content? Check reply.text + - Gets thread? Check reply.thread + +3. Document lookup working? + - File: `commentController.ts` lines 244-265 + - Has sourceDocument property? Check custom properties + - Fallback to workspace.textDocuments? Check line 252 + - Fallback to openTextDocument? Check line 258 + +4. Note creation working? + - File: `commentController.ts` line 291 + - Call NoteManager.createNote() + - Returns note with UUID? + +5. Thread replacement working? + - File: `commentController.ts` line 300 + - Dispose old thread? Check line 301 + - Remove from map? Check line 303 + - Create new thread? Check line 307 + +### Issue: Comment editor opening from + icon not saving + +**Check List:** +1. VSCode creates thread? + - Thread.uri set? Check source file URI + - No custom properties? Check absence of tempId + +2. handleSaveNewNote() detects VSCode thread? + - Line 244: tempId check (should be undefined) + - Line 247: sourceDocument check (should be undefined) + - Line 250-264: Document lookup fallback executed? + +3. Which fallback path taken? + - Path 1 (Line 252): Found in workspace.textDocuments? + - Path 2 (Line 258): Had to openTextDocument? + - Path 3 (Line 260): Error message shown? + +--- + +## Key Code Sections + +### Tracking Map +**File:** `commentController.ts:14-21` +```typescript +private commentThreads: Map; +``` + +### Thread Creation (For New Notes) +**File:** `commentController.ts:207-235` +```typescript +async openCommentEditor(document: vscode.TextDocument, range: vscode.Range) +``` + +### Thread Saving (New Note to Permanent) +**File:** `commentController.ts:240-308` +```typescript +async handleSaveNewNote(thread: vscode.CommentThread, content: string) +``` + +### Thread Creation (For Saved Notes) +**File:** `commentController.ts:62-98` +```typescript +createCommentThread(document: vscode.TextDocument, note: Note) +``` + +### Thread Edit Mode +**File:** `commentController.ts:457-480` +```typescript +async enableEditMode(noteId: string, filePath: string) +``` + +### Thread Deletion +**File:** `commentController.ts:152-158` +```typescript +deleteCommentThread(noteId: string) +``` + +--- + +## Thread States and Transitions + +``` +┌─────────────────────────────────────────────────────────────┐ +│ THREAD STATE DIAGRAM │ +└─────────────────────────────────────────────────────────────┘ + + [NOT CREATED] + │ + │ openCommentEditor() + ↓ + [TEMPORARY INPUT] + (temp-{timestamp}) + - Empty thread + - canReply = true + - collapsibleState = Expanded + │ + │ User types + clicks Save + │ handleSaveNewNote() + ↓ + [PERMANENT SAVED] + (note-id UUID) + - Content in preview mode + - canReply = false + - collapsibleState = Collapsed + │ + ┌───────────┼───────────┐ + │ │ │ + ↓ ↓ ↓ + [EDITING] [HISTORY] [DELETED] + - Edit mode - Replies - Disposed + - Editable - Expanded - Removed from map + - Unsaved - View only + │ │ │ + │ │ │ + ├───────────┴───────────┤ + │ + ↓ + [PREVIEW DISPLAY] + (normal state) + +States: +├─ NOT CREATED: Thread doesn't exist +├─ TEMPORARY INPUT: Empty thread for user input +├─ PERMANENT SAVED: Saved note with content +├─ EDITING: User editing note content +├─ HISTORY: History displayed as replies +└─ DELETED: Thread disposed, removed + +Transitions: +→ Can go to EDITING from PERMANENT SAVED +→ Can return from EDITING to PREVIEW DISPLAY +→ Can go to HISTORY from PERMANENT SAVED +→ Can go to DELETED from any state +``` + +--- + +## File Organization + +``` +src/ +├── commentController.ts # Main tracking and management +│ ├── Line 14-21: Tracking map +│ ├── Line 62-98: createCommentThread() +│ ├── Line 127-147: updateCommentThread() +│ ├── Line 152-158: deleteCommentThread() +│ ├── Line 163-173: loadCommentsForDocument() +│ ├── Line 178-186: refreshCommentsForDocument() +│ ├── Line 191-202: clearThreadsForDocument() +│ ├── Line 207-235: openCommentEditor() +│ ├── Line 240-308: handleSaveNewNote() +│ ├── Line 341-361: [extension.ts] editNote command +│ ├── Line 385-405: focusNoteThread() +│ ├── Line 410-452: showHistoryInThread() +│ ├── Line 457-480: enableEditMode() +│ └── Line 485-508: saveEditedNoteById() +│ +├── extension.ts # Command registration and handlers +│ ├── Line 167-196: addNote command +│ ├── Line 199-213: addNoteViaCodeLens command +│ ├── Line 216-230: viewNote command +│ ├── Line 232-280: deleteNote command +│ ├── Line 282-318: viewHistory command +│ ├── Line 320-338: refreshNotes command +│ ├── Line 341-361: editNote command +│ ├── Line 364-385: saveNote command +│ ├── Line 388-408: cancelEditNote command +│ ├── Line 411-425: saveNewNote command +│ └── Line 428-439: cancelNewNote command +│ +└── package.json # Configuration + ├── Line 140-195: Keybindings + └── Line 196-237: Menu configurations + +tests/ +├── commentController.test.ts # (Not yet written) +└── extension.test.ts # (Not yet written) +``` + +--- + +## API Usage Patterns + +### Pattern 1: Open Empty Editor (Keyboard/CodeLens) +``` +User Action → Command → openCommentEditor() → thread created + ↓ + (tracking: temp-{timestamp}) + ↓ + VSCode shows input + ↓ + User types content + ↓ + User clicks Save + ↓ + saveNewNote command → handleSaveNewNote() + ↓ + (tracking: temp-xxx → note-id) +``` + +### Pattern 2: Edit Existing Note +``` +User clicks Edit → editNote command → enableEditMode() + ↓ + Thread.comments[0].mode = Editing + ↓ + VSCode shows edit field + ↓ + User modifies content + ↓ + User clicks Save + ↓ + saveNote command → saveEditedNoteById() + ↓ + NoteManager.updateNote() + ↓ + updateCommentThread() → back to preview + ↓ + Thread.comments[0].mode = Preview +``` + +### Pattern 3: View History +``` +User clicks View History → viewNoteHistory command → showHistoryInThread() + ↓ + Retrieve note with history from NoteManager + ↓ + Build comment array [main, entry1, entry2, ...] + ↓ + Set thread.comments = [...all comments] + ↓ + focusNoteThread() → expand and scroll + ↓ + VSCode shows thread with replies +``` + +--- + +## Debugging Tips + +### Enable Console Logging +```typescript +// In commentController.ts +private log(msg: string, data?: any) { + console.log('[CommentController]', msg, data); +} + +// Usage in methods +this.log('Opening comment editor', { range, document }); +this.log('Thread tracked as', { key: tempId }); +this.log('Saving note', { noteId, content }); +``` + +### Check Tracking Map State +```typescript +// In VS Code console (Developer Tools) +// The commentController is not directly accessible, but you can: +// 1. Check all CommentThread objects +// 2. Verify thread properties (uri, range, comments, etc.) +// 3. Watch for thread.dispose() calls +``` + +### Trace User Actions +``` +1. User presses Ctrl+Alt+N + → Check: Command executed? (VS Code output channel) + → Check: addNote handler called? + → Check: openCommentEditor() called? + +2. User sees input box + → Check: Thread created with correct URI? + → Check: Thread has correct range? + → Check: Comments array empty? + +3. User clicks Save + → Check: saveNewNote command executed? + → Check: handleSaveNewNote() called? + → Check: Document lookup successful? + → Check: Note created with UUID? + +4. User sees saved note with content + → Check: New thread created? + → Check: Thread tracked with note ID? + → Check: Comments array has note content? +``` + +--- + +## Related Files + +### Supporting Components +- **NoteManager:** `/Users/nahian/Projects/code-notes/src/noteManager.ts` + - Creates and updates notes + - Provides note data to comment threads + +- **StorageManager:** `/Users/nahian/Projects/code-notes/src/storageManager.ts` + - Persists notes to disk + - Used by NoteManager + +- **CodeLensProvider:** `/Users/nahian/Projects/code-notes/src/codeLensProvider.ts` + - Triggers "Add Note" CodeLens action + - Calls `addNoteViaCodeLens` command + +### Configuration +- **package.json:** Command definitions and keybindings +- **tsconfig.json:** TypeScript compilation settings + +### Types +- **types.ts:** Note, Comment, and related interfaces + +--- + +## Summary + +The comment editor system uses: +- **One tracking map:** `commentThreads: Map` +- **Two ID types:** Temporary (`temp-{timestamp}`) and Permanent (`note-id`) +- **Multiple entry points:** Keyboard, CodeLens, VSCode native +, Edit button +- **Stateless fallbacks:** Can always recreate threads from storage +- **Explicit lifecycle:** Creation → Input → Save → Display → Edit/Delete + +For the keybinding issue, focus on: +1. Command registration and execution +2. Document lookup in `handleSaveNewNote()` +3. Thread creation and tracking +4. VSCode native thread handling + diff --git a/docs/COMMENT_EDITOR_SUMMARY.md b/docs/COMMENT_EDITOR_SUMMARY.md new file mode 100644 index 0000000..fb96c5b --- /dev/null +++ b/docs/COMMENT_EDITOR_SUMMARY.md @@ -0,0 +1,116 @@ +# Comment Editor Management - Quick Summary + +## Four Ways Comment Editors Are Opened + +| Trigger | Code | Where | State | +|---------|------|-------|-------| +| **Ctrl+Alt+N (Keyboard)** | `addNote` | `extension.ts:167` | Creates empty thread | +| **CodeLens "Add Note"** | `addNoteViaCodeLens` | `extension.ts:199` | Creates empty thread | +| **VSCode + icon** | (VSCode native) | N/A | Creates thread without our metadata | +| **Click Edit button** | `editNote` | `extension.ts:341` | Switches existing thread to edit mode | + +## How Comment Editors Are Tracked + +**Map:** `CommentController.commentThreads` + +**Contents:** +``` +Key: note.id (UUID) or temp-{timestamp} +Value: VSCode CommentThread object +``` + +**Example state:** +```typescript +commentThreads: { + "550e8400-e29b-41d4-a716-446655440000": CommentThread, // Saved note + "temp-1698835200123": CommentThread, // New note being edited +} +``` + +## Lifecycle Phases + +### Phase 1: Creation +- Keyboard or CodeLens → Call `openCommentEditor()` +- Sets: `tempId`, `sourceDocument` (custom properties) +- Stores in map as `temp-{timestamp}` + +### Phase 2: User Input +- User types content in expanded thread +- VSCode manages the UI + +### Phase 3: Save +- User clicks Save button +- `handleSaveNewNote()` called +- Note created with UUID +- Thread replaced in map: `temp-xxx` → `note-id` +- Old thread disposed + +### Phase 4: Display +- Thread shown in preview mode +- Buttons: Edit, Delete, View History + +## Handling VSCode + Icon Threads + +When user clicks **+ icon**, VSCode creates a thread without our custom properties. + +**Solution:** `handleSaveNewNote()` detects and handles both cases: + +1. Our threads have `sourceDocument` property → use it +2. VSCode threads don't → search `vscode.workspace.textDocuments` to find it +3. Last resort → `vscode.workspace.openTextDocument(thread.uri)` + +## Key Methods + +| Method | Purpose | File | Lines | +|--------|---------|------|-------| +| `openCommentEditor()` | Create new thread for input | commentController.ts | 207-235 | +| `createCommentThread()` | Create thread for saved note | commentController.ts | 62-98 | +| `handleSaveNewNote()` | Save new note from input | commentController.ts | 240-298 | +| `enableEditMode()` | Switch thread to edit mode | commentController.ts | 457-480 | +| `saveEditedNoteById()` | Save edited note | commentController.ts | 485-508 | +| `deleteCommentThread()` | Dispose and remove from map | commentController.ts | 152-158 | +| `focusNoteThread()` | Expand and scroll to thread | commentController.ts | 385-405 | +| `showHistoryInThread()` | Display history as replies | commentController.ts | 410-452 | + +## No Centralized Tracking For + +- **Open editors by document** - No `Map` +- **Edit state** - Implicit in `thread.comments[0].mode` +- **Creation source** - Can't query "keyboard vs CodeLens vs + icon" +- **Disposal events** - No listeners for when threads close + +## Current Cleanup + +1. **On note save:** Old thread → disposed, removed from map +2. **On note delete:** Thread → disposed, removed from map +3. **On file reload:** All threads → disposed, recreated +4. **On extension deactivate:** All threads → disposed, map cleared + +## Design Philosophy + +✓ **Lazy creation** - Threads created only when needed +✓ **On-demand loading** - Threads recreated from disk as needed +✓ **Explicit cleanup** - Threads disposed when no longer needed +✓ **Handle all cases** - Works via keyboard, CodeLens, + icon +✓ **Stateless fallback** - Can recover by reloading from storage + +## What Might Cause Keybinding Issues + +Looking at the branch name `fix/keybindings-not-opening-the-comment-editor`, potential issues could be: + +1. **Comment editor not responding to keyboard shortcuts** + - Check: `addNote` command registration (line 168) + - Check: Keybinding `when` clause (package.json line 145) + +2. **Comment editor not opening from + icon** + - Check: `handleSaveNewNote()` can't find document (line 250+) + - Check: Threading issues with VSCode native threads + +3. **Comment editor not opening from CodeLens** + - Check: `addNoteViaCodeLensCommand` (line 199) + - Check: CodeLens provider (codeLensProvider.ts) + +4. **Comment editor opening but not saving** + - Check: `saveNewNote` command (line 411) + - Check: `handleSaveNewNote()` document lookup (line 244-265) + diff --git a/docs/TODO.md b/docs/TODO.md index e7555f8..0870f04 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -972,7 +972,7 @@ All critical bugs have been fixed! The extension now works correctly for: 3. All unit tests continue to pass (41 tests) - **Location**: - `.nycrc` - simplified configuration (lines 1-23) -- **Version**: Fixed post-v0.1.4 (not yet released) +- **Version**: Fixed in v0.1.5 (pending release) **Test Status After Fixes:** - ✅ 41 unit tests passing (storageManager: 22 tests, gitIntegration: 19 tests) @@ -980,3 +980,224 @@ All critical bugs have been fixed! The extension now works correctly for: - ✅ Tests run using TypeScript compilation (compile:tsc) for easier debugging - ✅ Production extension uses esbuild for optimal bundle size and performance - ⚠️ Coverage reporting still needs adjustment for esbuild bundled output (low priority) + +**9. Fixed keyboard shortcuts not using modern comment UI (Post v0.1.4)** + +- **Issue**: Multiple keyboard shortcuts were using old UI patterns instead of the modern comment editor interface + 1. Ctrl+Alt+N (Cmd+Alt+N) for adding notes used a simple input box + 2. Ctrl+Alt+H (Cmd+Alt+H) for viewing history opened a separate markdown document +- **Root Cause**: + 1. The `addNote` command used `vscode.window.showInputBox()` instead of the comment editor + 2. The `viewHistory` command used `vscode.window.showTextDocument()` instead of showing history in the comment thread + 3. These were inconsistent with the modern UI used by buttons (which properly use comment threads) +- **Fix**: Updated both commands to use the comment controller methods: + 1. `addNote` now uses `commentController.openCommentEditor()` (same as CodeLens) + 2. `viewHistory` now uses `commentController.showHistoryInThread()` (same as history button) +- **Why this works**: + 1. **For addNote**: Comment editor provides multi-line input, markdown support, formatting shortcuts (Ctrl/Cmd+B, I, K), and Save/Cancel buttons + 2. **For viewHistory**: History displays inline in the comment thread, preserving context and allowing users to stay in their editor + 3. Consistent UX across all interaction methods (keyboard shortcuts, buttons, and CodeLens) + 4. Better integration with VSCode's native comment system +- **Keyboard Shortcuts Status**: + - ✅ **Ctrl+Alt+N** - Add Note (now opens comment editor) + - ✅ **Ctrl+Alt+H** - View History (now shows in comment thread) + - ✅ **Ctrl+Alt+D** - Delete Note (already correct - shows confirmation dialog) + - ✅ **Ctrl+Alt+R** - Refresh Notes (already correct - refreshes UI) + - ✅ **Ctrl/Cmd+B, I, K, etc.** - Markdown formatting (only work in comment editor) +- **Location**: + - `src/extension.ts` - updated `addNote` command (lines 167-196) + - `src/extension.ts` - updated `viewHistory` command (lines 282-318) +- **Version**: Fixed in v0.1.5 (pending release) + +**10. Fixed + icon comment editor not saving notes (Post v0.1.4)** + +- **Issue**: When clicking the + icon in the editor gutter to add a comment without selecting code, the comment editor opens but clicking Save doesn't save the note +- **Root Cause**: The `handleSaveNewNote` method expected threads to have custom properties (`tempId` and `sourceDocument`) that are only set by our `openCommentEditor()` method. When VSCode creates threads via the + icon, these properties don't exist, causing the method to fail silently because it couldn't find the document +- **Fix**: Updated `handleSaveNewNote` to handle both cases: + 1. Threads created by our code (via keyboard shortcuts or CodeLens) - uses the custom `sourceDocument` property + 2. Threads created by VSCode's + icon - finds the document by matching URIs from `vscode.workspace.textDocuments` + 3. Falls back to `vscode.workspace.openTextDocument(thread.uri)` if document not found in workspace + 4. Shows error message if document still cannot be found +- **Why this works**: + 1. The thread always has a `uri` property regardless of how it was created + 2. We can reliably find the document by matching its URI + 3. Handles all thread creation scenarios: keyboard shortcuts, CodeLens, and VSCode's native + icon + 4. Provides clear error messages if document cannot be found +- **Location**: + - `src/commentController.ts` - updated `handleSaveNewNote` method (lines 240-298) +- **Version**: Fixed in v0.1.5 (pending release) + + +## Enhancement: Auto-Collapse All Other Notes + +**Task:** Auto-collapse all other notes when opening/editing/viewing a note +**Status:** COMPLETE +**Date:** October 19, 2025 + +**Implementation:** + +1. **New Helper Method: `closeAllCommentEditors()`** (commentController.ts:198-220) + - Collapses ALL comment threads (not just expanded ones) + - Distinguishes between temporary threads (new notes) and editing threads + - Disposes temporary/editing threads completely + - Collapses all other threads regardless of current state + - Ensures only one note is visible at a time + +2. **Updated Methods:** + - ✅ `openCommentEditor()` - Collapses all others before opening new note editor + - ✅ `enableEditMode()` - Collapses all others before editing existing note + - ✅ `focusNoteThread()` - Collapses all others before viewing/expanding note + +3. **Behavior:** + - When adding a new note (keyboard/CodeLens) → ALL other notes collapse + - When editing an existing note → ALL other notes collapse + - When viewing a note → ALL other notes collapse + - Only one note visible at a time for better focus + - Cleaner, more focused editing experience with reduced visual clutter + +4. **Testing:** + - ✅ Code compiles successfully + - ✅ No TypeScript errors + - ✅ Build passes with esbuild + +**Location:** +- `src/commentController.ts` - added `closeAllCommentEditors()` method (lines 198-220) +- `src/commentController.ts` - updated `openCommentEditor()` (line 233) +- `src/commentController.ts` - updated `enableEditMode()` (line 492) +- `src/commentController.ts` - updated `focusNoteThread()` (line 420) + +**Version**: v0.1.5 + +--- + +## Enhancement: Full Note Hiding When Opening New Editor + +**Task:** Completely hide all note editors when opening a new one (not just collapse input) +**Status:** COMPLETE +**Date:** October 19, 2025 + +**Implementation:** + +1. **Updated `closeAllCommentEditors()` Method** (commentController.ts:209-220) + - Changed behavior from selective collapse to complete disposal + - Now disposes ALL comment threads completely (temp, editing, expanded, and collapsed) + - Clears all threads from the tracking map + - Ensures complete hiding from the editor view + +2. **Previous Behavior:** + - Temporary/editing threads were disposed + - Expanded threads were collapsed + - Already collapsed threads stayed collapsed + - Result: Notes were still visible in collapsed state + +3. **New Behavior:** + - ALL threads disposed completely regardless of state + - All threads removed from tracking map + - Result: Full hiding - no notes visible in editor at all + - Only the new editor being opened will be visible + +4. **Why This Works:** + - Disposal completely removes threads from the UI (not just collapses them) + - Clearing the map ensures clean state + - When a note is saved, a new thread is created via `createCommentThread()` + - User sees only the one note they're working on at any time + +**Benefits:** +- Cleaner, more focused editing experience +- No visual clutter from collapsed notes +- Improved concentration on current task +- Better UX for note management + +**Testing:** +- ✅ Code compiles successfully +- ✅ No TypeScript errors +- ✅ Build passes with esbuild + +**Location:** +- `src/commentController.ts` - simplified `closeAllCommentEditors()` method (lines 209-220) + +**Version**: v0.1.5 + +--- + +## Enhancement: Ctrl+Enter Keyboard Shortcut for Saving Notes + +**Task:** Add Ctrl+Enter (Cmd+Enter on Mac) keyboard shortcut to save/update notes +**Status:** COMPLETE +**Date:** October 19, 2025 + +**Implementation:** + +1. **New Keybinding Added** (package.json:195-200) + - Command: `codeContextNotes.saveNote` + - Key: `ctrl+enter` (Windows/Linux) + - Key: `cmd+enter` (macOS) + - Context: `commentEditorFocused` (only active in comment editor) + +2. **Behavior:** + - When creating a new note: Press Ctrl+Enter to save the note + - When editing an existing note: Press Ctrl+Enter to save changes + - Only works when focused in the comment editor input field + - Same command as the Save button in the UI + +3. **Benefits:** + - Faster workflow - no need to click the Save button + - Familiar keyboard shortcut (common in many apps) + - Consistent with VSCode's comment submission patterns + - Works for both new notes and updates + +**Testing:** +- ✅ Code compiles successfully +- ✅ No TypeScript errors +- ✅ Build passes with esbuild + +**Location:** +- `package.json` - added keybinding configuration (lines 195-200) + +**Version**: v0.1.5 + +--- + +## UI Improvement: Enhanced Labels with Relevant Information + +**Task:** Improve labels across all note views with more relevant, useful information +**Status:** COMPLETE +**Date:** October 19, 2025 + +**Implementation:** + +1. **New Note Editor** (openCommentEditor - line 256) + - Label: `"Add your note"` + - Clearer call-to-action instead of generic "Start discussion" + +2. **View/Edit Notes** (createComment - lines 98-115) + - Smart label showing update status: + - If note has been edited: `"Last updated [date]"` + - If note is new (no history): `"Created [date]"` + - Automatically detects most recent change from history + - Provides at-a-glance information about note freshness + +3. **History Entries** (showHistoryInThread - lines 464-481) + - Descriptive label: `"[Action] on [date] at [time]"` + - Example: `"Updated on 10/19/2025 at 2:30:00 PM"` + - Shows action type (Created, Updated, Deleted) with full timestamp + - Content in body (without action prefix for cleaner display) + +**Benefits:** +- More informative labels that provide useful context +- Users can quickly see when notes were last modified +- History entries clearly show what action was taken and when +- Better UX with actionable and informative labels +- Maintains clean UI while adding valuable information + +**Testing:** +- ✅ Code compiles successfully +- ✅ No TypeScript errors +- ✅ Build passes with esbuild + +**Location:** +- `src/commentController.ts` - enhanced label in `openCommentEditor()` (line 256) +- `src/commentController.ts` - smart label logic in `createComment()` (lines 98-115) +- `src/commentController.ts` - detailed label in `showHistoryInThread()` (lines 464-481) + +**Version**: v0.1.5 diff --git a/package.json b/package.json index 557a954..1b7b49e 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "code-context-notes", "displayName": "Code Context Notes - Smart Annotations", "description": "Add contextual notes to your code with full version history and intelligent tracking", - "version": "0.1.4", + "version": "0.1.5", "publisher": "jnahian", "icon": "images/icon.png", "galleryBanner": { @@ -191,6 +191,12 @@ "key": "ctrl+k", "mac": "cmd+k", "when": "commentEditorFocused" + }, + { + "command": "codeContextNotes.saveNote", + "key": "ctrl+enter", + "mac": "cmd+enter", + "when": "commentEditorFocused" } ], "menus": { diff --git a/src/commentController.ts b/src/commentController.ts index ae2a6ba..1816e13 100644 --- a/src/commentController.ts +++ b/src/commentController.ts @@ -38,18 +38,8 @@ export class CommentController { // Set up comment options to support markdown with formatting hints this.commentController.options = { - prompt: 'Add a note (supports markdown) - Press F1 or use shortcuts below', - placeHolder: 'Write your note here...\n\n' + - '💡 Keyboard Shortcuts:\n' + - ' Ctrl/Cmd+B = **bold**\n' + - ' Ctrl/Cmd+I = *italic*\n' + - ' Ctrl/Cmd+Shift+C = `code`\n' + - ' Ctrl/Cmd+Shift+K = ```code block```\n' + - ' Ctrl/Cmd+K = [link](url)\n\n' + - '📝 Markdown Syntax:\n' + - ' **bold** *italic* `code` [link](url)\n' + - ' ```language\\ncode\\n``` for code blocks\n' + - ' > quote | - list | # heading' + prompt: 'Add a note (supports markdown)', + placeHolder: 'Write your note here...' }; // Disable reactions by not setting a reactionHandler @@ -105,14 +95,24 @@ export class CommentController { markdownBody.isTrusted = true; markdownBody.supportHtml = true; + // Create a relevant label showing last update info + const createdDate = new Date(note.createdAt); + const lastUpdated = note.history && note.history.length > 0 + ? new Date(note.history[note.history.length - 1].timestamp) + : createdDate; + + const isUpdated = note.history && note.history.length > 0; + const label = isUpdated + ? `Last updated ${lastUpdated.toLocaleDateString()}` + : `Created ${createdDate.toLocaleDateString()}`; + const comment: vscode.Comment = { body: markdownBody, mode: vscode.CommentMode.Preview, author: { name: note.author }, - label: `Created ${new Date(note.createdAt).toLocaleDateString()}`, - // Add Edit button as a command + label: label, // @ts-ignore - VSCode API supports this but types might be incomplete contextValue: note.id // Don't set reactions property - leaving it undefined disables reactions UI @@ -201,6 +201,24 @@ export class CommentController { threadsToDelete.forEach(id => this.commentThreads.delete(id)); } + /** + * Close/hide all comment threads except the one being worked on + * This ensures only one note is visible at a time for better focus + * Completely disposes all threads to fully hide them from the editor + */ + private closeAllCommentEditors(): void { + const threadsToDelete: string[] = []; + + for (const [noteId, thread] of this.commentThreads.entries()) { + // Dispose the thread completely to hide it from the editor + thread.dispose(); + threadsToDelete.push(noteId); + } + + // Clear all threads from the map + threadsToDelete.forEach(id => this.commentThreads.delete(id)); + } + /** * Open comment editor for creating a new note */ @@ -208,6 +226,9 @@ export class CommentController { document: vscode.TextDocument, range: vscode.Range ): Promise { + // Close all other comment editors first + this.closeAllCommentEditors(); + const lineRange: LineRange = { start: range.start.line, end: range.end.line @@ -222,7 +243,7 @@ export class CommentController { thread.collapsibleState = vscode.CommentThreadCollapsibleState.Expanded; thread.canReply = true; - thread.label = 'New Note'; + thread.label = 'Add your note'; // Store thread temporarily with range info for the input handler const tempId = `temp-${Date.now()}`; @@ -242,9 +263,39 @@ export class CommentController { content: string ): Promise { const tempId = (thread as any).tempId; - const document = (thread as any).sourceDocument as vscode.TextDocument; - if (!document || !content || !thread.range) { + // Get document - either from our custom property or find it by URI + let document: vscode.TextDocument | undefined = (thread as any).sourceDocument as vscode.TextDocument; + + if (!document) { + // Thread was created by VSCode's + icon, not our openCommentEditor method + // Find the document by URI + const docs = vscode.workspace.textDocuments; + document = docs.find(d => d.uri.toString() === thread.uri.toString()); + + if (!document) { + // Try to open the document + try { + document = await vscode.workspace.openTextDocument(thread.uri); + } catch (error) { + vscode.window.showErrorMessage('Could not find the document for this note'); + thread.dispose(); + return; + } + } + } + + // Final check - document must be defined at this point + if (!document) { + vscode.window.showErrorMessage('Could not find the document for this note'); + thread.dispose(); + if (tempId) { + this.commentThreads.delete(tempId); + } + return; + } + + if (!content || !thread.range) { thread.dispose(); if (tempId) { this.commentThreads.delete(tempId); @@ -353,6 +404,9 @@ export class CommentController { * Focus and expand a comment thread for a note */ async focusNoteThread(noteId: string, filePath: string): Promise { + // Close all other comment editors first + this.closeAllCommentEditors(); + const thread = this.commentThreads.get(noteId); if (!thread) { vscode.window.showErrorMessage('Note thread not found'); @@ -397,16 +451,20 @@ export class CommentController { const historyComments: vscode.Comment[] = [mainComment]; if (note.history && note.history.length > 0) { - for (const entry of note.history) { + for (let i = 0; i < note.history.length; i++) { + const entry = note.history[i]; + const timestamp = new Date(entry.timestamp); + const label = `${entry.action} on ${timestamp.toLocaleDateString()} at ${timestamp.toLocaleTimeString()}`; + const historyComment: vscode.Comment = { body: new vscode.MarkdownString( - `**${entry.action}**\n\n${entry.content || '*(no content)*'}` + `${entry.content || '*(no content)*'}` ), mode: vscode.CommentMode.Preview, author: { name: entry.author }, - label: new Date(entry.timestamp).toLocaleString() + label: label // Don't set reactions property - leaving it undefined disables reactions UI }; historyComments.push(historyComment); @@ -425,6 +483,9 @@ export class CommentController { * Enable edit mode for a note */ async enableEditMode(noteId: string, filePath: string): Promise { + // Close all other comment editors first + this.closeAllCommentEditors(); + const note = await this.noteManager.getNoteById(noteId, filePath); if (!note) { vscode.window.showErrorMessage('Note not found'); @@ -436,6 +497,9 @@ export class CommentController { return; } + // Expand the thread + thread.collapsibleState = vscode.CommentThreadCollapsibleState.Expanded; + // Switch comment to edit mode if (thread.comments.length > 0) { const comment = thread.comments[0]; diff --git a/src/extension.ts b/src/extension.ts index dd0a3a7..01db73d 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -164,7 +164,7 @@ const x = 1; * error messages if workspace-dependent features (noteManager, commentController) are not initialized */ function registerAllCommands(context: vscode.ExtensionContext) { - // Add Note to Selection (via command palette) + // Add Note to Selection (via command palette or keyboard shortcut) const addNoteCommand = vscode.commands.registerCommand( 'codeContextNotes.addNote', async () => { @@ -185,24 +185,12 @@ function registerAllCommands(context: vscode.ExtensionContext) { return; } - // Prompt for note content - const content = await vscode.window.showInputBox({ - prompt: 'Enter your note', - placeHolder: 'Add context about this code...', - ignoreFocusOut: true - }); - - if (!content) { - return; - } - try { + // Open comment editor UI (modern approach) const range = new vscode.Range(selection.start.line, 0, selection.end.line, 0); - await commentController.handleCreateNote(editor.document, range, content); - codeLensProvider.refresh(); - vscode.window.showInformationMessage('Note added successfully!'); + await commentController.openCommentEditor(editor.document, range); } catch (error) { - vscode.window.showErrorMessage(`Failed to add note: ${error}`); + vscode.window.showErrorMessage(`Failed to open comment editor: ${error}`); } } ); @@ -291,10 +279,15 @@ function registerAllCommands(context: vscode.ExtensionContext) { } ); - // View Note History + // View Note History (via keyboard shortcut) const viewHistoryCommand = vscode.commands.registerCommand( 'codeContextNotes.viewHistory', async () => { + if (!noteManager || !commentController) { + vscode.window.showErrorMessage('Code Context Notes requires a workspace folder to be opened.'); + return; + } + const editor = vscode.window.activeTextEditor; if (!editor) { vscode.window.showErrorMessage('No active editor'); @@ -316,17 +309,8 @@ function registerAllCommands(context: vscode.ExtensionContext) { } try { - const history = await noteManager.getNoteHistory(note.id, filePath); - const historyText = history.map(h => - `${new Date(h.timestamp).toLocaleString()} - ${h.author} - ${h.action}\n${h.content}\n` - ).join('\n---\n\n'); - - const doc = await vscode.workspace.openTextDocument({ - content: `# Note History\n\n${historyText}`, - language: 'markdown' - }); - - await vscode.window.showTextDocument(doc); + // Show history in comment thread (same as the button) + await commentController.showHistoryInThread(note.id, filePath); } catch (error) { vscode.window.showErrorMessage(`Failed to view history: ${error}`); }