1-
21import * as vscode from 'vscode' ;
32import { processClipboardLinesPure , processSingleLinePaste , processTypedNodePaste } from '../utils/pasteUtils' ;
3+ import { ExtensionState } from '../state/extensionState' ;
4+
45function detectBulletFromLine ( line : string ) : string | null {
56 // Match a bullet at the start: bullet char + space (including '+')
67 const match = line . match ( / ^ \s * ( [ \u2022 \- \* \• \+ ] ) \s / ) ;
@@ -25,43 +26,90 @@ function getBulletStyle(document: vscode.TextDocument, lineNumber: number): stri
2526}
2627
2728export class PasteWithBullets {
29+ private extensionState : ExtensionState ;
30+
31+ constructor ( extensionState : ExtensionState ) {
32+ this . extensionState = extensionState ;
33+ }
34+
2835 public async pasteWithBulletsCommand ( ) : Promise < void > {
2936 const editor = vscode . window . activeTextEditor ;
3037 if ( ! editor ) { return ; }
3138
32- const clipboardText = await vscode . env . clipboard . readText ( ) ;
33- const clipboardLines = clipboardText . split ( / \r ? \n / ) ;
34- if ( clipboardLines . length === 0 ) {
39+ const documentModel = this . extensionState . getDocumentModel ( editor . document . uri . toString ( ) ) ;
40+ if ( ! documentModel ) {
41+ // Fallback to default paste if model not found
3542 await vscode . commands . executeCommand ( 'default:paste' ) ;
3643 return ;
3744 }
3845
39- const { selection, document } = editor ;
40- const currentLine = document . lineAt ( selection . start . line ) ;
46+ await documentModel . performBulkUpdate ( async ( ) => {
47+ const clipboardText = await vscode . env . clipboard . readText ( ) ;
48+ const clipboardLines = clipboardText . split ( / \r ? \n / ) ;
49+ if ( clipboardLines . length === 0 ) {
50+ await vscode . commands . executeCommand ( 'default:paste' ) ;
51+ return ;
52+ }
4153
54+ const { selection, document } = editor ;
55+ const currentLine = document . lineAt ( selection . start . line ) ;
4256
43- // Typed node paste
44- if ( clipboardLines . length > 0 && / ^ \( \w + \) / . test ( clipboardLines [ 0 ] . trim ( ) ) ) {
45- const adjustedClipboardLines = processTypedNodePaste ( { clipboardLines } ) ;
46- const textToInsert = adjustedClipboardLines . join ( '\n' ) ;
47- let startLine = selection . start . line ;
48- await editor . edit ( editBuilder => {
49- editBuilder . replace ( selection , textToInsert ) ;
50- } ) ;
51- // Place cursor at end of last pasted line
52- const lastLineIdx = adjustedClipboardLines . length - 1 ;
53- const lastLineText = adjustedClipboardLines [ lastLineIdx ] || '' ;
54- const newPosition = new vscode . Position ( startLine + lastLineIdx , lastLineText . length ) ;
55- editor . selection = new vscode . Selection ( newPosition , newPosition ) ;
56- return ;
57- }
57+ // Typed node paste
58+ if ( clipboardLines . length > 0 && / ^ \( \w + \) / . test ( clipboardLines [ 0 ] . trim ( ) ) ) {
59+ const adjustedClipboardLines = processTypedNodePaste ( { clipboardLines } ) ;
60+ const textToInsert = adjustedClipboardLines . join ( '\n' ) ;
61+ let startLine = selection . start . line ;
62+ await editor . edit ( editBuilder => {
63+ editBuilder . replace ( selection , textToInsert ) ;
64+ } ) ;
65+ // Cursor placement is tricky in bulk update; this might need adjustment
66+ const lastLineIdx = adjustedClipboardLines . length - 1 ;
67+ const lastLineText = adjustedClipboardLines [ lastLineIdx ] || '' ;
68+ const newPosition = new vscode . Position ( startLine + lastLineIdx , lastLineText . length ) ;
69+ editor . selection = new vscode . Selection ( newPosition , newPosition ) ;
70+ return ;
71+ }
72+
73+ // Multi-line paste
74+ if ( clipboardLines . length > 1 ) {
75+ let partBeforeCursor : string ;
76+ let partAfterCursor : string ;
77+ let startLine = selection . start . line ;
78+ if ( selection . start . character === currentLine . firstNonWhitespaceCharacterIndex ) {
79+ partBeforeCursor = '' ;
80+ partAfterCursor = currentLine . text . substring ( selection . start . character ) ;
81+ } else {
82+ partBeforeCursor = currentLine . text . substring ( 0 , selection . start . character ) ;
83+ partAfterCursor = currentLine . text . substring ( selection . start . character ) ;
84+ }
85+ const bullet = getBulletStyle ( document , currentLine . lineNumber ) ;
86+ const newLines = processClipboardLinesPure ( {
87+ clipboardLines,
88+ partBeforeCursor,
89+ partAfterCursor,
90+ currentLineText : currentLine . text ,
91+ currentLineIndent : currentLine . firstNonWhitespaceCharacterIndex ,
92+ bulletTypeForLine : ( ) => ( { bulletType : 'none' } ) ,
93+ getBullet : ( ) => bullet ,
94+ document,
95+ lineNumber : currentLine . lineNumber
96+ } ) ;
97+ await editor . edit ( editBuilder => {
98+ editBuilder . replace ( currentLine . range , newLines . join ( '\n' ) ) ;
99+ } ) ;
100+ const lastIdx = newLines . length - 1 ;
101+ const lastLineText = newLines [ lastIdx ] ;
102+ const afterTextLen = partAfterCursor . length ;
103+ const newChar = Math . max ( 0 , lastLineText . length - afterTextLen ) ;
104+ const newPosition = new vscode . Position ( startLine + lastIdx , newChar ) ;
105+ editor . selection = new vscode . Selection ( newPosition , newPosition ) ;
106+ return ;
107+ }
58108
59- // Multi-line paste
60- if ( clipboardLines . length > 1 ) {
109+ // Single-line paste
61110 let partBeforeCursor : string ;
62111 let partAfterCursor : string ;
63112 let startLine = selection . start . line ;
64- // If cursor is at first non-whitespace character, treat as start of line for bullet logic
65113 if ( selection . start . character === currentLine . firstNonWhitespaceCharacterIndex ) {
66114 partBeforeCursor = '' ;
67115 partAfterCursor = currentLine . text . substring ( selection . start . character ) ;
@@ -71,7 +119,7 @@ export class PasteWithBullets {
71119 }
72120 const bullet = getBulletStyle ( document , currentLine . lineNumber ) ;
73121 const newLines = processClipboardLinesPure ( {
74- clipboardLines,
122+ clipboardLines : [ clipboardLines [ 0 ] ] ,
75123 partBeforeCursor,
76124 partAfterCursor,
77125 currentLineText : currentLine . text ,
@@ -82,48 +130,12 @@ export class PasteWithBullets {
82130 lineNumber : currentLine . lineNumber
83131 } ) ;
84132 await editor . edit ( editBuilder => {
85- editBuilder . replace ( currentLine . range , newLines . join ( '\n' ) ) ;
133+ editBuilder . replace ( currentLine . range , newLines [ 0 ] ) ;
86134 } ) ;
87- // Place cursor just before the original partAfterCursor on the last pasted line
88- const lastIdx = newLines . length - 1 ;
89- const lastLineText = newLines [ lastIdx ] ;
90135 const afterTextLen = partAfterCursor . length ;
91- const newChar = Math . max ( 0 , lastLineText . length - afterTextLen ) ;
92- const newPosition = new vscode . Position ( startLine + lastIdx , newChar ) ;
136+ const newChar = Math . max ( 0 , newLines [ 0 ] . length - afterTextLen ) ;
137+ const newPosition = new vscode . Position ( startLine , newChar ) ;
93138 editor . selection = new vscode . Selection ( newPosition , newPosition ) ;
94- return ;
95- }
96-
97- // Single-line paste: use the same bullet detection and context as multi-line paste
98- let partBeforeCursor : string ;
99- let partAfterCursor : string ;
100- let startLine = selection . start . line ;
101- if ( selection . start . character === currentLine . firstNonWhitespaceCharacterIndex ) {
102- partBeforeCursor = '' ;
103- partAfterCursor = currentLine . text . substring ( selection . start . character ) ;
104- } else {
105- partBeforeCursor = currentLine . text . substring ( 0 , selection . start . character ) ;
106- partAfterCursor = currentLine . text . substring ( selection . start . character ) ;
107- }
108- const bullet = getBulletStyle ( document , currentLine . lineNumber ) ;
109- const newLines = processClipboardLinesPure ( {
110- clipboardLines : [ clipboardLines [ 0 ] ] ,
111- partBeforeCursor,
112- partAfterCursor,
113- currentLineText : currentLine . text ,
114- currentLineIndent : currentLine . firstNonWhitespaceCharacterIndex ,
115- bulletTypeForLine : ( ) => ( { bulletType : 'none' } ) ,
116- getBullet : ( ) => bullet ,
117- document,
118- lineNumber : currentLine . lineNumber
119- } ) ;
120- await editor . edit ( editBuilder => {
121- editBuilder . replace ( currentLine . range , newLines [ 0 ] ) ;
122139 } ) ;
123- // Place cursor just before the original partAfterCursor on the pasted line
124- const afterTextLen = partAfterCursor . length ;
125- const newChar = Math . max ( 0 , newLines [ 0 ] . length - afterTextLen ) ;
126- const newPosition = new vscode . Position ( startLine , newChar ) ;
127- editor . selection = new vscode . Selection ( newPosition , newPosition ) ;
128140 }
129141}
0 commit comments