1
+ /*---------------------------------------------------------------------------------------------
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License. See License.txt in the project root for license information.
4
+ *--------------------------------------------------------------------------------------------*/
5
+
6
+ 'use strict' ;
7
+
8
+ import { CodeActionProvider , TextDocument , Range , CancellationToken , CodeActionContext , Command , commands , workspace , WorkspaceEdit , window , QuickPickItem } from 'vscode' ;
9
+
10
+ import * as Proto from '../protocol' ;
11
+ import { ITypescriptServiceClient } from '../typescriptService' ;
12
+
13
+
14
+ export default class TypeScriptRefactorProvider implements CodeActionProvider {
15
+ private doRefactorCommandId : string ;
16
+ private selectRefactorCommandId : string ;
17
+
18
+ constructor (
19
+ private readonly client : ITypescriptServiceClient ,
20
+ mode : string
21
+ ) {
22
+ this . doRefactorCommandId = `_typescript.applyRefactoring.${ mode } ` ;
23
+ this . selectRefactorCommandId = `_typescript.selectRefactoring.${ mode } ` ;
24
+
25
+ commands . registerCommand ( this . doRefactorCommandId , this . doRefactoring , this ) ;
26
+ commands . registerCommand ( this . selectRefactorCommandId , this . selectRefactoring , this ) ;
27
+
28
+ }
29
+
30
+ public async provideCodeActions (
31
+ document : TextDocument ,
32
+ range : Range ,
33
+ _context : CodeActionContext ,
34
+ token : CancellationToken
35
+ ) : Promise < Command [ ] > {
36
+ if ( ! this . client . apiVersion . has240Features ( ) ) {
37
+ return [ ] ;
38
+ }
39
+
40
+ const file = this . client . normalizePath ( document . uri ) ;
41
+ if ( ! file ) {
42
+ return [ ] ;
43
+ }
44
+
45
+ const args : Proto . GetApplicableRefactorsRequestArgs = {
46
+ file : file ,
47
+ startLine : range . start . line + 1 ,
48
+ startOffset : range . start . character + 1 ,
49
+ endLine : range . end . line + 1 ,
50
+ endOffset : range . end . character + 1
51
+ } ;
52
+
53
+ try {
54
+ const response = await this . client . execute ( 'getApplicableRefactors' , args , token ) ;
55
+ if ( ! response || ! response . body ) {
56
+ return [ ] ;
57
+ }
58
+
59
+ const actions : Command [ ] = [ ] ;
60
+ for ( const info of response . body ) {
61
+ if ( info . inlineable === false ) {
62
+ actions . push ( {
63
+ title : info . description ,
64
+ command : this . selectRefactorCommandId ,
65
+ arguments : [ file , info , range ]
66
+ } ) ;
67
+ } else {
68
+ for ( const action of info . actions ) {
69
+ actions . push ( {
70
+ title : action . description ,
71
+ command : this . doRefactorCommandId ,
72
+ arguments : [ file , info . name , action . name , range ]
73
+ } ) ;
74
+ }
75
+ }
76
+ }
77
+ return actions ;
78
+ } catch ( err ) {
79
+ return [ ] ;
80
+ }
81
+ }
82
+
83
+ private toWorkspaceEdit ( edits : Proto . FileCodeEdits [ ] ) : WorkspaceEdit {
84
+ const workspaceEdit = new WorkspaceEdit ( ) ;
85
+ for ( const edit of edits ) {
86
+ for ( const textChange of edit . textChanges ) {
87
+ workspaceEdit . replace ( this . client . asUrl ( edit . fileName ) ,
88
+ new Range (
89
+ textChange . start . line - 1 , textChange . start . offset - 1 ,
90
+ textChange . end . line - 1 , textChange . end . offset - 1 ) ,
91
+ textChange . newText ) ;
92
+ }
93
+ }
94
+ return workspaceEdit ;
95
+ }
96
+
97
+ private async selectRefactoring ( file : string , info : Proto . ApplicableRefactorInfo , range : Range ) : Promise < boolean > {
98
+ return window . showQuickPick ( info . actions . map ( ( action ) : QuickPickItem => ( {
99
+ label : action . name ,
100
+ description : action . description
101
+ } ) ) ) . then ( selected => {
102
+ if ( ! selected ) {
103
+ return false ;
104
+ }
105
+ return this . doRefactoring ( file , info . name , selected . label , range ) ;
106
+ } ) ;
107
+ }
108
+
109
+ private async doRefactoring ( file : string , refactor : string , action : string , range : Range ) : Promise < boolean > {
110
+ const args : Proto . GetEditsForRefactorRequestArgs = {
111
+ file,
112
+ refactor,
113
+ action,
114
+ startLine : range . start . line + 1 ,
115
+ startOffset : range . start . character + 1 ,
116
+ endLine : range . end . line + 1 ,
117
+ endOffset : range . end . character + 1
118
+ } ;
119
+
120
+ const response = await this . client . execute ( 'getEditsForRefactor' , args ) ;
121
+ if ( ! response || ! response . body || ! response . body . edits . length ) {
122
+ return false ;
123
+ }
124
+
125
+ const edit = this . toWorkspaceEdit ( response . body . edits ) ;
126
+ return workspace . applyEdit ( edit ) ;
127
+ }
128
+ }
0 commit comments