@@ -89,6 +89,12 @@ class CsvEditorProvider implements vscode.CustomTextEditorProvider {
8989 CsvEditorProvider . editors . push ( this ) ;
9090 webviewPanel . webview . options = { enableScripts : true } ;
9191 this . updateWebviewContent ( ) ;
92+ webviewPanel . webview . postMessage ( { type : 'focus' } ) ;
93+ webviewPanel . onDidChangeViewState ( e => {
94+ if ( e . webviewPanel . active ) {
95+ e . webviewPanel . webview . postMessage ( { type : 'focus' } ) ;
96+ }
97+ } ) ;
9298
9399 // Handle messages from the webview.
94100 webviewPanel . webview . onDidReceiveMessage ( async e => {
@@ -187,7 +193,7 @@ class CsvEditorProvider implements vscode.CustomTextEditorProvider {
187193 while ( data [ row ] . length <= col ) data [ row ] . push ( '' ) ;
188194 data [ row ] [ col ] = value ;
189195 const newCsvText = Papa . unparse ( data , { delimiter : separator } ) ;
190- const fullRange = new vscode . Range ( 0 , 0 , this . document . lineCount , this . document . lineAt ( this . document . lineCount - 1 ) . text . length ) ;
196+ const fullRange = new vscode . Range ( 0 , 0 , this . document . lineCount , this . document . lineCount ? this . document . lineAt ( this . document . lineCount - 1 ) . text . length : 0 ) ;
191197 const edit = new vscode . WorkspaceEdit ( ) ;
192198 edit . replace ( this . document . uri , fullRange , newCsvText ) ;
193199 await vscode . workspace . applyEdit ( edit ) ;
@@ -478,6 +484,7 @@ class CsvEditorProvider implements vscode.CustomTextEditorProvider {
478484 <div id="contextMenu"></div>
479485 <script nonce="${ nonce } ">
480486 document.body.setAttribute('tabindex', '0'); document.body.focus();
487+ window.addEventListener('mousedown', () => document.body.focus());
481488 const vscode = acquireVsCodeApi();
482489 let isUpdating = false, isSelecting = false, anchorCell = null, currentSelection = [];
483490 let startCell = null, endCell = null, selectionMode = "cell";
@@ -545,6 +552,7 @@ class CsvEditorProvider implements vscode.CustomTextEditorProvider {
545552 const target = e.target;
546553 selectionMode = (target.tagName === 'TH') ? "column" : (target.getAttribute('data-col') === '-1' ? "row" : "cell");
547554 startCell = target; endCell = target; isSelecting = true; e.preventDefault();
555+ target.focus();
548556 });
549557 table.addEventListener('mousemove', e => {
550558 if(!isSelecting) return;
@@ -682,6 +690,56 @@ class CsvEditorProvider implements vscode.CustomTextEditorProvider {
682690 if ((e.ctrlKey || e.metaKey) && e.key === 'c' && currentSelection.length > 0) {
683691 e.preventDefault(); copySelectionToClipboard(); return;
684692 }
693+
694+ /* ──────── NEW: ENTER + DIRECT TYPING HANDLERS ──────── */
695+ if (!editingCell && anchorCell && currentSelection.length === 1) {
696+ /* Enter opens edit mode */
697+ if (e.key === 'Enter') {
698+ e.preventDefault();
699+ editCell(anchorCell);
700+ return;
701+ }
702+ /* Typing clears cell and opens edit mode */
703+ if (e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {
704+ e.preventDefault();
705+ const cell = anchorCell;
706+ editCell(cell);
707+ cell.innerText = '';
708+ if (document.execCommand) {
709+ document.execCommand('insertText', false, e.key);
710+ } else {
711+ cell.innerText = e.key;
712+ }
713+ setCursorToEnd(cell);
714+ return;
715+ }
716+ }
717+
718+ /* ──────── ARROW KEY NAVIGATION ──────── */
719+ if (!editingCell && anchorCell && ['ArrowUp','ArrowDown','ArrowLeft','ArrowRight'].includes(e.key)) {
720+ const { row, col } = getCellCoords(anchorCell);
721+ let targetRow = row, targetCol = col;
722+ switch(e.key){
723+ case 'ArrowUp': targetRow = row - 1; break;
724+ case 'ArrowDown': targetRow = row + 1; break;
725+ case 'ArrowLeft': targetCol = col - 1; break;
726+ case 'ArrowRight':targetCol = col + 1; break;
727+ }
728+ if(targetRow < 0 || targetCol < 0) return;
729+ const tag = (hasHeader && targetRow === 0 ? 'th' : 'td');
730+ const nextCell = table.querySelector(\`\${tag}[data-row="\${targetRow}"][data-col="\${targetCol}"]\`);
731+ if(nextCell){
732+ e.preventDefault();
733+ clearSelection();
734+ nextCell.classList.add('selected');
735+ currentSelection.push(nextCell);
736+ anchorCell = nextCell;
737+ nextCell.focus({preventScroll:true});
738+ nextCell.scrollIntoView({ block:'nearest', inline:'nearest', behavior:'smooth' });
739+ }
740+ return;
741+ }
742+
685743 if (editingCell && ((e.ctrlKey || e.metaKey) && e.key === 's')) {
686744 e.preventDefault();
687745 editingCell.blur();
@@ -700,10 +758,8 @@ class CsvEditorProvider implements vscode.CustomTextEditorProvider {
700758 editingCell.blur();
701759 let nextCell;
702760 if (e.shiftKey) {
703- // Shift+Tab: move to the previous cell (decrement column index)
704761 nextCell = table.querySelector('td[data-row="'+row+'"][data-col="'+(col-1)+'"]');
705762 } else {
706- // Tab: move to the next cell (increment column index)
707763 nextCell = table.querySelector('td[data-row="'+row+'"][data-col="'+(col+1)+'"]');
708764 }
709765 if (nextCell) {
@@ -713,7 +769,6 @@ class CsvEditorProvider implements vscode.CustomTextEditorProvider {
713769 if (editingCell && e.key === 'Escape') {
714770 e.preventDefault(); editingCell.innerText = originalCellValue; editingCell.blur();
715771 }
716- // If not editing, pressing Escape clears the selection.
717772 if (!editingCell && e.key === 'Escape') {
718773 clearSelection();
719774 }
@@ -738,7 +793,6 @@ class CsvEditorProvider implements vscode.CustomTextEditorProvider {
738793 cell.classList.add('editing');
739794 cell.setAttribute('contenteditable', 'true');
740795 cell.focus();
741- // Attach a blur handler to commit cell changes.
742796 const onBlurHandler = () => {
743797 const value = cell.innerText;
744798 const coords = getCellCoords(cell);
@@ -771,15 +825,16 @@ class CsvEditorProvider implements vscode.CustomTextEditorProvider {
771825 };
772826 window.addEventListener('message', event => {
773827 const message = event.data;
774- if(message.type === 'updateCell'){
828+ if(message.type === 'focus'){
829+ document.body.focus();
830+ } else if(message.type === 'updateCell'){
775831 isUpdating = true;
776832 const { row, col, value } = message;
777833 const cell = table.querySelector('td[data-row="'+row+'"][data-col="'+col+'"]');
778834 if(cell){ cell.innerText = value; }
779835 isUpdating = false;
780836 }
781837 });
782- // Global Escape handler to clear selection when not editing.
783838 document.addEventListener('keydown', e => {
784839 if(!editingCell && e.key === 'Escape'){
785840 clearSelection();
0 commit comments