* This is easily the worst function in VSCodeVim. * * We need to know when VSCode has updated our selection, so that we can sync * that internally. Unfortunately, VSCode has a habit of calling this * function at weird times, or or with incomplete information, so we have to * do a lot
(e: vscode.TextEditorSelectionChangeEvent)
| 171 | * cursor start position). |
| 172 | */ |
| 173 | public async handleSelectionChange(e: vscode.TextEditorSelectionChangeEvent): Promise<void> { |
| 174 | if ( |
| 175 | vscode.window.activeTextEditor === undefined || |
| 176 | e.textEditor.document !== vscode.window.activeTextEditor.document |
| 177 | ) { |
| 178 | // we don't care if there is no active editor |
| 179 | // or user selection changed in a paneled window (e.g debug console/terminal) |
| 180 | // This check is made before enqueuing this selection change, but sometimes |
| 181 | // between the enqueueing and the actual calling of this function the editor |
| 182 | // might close or change to other document |
| 183 | return; |
| 184 | } |
| 185 | const selection = e.selections[0]; |
| 186 | Logger.debug( |
| 187 | `Selection change: ${selection.anchor.toString()}, ${selection.active}, SelectionsLength: ${ |
| 188 | e.selections.length |
| 189 | }`, |
| 190 | ); |
| 191 | |
| 192 | // If our previous cursors are not included on any of the current selections, then a snippet |
| 193 | // must have been inserted. |
| 194 | const isSnippetSelectionChange = () => { |
| 195 | return e.selections.every((s) => { |
| 196 | return this.vimState.cursors.every((c) => !s.contains(new vscode.Range(c.start, c.stop))); |
| 197 | }); |
| 198 | }; |
| 199 | |
| 200 | if ( |
| 201 | (e.selections.length !== this.vimState.cursors.length || this.vimState.isMultiCursor) && |
| 202 | this.vimState.currentMode !== Mode.VisualBlock |
| 203 | ) { |
| 204 | const allowedModes = [Mode.Normal]; |
| 205 | if (!isSnippetSelectionChange()) { |
| 206 | allowedModes.push(Mode.Insert, Mode.Replace); |
| 207 | } |
| 208 | // Number of selections changed, make sure we know about all of them still |
| 209 | this.vimState.cursors = e.textEditor.selections.map( |
| 210 | (sel) => |
| 211 | new Cursor( |
| 212 | // Adjust the cursor positions because cursors & selections don't match exactly |
| 213 | sel.anchor.isAfter(sel.active) ? sel.anchor.getLeft() : sel.anchor, |
| 214 | sel.active, |
| 215 | ), |
| 216 | ); |
| 217 | if ( |
| 218 | e.selections.some((s) => !s.anchor.isEqual(s.active)) && |
| 219 | allowedModes.includes(this.vimState.currentMode) |
| 220 | ) { |
| 221 | // If we got a visual selection and we are on normal, insert or replace mode, enter visual mode. |
| 222 | // We shouldn't go to visual mode on any other mode, because the other visual modes are handled |
| 223 | // very differently than vscode so only our extension will create them. And the other modes |
| 224 | // like the plugin modes shouldn't be changed or else it might mess up the plugins actions. |
| 225 | await this.setCurrentMode(Mode.Visual); |
| 226 | } |
| 227 | return this.updateView({ drawSelection: false, revealRange: false }); |
| 228 | } |
| 229 | |
| 230 | /** |
no test coverage detected