@@ -34,7 +34,7 @@ export default async function genericCodeActionsProvider(params: CodeActionParam
34
34
35
35
const extractOption = getExtractProcedureAction ( document , docs , range ) ;
36
36
if ( extractOption ) {
37
- return [ extractOption ] ;
37
+ actions . push ( extractOption ) ;
38
38
}
39
39
40
40
const linterActions = await getLinterCodeActions ( docs , document , range ) ;
@@ -47,6 +47,11 @@ export default async function genericCodeActionsProvider(params: CodeActionParam
47
47
if ( testActions ) {
48
48
actions . push ( ...testActions ) ;
49
49
}
50
+
51
+ const monitorAction = surroundWithMonitorAction ( isFree , document , docs , range ) ;
52
+ if ( monitorAction ) {
53
+ actions . push ( monitorAction ) ;
54
+ }
50
55
}
51
56
}
52
57
@@ -327,11 +332,105 @@ function getAssertion(type: RpgleVariableType): string {
327
332
}
328
333
}
329
334
330
-
331
335
function asPosix ( inPath ?: string ) {
332
336
return inPath ? inPath . split ( path . sep ) . join ( path . posix . sep ) : `` ;
333
337
}
334
338
339
+ function lineAt ( document : TextDocument , line : number ) : string {
340
+ return document . getText ( Range . create ( line , 0 , line , 1000 ) ) . trimEnd ( ) ;
341
+ }
342
+
343
+ function getBodyRangeForRange ( docs : Cache , rangeStart : number , rangeEnd : number , document : TextDocument ) {
344
+ let validStart = - 1 ;
345
+ let validEnd = - 1 ;
346
+
347
+ const currentProcedure = docs . procedures . find ( sub => rangeStart >= sub . position . range . line && rangeEnd <= sub . range . end ! ) ;
348
+
349
+ if ( currentProcedure && currentProcedure . scope && currentProcedure . range . end ) {
350
+ validStart = currentProcedure . scope . getDefinitionBlockEnd ( document . uri ) + 1 ;
351
+ validEnd = currentProcedure . range . end - 1 ;
352
+ } else {
353
+ validStart = docs . getDefinitionBlockEnd ( document . uri ) + 1 ;
354
+ const firstProc = docs . procedures . find ( p => ! Object . keys ( p . keyword ) . some ( k => k . toLowerCase ( ) . startsWith ( `ext` ) ) ) ;
355
+ validEnd = firstProc && firstProc . range . start ? firstProc . range . start - 1 : document . lineCount - 1 ;
356
+ }
357
+
358
+ if ( validStart < 0 || validEnd < 0 ) {
359
+ return ;
360
+ }
361
+
362
+ return { validStart, validEnd } ;
363
+ }
364
+
365
+ function determineIndent ( line : string ) : number {
366
+ const match = line . match ( / ^ \s + / ) ;
367
+ if ( match ) {
368
+ return match [ 0 ] . length ;
369
+ }
370
+ return 0 ;
371
+ }
372
+
373
+ export function surroundWithMonitorAction ( isFree : boolean , document : TextDocument , docs : Cache , range : Range ) : CodeAction | undefined {
374
+ let rangeStart = range . start . line ;
375
+ let rangeEnd = range . end . line ;
376
+
377
+ if ( rangeStart === rangeEnd ) {
378
+ // Only works for multi-line selections
379
+ return ;
380
+ }
381
+
382
+ const validRange = getBodyRangeForRange ( docs , rangeStart , rangeEnd , document ) ;
383
+
384
+ if ( ! validRange ) {
385
+ return ;
386
+ }
387
+
388
+ let indent = 0 ;
389
+
390
+ if ( isFree ) {
391
+ indent = determineIndent ( lineAt ( document , rangeStart ) ) ;
392
+ } else {
393
+ const freePortion = lineAt ( document , rangeStart ) . substring ( 7 ) ;
394
+ indent = determineIndent ( freePortion ) + 7 ;
395
+ }
396
+
397
+ const newLine = `\n` ;
398
+ const indentStr = ` ` . repeat ( indent ) ;
399
+ const space = `${ newLine } ${ indentStr } ` ;
400
+
401
+ if ( rangeStart >= validRange . validStart && rangeEnd <= validRange . validEnd ) {
402
+ const refactorAction = CodeAction . create ( `Surround with monitor` , CodeActionKind . RefactorRewrite ) ;
403
+
404
+ refactorAction . edit = {
405
+ changes : {
406
+ [ document . uri ] : [
407
+ TextEdit . insert (
408
+ Position . create ( rangeStart , 0 ) ,
409
+ `${ indentStr } monitor;${ newLine } `
410
+ ) ,
411
+ TextEdit . insert (
412
+ Position . create ( rangeEnd + 1 , 0 ) ,
413
+ `${ space } on-error *all;${ space } // TODO: implement${ space } endmon;${ newLine } `
414
+ )
415
+ ]
416
+ } ,
417
+ } ;
418
+
419
+ if ( isFree ) {
420
+ // Then format the document
421
+ refactorAction . command = {
422
+ command : `editor.action.formatDocument` ,
423
+ title : `Format`
424
+ } ;
425
+ }
426
+
427
+ return refactorAction ;
428
+ }
429
+
430
+
431
+ return ;
432
+ }
433
+
335
434
export function getSubroutineActions ( document : TextDocument , docs : Cache , range : Range ) : CodeAction | undefined {
336
435
if ( range . start . line === range . end . line ) {
337
436
const currentGlobalSubroutine = docs . subroutines . find ( sub => sub . position . range . line === range . start . line && sub . range . start && sub . range . end ) ;
@@ -354,7 +453,7 @@ export function getSubroutineActions(document: TextDocument, docs: Cache, range:
354
453
const newProcedure = [
355
454
`Dcl-Proc ${ currentGlobalSubroutine . name } ;` ,
356
455
` Dcl-Pi *N;` ,
357
- ...extracted . references . map ( ( ref , i ) => ` ${ extracted . newParamNames [ i ] } ${ ref . dec . type === `struct` ? `likeDS ` : `like ` } (${ ref . dec . name } );` ) ,
456
+ ...extracted . references . map ( ( ref , i ) => ` ${ extracted . newParamNames [ i ] } ${ ref . dec . type === `struct` ? `LikeDS ` : `Like ` } (${ ref . dec . name } );` ) ,
358
457
` End-Pi;` ,
359
458
`` ,
360
459
caseInsensitiveReplaceAll ( extracted . newBody , `leavesr` , `return` ) ,
@@ -393,39 +492,50 @@ export function getSubroutineActions(document: TextDocument, docs: Cache, range:
393
492
}
394
493
395
494
export function getExtractProcedureAction ( document : TextDocument , docs : Cache , range : Range ) : CodeAction | undefined {
396
- if ( range . end . line > range . start . line ) {
397
- const lastLine = document . offsetAt ( { line : document . lineCount , character : 0 } ) ;
495
+ const rangeStart = range . start . line ;
496
+ const rangeEnd = range . end . line ;
497
+ if ( rangeEnd > rangeStart ) {
398
498
399
- const extracted = createExtract ( document , range , docs ) ;
499
+ const validRange = getBodyRangeForRange ( docs , rangeStart , rangeEnd , document ) ;
400
500
401
- const newProcedure = [
402
- `Dcl-Proc NewProcedure;` ,
403
- ` Dcl-Pi *N;` ,
404
- ...extracted . references . map ( ( ref , i ) => ` ${ extracted . newParamNames [ i ] } ${ ref . dec . type === `struct` ? `likeDS` : `like` } (${ ref . dec . name } );` ) ,
405
- ` End-Pi;` ,
406
- `` ,
407
- extracted . newBody ,
408
- `End-Proc;`
409
- ] . join ( `\n` )
501
+ if ( ! validRange ) {
502
+ return ;
503
+ }
410
504
411
- const newAction = CodeAction . create ( `Extract to new procedure` , CodeActionKind . RefactorExtract ) ;
505
+ // Ensure the selected range is within a body range
506
+ if ( rangeStart >= validRange . validStart && rangeEnd <= validRange . validEnd ) {
507
+ const extracted = createExtract ( document , range , docs ) ;
412
508
413
- // First do the exit
414
- newAction . edit = {
415
- changes : {
416
- [ document . uri ] : [
417
- TextEdit . replace ( extracted . range , `NewProcedure( ${ extracted . references . map ( r => r . dec . name ) . join ( `:` ) } );` ) ,
418
- TextEdit . insert ( document . positionAt ( lastLine ) , `\n\n` + newProcedure )
419
- ]
420
- } ,
421
- } ;
509
+ const newProcedure = [
510
+ `Dcl-Proc NewProcedure;` ,
511
+ ` Dcl-Pi *N;` ,
512
+ ... extracted . references . map ( ( ref , i ) => ` ${ extracted . newParamNames [ i ] } ${ ref . dec . type === `struct` ? `LikeDS` : `Like` } ( ${ ref . dec . name } );` ) ,
513
+ ` End-Pi;` ,
514
+ `` ,
515
+ extracted . newBody ,
516
+ `End-Proc;`
517
+ ] . join ( `\n` )
422
518
423
- // Then format the document
424
- newAction . command = {
425
- command : `editor.action.formatDocument` ,
426
- title : `Format`
427
- } ;
519
+ const newAction = CodeAction . create ( `Extract to new procedure` , CodeActionKind . RefactorExtract ) ;
520
+ const lastLine = document . offsetAt ( { line : document . lineCount , character : 0 } ) ;
428
521
429
- return newAction ;
522
+ // First do the exit
523
+ newAction . edit = {
524
+ changes : {
525
+ [ document . uri ] : [
526
+ TextEdit . replace ( extracted . range , `NewProcedure(${ extracted . references . map ( r => r . dec . name ) . join ( `:` ) } );` ) ,
527
+ TextEdit . insert ( document . positionAt ( lastLine ) , `\n\n` + newProcedure )
528
+ ]
529
+ } ,
530
+ } ;
531
+
532
+ // Then format the document
533
+ newAction . command = {
534
+ command : `editor.action.formatDocument` ,
535
+ title : `Format`
536
+ } ;
537
+
538
+ return newAction ;
539
+ }
430
540
}
431
541
}
0 commit comments