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 )) {
32
45
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 );
46
+ // Remove oldest command if max history size is exceeded.
47
+ if (this .commandHistory .size () >= this .maxHistorySize ) {
48
+ this .commandHistory .removeFirst ();
49
+ }
50
+
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,22 @@ 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
+ return this .hasNextCommand () ? this .iterator .next () : null ;
60
82
}
61
83
62
84
/**
@@ -65,7 +87,14 @@ public String getNextCommand() {
65
87
* returns {@code false} otherwise.
66
88
*/
67
89
public boolean hasPreviousCommand () {
68
- return this .selectedCommandIndex > 0 ;
90
+ if (this .iterator == null ) {
91
+ return this .commandHistory .size () > 1 ;
92
+ }
93
+ if (this .iteratorAsc ) {
94
+ this .iterator .previous (); // Current command, descending.
95
+ this .iteratorAsc = false ;
96
+ }
97
+ return this .iterator .hasPrevious ();
69
98
}
70
99
71
100
/**
@@ -86,14 +115,21 @@ public String getPreviousCommand(String currentCommand) {
86
115
return null ;
87
116
}
88
117
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 ));
118
+ // Store current unexecuted command and create iterator if not traversing.
119
+ if (this .iterator == null ) {
120
+ this .iterator =
121
+ this .commandHistory .listIterator (this .commandHistory .size ());
122
+ this .iterator .previous (); // Last element, descending.
123
+ this .iteratorAsc = false ;
124
+ }
125
+
126
+ // Store current unexecuted command if on 'current' index.
127
+ if (this .iterator .nextIndex () == this .commandHistory .size () - 1 ) {
128
+ this .iterator .set (currentCommand == null ? "" : currentCommand );
93
129
}
94
130
95
131
// Return the previous command.
96
- return this .commandHistory . get (-- this . selectedCommandIndex );
132
+ return this .iterator . previous ( );
97
133
}
98
134
99
135
/**
@@ -103,16 +139,16 @@ public String getPreviousCommand(String currentCommand) {
103
139
* was set.
104
140
*/
105
141
public String resetHistoryLocation () {
106
- this .selectedCommandIndex = this . commandHistory . size () - 1 ;
142
+ this .iterator = null ;
107
143
return this .commandHistory .set (this .commandHistory .size () - 1 , "" );
108
144
}
109
145
110
146
/**
111
147
* Clears the command history.
112
148
*/
113
149
public void clear () {
150
+ this .iterator = null ;
114
151
this .commandHistory .clear ();
115
- this .commandHistory .add ("" ); // Current command placeholder.
116
- this .selectedCommandIndex = 0 ;
152
+ this .commandHistory .addLast ("" ); // Current command placeholder.
117
153
}
118
154
}
0 commit comments