1
+ import vscode = require( 'vscode' ) ;
2
+ import { languages , TextDocument , TextEdit , FormattingOptions , CancellationToken } from 'vscode'
3
+ import { LanguageClient , RequestType , NotificationType } from 'vscode-languageclient' ;
4
+ import Window = vscode . window ;
5
+ import { IFeature } from '../feature' ;
6
+
7
+ export namespace ScriptFileMarkersRequest {
8
+ export const type : RequestType < any , any , void > = { get method ( ) : string { return "powerShell/getScriptFileMarkers" ; } } ;
9
+ }
10
+
11
+ // TODO move some of the common interface to a separate file?
12
+ interface ScriptFileMarkersRequestParams {
13
+ filePath : string ;
14
+ rules : string [ ] ;
15
+ }
16
+
17
+ interface ScriptFileMarkersRequestResultParams {
18
+ markers : ScriptFileMarker [ ] ;
19
+ }
20
+
21
+ interface ScriptFileMarker {
22
+ message : string ;
23
+ level : ScriptFileMarkerLevel ;
24
+ scriptRegion : ScriptRegion ;
25
+ correction : MarkerCorrection ;
26
+ }
27
+
28
+ enum ScriptFileMarkerLevel {
29
+ Information = 0 ,
30
+ Warning ,
31
+ Error
32
+ }
33
+
34
+ interface ScriptRegion {
35
+ file : string ;
36
+ text : string ;
37
+ startLineNumber : number ;
38
+ startColumnNumber : number ;
39
+ startOffset : number ;
40
+ endLineNumber : number ;
41
+ endColumnNumber : number ;
42
+ endOffset : number ;
43
+ }
44
+
45
+ interface MarkerCorrection {
46
+ name : string ;
47
+ edits : ScriptRegion [ ]
48
+ }
49
+
50
+ class PSDocumentFormattingEditProvider implements vscode . DocumentFormattingEditProvider {
51
+ private languageClient : LanguageClient ;
52
+ private readonly ruleOrder : string [ ] = [
53
+ "PSPlaceCloseBrace" ,
54
+ "PSPlaceOpenBrace" ] ;
55
+
56
+ provideDocumentFormattingEdits (
57
+ document : TextDocument ,
58
+ options : FormattingOptions ,
59
+ token : CancellationToken ) : TextEdit [ ] | Thenable < TextEdit [ ] > {
60
+
61
+ // we need to order the edits such that edit i should not invalidate
62
+ // the edits in edit j s.t i < j (seems like a hard problem)
63
+ // or
64
+ // peform edits ourself and return an empty textedit array
65
+ return this . applyEditsInOrder ( document , options , 0 ) ;
66
+ }
67
+
68
+ applyEditsInOrder (
69
+ document : TextDocument ,
70
+ options : FormattingOptions ,
71
+ index : number ) : Thenable < TextEdit [ ] > | TextEdit [ ] {
72
+ if ( this . languageClient !== null && index < this . ruleOrder . length ) {
73
+ return this . languageClient . sendRequest (
74
+ ScriptFileMarkersRequest . type ,
75
+ {
76
+ filePath : document . fileName ,
77
+ rules : [ this . ruleOrder [ index ] ]
78
+ } )
79
+ . then ( ( result : ScriptFileMarkersRequestResultParams ) => {
80
+
81
+ // TODO modify undo stops to make sure all the edits
82
+ // can be undone and redone in a single step
83
+ this . applyEdits ( result . markers , 0 ) ;
84
+ this . applyEditsInOrder ( document , options , ++ index ) ;
85
+
86
+ // we do not return a valid array because our text edits
87
+ // need to be executed in a particular order and it is
88
+ // easier if we perform the edits ourselves
89
+ return TextEdit [ 0 ] ;
90
+ } ) ;
91
+ } else {
92
+ return TextEdit [ 0 ] ;
93
+ }
94
+ }
95
+
96
+ applyEdits ( markers : ScriptFileMarker [ ] , index : number ) : void {
97
+ if ( index >= markers . length ) {
98
+ return ;
99
+ }
100
+
101
+ let edit : ScriptRegion = markers [ index ++ ] . correction . edits [ 0 ] ;
102
+ Window . activeTextEditor . edit ( ( editBuilder ) => {
103
+ editBuilder . replace (
104
+ new vscode . Range (
105
+ edit . startLineNumber - 1 ,
106
+ edit . startColumnNumber - 1 ,
107
+ edit . endLineNumber - 1 ,
108
+ edit . endColumnNumber - 1 ) ,
109
+ edit . text ) ;
110
+ } ) . then ( ( isEditApplied ) => {
111
+ this . applyEdits ( markers , index ) ;
112
+ } ) ; // TODO handle rejection
113
+
114
+ }
115
+
116
+ setLanguageClient ( languageClient : LanguageClient ) : void {
117
+ this . languageClient = languageClient ;
118
+ }
119
+ }
120
+
121
+ export class DocumentFormatterFeature implements IFeature {
122
+ private disposable : vscode . Disposable ;
123
+ private languageClient : LanguageClient ;
124
+ private documentFormattingEditProvider : PSDocumentFormattingEditProvider ;
125
+
126
+ constructor ( ) {
127
+ this . documentFormattingEditProvider = new PSDocumentFormattingEditProvider ( ) ;
128
+ this . disposable = vscode . languages . registerDocumentFormattingEditProvider (
129
+ "powershell" ,
130
+ this . documentFormattingEditProvider ) ;
131
+ }
132
+
133
+ public setLanguageClient ( languageclient : LanguageClient ) : void {
134
+ this . languageClient = languageclient ;
135
+ this . documentFormattingEditProvider . setLanguageClient ( languageclient ) ;
136
+ }
137
+
138
+ public dispose ( ) : any {
139
+ this . disposable . dispose ( ) ;
140
+ }
141
+ }
0 commit comments