@@ -602,7 +602,7 @@ class CsvEditorProvider implements vscode.CustomTextEditorProvider {
602602 document.body.setAttribute('tabindex', '0'); document.body.focus();
603603 const vscode = acquireVsCodeApi();
604604 let lastContextIsHeader = false; // remembers whether we right-clicked a <th>
605- let isUpdating = false, isSelecting = false, anchorCell = null, currentSelection = [];
605+ let isUpdating = false, isSelecting = false, anchorCell = null, rangeEndCell = null, currentSelection = [];
606606 let startCell = null, endCell = null, selectionMode = "cell";
607607 let editingCell = null, originalCellValue = "";
608608 const table = document.querySelector('table');
@@ -704,8 +704,32 @@ class CsvEditorProvider implements vscode.CustomTextEditorProvider {
704704
705705 table.addEventListener('mousedown', e => {
706706 if(e.target.tagName !== 'TD' && e.target.tagName !== 'TH') return;
707- if(editingCell){ if(e.target !== editingCell) editingCell.blur(); else return; } else clearSelection();
708707 const target = e.target;
708+
709+ // ──────── NEW: Shift+Click range selection ────────
710+ if (
711+ e.shiftKey &&
712+ anchorCell &&
713+ !editingCell &&
714+ target.getAttribute('data-row') !== null &&
715+ target.getAttribute('data-col') !== null &&
716+ anchorCell.getAttribute('data-row') !== null &&
717+ anchorCell.getAttribute('data-col') !== null &&
718+ target.getAttribute('data-col') !== '-1' &&
719+ anchorCell.getAttribute('data-col') !== '-1'
720+ ) {
721+ e.preventDefault();
722+ selectRange(
723+ getCellCoords(anchorCell),
724+ getCellCoords(target)
725+ );
726+ rangeEndCell = target;
727+ anchorCell.focus();
728+ return;
729+ }
730+
731+ if(editingCell){ if(e.target !== editingCell) editingCell.blur(); else return; } else clearSelection();
732+
709733 /* ──────── NEW: select-all via top-left header cell ──────── */
710734 if (
711735 target.tagName === 'TH' && // header cell
@@ -722,7 +746,7 @@ class CsvEditorProvider implements vscode.CustomTextEditorProvider {
722746 /* ──────── END NEW BLOCK ──────── */
723747
724748 selectionMode = (target.tagName === 'TH') ? "column" : (target.getAttribute('data-col') === '-1' ? "row" : "cell");
725- startCell = target; endCell = target; isSelecting = true; e.preventDefault();
749+ startCell = target; endCell = target; rangeEndCell = target; isSelecting = true; e.preventDefault();
726750 target.focus();
727751 });
728752 table.addEventListener('mousemove', e => {
@@ -731,6 +755,7 @@ class CsvEditorProvider implements vscode.CustomTextEditorProvider {
731755 if(selectionMode === "cell"){
732756 if(target.tagName === 'TD' || target.tagName === 'TH'){
733757 endCell = target;
758+ rangeEndCell = target;
734759 selectRange(getCellCoords(startCell), getCellCoords(endCell));
735760 }
736761 } else if(selectionMode === "column"){
@@ -739,6 +764,7 @@ class CsvEditorProvider implements vscode.CustomTextEditorProvider {
739764 target = table.querySelector('thead th[data-col="'+col+'"]') || target;
740765 }
741766 endCell = target;
767+ rangeEndCell = target;
742768 const startCol = parseInt(startCell.getAttribute('data-col'));
743769 const endCol = parseInt(endCell.getAttribute('data-col'));
744770 selectFullColumnRange(startCol, endCol);
@@ -748,6 +774,7 @@ class CsvEditorProvider implements vscode.CustomTextEditorProvider {
748774 target = table.querySelector('td[data-col="-1"][data-row="'+row+'"]') || target;
749775 }
750776 endCell = target;
777+ rangeEndCell = target;
751778 const startRow = parseInt(startCell.getAttribute('data-row'));
752779 const endRow = parseInt(endCell.getAttribute('data-row'));
753780 selectFullRowRange(startRow, endRow);
@@ -758,16 +785,20 @@ class CsvEditorProvider implements vscode.CustomTextEditorProvider {
758785 isSelecting = false;
759786 if(selectionMode === "cell"){
760787 if(startCell === endCell){
761- clearSelection(); startCell.classList.add('selected'); currentSelection.push(startCell); anchorCell = startCell;
762- } else { anchorCell = startCell; }
788+ clearSelection();
789+ startCell.classList.add('selected');
790+ currentSelection.push(startCell);
791+ }
792+ anchorCell = startCell;
793+ rangeEndCell = endCell;
763794 } else if(selectionMode === "column"){
764795 const startCol = parseInt(startCell.getAttribute('data-col'));
765796 const endCol = parseInt(endCell.getAttribute('data-col'));
766- selectFullColumnRange(startCol, endCol); anchorCell = startCell;
797+ selectFullColumnRange(startCol, endCol); anchorCell = startCell; rangeEndCell = endCell;
767798 } else if(selectionMode === "row"){
768799 const startRow = parseInt(startCell.getAttribute('data-row'));
769800 const endRow = parseInt(endCell.getAttribute('data-row'));
770- selectFullRowRange(startRow, endRow); anchorCell = startCell;
801+ selectFullRowRange(startRow, endRow); anchorCell = startCell; rangeEndCell = endCell;
771802 }
772803 });
773804 const selectRange = (start, end) => {
@@ -887,6 +918,28 @@ class CsvEditorProvider implements vscode.CustomTextEditorProvider {
887918 }
888919
889920 /* ──────── ARROW KEY NAVIGATION ──────── */
921+ if (!editingCell && anchorCell && e.shiftKey && ['ArrowUp','ArrowDown','ArrowLeft','ArrowRight'].includes(e.key)) {
922+ const { row, col } = getCellCoords(rangeEndCell || anchorCell);
923+ let targetRow = row, targetCol = col;
924+ switch(e.key){
925+ case 'ArrowUp': targetRow = row - 1; break;
926+ case 'ArrowDown': targetRow = row + 1; break;
927+ case 'ArrowLeft': targetCol = col - 1; break;
928+ case 'ArrowRight':targetCol = col + 1; break;
929+ }
930+ if(targetRow < 0 || targetCol < 0) return;
931+ const tag = (hasHeader && targetRow === 0 ? 'th' : 'td');
932+ const nextCell = table.querySelector(\`\${tag}[data-row="\${targetRow}"][data-col="\${targetCol}"]\`);
933+ if(nextCell){
934+ e.preventDefault();
935+ rangeEndCell = nextCell;
936+ selectRange(getCellCoords(anchorCell), getCellCoords(rangeEndCell));
937+ anchorCell.focus({preventScroll:true});
938+ rangeEndCell.scrollIntoView({ block:'nearest', inline:'nearest', behavior:'smooth' });
939+ }
940+ return;
941+ }
942+
890943 if (!editingCell && anchorCell && ['ArrowUp','ArrowDown','ArrowLeft','ArrowRight'].includes(e.key)) {
891944 const { row, col } = getCellCoords(anchorCell);
892945 let targetRow = row, targetCol = col;
@@ -905,6 +958,7 @@ class CsvEditorProvider implements vscode.CustomTextEditorProvider {
905958 nextCell.classList.add('selected');
906959 currentSelection.push(nextCell);
907960 anchorCell = nextCell;
961+ rangeEndCell = nextCell;
908962 nextCell.focus({preventScroll:true});
909963 nextCell.scrollIntoView({ block:'nearest', inline:'nearest', behavior:'smooth' });
910964 }
0 commit comments