separate the function of reading tokens
@@ -0,0 +1,67 @@ | ||
1 | +package jp.sourceforge.nine.action.javamode; | |
2 | + | |
3 | +import java.util.ArrayList; | |
4 | +import java.util.ListIterator; | |
5 | + | |
6 | +import jp.sourceforge.nine.document.DocumentAttachment; | |
7 | +import jp.sourceforge.nine.document.MarkableDocument; | |
8 | +import jp.sourceforge.nine.javamode.JavaDocumentAttachment; | |
9 | +import jp.sourceforge.nine.parser.Token; | |
10 | +import jp.sourceforge.nine.parser.TokenLine; | |
11 | +import jp.sourceforge.nine.parser.javamode.JavaStatus; | |
12 | +import jp.sourceforge.nine.parser.javamode.JavaStatusManager; | |
13 | +import jp.sourceforge.nine.parser.javamode.JavaType; | |
14 | + | |
15 | +public class JavaTokenReader { | |
16 | + private int lineIndex = 0; | |
17 | + private ArrayList<TokenLine<JavaType, JavaStatus>> tokenLines = null; | |
18 | + private ListIterator<Token<JavaType>> iterator = null; | |
19 | + private final JavaStatusManager statusManager = new JavaStatusManager(); | |
20 | + | |
21 | + public void open(MarkableDocument doc) /* throws Exception */ { | |
22 | + JavaDocumentAttachment a = getJavaDocumentAttachment(doc); | |
23 | +// if (a == null) { | |
24 | +// throw new Exception("cannot get the document attachment."); | |
25 | +// } | |
26 | + tokenLines = a.getTokenList(); | |
27 | + } | |
28 | + | |
29 | + private JavaDocumentAttachment getJavaDocumentAttachment(MarkableDocument doc) { | |
30 | + DocumentAttachment a = doc.getDocumentAttachment(); | |
31 | + if (a instanceof JavaDocumentAttachment) { | |
32 | + return (JavaDocumentAttachment) a; | |
33 | + } | |
34 | + return null; | |
35 | + } | |
36 | + | |
37 | + | |
38 | + public void moveToLine(int line) { | |
39 | + lineIndex = line; | |
40 | + iterator = tokenLines.get(line).listIterator(); | |
41 | + JavaStatus s = (line == 0) ? | |
42 | + JavaStatus.NORMAL : tokenLines.get(line - 1).getEndStatus(); | |
43 | + statusManager.setCurrentStatus(s); | |
44 | + } | |
45 | + | |
46 | + public Token<JavaType> advance() { | |
47 | + Token<JavaType> ret = null; | |
48 | + if (iterator == null) { moveToLine(0); } | |
49 | + if (iterator.hasNext()) { | |
50 | + ret = iterator.next(); | |
51 | + } else if (lineIndex + 1 < tokenLines.size()) { | |
52 | + statusManager.sendLineEnd(); | |
53 | + iterator = tokenLines.get(++lineIndex).listIterator(); | |
54 | + return advance(); | |
55 | + } | |
56 | + if (ret != null) { statusManager.switchStatus(ret.type); } | |
57 | + return ret; | |
58 | + } | |
59 | + | |
60 | + public int getCurrentLineIndex() { | |
61 | + return lineIndex; | |
62 | + } | |
63 | + | |
64 | + public JavaStatus getStatus() { | |
65 | + return statusManager.getStatus(); | |
66 | + } | |
67 | +} |
@@ -19,7 +19,6 @@ | ||
19 | 19 | package jp.sourceforge.nine.action.javamode; |
20 | 20 | |
21 | 21 | import java.awt.event.ActionEvent; |
22 | -import java.util.ArrayList; | |
23 | 22 | import java.util.Stack; |
24 | 23 | |
25 | 24 | import javax.swing.text.Document; |
@@ -28,13 +27,9 @@ | ||
28 | 27 | |
29 | 28 | import jp.sourceforge.nine.MainTextPane; |
30 | 29 | import jp.sourceforge.nine.action.ScriptableTextAction; |
31 | -import jp.sourceforge.nine.document.DocumentAttachment; | |
32 | 30 | import jp.sourceforge.nine.document.MarkableDocument; |
33 | -import jp.sourceforge.nine.javamode.JavaDocumentAttachment; | |
34 | 31 | import jp.sourceforge.nine.parser.Token; |
35 | -import jp.sourceforge.nine.parser.TokenLine; | |
36 | 32 | import jp.sourceforge.nine.parser.javamode.JavaStatus; |
37 | -import jp.sourceforge.nine.parser.javamode.JavaStatusManager; | |
38 | 33 | import jp.sourceforge.nine.parser.javamode.JavaType; |
39 | 34 | |
40 | 35 | /** |
@@ -42,15 +37,13 @@ | ||
42 | 37 | * 基本的には、直前のカッコ類を検出し、その行のインデント情報を元に、カレント行のインデントを自動的に変更します。 |
43 | 38 | * インデントは、GNU に近い様式で行われる予定ですが、少なくとも現状ではまったく厳密ではありません。 |
44 | 39 | * また、このバージョンでは実装もまったく不完全です。 |
45 | - * たとえば、通常の文を途中で改行しても、インデントが増えません。 | |
46 | 40 | * switch case 文の case が適切にインデントされません。 |
47 | 41 | * |
48 | 42 | * @author mshio |
49 | 43 | */ |
50 | 44 | public class JavaTabAction extends ScriptableTextAction { |
51 | - private static final long serialVersionUID = -8283585316654470522L; | |
45 | + private static final long serialVersionUID = -7410627453399243851L; | |
52 | 46 | public static final String ACTION_NAME = "java-indent"; |
53 | - private final JavaStatusManager statusManager = new JavaStatusManager(); | |
54 | 47 | private final String INDENT = "\t"; |
55 | 48 | |
56 | 49 | private Terminal status = Terminal.SEMICOLON; |
@@ -67,23 +60,20 @@ | ||
67 | 60 | JTextComponent text = getTextComponent(e); |
68 | 61 | MarkableDocument doc = getMarkableDocument(text); |
69 | 62 | if (doc == null) return; |
63 | + | |
70 | 64 | Element root = doc.getDefaultRootElement(); |
71 | 65 | int currentRowIndex = root.getElementIndex(text.getCaretPosition()); |
72 | 66 | String currentRowText = getRowText(text, root, currentRowIndex); |
73 | - JavaType lineTopTokenType = null; | |
74 | - TokenInfo markToken = null; | |
75 | - JavaDocumentAttachment a = getJavaDocumentAttachment(doc); | |
76 | - if (a != null) { | |
77 | - ArrayList<TokenLine<JavaType, JavaStatus>> list = a.getTokenList(); | |
78 | - lineTopTokenType = getStartTokenType(list, currentRowIndex); | |
79 | - markToken = getLastMarkToken(list, currentRowIndex, lineTopTokenType); | |
80 | - String indent = getLastLineIndent(text, root, currentRowIndex, | |
81 | - markToken, lineTopTokenType); | |
82 | - if (indent != null && indent.length() > 0) { | |
83 | - editIndent(text, currentRowText, indent, root, currentRowIndex); | |
84 | - } | |
85 | - } else { | |
86 | - text.replaceSelection(INDENT); | |
67 | + | |
68 | + JavaTokenReader tokenReader = new JavaTokenReader(); | |
69 | + tokenReader.open(doc); | |
70 | + JavaType lineTopTokenType = getStartTokenType(doc, currentRowIndex); | |
71 | + TokenInfo markToken = | |
72 | + getLastMarkToken(tokenReader, currentRowIndex, lineTopTokenType); | |
73 | + String indent = getLastLineIndent(text, root, currentRowIndex, | |
74 | + markToken, lineTopTokenType); | |
75 | + if (indent != null && indent.length() > 0) { | |
76 | + editIndent(text, currentRowText, indent, root, currentRowIndex); | |
87 | 77 | } |
88 | 78 | } |
89 | 79 |
@@ -102,23 +92,22 @@ | ||
102 | 92 | } |
103 | 93 | } |
104 | 94 | |
105 | - private JavaType getStartTokenType(ArrayList<TokenLine<JavaType, JavaStatus>> list, | |
106 | - int rowIndex) { | |
95 | + private JavaType getStartTokenType(MarkableDocument doc, int rowIndex) { | |
107 | 96 | JavaType ret = null; |
97 | + JavaTokenReader r = new JavaTokenReader(); | |
98 | + r.open(doc); | |
99 | + r.moveToLine(rowIndex); | |
100 | + if (r.getStatus() != JavaStatus.NORMAL) { return null; } | |
108 | 101 | |
109 | - if (rowIndex > 0) { | |
110 | - TokenLine<JavaType, JavaStatus> prev = list.get(rowIndex - 1); | |
111 | - JavaStatus s = prev.getEndStatus(); | |
112 | - if (s == JavaStatus.BLOCK_COMMENT) { return null; } | |
113 | - } | |
114 | - | |
115 | - TokenLine<JavaType, JavaStatus> l = list.get(rowIndex); | |
116 | - for (Token<JavaType> t : l) { | |
117 | - if (t.type != JavaType.WHITE_SPACE) { | |
102 | + do { | |
103 | + Token<JavaType> t = r.advance(); | |
104 | + if (t == null) { | |
105 | + break; | |
106 | + } else if (t.type != JavaType.WHITE_SPACE) { | |
118 | 107 | ret = t.type; |
119 | 108 | break; |
120 | 109 | } |
121 | - } | |
110 | + } while (r.getCurrentLineIndex() <= rowIndex); | |
122 | 111 | return ret; |
123 | 112 | } |
124 | 113 |
@@ -160,81 +149,75 @@ | ||
160 | 149 | return ret; |
161 | 150 | } |
162 | 151 | |
163 | - private TokenInfo getLastMarkToken(ArrayList<TokenLine<JavaType, JavaStatus>> list, | |
152 | + private TokenInfo getLastMarkToken(JavaTokenReader tokenReader, | |
164 | 153 | int row, JavaType lineTopTokenType) { |
165 | 154 | TokenInfo ret = null; |
155 | + int parenNest = 0; | |
166 | 156 | TokenInfo blockHeader = null; |
167 | 157 | int blockEndLine = -1; |
168 | - int index = 0; | |
169 | - int parenNest = 0; | |
158 | + Terminal s = Terminal.SEMICOLON; | |
170 | 159 | Stack<TokenInfo> info = new Stack<TokenInfo>(); |
171 | - Terminal s = Terminal.SEMICOLON; | |
172 | - statusManager.setCurrentStatus(JavaStatus.NORMAL); | |
160 | + int index; | |
173 | 161 | |
174 | - for (TokenLine<JavaType, JavaStatus> l : list) { | |
175 | - for (Token<JavaType> t : l) { | |
176 | - JavaType type = t.type; | |
177 | - statusManager.switchStatus(type); | |
178 | - if (statusManager.getStatus() != JavaStatus.NORMAL) { continue; } | |
179 | - switch (type) { | |
180 | - case PARENTHESIS_END: | |
181 | - parenNest--; | |
182 | - if (parenNest < 0) { parenNest = 0; } | |
183 | - case BRACE_END: | |
184 | - if (info.size() > 0) { | |
185 | - ret = info.pop(); | |
186 | - if (t.type == JavaType.BRACE_END) { | |
187 | - blockHeader = ret; | |
188 | - blockEndLine = index; | |
189 | - } | |
162 | + while (tokenReader.getCurrentLineIndex() < row) { | |
163 | + Token<JavaType> t = tokenReader.advance(); | |
164 | + index = tokenReader.getCurrentLineIndex(); | |
165 | + if (t == null || index >= row) { break; } | |
166 | + if (tokenReader.getStatus() != JavaStatus.NORMAL) { continue; } | |
167 | + | |
168 | + switch (t.type) { | |
169 | + case PARENTHESIS_END: | |
170 | + parenNest--; | |
171 | + if (parenNest < 0) { parenNest = 0; } | |
172 | + case BRACE_END: | |
173 | + if (info.size() > 0) { | |
174 | + ret = info.pop(); | |
175 | + if (t.type == JavaType.BRACE_END) { | |
176 | + blockHeader = ret; | |
177 | + blockEndLine = index; | |
190 | 178 | } |
191 | - case SEMICOLON: | |
192 | - s = Terminal.SEMICOLON; | |
193 | - break; | |
194 | - case BRACE_BEGIN: | |
195 | - s = Terminal.BRACE; | |
196 | - if (ret == null) { ret = new TokenInfo(t, index); } | |
197 | - if (parenNest <= 0) { | |
198 | - info.push(ret); | |
199 | - } else if (info.size() > 0) { | |
200 | - ret = info.pop(); | |
201 | - info.push(ret); | |
202 | - parenNest = 0; | |
203 | - } | |
204 | - break; | |
205 | - case PARENTHESIS_BEGIN: | |
206 | - parenNest++; | |
207 | - s = Terminal.PARENTHESIS; | |
208 | - if (ret == null) { ret = new TokenInfo(t, index); } | |
179 | + } | |
180 | + case SEMICOLON: | |
181 | + s = Terminal.SEMICOLON; | |
182 | + break; | |
183 | + case BRACE_BEGIN: | |
184 | + s = Terminal.BRACE; | |
185 | + if (ret == null) { ret = new TokenInfo(t, index); } | |
186 | + if (parenNest <= 0) { | |
209 | 187 | info.push(ret); |
210 | - break; | |
211 | - case WHITE_SPACE: | |
212 | - case BLOCK_COMMENT_END: | |
213 | - // Does nothing. | |
214 | - break; | |
215 | - default: | |
216 | - if (parenNest > 0 && (t.type == JavaType.COMMA || t.type == JavaType.MARK)) { | |
217 | - s = Terminal.SEMICOLON; | |
218 | - } else if (s != null) { | |
219 | - if (ret == null || ret.row != index || (parenNest > 0 && s != Terminal.SEMICOLON)) { | |
220 | - if (blockEndLine == index) { | |
221 | - ret = blockHeader; | |
222 | - } else { | |
223 | - ret = new TokenInfo(t, index); | |
224 | - } | |
225 | - s = null; | |
226 | - } | |
227 | - } | |
228 | - break; | |
188 | + } else if (info.size() > 0) { | |
189 | + ret = info.pop(); | |
190 | + info.push(ret); | |
191 | + parenNest = 0; | |
229 | 192 | } |
193 | + break; | |
194 | + case PARENTHESIS_BEGIN: | |
195 | + parenNest++; | |
196 | + s = Terminal.PARENTHESIS; | |
197 | + if (ret == null) { ret = new TokenInfo(t, index); } | |
198 | + info.push(ret); | |
199 | + break; | |
200 | + case WHITE_SPACE: | |
201 | + case BLOCK_COMMENT_END: | |
202 | + // Does nothing. | |
203 | + break; | |
204 | + default: | |
205 | + if (parenNest > 0 && (t.type == JavaType.COMMA || t.type == JavaType.MARK)) { | |
206 | + s = Terminal.SEMICOLON; | |
207 | + } else if (s != null && (ret == null || ret.row != index || | |
208 | + (parenNest > 0 && s != Terminal.SEMICOLON))) { | |
209 | + ret = (blockEndLine == index && parenNest <= 0) ? | |
210 | + blockHeader : new TokenInfo(t, index); | |
211 | + s = null; | |
212 | + } | |
213 | + break; | |
230 | 214 | } |
231 | - if (++index >= row) break; | |
232 | - statusManager.sendLineEnd(); | |
233 | 215 | } |
234 | 216 | status = s; |
235 | 217 | boolean closedBracket = lineTopTokenType == JavaType.BRACE_END || |
236 | 218 | lineTopTokenType == JavaType.PARENTHESIS_END; |
237 | 219 | if (closedBracket && info.size() > 0) { ret = info.pop(); } |
220 | + | |
238 | 221 | return ret; |
239 | 222 | } |
240 | 223 |
@@ -253,14 +236,6 @@ | ||
253 | 236 | return null; |
254 | 237 | } |
255 | 238 | |
256 | - private JavaDocumentAttachment getJavaDocumentAttachment(MarkableDocument doc) { | |
257 | - DocumentAttachment a = doc.getDocumentAttachment(); | |
258 | - if (a instanceof JavaDocumentAttachment) { | |
259 | - return (JavaDocumentAttachment) a; | |
260 | - } | |
261 | - return null; | |
262 | - } | |
263 | - | |
264 | 239 | private String getRowText(JTextComponent t, Element root, int row) { |
265 | 240 | Element r = root.getElement(row); |
266 | 241 | int s = r.getStartOffset(); |