@@ -3,20 +3,28 @@ import * as vscode from "vscode";
33import { assert } from "./util" ;
44import { unwrapUndefinable } from "./undefinable" ;
55
6- export async function applySnippetWorkspaceEdit ( edit : vscode . WorkspaceEdit ) {
7- if ( edit . entries ( ) . length === 1 ) {
8- const [ uri , edits ] = unwrapUndefinable ( edit . entries ( ) [ 0 ] ) ;
6+ export type SnippetTextDocumentEdit = [ vscode . Uri , ( vscode . TextEdit | vscode . SnippetTextEdit ) [ ] ] ;
7+
8+ export async function applySnippetWorkspaceEdit (
9+ edit : vscode . WorkspaceEdit ,
10+ editEntries : SnippetTextDocumentEdit [ ] ,
11+ ) {
12+ if ( editEntries . length === 1 ) {
13+ const [ uri , edits ] = unwrapUndefinable ( editEntries [ 0 ] ) ;
914 const editor = await editorFromUri ( uri ) ;
10- if ( editor ) await applySnippetTextEdits ( editor , edits ) ;
15+ if ( editor ) {
16+ edit . set ( uri , edits ) ;
17+ await vscode . workspace . applyEdit ( edit ) ;
18+ }
1119 return ;
1220 }
13- for ( const [ uri , edits ] of edit . entries ( ) ) {
21+ for ( const [ uri , edits ] of editEntries ) {
1422 const editor = await editorFromUri ( uri ) ;
1523 if ( editor ) {
1624 await editor . edit ( ( builder ) => {
1725 for ( const indel of edits ) {
1826 assert (
19- ! parseSnippet ( indel . newText ) ,
27+ ! ( indel instanceof vscode . SnippetTextEdit ) ,
2028 `bad ws edit: snippet received with multiple edits: ${ JSON . stringify (
2129 edit ,
2230 ) } `,
@@ -39,53 +47,30 @@ async function editorFromUri(uri: vscode.Uri): Promise<vscode.TextEditor | undef
3947}
4048
4149export async function applySnippetTextEdits ( editor : vscode . TextEditor , edits : vscode . TextEdit [ ] ) {
42- const selections : vscode . Selection [ ] = [ ] ;
43- let lineDelta = 0 ;
44- await editor . edit ( ( builder ) => {
45- for ( const indel of edits ) {
46- const parsed = parseSnippet ( indel . newText ) ;
47- if ( parsed ) {
48- const [ newText , [ placeholderStart , placeholderLength ] ] = parsed ;
49- const prefix = newText . substr ( 0 , placeholderStart ) ;
50- const lastNewline = prefix . lastIndexOf ( "\n" ) ;
51-
52- const startLine = indel . range . start . line + lineDelta + countLines ( prefix ) ;
53- const startColumn =
54- lastNewline === - 1
55- ? indel . range . start . character + placeholderStart
56- : prefix . length - lastNewline - 1 ;
57- const endColumn = startColumn + placeholderLength ;
58- selections . push (
59- new vscode . Selection (
60- new vscode . Position ( startLine , startColumn ) ,
61- new vscode . Position ( startLine , endColumn ) ,
62- ) ,
63- ) ;
64- builder . replace ( indel . range , newText ) ;
65- } else {
66- builder . replace ( indel . range , indel . newText ) ;
67- }
68- lineDelta +=
69- countLines ( indel . newText ) - ( indel . range . end . line - indel . range . start . line ) ;
70- }
71- } ) ;
72- if ( selections . length > 0 ) editor . selections = selections ;
73- if ( selections . length === 1 ) {
74- const selection = unwrapUndefinable ( selections [ 0 ] ) ;
75- editor . revealRange ( selection , vscode . TextEditorRevealType . InCenterIfOutsideViewport ) ;
76- }
50+ const edit = new vscode . WorkspaceEdit ( ) ;
51+ edit . set ( editor . document . uri , toSnippetTextEdits ( edits ) ) ;
52+ await vscode . workspace . applyEdit ( edit ) ;
7753}
7854
79- function parseSnippet ( snip : string ) : [ string , [ number , number ] ] | undefined {
80- const m = snip . match ( / \$ ( 0 | \{ 0 : ( [ ^ } ] * ) \} ) / ) ;
81- if ( ! m ) return undefined ;
82- const placeholder = m [ 2 ] ?? "" ;
83- if ( m . index == null ) return undefined ;
84- const range : [ number , number ] = [ m . index , placeholder . length ] ;
85- const insert = snip . replace ( m [ 0 ] , placeholder ) ;
86- return [ insert , range ] ;
55+ function hasSnippet ( snip : string ) : boolean {
56+ const m = snip . match ( / \$ \d + | \{ \d + : [ ^ } ] * \} / ) ;
57+ return m != null ;
8758}
8859
89- function countLines ( text : string ) : number {
90- return ( text . match ( / \n / g) || [ ] ) . length ;
60+ function toSnippetTextEdits (
61+ edits : vscode . TextEdit [ ] ,
62+ ) : ( vscode . TextEdit | vscode . SnippetTextEdit ) [ ] {
63+ return edits . map ( ( textEdit ) => {
64+ // Note: text edits without any snippets are returned as-is instead of
65+ // being wrapped in a SnippetTextEdit, as otherwise it would be
66+ // treated as if it had a tab stop at the end.
67+ if ( hasSnippet ( textEdit . newText ) ) {
68+ return new vscode . SnippetTextEdit (
69+ textEdit . range ,
70+ new vscode . SnippetString ( textEdit . newText ) ,
71+ ) ;
72+ } else {
73+ return textEdit ;
74+ }
75+ } ) ;
9176}
0 commit comments