@@ -33,170 +33,10 @@ import {
33
33
} from './../../mode/mode' ;
34
34
import { Register , RegisterMode } from './../../register/register' ;
35
35
import { TextEditor } from './../../textEditor' ;
36
- import { Transformation } from './../../transformations/transformations' ;
37
36
import { BaseCommand , RegisterAction } from './../base' ;
38
37
import * as operator from './../operator' ;
39
38
import { Uri } from 'vscode' ;
40
39
41
- /**
42
- * A very special snowflake.
43
- *
44
- * Each keystroke when typing in Insert mode is its own Action, which means naively replaying a
45
- * realistic insertion (via `.` or a macro) does many small insertions, which is very slow.
46
- * So instead, we fold all those actions after the fact into a single DocumentContentChangeAction,
47
- * which compresses the changes, generally into a single document edit per cursor.
48
- */
49
- export class DocumentContentChangeAction extends BaseCommand {
50
- modes = [ ] ;
51
- keys = [ ] ;
52
- private readonly cursorStart : Position ;
53
- private cursorEnd : Position ;
54
-
55
- constructor ( cursorStart : Position ) {
56
- super ( ) ;
57
- this . cursorStart = cursorStart ;
58
- this . cursorEnd = cursorStart ;
59
- }
60
-
61
- private contentChanges : vscode . TextDocumentContentChangeEvent [ ] = [ ] ;
62
-
63
- public addChanges ( changes : vscode . TextDocumentContentChangeEvent [ ] , cursorPosition : Position ) {
64
- this . contentChanges = [ ...this . contentChanges , ...changes ] ;
65
- this . compressChanges ( ) ;
66
- this . cursorEnd = cursorPosition ;
67
- }
68
-
69
- public getTransformation ( positionDiff : PositionDiff ) : Transformation {
70
- return {
71
- type : 'contentChange' ,
72
- changes : this . contentChanges ,
73
- diff : positionDiff ,
74
- } ;
75
- }
76
-
77
- public override async exec ( position : Position , vimState : VimState ) : Promise < void > {
78
- if ( this . contentChanges . length === 0 ) {
79
- return ;
80
- }
81
-
82
- let originalLeftBoundary = this . cursorStart ;
83
-
84
- let rightBoundary : Position = position ;
85
- for ( const change of this . contentChanges ) {
86
- if ( change . range . start . line < originalLeftBoundary . line ) {
87
- // This change should be ignored
88
- const linesAffected = change . range . end . line - change . range . start . line + 1 ;
89
- const resultLines = change . text . split ( '\n' ) . length ;
90
- originalLeftBoundary = originalLeftBoundary . with (
91
- Math . max ( 0 , originalLeftBoundary . line + resultLines - linesAffected ) ,
92
- ) ;
93
- continue ;
94
- }
95
-
96
- // Translates diffPos from a position relative to originalLeftBoundary to one relative to position
97
- const translate = ( diffPos : Position ) : Position => {
98
- const lineOffset = diffPos . line - originalLeftBoundary . line ;
99
- const char =
100
- lineOffset === 0
101
- ? position . character + diffPos . character - originalLeftBoundary . character
102
- : diffPos . character ;
103
- // TODO: Should we document.validate() this position?
104
- return new Position ( Math . max ( position . line + lineOffset , 0 ) , Math . max ( char , 0 ) ) ;
105
- } ;
106
-
107
- const replaceRange = new vscode . Range (
108
- translate ( change . range . start ) ,
109
- translate ( change . range . end ) ,
110
- ) ;
111
-
112
- if ( replaceRange . start . isAfter ( rightBoundary ) ) {
113
- // This change should be ignored as it's out of boundary
114
- continue ;
115
- }
116
-
117
- // Calculate new right boundary
118
- const textDiffLines = change . text . split ( '\n' ) ;
119
- const numLinesAdded = textDiffLines . length - 1 ;
120
- const newRightBoundary =
121
- numLinesAdded === 0
122
- ? new Position ( replaceRange . start . line , replaceRange . start . character + change . text . length )
123
- : new Position ( replaceRange . start . line + numLinesAdded , textDiffLines . pop ( ) ! . length ) ;
124
-
125
- rightBoundary = laterOf ( rightBoundary , newRightBoundary ) ;
126
-
127
- if ( replaceRange . start . isEqual ( replaceRange . end ) ) {
128
- vimState . recordedState . transformer . insert (
129
- replaceRange . start ,
130
- change . text ,
131
- PositionDiff . exactPosition ( translate ( this . cursorEnd ) ) ,
132
- ) ;
133
- } else {
134
- vimState . recordedState . transformer . replace (
135
- replaceRange ,
136
- change . text ,
137
- PositionDiff . exactPosition ( translate ( this . cursorEnd ) ) ,
138
- ) ;
139
- }
140
- }
141
- }
142
-
143
- private compressChanges ( ) : void {
144
- const merge = (
145
- first : vscode . TextDocumentContentChangeEvent ,
146
- second : vscode . TextDocumentContentChangeEvent ,
147
- ) : vscode . TextDocumentContentChangeEvent | undefined => {
148
- if ( first . rangeOffset + first . text . length === second . rangeOffset ) {
149
- // Simple concatenation
150
- return {
151
- text : first . text + second . text ,
152
- range : first . range ,
153
- rangeOffset : first . rangeOffset ,
154
- rangeLength : first . rangeLength ,
155
- } ;
156
- } else if (
157
- first . rangeOffset <= second . rangeOffset &&
158
- first . text . length >= second . rangeLength
159
- ) {
160
- const start = second . rangeOffset - first . rangeOffset ;
161
- const end = start + second . rangeLength ;
162
- const text = first . text . slice ( 0 , start ) + second . text + first . text . slice ( end ) ;
163
- // `second` replaces part of `first`
164
- // Most often, this is the result of confirming an auto-completion
165
- return {
166
- text,
167
- range : first . range ,
168
- rangeOffset : first . rangeOffset ,
169
- rangeLength : first . rangeLength ,
170
- } ;
171
- } else {
172
- // TODO: Do any of the cases falling into this `else` matter?
173
- // TODO: YES - make an insertion and then autocomplete to something totally different (replace subsumes insert)
174
- return undefined ;
175
- }
176
- } ;
177
-
178
- const compressed : vscode . TextDocumentContentChangeEvent [ ] = [ ] ;
179
- let prev : vscode . TextDocumentContentChangeEvent | undefined ;
180
- for ( const change of this . contentChanges ) {
181
- if ( prev === undefined ) {
182
- prev = change ;
183
- } else {
184
- const merged = merge ( prev , change ) ;
185
- if ( merged ) {
186
- prev = merged ;
187
- } else {
188
- compressed . push ( prev ) ;
189
- prev = change ;
190
- }
191
- }
192
- }
193
- if ( prev !== undefined ) {
194
- compressed . push ( prev ) ;
195
- }
196
- this . contentChanges = compressed ;
197
- }
198
- }
199
-
200
40
@RegisterAction
201
41
class DisableExtension extends BaseCommand {
202
42
modes = [
0 commit comments