@@ -2,6 +2,11 @@ import * as vscode from "vscode";
2
2
import { AtelierAPI } from "../api" ;
3
3
import { config , FILESYSTEM_SCHEMA } from "../extension" ;
4
4
import { outputChannel } from "../utils" ;
5
+ import { DocumentContentProvider } from "../providers/DocumentContentProvider" ;
6
+ import { ClassNode } from "../explorer/models/classesNode" ;
7
+ import { PackageNode } from "../explorer/models/packageNode" ;
8
+ import { RoutineNode } from "../explorer/models/routineNode" ;
9
+ import { NodeBase } from "../explorer/models/nodeBase" ;
5
10
6
11
interface StudioAction extends vscode . QuickPickItem {
7
12
name : string ;
@@ -13,10 +18,19 @@ class StudioActions {
13
18
private api : AtelierAPI ;
14
19
private name : string ;
15
20
16
- public constructor ( uri : vscode . Uri ) {
17
- this . uri = uri ;
18
- this . name = this . uri . path . slice ( 1 ) . replace ( / \/ / g, "." ) ;
19
- this . api = new AtelierAPI ( uri . authority ) ;
21
+ public constructor ( uriOrNode : vscode . Uri | PackageNode | ClassNode | RoutineNode ) {
22
+ if ( uriOrNode instanceof vscode . Uri ) {
23
+ const uri : vscode . Uri = uriOrNode ;
24
+ this . uri = uri ;
25
+ this . name = this . uri . path . slice ( 1 ) . replace ( / \/ / g, "." ) ;
26
+ this . api = new AtelierAPI ( uri . authority ) ;
27
+ } else {
28
+ const node : NodeBase = uriOrNode ;
29
+ this . api = new AtelierAPI ( ) ;
30
+ this . name = ( node instanceof PackageNode )
31
+ ? node . fullName + ".PKG"
32
+ : node . fullName ;
33
+ }
20
34
}
21
35
22
36
public processUserAction ( userAction ) : Thenable < any > {
@@ -36,79 +50,133 @@ class StudioActions {
36
50
. showWarningMessage ( target , { modal : true } , "Yes" , "No" )
37
51
. then ( answer => ( answer === "Yes" ? "1" : answer === "No" ? "0" : "2" ) ) ;
38
52
case 2 : // Run a CSP page/Template. The Target is the full url to the CSP page/Template
39
- // Open the target URL in a webview
40
- const conn = config ( ) . conn ;
41
- const column = vscode . window . activeTextEditor
42
- ? vscode . window . activeTextEditor . viewColumn
43
- : undefined ;
44
- const panel = vscode . window . createWebviewPanel (
45
- 'studioactionwebview' ,
46
- 'CSP Page' ,
47
- column || vscode . ViewColumn . One ,
48
- {
49
- enableScripts : true ,
50
- }
51
- ) ;
52
- panel . webview . html = `
53
- <!DOCTYPE html>
54
- <html lang="en">
55
- <head>
56
- <style type="text/css">
57
- body, html
58
- {
59
- margin: 0; padding: 0; height: 100%; overflow: hidden;
60
- }
61
- #content
62
- {
63
- position:absolute; left: 0; right: 0; bottom: 0; top: 0px;
64
- }
65
- </style>
66
- </head>
67
- <body>
68
- <div id="content">
69
- <iframe src="http://${ conn . host } :${ conn . port } ${ target } " onLoad="checkForCancelState()" width="100%" height="100%" frameborder="0"></iframe>
70
- </div>
71
- <script>
72
- function checkForCancelState() {
73
- var x = document.getElementsByTagName("BODY")[0];
74
- console.log(x);
75
- }
76
- </script>
77
- </body>
78
- </html>
79
- ` ;
80
- panel . onDidDispose (
81
- ( ) => {
82
- // fire a cancel answer if the user closes the webview
83
- return "2" ;
84
- }
85
- ) ;
86
- // TODO: use panel.dispose() when the cancel text is sent back in the iframe
87
- break ;
88
- // throw new Error("Not suppoorted");
53
+ return new Promise ( ( resolve ) => {
54
+ let answer = "2" ;
55
+ const conn = config ( ) . conn ;
56
+ const column = vscode . window . activeTextEditor
57
+ ? vscode . window . activeTextEditor . viewColumn
58
+ : undefined ;
59
+ const panel = vscode . window . createWebviewPanel (
60
+ "studioactionwebview" ,
61
+ "Studio Extension Page" ,
62
+ column || vscode . ViewColumn . One ,
63
+ {
64
+ enableScripts : true ,
65
+ }
66
+ ) ;
67
+ panel . webview . onDidReceiveMessage ( message => {
68
+ if ( message . result && message . result === "done" ) {
69
+ answer = "1" ;
70
+ panel . dispose ( ) ;
71
+ }
72
+ } ) ;
73
+ panel . onDidDispose ( ( ) => resolve ( answer ) ) ;
74
+
75
+ const url = new URL ( `http://${ conn . host } :${ conn . port } ${ target } ` ) ;
76
+ const api = new AtelierAPI ( ) ;
77
+ api . actionQuery ( "select %Atelier_v1_Utils.General_GetCSPToken(?) token" , [ url . toString ( ) ] ) . then ( tokenObj => {
78
+ const csptoken = tokenObj . result . content [ 0 ] . token ;
79
+ url . searchParams . set ( 'CSPCHD' , csptoken ) ;
80
+ url . searchParams . set ( 'Namespace' , conn . ns ) ;
81
+ panel . webview . html = `
82
+ <!DOCTYPE html>
83
+ <html lang="en">
84
+ <head>
85
+ <style type="text/css">
86
+ body, html {
87
+ margin: 0; padding: 0; height: 100%; overflow: hidden;
88
+ background-color: white;
89
+ }
90
+ #content {
91
+ position:absolute; left: 0; right: 0; bottom: 0; top: 0px;
92
+ }
93
+ </style>
94
+ </head>
95
+ <body>
96
+ <div id="content">
97
+ <iframe src="${ url . toString ( ) } " width="100%" height="100%" frameborder="0"></iframe>
98
+ </div>
99
+ <script>
100
+ const vscode = acquireVsCodeApi();
101
+ window.addEventListener("message", receiveMessage, false);
102
+ function receiveMessage(event) {
103
+ vscode.postMessage(event.data);
104
+ }
105
+ </script>
106
+ </body>
107
+ </html>
108
+ ` ;
109
+ } ) ;
110
+ } ) ;
89
111
case 3 : // Run an EXE on the client.
90
112
throw new Error ( "Not suppoorted" ) ;
91
113
case 4 : // Insert the text in Target in the current document at the current selection point
92
- throw new Error ( "Not suppoorted" ) ;
114
+ const editor = vscode . window . activeTextEditor ;
115
+ if ( editor ) {
116
+ editor . edit ( editBuilder => {
117
+ editBuilder . replace ( editor . selection , target ) ;
118
+ } ) ;
119
+ }
120
+ return ;
93
121
case 5 : // Studio will open the documents listed in Target
94
- throw new Error ( "Not suppoorted" ) ;
122
+ target . split ( "," ) . forEach ( element => {
123
+ let classname = element ;
124
+ let method : string ;
125
+ let offset = 0 ;
126
+ if ( element . includes ( ":" ) ) {
127
+ [ classname , method ] = element . split ( ":" ) ;
128
+ if ( method . includes ( "+" ) ) {
129
+ offset = + method . split ( "+" ) [ 1 ] ;
130
+ method = method . split ( "+" ) [ 0 ] ;
131
+ }
132
+ }
133
+
134
+ const splitClassname = classname . split ( "." ) ;
135
+ const filetype = splitClassname [ splitClassname . length - 1 ] ;
136
+ const isCorrectMethod = ( text : string ) => ( filetype === "cls" )
137
+ ? text . match ( "Method " + method )
138
+ : text . startsWith ( method )
139
+
140
+ const uri = DocumentContentProvider . getUri ( classname ) ;
141
+ vscode . window . showTextDocument ( uri , { "preview" : false } ) . then ( newEditor => {
142
+ if ( method ) {
143
+ const document = newEditor . document ;
144
+ for ( let i = 0 ; i < document . lineCount ; i ++ ) {
145
+ const line = document . lineAt ( i ) ;
146
+ if ( isCorrectMethod ( line . text ) ) {
147
+ if ( ! line . text . endsWith ( "{" ) ) offset ++ ;
148
+ const cursor = newEditor . selection . active ;
149
+ const newPosition = cursor . with ( i + offset , 0 ) ;
150
+ newEditor . selection = new vscode . Selection ( newPosition , newPosition ) ;
151
+ break ;
152
+ }
153
+ }
154
+ }
155
+ } ) ;
156
+ } ) ;
157
+ return ;
95
158
case 6 : // Display an alert dialog in Studio with the text from the Target variable.
96
159
return vscode . window . showWarningMessage ( target , { modal : true } ) ;
97
160
case 7 : // Display a dialog with a textbox and Yes/No/Cancel buttons.
98
161
return vscode . window . showInputBox ( {
99
162
prompt : target ,
163
+ } ) . then ( msg => {
164
+ return {
165
+ "msg" : ( msg ? msg : "" ) ,
166
+ "answer" : ( msg ? 1 : 2 )
167
+ }
100
168
} ) ;
101
169
default :
102
170
throw new Error ( "Not suppoorted" ) ;
103
171
}
104
172
}
105
173
106
- private userAction ( action , afterUserAction = false , answer = "" , msg = "" ) : Thenable < void > {
174
+ private userAction ( action , afterUserAction = false , answer = "" , msg = "" , type = 0 ) : Thenable < void > {
107
175
if ( ! action ) {
108
176
return ;
109
177
}
110
- const func = afterUserAction ? "AfterUserAction" : "UserAction" ;
111
- const query = `select * from %Atelier_v1_Utils.Extension_${ func } (?, ?, ?, ?) ` ;
178
+ const func = afterUserAction ? "AfterUserAction(?, ?, ?, ?, ?) " : "UserAction(?, ?, ?, ?) " ;
179
+ const query = `select * from %Atelier_v1_Utils.Extension_${ func } ` ;
112
180
let selectedText = "" ;
113
181
const editor = vscode . window . activeTextEditor ;
114
182
if ( ! editor ) {
@@ -118,8 +186,9 @@ class StudioActions {
118
186
selectedText = editor . document . getText ( selection ) ;
119
187
120
188
const parameters = afterUserAction
121
- ? [ "0" , action . id , this . name , answer ]
122
- : [ "0" , action . id , this . name , selectedText ] ;
189
+ ? [ type . toString ( ) , action . id , this . name , answer , msg ]
190
+ : [ type . toString ( ) , action . id , this . name , selectedText ] ;
191
+
123
192
return vscode . window . withProgress (
124
193
{
125
194
cancellable : false ,
@@ -129,34 +198,44 @@ class StudioActions {
129
198
( ) =>
130
199
this . api
131
200
. actionQuery ( query , parameters )
132
- . then ( data => data . result . content . pop ( ) )
201
+ . then ( data => {
202
+ const actionInfo = data . result . content . pop ( ) ;
203
+ actionInfo . save = action . save ;
204
+ return actionInfo ;
205
+ } )
206
+ . then ( this . processSaveFlag )
133
207
. then ( this . processUserAction )
134
208
. then ( answer => {
135
209
if ( answer ) {
136
- return this . userAction ( action , true , answer ) ;
210
+ return ( answer . msg || answer . msg === "" )
211
+ ? this . userAction ( action , true , answer . answer , answer . msg , type )
212
+ : this . userAction ( action , true , answer , "" , type ) ;
137
213
}
138
214
} )
139
215
. catch ( err => {
216
+ console . log ( err ) ;
140
217
outputChannel . appendLine ( `Studio Action "${ action . label } " not supported` ) ;
141
218
outputChannel . show ( ) ;
142
219
} )
143
220
) ;
144
221
}
145
222
146
- private constructMenu ( menu ) : any [ ] {
223
+ private constructMenu ( menu , contextOnly = false ) : any [ ] {
147
224
return menu
225
+ . filter ( menuGroup => ! ( contextOnly && menuGroup . type === "main" ) )
148
226
. reduce (
149
227
( list , sub ) =>
150
228
list . concat (
151
229
sub . items
152
230
. filter ( el => el . id !== "" && el . separator == 0 )
153
- // .filter(el => el.enabled == 1)
231
+ . filter ( el => el . enabled == 1 )
154
232
. map ( el => ( {
155
233
...el ,
156
234
id : `${ sub . id } ,${ el . id } ` ,
157
235
label : el . name . replace ( "&" , "" ) ,
158
236
itemId : el . id ,
159
237
type : sub . type ,
238
+ description : sub . name . replace ( "&" , "" ) ,
160
239
} ) )
161
240
) ,
162
241
[ ]
@@ -170,19 +249,57 @@ class StudioActions {
170
249
} ) ;
171
250
}
172
251
173
- public getMenu ( menuType : string ) : Thenable < any > {
252
+ public getMenu ( menuType : string , contextOnly = false ) : Thenable < any > {
253
+ let selectedText = "" ;
254
+ const editor = vscode . window . activeTextEditor ;
255
+ if ( this . uri && editor ) {
256
+ const selection = editor . selection ;
257
+ selectedText = editor . document . getText ( selection ) ;
258
+ }
259
+
174
260
const query = "select * from %Atelier_v1_Utils.Extension_GetMenus(?,?,?)" ;
175
- const parameters = [ menuType , this . name , "" ] ;
261
+ const parameters = [ menuType , this . name , selectedText ] ;
176
262
177
263
return this . api
178
264
. actionQuery ( query , parameters )
179
265
. then ( data => data . result . content )
180
- . then ( this . constructMenu )
266
+ . then ( menu => this . constructMenu ( menu , contextOnly ) )
181
267
. then ( menuItems => {
182
268
return vscode . window . showQuickPick < StudioAction > ( menuItems , { canPickMany : false } ) ;
183
269
} )
184
270
. then ( action => this . userAction ( action ) ) ;
185
271
}
272
+
273
+ public attemptedEdit ( ) {
274
+ const query = "select * from %Atelier_v1_Utils.Extension_GetStatus(?)" ;
275
+ this . api . actionQuery ( query , [ this . name ] ) . then ( statusObj => {
276
+ const docStatus = statusObj . result . content . pop ( ) ;
277
+ // if(!docStatus.editable && docStatus.inSourceControl && !docStatus.isCheckedOut) {
278
+ if ( ! docStatus . editable ) {
279
+ const attemptedEditAction = {
280
+ id : "0" ,
281
+ label : "Attempted Edit"
282
+ } ;
283
+ vscode . commands . executeCommand ( 'undo' ) ;
284
+ this . userAction ( attemptedEditAction , false , "" , "" , 1 ) ;
285
+ } // else if(!docStatus.editable && docStatus.in)
286
+ } ) ;
287
+ }
288
+
289
+ private async processSaveFlag ( userAction ) {
290
+ if ( userAction . save ) {
291
+ const bitString = userAction . save . toString ( ) . padStart ( 3 , "0" ) ;
292
+ // Save the current document
293
+ if ( bitString . charAt ( 0 ) === "1" ) {
294
+ await vscode . window . activeTextEditor . document . save ( ) ;
295
+ }
296
+ // Save all documents
297
+ if ( bitString . charAt ( 2 ) === "1" ) {
298
+ await vscode . workspace . saveAll ( ) ;
299
+ }
300
+ }
301
+ return userAction ;
302
+ }
186
303
}
187
304
188
305
// export function contextMenu(uri: vscode.Uri): Promise<void> {
@@ -197,3 +314,20 @@ export async function mainMenu(uri: vscode.Uri) {
197
314
const studioActions = new StudioActions ( uri ) ;
198
315
return studioActions && studioActions . getMenu ( "" ) ;
199
316
}
317
+
318
+ export async function fireAttemptedEdit ( uri : vscode . Uri ) {
319
+ if ( ! uri || uri . scheme !== FILESYSTEM_SCHEMA ) {
320
+ return ;
321
+ }
322
+ const studioActions = new StudioActions ( uri ) ;
323
+ studioActions . attemptedEdit ( ) ;
324
+ }
325
+
326
+ export async function contextMenu ( node : PackageNode | ClassNode | RoutineNode ) : Promise < any > {
327
+ const nodeOrUri = node || vscode . window . activeTextEditor . document . uri ;
328
+ if ( ! nodeOrUri || ( nodeOrUri instanceof vscode . Uri && nodeOrUri . scheme !== FILESYSTEM_SCHEMA ) ) {
329
+ return ;
330
+ }
331
+ const studioActions = new StudioActions ( nodeOrUri ) ;
332
+ return studioActions && studioActions . getMenu ( "" , true ) ;
333
+ }
0 commit comments