1
1
/*
2
- * Copyright (c) 1998, 2020 , Oracle and/or its affiliates. All rights reserved.
2
+ * Copyright (c) 1998, 2021 , Oracle and/or its affiliates. All rights reserved.
3
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
4
*
5
5
* This code is free software; you can redistribute it and/or modify it
44
44
import java .io .*;
45
45
46
46
public class TTY implements EventNotifier {
47
+ /**
48
+ * Commands that are repeatable on empty input.
49
+ */
50
+ protected static final Set <String > REPEATABLE = Set .of (
51
+ "up" , "down" , "step" , "stepi" , "next" , "cont" , "list" , "pop" , "reenter"
52
+ );
53
+
54
+ /**
55
+ * Commands that reset the default source line to be displayed by {@code list}.
56
+ */
57
+ protected static final Set <String > LIST_RESET = Set .of (
58
+ "run" , "suspend" , "resume" , "up" , "down" , "kill" , "interrupt" , "threadgroup" , "step" , "stepi" , "next" , "cont" ,
59
+ "pop" , "reenter"
60
+ );
61
+
47
62
EventHandler handler = null ;
48
63
49
64
/**
@@ -59,6 +74,16 @@ public class TTY implements EventNotifier {
59
74
60
75
private volatile boolean shuttingDown = false ;
61
76
77
+ /**
78
+ * The number of the next source line to target for {@code list}, if any.
79
+ */
80
+ protected Integer nextListTarget = null ;
81
+
82
+ /**
83
+ * Whether to repeat when the user enters an empty command.
84
+ */
85
+ protected boolean repeat = false ;
86
+
62
87
public void setShuttingDown (boolean s ) {
63
88
shuttingDown = s ;
64
89
}
@@ -335,6 +360,7 @@ void help() {
335
360
{"read" , "y" , "y" },
336
361
{"redefine" , "n" , "n" },
337
362
{"reenter" , "n" , "n" },
363
+ {"repeat" , "y" , "y" },
338
364
{"resume" , "n" , "n" },
339
365
{"run" , "y" , "n" },
340
366
{"save" , "n" , "n" },
@@ -408,12 +434,15 @@ private boolean isReadOnlyCmd(int ii) {
408
434
};
409
435
410
436
411
- void executeCommand (StringTokenizer t ) {
437
+ /**
438
+ * @return the name (first token) of the command processed
439
+ */
440
+ String executeCommand (StringTokenizer t ) {
412
441
String cmd = t .nextToken ().toLowerCase ();
442
+
413
443
// Normally, prompt for the next command after this one is done
414
444
boolean showPrompt = true ;
415
445
416
-
417
446
/*
418
447
* Anything starting with # is discarded as a no-op or 'comment'.
419
448
*/
@@ -426,15 +455,16 @@ void executeCommand(StringTokenizer t) {
426
455
try {
427
456
int repeat = Integer .parseInt (cmd );
428
457
String subcom = t .nextToken ("" );
429
- while ( repeat -- > 0 ) {
430
- executeCommand (new StringTokenizer (subcom ));
458
+ for ( int r = 0 ; r < repeat ; r += 1 ) {
459
+ cmd = executeCommand (new StringTokenizer (subcom ));
431
460
showPrompt = false ; // Bypass the printPrompt() below.
432
461
}
433
462
} catch (NumberFormatException exc ) {
434
463
MessageOutput .println ("Unrecognized command. Try help..." , cmd );
435
464
}
436
465
} else {
437
466
int commandNumber = isCommand (cmd );
467
+
438
468
/*
439
469
* Check for an unknown command
440
470
*/
@@ -448,7 +478,6 @@ void executeCommand(StringTokenizer t) {
448
478
MessageOutput .println ("Command is not supported on a read-only VM connection" ,
449
479
cmd );
450
480
} else {
451
-
452
481
Commands evaluator = new Commands ();
453
482
try {
454
483
if (cmd .equals ("print" )) {
@@ -550,7 +579,7 @@ void executeCommand(StringTokenizer t) {
550
579
} else if (cmd .equals ("unwatch" )) {
551
580
evaluator .commandUnwatch (t );
552
581
} else if (cmd .equals ("list" )) {
553
- evaluator .commandList (t );
582
+ nextListTarget = evaluator .commandList (t , repeat ? nextListTarget : null );
554
583
} else if (cmd .equals ("lines" )) { // Undocumented command: useful for testing.
555
584
evaluator .commandLines (t );
556
585
} else if (cmd .equals ("classpath" )) {
@@ -596,6 +625,8 @@ void executeCommand(StringTokenizer t) {
596
625
} else if (cmd .equals ("version" )) {
597
626
evaluator .commandVersion (progname ,
598
627
Bootstrap .virtualMachineManager ());
628
+ } else if (cmd .equals ("repeat" )) {
629
+ doRepeat (t );
599
630
} else if (cmd .equals ("quit" ) || cmd .equals ("exit" )) {
600
631
if (handler != null ) {
601
632
handler .shutdown ();
@@ -620,6 +651,12 @@ void executeCommand(StringTokenizer t) {
620
651
if (showPrompt ) {
621
652
MessageOutput .printPrompt ();
622
653
}
654
+
655
+ if (LIST_RESET .contains (cmd )) {
656
+ nextListTarget = null ;
657
+ }
658
+
659
+ return cmd ;
623
660
}
624
661
625
662
/*
@@ -661,7 +698,6 @@ void unmonitorCommand(StringTokenizer t) {
661
698
}
662
699
}
663
700
664
-
665
701
void readCommand (StringTokenizer t ) {
666
702
if (t .hasMoreTokens ()) {
667
703
String cmdfname = t .nextToken ();
@@ -673,6 +709,19 @@ void readCommand(StringTokenizer t) {
673
709
}
674
710
}
675
711
712
+ protected void doRepeat (StringTokenizer t ) {
713
+ if (t .hasMoreTokens ()) {
714
+ var choice = t .nextToken ().toLowerCase ();
715
+ if ((choice .equals ("on" ) || choice .equals ("off" )) && !t .hasMoreTokens ()) {
716
+ repeat = choice .equals ("on" );
717
+ } else {
718
+ MessageOutput .println ("repeat usage" );
719
+ }
720
+ } else {
721
+ MessageOutput .println (repeat ? "repeat is on" : "repeat is off" );
722
+ }
723
+ }
724
+
676
725
/**
677
726
* Read and execute a command file. Return true if the file was read
678
727
* else false;
@@ -749,8 +798,6 @@ public TTY() throws Exception {
749
798
BufferedReader in =
750
799
new BufferedReader (new InputStreamReader (System .in ));
751
800
752
- String lastLine = null ;
753
-
754
801
Thread .currentThread ().setPriority (Thread .NORM_PRIORITY );
755
802
756
803
/*
@@ -788,6 +835,9 @@ public TTY() throws Exception {
788
835
789
836
// Process interactive commands.
790
837
MessageOutput .printPrompt ();
838
+
839
+ String lastLine = null ;
840
+ String lastCommandName = null ;
791
841
while (true ) {
792
842
String ln = in .readLine ();
793
843
if (ln == null ) {
@@ -809,7 +859,11 @@ public TTY() throws Exception {
809
859
StringTokenizer t = new StringTokenizer (ln );
810
860
if (t .hasMoreTokens ()) {
811
861
lastLine = ln ;
812
- executeCommand (t );
862
+ lastCommandName = executeCommand (t );
863
+ } else if (repeat && lastLine != null && REPEATABLE .contains (lastCommandName )) {
864
+ // We want list auto-advance even if the user started with a listing target.
865
+ String newCommand = lastCommandName .equals ("list" ) && nextListTarget != null ? "list" : lastLine ;
866
+ executeCommand (new StringTokenizer (newCommand ));
813
867
} else {
814
868
MessageOutput .printPrompt ();
815
869
}
0 commit comments