1
1
package processing .app ;
2
2
3
- import java .util .ArrayList ;
4
- import java .util .List ;
3
+ import java .util .LinkedList ;
4
+ import java .util .ListIterator ;
5
5
6
6
/**
7
7
* Keeps track of command history in console-like applications.
8
8
* @author P.J.S. Kools
9
9
*/
10
10
public class CommandHistory {
11
11
12
- private List <String > commandHistory = new ArrayList <String >();
13
- private int selectedCommandIndex = 0 ;
12
+ private final LinkedList <String > commandHistory = new LinkedList <String >();
14
13
private final int maxHistorySize ;
14
+ private ListIterator <String > iterator = null ;
15
+ private boolean iteratorAsc ;
15
16
16
17
/**
17
18
* Create a new {@link CommandHistory}.
18
19
* @param maxHistorySize - The max command history size.
19
20
*/
20
21
public CommandHistory (int maxHistorySize ) {
21
22
this .maxHistorySize = (maxHistorySize < 0 ? 0 : maxHistorySize );
22
- this .commandHistory .add ("" ); // Current command placeholder.
23
+ this .commandHistory .addLast ("" ); // Current command placeholder.
23
24
}
24
25
25
26
/**
26
27
* Adds the given command to the history and resets the history traversal
27
- * position to the latest command. If the max history size is exceeded,
28
- * the oldest command will be removed from the history.
28
+ * position to the latest command. If the latest command in the history is
29
+ * equal to the given command, it will not be added to the history.
30
+ * If the max history size is exceeded, the oldest command will be removed
31
+ * from the history.
29
32
* @param command - The command to add.
30
33
*/
31
34
public void addCommand (String command ) {
35
+ if (this .maxHistorySize == 0 ) {
36
+ return ;
37
+ }
38
+
39
+ // Remove 'current' command.
40
+ this .commandHistory .removeLast ();
41
+
42
+ // Add new command if it differs from the latest command.
43
+ if (this .commandHistory .isEmpty ()
44
+ || !this .commandHistory .getLast ().equals (command )) {
45
+
46
+ // Remove oldest command if max history size is exceeded.
47
+ if (this .commandHistory .size () >= this .maxHistorySize ) {
48
+ this .commandHistory .removeFirst ();
49
+ }
32
50
33
- // Remove the oldest command if the max history size is exceeded.
34
- if (this .commandHistory .size () >= this .maxHistorySize + 1 ) {
35
- this .commandHistory .remove (0 );
51
+ // Add new command and reset 'current' command.
52
+ this .commandHistory .addLast (command );
36
53
}
37
54
38
- // Add the new command, reset the 'current' command and reset the index.
39
- this .commandHistory .set (this .commandHistory .size () - 1 , command );
40
- this .commandHistory .add ("" ); // Current command placeholder.
41
- this .selectedCommandIndex = this .commandHistory .size () - 1 ;
55
+ // Re-add 'current' command and reset command iterator.
56
+ this .commandHistory .addLast ("" ); // Current command placeholder.
57
+ this .iterator = null ;
42
58
}
43
59
44
60
/**
@@ -47,16 +63,35 @@ public void addCommand(String command) {
47
63
* returns {@code false} otherwise.
48
64
*/
49
65
public boolean hasNextCommand () {
50
- return this .selectedCommandIndex + 1 < this .commandHistory .size ();
66
+ if (this .iterator == null ) {
67
+ return false ;
68
+ }
69
+ if (!this .iteratorAsc ) {
70
+ this .iterator .next (); // Current command, ascending.
71
+ this .iteratorAsc = true ;
72
+ }
73
+ return this .iterator .hasNext ();
51
74
}
52
75
53
76
/**
54
77
* Gets the next (more recent) command from the history.
55
78
* @return The next command or {@code null} if no next command is available.
56
79
*/
57
80
public String getNextCommand () {
58
- return this .hasNextCommand ()
59
- ? this .commandHistory .get (++this .selectedCommandIndex ) : null ;
81
+
82
+ // Return null if there is no next command available.
83
+ if (!this .hasNextCommand ()) {
84
+ return null ;
85
+ }
86
+
87
+ // Get next command.
88
+ String next = this .iterator .next ();
89
+
90
+ // Reset 'current' command when at the end of the list.
91
+ if (this .iterator .nextIndex () == this .commandHistory .size ()) {
92
+ this .iterator .set ("" ); // Reset 'current' command.
93
+ }
94
+ return next ;
60
95
}
61
96
62
97
/**
@@ -65,15 +100,22 @@ public String getNextCommand() {
65
100
* returns {@code false} otherwise.
66
101
*/
67
102
public boolean hasPreviousCommand () {
68
- return this .selectedCommandIndex > 0 ;
103
+ if (this .iterator == null ) {
104
+ return this .commandHistory .size () > 1 ;
105
+ }
106
+ if (this .iteratorAsc ) {
107
+ this .iterator .previous (); // Current command, descending.
108
+ this .iteratorAsc = false ;
109
+ }
110
+ return this .iterator .hasPrevious ();
69
111
}
70
112
71
113
/**
72
114
* Gets the previous (older) command from the history.
73
115
* When this method is called while the most recent command in the history is
74
116
* selected, this will store the current command as temporary latest command
75
- * so that {@link #getNextCommand()} will return it. This temporary latest
76
- * command gets reset when this case occurs again or when
117
+ * so that {@link #getNextCommand()} will return it once . This temporary
118
+ * latest command gets reset when this case occurs again or when
77
119
* {@link #addCommand(String)} is invoked.
78
120
* @param currentCommand - The current unexecuted command.
79
121
* @return The previous command or {@code null} if no previous command is
@@ -86,14 +128,21 @@ public String getPreviousCommand(String currentCommand) {
86
128
return null ;
87
129
}
88
130
89
- // Store current unexecuted command if not traversing already.
90
- if (this .selectedCommandIndex == this .commandHistory .size () - 1 ) {
91
- this .commandHistory .set (this .commandHistory .size () - 1 ,
92
- (currentCommand == null ? "" : currentCommand ));
131
+ // Store current unexecuted command and create iterator if not traversing.
132
+ if (this .iterator == null ) {
133
+ this .iterator =
134
+ this .commandHistory .listIterator (this .commandHistory .size ());
135
+ this .iterator .previous (); // Last element, descending.
136
+ this .iteratorAsc = false ;
137
+ }
138
+
139
+ // Store current unexecuted command if on 'current' index.
140
+ if (this .iterator .nextIndex () == this .commandHistory .size () - 1 ) {
141
+ this .iterator .set (currentCommand == null ? "" : currentCommand );
93
142
}
94
143
95
144
// Return the previous command.
96
- return this .commandHistory . get (-- this . selectedCommandIndex );
145
+ return this .iterator . previous ( );
97
146
}
98
147
99
148
/**
@@ -103,16 +152,16 @@ public String getPreviousCommand(String currentCommand) {
103
152
* was set.
104
153
*/
105
154
public String resetHistoryLocation () {
106
- this .selectedCommandIndex = this . commandHistory . size () - 1 ;
155
+ this .iterator = null ;
107
156
return this .commandHistory .set (this .commandHistory .size () - 1 , "" );
108
157
}
109
158
110
159
/**
111
160
* Clears the command history.
112
161
*/
113
162
public void clear () {
163
+ this .iterator = null ;
114
164
this .commandHistory .clear ();
115
- this .commandHistory .add ("" ); // Current command placeholder.
116
- this .selectedCommandIndex = 0 ;
165
+ this .commandHistory .addLast ("" ); // Current command placeholder.
117
166
}
118
167
}
0 commit comments