Skip to content

Commit 1c629ea

Browse files
committed
Merge pull request #6 from pH-7/patrick-slagle-autocomplete
Patrick slagle autocomplete
2 parents 04b6905 + 04c9a5e commit 1c629ea

File tree

3 files changed

+428
-41
lines changed

3 files changed

+428
-41
lines changed
Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
package simplejavatexteditor;
2+
3+
import java.awt.event.ActionEvent;
4+
import java.awt.event.KeyEvent;
5+
import java.awt.event.KeyListener;
6+
import java.util.ArrayList;
7+
import java.util.Collections;
8+
import javax.swing.AbstractAction;
9+
import javax.swing.ActionMap;
10+
import javax.swing.InputMap;
11+
import javax.swing.JTextArea;
12+
import javax.swing.KeyStroke;
13+
import javax.swing.SwingUtilities;
14+
import javax.swing.event.DocumentEvent;
15+
import javax.swing.event.DocumentListener;
16+
import javax.swing.text.BadLocationException;
17+
18+
/**
19+
* <h1>Auto complete functionality multiple programming languages, including brackets and
20+
* parentheses</h1>
21+
*
22+
* <p>
23+
* An ArrayList is created for the keywords and the brackets.
24+
* Logic for setting the content of the ArrayList is
25+
* found in UI.java. If the word currently being typed
26+
* matches a word in the list, a Runnable inner class is
27+
* implemented to handle the word completion.
28+
*
29+
* Two other inner classes are also used. The second one handles when the enter
30+
* key is pressed in response to an auto complete suggestion. The third one
31+
* performs additional logic on brackets.
32+
* </p>
33+
*
34+
*
35+
* @author Patrick Slagle
36+
* @since 2016-12-03
37+
*/
38+
public class AutoComplete
39+
implements DocumentListener {
40+
41+
private ArrayList<String> brackets = new ArrayList<>();
42+
private ArrayList<String> bracketCompletions = new ArrayList<>();
43+
44+
private ArrayList<String> words = new ArrayList<>();
45+
46+
SupportedKeywords kw;
47+
48+
//Keep track of when code completion
49+
//has been activated
50+
private enum Mode {
51+
52+
INSERT, COMPLETION
53+
};
54+
55+
private final UI ui;
56+
private Mode mode = Mode.INSERT;
57+
private final JTextArea textArea;
58+
private static final String COMMIT_ACTION = "commit";
59+
private boolean isKeyword;
60+
private int pos;
61+
private String content;
62+
63+
public AutoComplete(UI ui, ArrayList<String> al) {
64+
//Set the keywords
65+
words = al;
66+
kw = new SupportedKeywords();
67+
brackets = kw.getbrackets();
68+
bracketCompletions = kw.getbracketCompletions();
69+
70+
//Access the editor
71+
this.ui = ui;
72+
textArea = ui.getEditor();
73+
74+
//Set the handler for the enter key
75+
InputMap im = textArea.getInputMap();
76+
ActionMap am = textArea.getActionMap();
77+
im.put(KeyStroke.getKeyStroke("ENTER "), COMMIT_ACTION);
78+
am.put(COMMIT_ACTION, new CommitAction());
79+
80+
Collections.sort(words);
81+
}
82+
83+
/**
84+
* A character has been typed into the document.
85+
* This method performs the primary
86+
* check to find a keyword completion.
87+
*
88+
* @param e
89+
*/
90+
@Override
91+
public void insertUpdate(DocumentEvent e) {
92+
pos = e.getOffset();
93+
content = null;
94+
95+
try {
96+
content = textArea.getText(0, pos + 1);
97+
} catch (BadLocationException ex) {
98+
ex.printStackTrace();
99+
}
100+
101+
if (e.getLength() != 1) {
102+
return;
103+
}
104+
105+
//Before checking for a keyword
106+
checkForBracket();
107+
108+
//Get the beginning of the word being typed
109+
int start;
110+
for (start = pos; start >= 0; start--) {
111+
if (!Character.isLetter(content.charAt(start))) {
112+
break;
113+
}
114+
}
115+
116+
//Auto complete will start
117+
//after two characters are typed
118+
if (pos - start < 2) {
119+
return;
120+
}
121+
122+
//Search for a match on the word being typed
123+
//in the keywords ArrayList
124+
String prefix = content.substring(start + 1);
125+
int n = Collections.binarySearch(words, prefix);
126+
127+
if (n < 0 && -n < words.size()) {
128+
String match = words.get(-n - 1);
129+
130+
if (match.startsWith(prefix)) {
131+
String completion = match.substring(pos - start);
132+
isKeyword = true;
133+
SwingUtilities.invokeLater(
134+
new CompletionTask(completion, pos + 1));
135+
} else {
136+
mode = Mode.INSERT;
137+
}
138+
}
139+
}
140+
141+
/**
142+
* Performs a check to see if the last
143+
* key typed was one of the supported
144+
* bracket characters
145+
*/
146+
private void checkForBracket() {
147+
//String of the last typed character
148+
char c = content.charAt(pos);
149+
String s = String.valueOf(c);
150+
151+
for (int i = 0; i < brackets.size(); i++) {
152+
if (brackets.get(i).equals(s)) {
153+
isKeyword = false;
154+
SwingUtilities.invokeLater(
155+
new CompletionTask(bracketCompletions.get(i), pos + 1));
156+
}
157+
}
158+
}
159+
160+
/**
161+
* So that future classes can view the keyword list in the future.
162+
*
163+
* @return the keywords
164+
*/
165+
private ArrayList<String> getKeywords() {
166+
return words;
167+
}
168+
169+
/**
170+
* So that these keywords can be modified or added to in the future.
171+
*
172+
* @param keyword the keyword to set
173+
*/
174+
private void setKeywords(String keyword) {
175+
words.add(keyword);
176+
}
177+
178+
/**
179+
* Handles the auto complete suggestion
180+
* generated when the user is typing a
181+
* word that matches a keyword.
182+
*/
183+
private class CompletionTask
184+
implements Runnable {
185+
186+
private final String completion;
187+
private final int position;
188+
189+
public CompletionTask(String completion, int position) {
190+
this.completion = completion;
191+
this.position = position;
192+
}
193+
194+
@Override
195+
public void run() {
196+
textArea.insert(completion, position);
197+
198+
textArea.setCaretPosition(position + completion.length());
199+
textArea.moveCaretPosition(position);
200+
mode = Mode.COMPLETION;
201+
if (!isKeyword) {
202+
textArea.addKeyListener(new HandleBracketEvent());
203+
}
204+
}
205+
}
206+
207+
/**
208+
* Enter key is pressed in response to an
209+
* auto complete suggestion. Respond
210+
* appropriately.
211+
*/
212+
private class CommitAction
213+
extends AbstractAction {
214+
215+
@Override
216+
public void actionPerformed(ActionEvent e) {
217+
218+
if (mode == Mode.COMPLETION) {
219+
int pos = textArea.getSelectionEnd();
220+
221+
if (isKeyword) {
222+
textArea.insert(" ", pos);
223+
textArea.setCaretPosition(pos + 1);
224+
mode = Mode.INSERT;
225+
}
226+
} else {
227+
mode = Mode.INSERT;
228+
textArea.replaceSelection("\n");
229+
}
230+
}
231+
}
232+
233+
/**
234+
* Additional logic for bracket auto complete
235+
*/
236+
private class HandleBracketEvent
237+
implements KeyListener {
238+
239+
@Override
240+
public void keyTyped(KeyEvent e) {
241+
//Bracket auto complete needs special attention.
242+
//Multiple possible responses are needed.
243+
String keyEvent = String.valueOf(e.getKeyChar());
244+
for (String bracketCompletion : bracketCompletions) {
245+
if (keyEvent.equals(bracketCompletion)) {
246+
textArea.replaceRange("", pos, pos + 1);
247+
mode = Mode.INSERT;
248+
textArea.removeKeyListener(this);
249+
}
250+
}
251+
int currentPosition = textArea.getCaretPosition();
252+
switch (e.getKeyChar()) {
253+
case '\n':
254+
textArea.insert("\n\n", currentPosition);
255+
textArea.setCaretPosition(currentPosition + 1);
256+
mode = Mode.INSERT;
257+
textArea.removeKeyListener(this);
258+
break;
259+
default:
260+
textArea.setCaretPosition(pos);
261+
mode = Mode.INSERT;
262+
textArea.removeKeyListener(this);
263+
break;
264+
}
265+
}
266+
267+
@Override
268+
public void keyPressed(KeyEvent e) {
269+
}
270+
271+
@Override
272+
public void keyReleased(KeyEvent e) {
273+
}
274+
}
275+
276+
@Override
277+
public void removeUpdate(DocumentEvent e) {
278+
}
279+
280+
@Override
281+
public void changedUpdate(DocumentEvent e) {
282+
}
283+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package simplejavatexteditor;
2+
3+
import java.util.ArrayList;
4+
5+
/**
6+
* <h1>A class to store the programming language keywords and
7+
* provide access to them.</h1>
8+
*
9+
* <p>Makes multiple language support possible and makes adding new language
10+
* support convenient. To add more keywords, add a string array and getters
11+
* to this class. Then, update the switch statement in UI.java.</p>
12+
*/
13+
public class SupportedKeywords {
14+
private String[] java = {"abstract", "assert", "boolean",
15+
"break", "byte", "case", "catch", "char", "class", "const",
16+
"continue", "default", "do", "double", "else", "extends", "false",
17+
"final", "finally", "float", "for", "goto", "if", "implements",
18+
"import", "instanceof", "int", "System", "out", "print()", "println()",
19+
"new", "null", "package", "private", "protected", "public", "interface",
20+
"long", "native", "return", "short", "static", "strictfp", "super", "switch",
21+
"synchronized", "this", "throw", "throws", "transient", "true",
22+
"try", "void", "volatile", "while", "String"};
23+
24+
private String[] cpp = { "auto", "const", "double", "float", "int", "short",
25+
"struct", "unsigned", "break", "continue", "else", "for", "long", "signed",
26+
"switch", "void", "case", "default", "enum", "goto", "register", "sizeof",
27+
"typedef", "volatile", "char", "do", "extern", "if", "return", "static",
28+
"union", "while", "asm", "dynamic_cast", "namespace", "reinterpret_cast", "try",
29+
"bool", "explicit", "new", "static_cast", "typeid", "catch", "false", "operator",
30+
"template", "typename", "class", "friend", "private", "this", "using", "const_cast",
31+
"inline", "public", "throw", "virtual", "delete", "mutable", "protected", "true", "wchar_t" };
32+
33+
private String[] brackets = { "{", "(" };
34+
private String[] bCompletions = { "}", ")" };
35+
public String[] getJavaKeywords() {
36+
return java;
37+
}
38+
public String[] getCppKeywords() {
39+
return cpp;
40+
}
41+
public ArrayList<String> getbracketCompletions() {
42+
ArrayList<String> al = new ArrayList<>();
43+
for(String completion : bCompletions) {
44+
al.add(completion);
45+
}
46+
return al;
47+
}
48+
public ArrayList<String> getbrackets() {
49+
ArrayList<String> al = new ArrayList<>();
50+
for(String completion : brackets) {
51+
al.add(completion);
52+
}
53+
return al;
54+
}
55+
public ArrayList<String> setKeywords(String[] arr) {
56+
ArrayList<String> al = new ArrayList<>();
57+
for(String words : arr) {
58+
al.add(words);
59+
}
60+
return al;
61+
}
62+
}

0 commit comments

Comments
 (0)