• R/O
  • SSH
  • HTTPS

nine: コミット


コミットメタ情報

リビジョン68 (tree)
日時2010-07-24 19:56:11
作者mshio

ログメッセージ

add the function of auto-indent in the java-mode

変更サマリ

差分

--- nine/trunk/src/jp/sourceforge/nine/MainTablePane.java (revision 67)
+++ nine/trunk/src/jp/sourceforge/nine/MainTablePane.java (revision 68)
@@ -156,11 +156,6 @@
156156 return parentPanel;
157157 }
158158
159- public BufferWindow renewWindow() {
160- parentPanel = new BufferWindow(this);
161- return parentPanel;
162- }
163-
164159 public boolean forceDefaultAction() {
165160 return false;
166161 }
--- nine/trunk/src/jp/sourceforge/nine/RootPanel.java (revision 67)
+++ nine/trunk/src/jp/sourceforge/nine/RootPanel.java (revision 68)
@@ -143,7 +143,6 @@
143143
144144 RootPanel rootPanel = (RootPanel) e.getSource();
145145 rootPanel.revalidate();
146-// rootPanel.repaint();
147146 }
148147 }
149148
--- nine/trunk/src/jp/sourceforge/nine/editorkit/BasicEditorKit.java (revision 67)
+++ nine/trunk/src/jp/sourceforge/nine/editorkit/BasicEditorKit.java (revision 68)
@@ -40,7 +40,7 @@
4040 keymapRegistry = new HashMap<String, JmKeymap>();
4141 }
4242
43- public abstract void deinstall(BasicTextPane textPane);
43+ public abstract void uninstall(BasicTextPane textPane);
4444
4545 public abstract void install(BasicTextPane textPane);
4646
--- nine/trunk/src/jp/sourceforge/nine/editorkit/TextEditorKit.java (revision 67)
+++ nine/trunk/src/jp/sourceforge/nine/editorkit/TextEditorKit.java (revision 68)
@@ -106,7 +106,7 @@
106106 }
107107
108108 @Override
109- public void deinstall(BasicTextPane textPane) {
109+ public void uninstall(BasicTextPane textPane) {
110110 if (rightClickListener != null) {
111111 textPane.removeMouseListener(rightClickListener);
112112 }
--- nine/trunk/src/jp/sourceforge/nine/editorkit/MinibufferEditorKit.java (revision 67)
+++ nine/trunk/src/jp/sourceforge/nine/editorkit/MinibufferEditorKit.java (revision 68)
@@ -69,7 +69,7 @@
6969 }
7070
7171 @Override
72- public void deinstall(BasicTextPane textPane) {
72+ public void uninstall(BasicTextPane textPane) {
7373 }
7474
7575 @Override
--- nine/trunk/src/jp/sourceforge/nine/MainBufferPane.java (revision 67)
+++ nine/trunk/src/jp/sourceforge/nine/MainBufferPane.java (revision 68)
@@ -1,8 +1,19 @@
11 /*
22 * Copyright (C) 2008-2009, mshio <mshio@users.sourceforge.jp>
3- * You can redistribute it and/or modify it under GPLv2,
4- * as published by the Free Software Foundation.
53 *
4+ * This program is free software: you can redistribute it and/or
5+ * modify it under the terms of the GNU General Public License
6+ * as published by the Free Software Foundation; either version 2
7+ * of the License, or any later version.
8+ *
9+ * This program is distributed in the hope that it will be useful,
10+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+ * GNU General Public License for more details.
13+ *
14+ * You should have received a copy of the GNU General Public License
15+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
16+ * ---
617 * Require JDK 1.5 (or later)
718 */
819 package jp.sourceforge.nine;
@@ -22,13 +33,6 @@
2233 public interface MainBufferPane {
2334
2435 /**
25- * Renews the {@code BufferPanel} associated with this component
26- * and returns it.
27- * @return new {@code BufferPanel}
28- */
29- public abstract BufferWindow renewWindow();
30-
31- /**
3236 * Returns the {@code BufferPanel} associated with this component.
3337 * @return {@code BufferPanel} associated with this component
3438 */
--- nine/trunk/src/jp/sourceforge/nine/Main.java (revision 67)
+++ nine/trunk/src/jp/sourceforge/nine/Main.java (revision 68)
@@ -167,8 +167,8 @@
167167 NineFrame f = new NineFrame(APPLICATION_NAME);
168168 frames.add(f);
169169
170+ f.setRootPanel(new RootPanel(bufferPane));
170171 f.setSize(600, 600);
171- f.setRootPanel(new RootPanel(bufferPane));
172172 f.setVisible(true);
173173 }
174174
--- nine/trunk/src/jp/sourceforge/nine/BasicTextPane.java (revision 67)
+++ nine/trunk/src/jp/sourceforge/nine/BasicTextPane.java (revision 68)
@@ -144,7 +144,7 @@
144144 */
145145 protected void setEditorKit(BasicEditorKit kit) {
146146 BasicEditorKit old = this.kit;
147- if (old != null) { old.deinstall(this); }
147+ if (old != null) { old.uninstall(this); }
148148 this.kit = kit;
149149 if (this.kit != null) {
150150 this.kit.install(this);
--- nine/trunk/src/jp/sourceforge/nine/MainTextPane.java (revision 67)
+++ nine/trunk/src/jp/sourceforge/nine/MainTextPane.java (revision 68)
@@ -324,17 +324,6 @@
324324 return k;
325325 }
326326
327- /*
328- * (non-Javadoc)
329- * @see jp.sourceforge.nine.MainBufferPane#renewWindow()
330- */
331- public BufferWindow renewWindow() {
332- int row = bufferWindow.getModeLine().getRowPosition();
333- bufferWindow = new BufferWindow(this);
334- bufferWindow.getModeLine().setRowPosition(row);
335- return bufferWindow;
336- }
337-
338327 public BufferWindow getWindow() {
339328 return bufferWindow;
340329 }
--- nine/trunk/src/jp/sourceforge/nine/action/FindFileOtherFrameAction.java (revision 67)
+++ nine/trunk/src/jp/sourceforge/nine/action/FindFileOtherFrameAction.java (revision 68)
@@ -58,4 +58,5 @@
5858 public void suggestionKeyPressed(ActionEvent e) {
5959 super.suggestionKeyPressed(e);
6060 }
61+
6162 }
--- nine/trunk/src/jp/sourceforge/nine/action/MakeFrameCommand.java (revision 67)
+++ nine/trunk/src/jp/sourceforge/nine/action/MakeFrameCommand.java (revision 68)
@@ -18,6 +18,7 @@
1818 */
1919 package jp.sourceforge.nine.action;
2020
21+import javax.swing.JFrame;
2122 import javax.swing.SwingUtilities;
2223
2324 import jp.sourceforge.nine.Main;
@@ -24,6 +25,7 @@
2425 import jp.sourceforge.nine.MainBufferPane;
2526 import jp.sourceforge.nine.action.util.Command;
2627 import jp.sourceforge.nine.buffer.BufferManager;
28+import jp.sourceforge.nine.util.NineUtilities;
2729
2830 public class MakeFrameCommand implements Command<Boolean> {
2931 private final MainBufferPane bufferPane;
@@ -41,6 +43,8 @@
4143 SwingUtilities.invokeLater(new Runnable() {
4244 public void run() {
4345 Main.application.createFrame(bufferPane);
46+ JFrame[] frames = Main.application.getFrames();
47+ changeNewFrameLocation(frames);
4448 }
4549 });
4650
@@ -47,4 +51,35 @@
4751 return true;
4852 }
4953
54+ // TODO
55+ private void changeNewFrameLocation(JFrame[] frames) {
56+ int[] desktop = NineUtilities.getDesktopSize();
57+ int x0 = desktop[0];
58+ int x1 = 0;
59+ JFrame current = null;
60+ for (int i = 0; i < frames.length - 1; i++) {
61+ if ((frames[i].getExtendedState() & JFrame.ICONIFIED) != 0) { continue; }
62+ int x = frames[i].getX();
63+ if (x < x0) { x0 = x; }
64+ int w = x + frames[i].getWidth();
65+ if (w > x1) { x1 = w; }
66+ if (frames[i].isFocused()) { current = frames[i]; }
67+ }
68+ JFrame target = frames[frames.length - 1];
69+ int x;
70+ if ((x0 + x1) / 2 < desktop[0] / 2) {
71+ x = x1 + 10;
72+ if (x + target.getWidth() > desktop[0]) {
73+ if (current != null &&
74+ current.getX() + current.getWidth() / 2 > desktop[0] / 2) {
75+ x = Math.max(x0 - target.getWidth() - 10, 0);
76+ } else {
77+ x = desktop[0] - target.getWidth();
78+ }
79+ }
80+ } else {
81+ x = Math.max(x0 - target.getWidth() - 10, 0);
82+ }
83+ target.setLocation(x, target.getY());
84+ }
5085 }
--- nine/trunk/site-js/java-mode/java-mode.js (nonexistent)
+++ nine/trunk/site-js/java-mode/java-mode.js (revision 68)
@@ -0,0 +1,40 @@
1+/*
2+ * Copyright (C) 2008-2009, mshio <mshio@users.sourceforge.jp>
3+ *
4+ * This program is free software: you can redistribute it and/or
5+ * modify it under the terms of the GNU General Public License
6+ * as published by the Free Software Foundation; either version 2
7+ * of the License, or any later version.
8+ *
9+ * This program is distributed in the hope that it will be useful,
10+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+ * GNU General Public License for more details.
13+ *
14+ * You should have received a copy of the GNU General Public License
15+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
16+ */
17+automodeSet("text/java",
18+ "java",
19+ "jp.sourceforge.nine.javamode.JavaEditorKit"
20+);
21+
22+with (defineKeymap("java-mode-keymap")) {
23+// defineKey("TAB", "javamode-tabulate");
24+// defineKey("}", "closing-curly-brace");
25+ defineKey("TAB", "java-indent");
26+};
27+
28+actionDefinitions.TEXT['java-indent'] = {
29+ name: 'jp.sourceforge.nine.action.javamode.JavaTabAction',
30+ plugin: true,
31+};
32+actionDefinitions.TEXT['java-mode'] = {
33+ name: 'jp.sourceforge.nine.action.ScriptTextAction',
34+ types: ['String'],
35+ args: ['java-mode'],
36+};
37+
38+interactives['java-mode'] = function() {
39+ ChangeMode(textComponent, 'text/java');
40+};
--- nine-xml-mode/trunk/src/jp/sourceforge/nine/xmlmode/XmlEditorKit.java (revision 67)
+++ nine-xml-mode/trunk/src/jp/sourceforge/nine/xmlmode/XmlEditorKit.java (revision 68)
@@ -63,7 +63,7 @@
6363 }
6464
6565 @Override
66- public void deinstall(BasicTextPane textPane) {
66+ public void uninstall(BasicTextPane textPane) {
6767 CaretListener[] ls = textPane.getCaretListeners();
6868 for (CaretListener l : ls) {
6969 if (l instanceof HighlightCaretListener) {
@@ -70,7 +70,7 @@
7070 textPane.removeCaretListener(l);
7171 }
7272 }
73- super.deinstall(textPane);
73+ super.uninstall(textPane);
7474 }
7575
7676 @Override
--- nine-java-mode/trunk/src/jp/sourceforge/nine/javamode/JavaEditorKit.java (revision 67)
+++ nine-java-mode/trunk/src/jp/sourceforge/nine/javamode/JavaEditorKit.java (revision 68)
@@ -19,9 +19,11 @@
1919 package jp.sourceforge.nine.javamode;
2020
2121 import javax.swing.Action;
22+import javax.swing.event.CaretListener;
2223 import javax.swing.text.Document;
2324 import javax.swing.text.TextAction;
2425
26+import jp.sourceforge.nine.BasicTextPane;
2527 import jp.sourceforge.nine.MainTextPane;
2628 import jp.sourceforge.nine.document.DocumentAttachment;
2729 import jp.sourceforge.nine.editorkit.TextEditorKit;
@@ -58,6 +60,23 @@
5860 }
5961
6062 @Override
63+ public void install(BasicTextPane textPane) {
64+ textPane.addCaretListener(new HighlightCaretListener());
65+ super.install(textPane);
66+ }
67+
68+ @Override
69+ public void uninstall(BasicTextPane textPane) {
70+ CaretListener[] ls = textPane.getCaretListeners();
71+ for (CaretListener l : ls) {
72+ if (l instanceof HighlightCaretListener) {
73+ textPane.removeCaretListener(l);
74+ }
75+ }
76+ super.uninstall(textPane);
77+ }
78+
79+ @Override
6180 protected ViewPainter createViewPainter(Document document) {
6281 PlainStringPainterMaker<JavaType, JavaStatus> m =
6382 new PlainStringPainterMaker<JavaType, JavaStatus>();
--- nine-java-mode/trunk/src/jp/sourceforge/nine/javamode/JavaColorController.java (revision 67)
+++ nine-java-mode/trunk/src/jp/sourceforge/nine/javamode/JavaColorController.java (revision 68)
@@ -33,9 +33,6 @@
3333 switch (status) {
3434 case NORMAL:
3535 switch (type) {
36- case KEYWORD:
37- ret = DefaultBrush.COLOR_KEYWORD;
38- break;
3936 case DOUBLE_QUOTE:
4037 case SINGLE_QUOTE:
4138 if (! escaping) { ret = DefaultBrush.COLOR_STRING; }
@@ -44,6 +41,11 @@
4441 case LINE_COMMENT_BEGIN:
4542 ret = DefaultBrush.COLOR_COMMENT;
4643 break;
44+ default:
45+ if (type.isKeyword()) {
46+ ret = DefaultBrush.COLOR_KEYWORD;
47+ }
48+ break;
4749 }
4850 break;
4951 case DOUBLE_QUOTE:
--- nine-java-mode/trunk/src/jp/sourceforge/nine/javamode/HighlightCaretListener.java (nonexistent)
+++ nine-java-mode/trunk/src/jp/sourceforge/nine/javamode/HighlightCaretListener.java (revision 68)
@@ -0,0 +1,218 @@
1+/*
2+ * Copyright (C) 2009, mshio <mshio@users.sourceforge.jp>
3+ *
4+ * This program is free software: you can redistribute it and/or
5+ * modify it under the terms of the GNU General Public License
6+ * as published by the Free Software Foundation; either version 2
7+ * of the License, or any later version.
8+ *
9+ * This program is distributed in the hope that it will be useful,
10+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+ * GNU General Public License for more details.
13+ *
14+ * You should have received a copy of the GNU General Public License
15+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
16+ *
17+ * Require JDK 1.5 (or later)
18+ */
19+package jp.sourceforge.nine.javamode;
20+
21+import java.awt.Color;
22+import java.util.ArrayList;
23+
24+import javax.swing.SwingUtilities;
25+import javax.swing.event.CaretEvent;
26+import javax.swing.event.CaretListener;
27+import javax.swing.text.BadLocationException;
28+import javax.swing.text.DefaultHighlighter;
29+import javax.swing.text.Element;
30+import javax.swing.text.Highlighter;
31+
32+import jp.sourceforge.nine.MainTextPane;
33+import jp.sourceforge.nine.document.DocumentAttachment;
34+import jp.sourceforge.nine.document.MarkableDocument;
35+import jp.sourceforge.nine.parser.Token;
36+import jp.sourceforge.nine.parser.TokenLine;
37+import jp.sourceforge.nine.parser.javamode.JavaStatus;
38+import jp.sourceforge.nine.parser.javamode.JavaStatusManager;
39+import jp.sourceforge.nine.parser.javamode.JavaType;
40+
41+public class HighlightCaretListener implements CaretListener {
42+ protected final static Color HIGHLIGHT = new Color(0xccccff);
43+
44+ protected MainTextPane textPane = null;
45+ protected MarkableDocument document = null;
46+ ArrayList<TokenLine<JavaType, JavaStatus>> tokenlist;
47+ JavaStatusManager statusManager = new JavaStatusManager();
48+
49+ public void caretUpdate(final CaretEvent e) {
50+ textPane = getMainTextPane(e);
51+ MarkableDocument doc = (MarkableDocument) textPane.getDocument();
52+ if (document != doc) {
53+ document = doc;
54+ tokenlist = getTokenList(doc);
55+ }
56+ SwingUtilities.invokeLater(new Runnable() {
57+ public void run() { action(e); }
58+ });
59+ }
60+
61+ private void action(CaretEvent e) {
62+ int pos = e.getDot();
63+ int row = getCurrentRowIndex(pos);
64+ int col = getCurrentColumnIndex(pos, row);
65+ dehighlight();
66+ TokenLine<JavaType, JavaStatus> line = tokenlist.get(row);
67+ JavaStatus status = row == 0 ?
68+ JavaStatus.NORMAL : tokenlist.get(row - 1).getEndStatus();
69+ statusManager.setCurrentStatus(status);
70+ for (Token<JavaType> token : line) {
71+ JavaType type = token.getType();
72+ statusManager.switchStatus(type);
73+ if (statusManager.getStatus() == JavaStatus.NORMAL &&
74+ token.getOffset() + token.getLength() == col) {
75+ boolean searchForward = false;
76+ JavaType searchType = null;
77+ switch (type) {
78+ case BRACE_BEGIN:
79+ searchForward = true;
80+ searchType = JavaType.BRACE_END;
81+ break;
82+ case BRACE_END:
83+ searchType = JavaType.BRACE_BEGIN;
84+ break;
85+ case BRACKET_BEGIN:
86+ searchForward = true;
87+ searchType = JavaType.BRACKET_END;
88+ break;
89+ case BRACKET_END:
90+ searchType = JavaType.BRACKET_BEGIN;
91+ break;
92+ case PARENTHESIS_BEGIN:
93+ searchForward = true;
94+ searchType = JavaType.PARENTHESIS_END;
95+ break;
96+ case PARENTHESIS_END:
97+ searchType = JavaType.PARENTHESIS_BEGIN;
98+ break;
99+ }
100+ if (searchType != null) {
101+ search(searchForward, row, type, searchType, col);
102+ }
103+ }
104+ }
105+ }
106+
107+ private void search(boolean forward, int row, JavaType type, JavaType search, int col) {
108+ if (forward) {
109+ searchForward(row, type, search, col);
110+ } else {
111+ searchBackward(row, type, search, col);
112+ }
113+ }
114+
115+ private void searchForward(int row, JavaType type, JavaType search, int col) {
116+ int count = 0;
117+ for (int i = row; i < tokenlist.size(); i++) {
118+ TokenLine<JavaType, JavaStatus> line = tokenlist.get(i);
119+ for (Token<JavaType> t : line) {
120+ statusManager.switchStatus(t.getType());
121+ if (statusManager.getStatus() == JavaStatus.NORMAL &&
122+ ! (i == row && t.getOffset() < col)) {
123+ if (t.getType() == search) {
124+ if (count-- == 0) {
125+ int offs = getRowStartOffset(i) + t.getOffset();
126+ highlight(offs);
127+ return;
128+ }
129+ } else if (t.getType() == type) {
130+ count++;
131+ }
132+ }
133+ }
134+ statusManager.sendLineEnd();
135+ }
136+ }
137+
138+ private void searchBackward(int row, JavaType type, JavaType search, int col) {
139+ int count = 0;
140+ for (int i = row; i >= 0; i--) {
141+ TokenLine<JavaType, JavaStatus> line = tokenlist.get(i);
142+ for (int j = line.size() - 1; j >= 0; j--) {
143+ Token<JavaType> token = line.get(j);
144+ if (i == row && token.getOffset() + token.getLength() >= col) { continue; }
145+ if (token.getType() == search) {
146+ if (statusIsNormal(i, j)) {
147+ if (count-- == 0) {
148+ int offs = getRowStartOffset(i) + token.getOffset();
149+ highlight(offs);
150+ return;
151+ }
152+ }
153+ } else if (token.getType() == type) {
154+ if (statusIsNormal(i, j)) { count++; }
155+ }
156+ }
157+ }
158+ }
159+
160+ private boolean statusIsNormal(int row, int tokenOffset) {
161+ JavaStatus prev = row == 0 ?
162+ JavaStatus.NORMAL : tokenlist.get(row - 1).getEndStatus();
163+ statusManager.setCurrentStatus(prev);
164+ TokenLine<JavaType, JavaStatus> line = tokenlist.get(row);
165+ for (int i = 0; i < line.size(); i++) {
166+ Token<JavaType> token = line.get(i);
167+ statusManager.switchStatus(token.getType());
168+ if (i == tokenOffset) {
169+ return statusManager.getStatus() == JavaStatus.NORMAL;
170+ }
171+ }
172+ return false;
173+ }
174+
175+ protected int getCurrentRowIndex(int pos) {
176+ Element root = document.getDefaultRootElement();
177+ return root.getElementIndex(pos);
178+ }
179+
180+ protected int getRowStartOffset(int index) {
181+ Element e = document.getDefaultRootElement().getElement(index);
182+ return e.getStartOffset();
183+ }
184+
185+ protected int getCurrentColumnIndex(int pos, int index) {
186+ int startOffs = getRowStartOffset(index);
187+ return pos - startOffs;
188+ }
189+
190+ protected void highlight(int pos) {
191+ Highlighter.HighlightPainter p =
192+ new DefaultHighlighter.DefaultHighlightPainter(HIGHLIGHT);
193+ try {
194+ textPane.getHighlighter().addHighlight(pos, pos + 1, p);
195+ } catch (BadLocationException e) {
196+ e.printStackTrace();
197+ }
198+ }
199+
200+ protected void dehighlight() {
201+ textPane.getHighlighter().removeAllHighlights();
202+ }
203+
204+ protected MainTextPane getMainTextPane(CaretEvent e) {
205+ Object o = e.getSource();
206+ return (o instanceof MainTextPane) ? (MainTextPane) o : null;
207+ }
208+
209+ private ArrayList<TokenLine<JavaType, JavaStatus>>
210+ getTokenList(MarkableDocument document) {
211+ DocumentAttachment da = document.getDocumentAttachment();
212+ if (da instanceof JavaDocumentAttachment) {
213+ JavaDocumentAttachment jda = (JavaDocumentAttachment) da;
214+ return jda.getTokenList();
215+ }
216+ return null;
217+ }
218+}
--- nine-java-mode/trunk/src/jp/sourceforge/nine/parser/javamode/JavaType.java (revision 67)
+++ nine-java-mode/trunk/src/jp/sourceforge/nine/parser/javamode/JavaType.java (revision 68)
@@ -18,6 +18,8 @@
1818 */
1919 package jp.sourceforge.nine.parser.javamode;
2020
21+import jp.sourceforge.nine.util.NineLogger;
22+
2123 public enum JavaType {
2224 BLOCK_COMMENT_BEGIN,
2325 BLOCK_COMMENT_END,
@@ -26,14 +28,80 @@
2628 DOUBLE_QUOTE,
2729 SINGLE_QUOTE,
2830 BACK_SLASH,
31+ GREATER_THAN,
32+ LESSER_THAN,
33+ AT_MARK,
2934 KEYWORD,
3035 WHITE_SPACE,
36+ MARK,
37+ SEMICOLON,
38+ NORMAL,
39+
40+ // BRACKETS
3141 BRACE_BEGIN,
3242 BRACE_END,
33- MARK,
34- NORMAL,
43+ PARENTHESIS_BEGIN,
44+ PARENTHESIS_END,
45+ BRACKET_BEGIN,
46+ BRACKET_END,
47+
48+ // KEYWORDS
49+ KW_ABSTRACT,
50+ KW_BREAK,
51+ KW_CASE,
52+ KW_CATCH,
53+ KW_CLASS,
54+ KW_CONST,
55+ KW_CONTINUE,
56+ KW_DEFAULT,
57+ KW_DO,
58+ KW_ELSE,
59+ KW_EXTENDS,
60+ KW_FINAL,
61+ KW_FINALLY,
62+ KW_FOR,
63+ KW_IF,
64+ KW_IMPLEMENTS,
65+ KW_IMPORT,
66+ KW_INSTANCEOF,
67+ KW_INTERFACE,
68+ KW_NATIVE,
69+ KW_NEW,
70+ KW_PACKAGE,
71+ KW_PRIVATE,
72+ KW_PROTECTED,
73+ KW_PUBLIC,
74+ KW_RETURN,
75+ KW_STATIC,
76+ KW_STRICTFP,
77+ KW_SUPER,
78+ KW_SWITCH,
79+ KW_SYNCHRONIZED,
80+ KW_THIS,
81+ KW_THROW,
82+ KW_THROWS,
83+ KW_TRANSIENT,
84+ KW_TRY,
85+ KW_VOLATILE,
86+ KW_WHILE,
3587 ;
3688
89+ public boolean isKeyword() {
90+ String s = name();
91+ return (s.startsWith("KW_"));
92+ }
93+
94+ public static JavaType getKeywordType(String keyword) {
95+ JavaType ret = null;
96+ String n = "KW_" + keyword.toUpperCase();
97+ try {
98+ ret = JavaType.valueOf(n);
99+ } catch (Exception e) {
100+ NineLogger.instance.severe(e);
101+ }
102+ return ret;
103+ }
104+
37105 public JavaStatus getStatus() {
38106 JavaStatus ret;
39107 switch (this) {
--- nine-java-mode/trunk/src/jp/sourceforge/nine/parser/javamode/JavaTokenizer.java (revision 67)
+++ nine-java-mode/trunk/src/jp/sourceforge/nine/parser/javamode/JavaTokenizer.java (revision 68)
@@ -18,7 +18,6 @@
1818 */
1919 package jp.sourceforge.nine.parser.javamode;
2020
21-import jp.sourceforge.nine.js.ModeProperties;
2221 import jp.sourceforge.nine.parser.DefaultMarkScanner;
2322 import jp.sourceforge.nine.parser.DefaultTokenizer;
2423 import jp.sourceforge.nine.parser.StatusManager;
@@ -27,12 +26,44 @@
2726
2827
2928 public class JavaTokenizer extends DefaultTokenizer<JavaType, JavaStatus> {
30- private final String[] keywords;
29+ private static final Keyword[] keywords;
3130
31+ static {
32+ keywords = createKeywords();
33+ }
34+
35+ private static Keyword[] createKeywords() {
36+ Keyword[] ret = null;
37+ String[] words = {
38+ "abstract", "break",
39+ "case", "catch",
40+ "class", "const",
41+ "continue", "default",
42+ "do", "else",
43+ "extends", "final",
44+ "finally", "for",
45+ "if", "implements",
46+ "import", "instanceof",
47+ "interface", "native",
48+ "new", "package",
49+ "private", "protected",
50+ "public", "return",
51+ "static", "strictfp",
52+ "super", "switch",
53+ "synchronized", "this",
54+ "throw", "throws",
55+ "transient", "try",
56+ "volatile", "while"
57+ };
58+ ret = new Keyword[words.length];
59+ for (int i = 0; i < words.length; i++) {
60+ ret[i] = new Keyword(words[i], JavaType.getKeywordType(words[i]));
61+ }
62+ return ret;
63+ }
64+
3265 public JavaTokenizer(StatusManager<JavaStatus, JavaType> statusManager) {
3366 super(statusManager);
34- ModeProperties m = ModeProperties.getInstance();
35- keywords = m.getKeywords("text/java");
3667 }
3768
3869 @Override
@@ -47,8 +78,8 @@
4778
4879 static class JavaWordScanner
4980 extends WordScanner<JavaType, JavaStatus> {
50- private String[] keywords = null;
51- boolean[] keywordNotMatch;
81+ private static Keyword[] keywords = JavaTokenizer.keywords;
82+ boolean[] keywordNotMatch = new boolean[keywords.length];
5283
5384 public JavaWordScanner(JavaTokenizer tokenizer) {
5485 super(tokenizer);
@@ -56,12 +87,11 @@
5687
5788 @Override
5889 protected void characterMatched(char ch, int offset, int length) {
59- if (keywords == null) { setupKeywordList(); }
6090 // check keywords
6191 for (int i = 0; i < keywords.length; i++) {
6292 if (keywordNotMatch[i]) { continue; }
6393
64- String w = keywords[i];
94+ String w = keywords[i].keyword;
6595 if (w.length() <= length) {
6696 keywordNotMatch[i] = true;
6797 } else if (w.charAt(length) != ch) {
@@ -74,33 +104,28 @@
74104 protected void characterUnmatched(char ch, int offset, int length) {
75105 int start = offset - length;
76106 checkKeywordsLength(length);
77- JavaType type = currentIsKeyword() ? JavaType.KEYWORD : JavaType.NORMAL;
107+ Integer x = currentIsKeyword();
108+ JavaType type = x != null ? keywords[x].type : JavaType.NORMAL;
78109 tokenizer.setTokenIntoLine(type, start, length);
79- if (keywords != null) {
80- keywordNotMatch = new boolean[keywords.length];
81- }
110+ keywordNotMatch = new boolean[keywords.length];
82111 }
83112
84113 private void checkKeywordsLength(int length) {
85114 for (int i = 0; i < keywords.length; i++) {
86115 if (! keywordNotMatch[i] &&
87- keywords[i].length() != length) {
116+ keywords[i].keyword.length() != length) {
88117 keywordNotMatch[i] = true;
89118 }
90119 }
91120 }
92121
93- private boolean currentIsKeyword() {
122+ private Integer currentIsKeyword() {
94123 for (int i = 0; i < keywordNotMatch.length; i++) {
95- if (! keywordNotMatch[i]) { return true; }
124+ if (! keywordNotMatch[i]) { return i; }
96125 }
97- return false;
126+ return null;
98127 }
99128
100- private void setupKeywordList() {
101- keywords = ((JavaTokenizer) tokenizer).keywords;
102- keywordNotMatch = new boolean[keywords.length];
103- }
104129 }
105130
106131
@@ -160,6 +185,30 @@
160185 case '}':
161186 type = JavaType.BRACE_END;
162187 break;
188+ case '(':
189+ type = JavaType.PARENTHESIS_BEGIN;
190+ break;
191+ case ')':
192+ type = JavaType.PARENTHESIS_END;
193+ break;
194+ case '[':
195+ type = JavaType.BRACKET_BEGIN;
196+ break;
197+ case ']':
198+ type = JavaType.BRACKET_END;
199+ break;
200+ case '<':
201+ type = JavaType.LESSER_THAN;
202+ break;
203+ case '>':
204+ type = JavaType.GREATER_THAN;
205+ break;
206+ case '@':
207+ type = JavaType.AT_MARK;
208+ break;
209+ case ';':
210+ type = JavaType.SEMICOLON;
211+ break;
163212 default:
164213 type = JavaType.MARK;
165214 break;
@@ -186,4 +235,15 @@
186235 tokenizer.setTokenIntoLine(type, offset - 1, 1);
187236 }
188237 }
238+
239+
240+ static class Keyword {
241+ final String keyword;
242+ final JavaType type;
243+
244+ Keyword(String keyword, JavaType type) {
245+ this.keyword = keyword;
246+ this.type = type;
247+ }
248+ }
189249 }
--- nine-java-mode/trunk/src/jp/sourceforge/nine/action/javamode/JavaTabAction.java (nonexistent)
+++ nine-java-mode/trunk/src/jp/sourceforge/nine/action/javamode/JavaTabAction.java (revision 68)
@@ -0,0 +1,291 @@
1+/*
2+ * Copyright (C) 2010, mshio <mshio@users.sourceforge.jp>
3+ *
4+ * This program is free software: you can redistribute it and/or
5+ * modify it under the terms of the GNU General Public License
6+ * as published by the Free Software Foundation; either version 2
7+ * of the License, or any later version.
8+ *
9+ * This program is distributed in the hope that it will be useful,
10+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+ * GNU General Public License for more details.
13+ *
14+ * You should have received a copy of the GNU General Public License
15+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
16+ *
17+ * Require JDK 1.5 (or later)
18+ */
19+package jp.sourceforge.nine.action.javamode;
20+
21+import java.awt.event.ActionEvent;
22+import java.util.ArrayList;
23+import java.util.Stack;
24+
25+import javax.swing.text.Document;
26+import javax.swing.text.Element;
27+import javax.swing.text.JTextComponent;
28+
29+import jp.sourceforge.nine.MainTextPane;
30+import jp.sourceforge.nine.action.ScriptableTextAction;
31+import jp.sourceforge.nine.document.DocumentAttachment;
32+import jp.sourceforge.nine.document.MarkableDocument;
33+import jp.sourceforge.nine.javamode.JavaDocumentAttachment;
34+import jp.sourceforge.nine.parser.Token;
35+import jp.sourceforge.nine.parser.TokenLine;
36+import jp.sourceforge.nine.parser.javamode.JavaStatus;
37+import jp.sourceforge.nine.parser.javamode.JavaStatusManager;
38+import jp.sourceforge.nine.parser.javamode.JavaType;
39+
40+/**
41+ * カレント行の文字列に対して、自動インデントを行うクラスです。
42+ * 基本的には、直前のカッコ類を検出し、その行のインデント情報を元に、カレント行のインデントを自動的に変更します。
43+ * インデントは、GNU に近い様式で行われる予定ですが、少なくとも現状ではまったく厳密ではありません。
44+ * また、このバージョンでは実装もまったく不完全です。
45+ * たとえば、通常の文を途中で改行しても、インデントが増えません。
46+ * switch case 文の case が適切にインデントされません。
47+ *
48+ * @author mshio
49+ */
50+public class JavaTabAction extends ScriptableTextAction {
51+ private static final long serialVersionUID = -8283585316654470522L;
52+ public static final String ACTION_NAME = "java-indent";
53+ private final JavaStatusManager statusManager = new JavaStatusManager();
54+
55+ public JavaTabAction() {
56+ super(ACTION_NAME);
57+ }
58+
59+ /**
60+ * 自動インデントを実行します。
61+ */
62+ @Override
63+ public void perform(ActionEvent e) {
64+ JTextComponent text = getTextComponent(e);
65+ MarkableDocument doc = getMarkableDocument(text);
66+ if (doc == null) return;
67+ Element root = doc.getDefaultRootElement();
68+ int currentRow = root.getElementIndex(text.getCaretPosition());
69+ KeywordInfo lastBracket = getLastBracket(text, doc, currentRow);
70+ if (lastBracket == null) return;
71+
72+ if (lastBracket != null) {
73+ String indent = getIndentText(text, doc, currentRow, lastBracket);
74+ String line = getCurrentText(text, doc);
75+ int s = root.getElement(currentRow).getStartOffset();
76+ int pos = getNextCaretPosition(text, line, indent, s);
77+ editText(text, root, currentRow, line, indent, pos);
78+ }
79+ }
80+
81+ private void editText(JTextComponent text, Element root, int currentRow,
82+ String line, String indent, int caretPosition) {
83+ Element r = root.getElement(currentRow);
84+ if (text instanceof MainTextPane) {
85+ MainTextPane pane = (MainTextPane) text;
86+ pane.beginUndoTransaction();
87+ text.setSelectionStart(r.getStartOffset());
88+ text.setSelectionEnd(r.getEndOffset());
89+ text.replaceSelection(indent + getLeftTrimedText(line));
90+ text.setCaretPosition(caretPosition);
91+ pane.endUndoTransaction();
92+ }
93+ }
94+
95+ /**
96+ * Converts the text component into {@code MarkableDocument} object.
97+ *
98+ * @param textComponent the text component
99+ * @return {@code MarkableDocument} object, or null if the text component
100+ * is not an instance of {@code MarkableDocument}.
101+ */
102+ private MarkableDocument getMarkableDocument(JTextComponent textComponent) {
103+ Document d = textComponent.getDocument();
104+ if (d instanceof MarkableDocument) {
105+ return (MarkableDocument) d;
106+ }
107+ return null;
108+ }
109+
110+ private JavaDocumentAttachment getJavaDocumentAttachment(MarkableDocument doc) {
111+ DocumentAttachment a = doc.getDocumentAttachment();
112+ if (a instanceof JavaDocumentAttachment) {
113+ return (JavaDocumentAttachment) a;
114+ }
115+ return null;
116+ }
117+
118+ private String getIndentText(JTextComponent text, Document doc,
119+ int currentRow, KeywordInfo bracket) {
120+ Element root = doc.getDefaultRootElement();
121+ String bracketLine = getRowText(text, doc, root, bracket.row);
122+ String currentLine = getRowText(text, doc, root, currentRow);
123+ boolean closed = isClosedBracket(currentLine);
124+ return getIndentText(bracketLine, bracket.token, closed);
125+ }
126+
127+ private KeywordInfo getLastBracket(JTextComponent t, MarkableDocument doc, int currentRow) {
128+ JavaDocumentAttachment a = getJavaDocumentAttachment(doc);
129+ if (a == null) return null;
130+ ArrayList<TokenLine<JavaType, JavaStatus>> list = a.getTokenList();
131+ return getLastBracket(list, currentRow);
132+ }
133+
134+ private KeywordInfo getLastBracket(ArrayList<TokenLine<JavaType, JavaStatus>> list,
135+ int row) {
136+ int i = 0;
137+ Stack<KeywordInfo> s = new Stack<KeywordInfo>();
138+ statusManager.setCurrentStatus(JavaStatus.NORMAL);
139+
140+ for (TokenLine<JavaType, JavaStatus> l : list) {
141+ for (Token<JavaType> t : l) {
142+ JavaType type = t.getType();
143+ statusManager.switchStatus(type);
144+ if (statusManager.getStatus() != JavaStatus.NORMAL) { continue; }
145+ switch (type) {
146+ case KW_IF:
147+ case KW_WHILE:
148+ case KW_FOR:
149+ case BRACE_BEGIN:
150+ case PARENTHESIS_BEGIN:
151+ case BRACKET_BEGIN:
152+ s.add(new KeywordInfo(t, i));
153+ break;
154+ case PARENTHESIS_END:
155+ case BRACKET_END:
156+ s.pop();
157+ break;
158+ case BRACE_END:
159+ s.pop();
160+ modifyIfStatement(s);
161+ break;
162+ case SEMICOLON:
163+ modifyIfStatement(s);
164+ break;
165+ }
166+ }
167+ if (++i >= row) break;
168+ statusManager.sendLineEnd();
169+ }
170+ return s.size() > 0 ? s.pop() : null;
171+ }
172+
173+ private void modifyIfStatement(Stack<KeywordInfo> stack) {
174+ if (stack.isEmpty()) { return; }
175+ KeywordInfo b = stack.peek();
176+ if (b != null) {
177+ JavaType t = b.token.getType();
178+ if (t == JavaType.KW_IF || t == JavaType.KW_FOR || t == JavaType.KW_WHILE) {
179+ stack.pop();
180+ }
181+ }
182+ }
183+
184+ private String getRowText(JTextComponent t, Document doc, Element root, int row) {
185+ Element r = root.getElement(row);
186+ int s = r.getStartOffset();
187+ int e = r.getEndOffset();
188+ int len = t.getText().length();
189+ e = len < e ? len : e;
190+ return s == e ? "" : t.getText().substring(s, e);
191+ }
192+
193+ private String getIndentText(String text, Token<JavaType> token, boolean closed) {
194+ int left = 0;
195+ for (char ch : text.toCharArray()) {
196+ if (ch != ' ' && ch != '\t') break;
197+ left++;
198+ }
199+ String indent = text.substring(0, left);
200+ JavaType t = token.getType();
201+ if (t == JavaType.BRACE_BEGIN) {
202+ return closed ? indent : indent + "\t";
203+ } else if (t == JavaType.BRACKET_BEGIN || t == JavaType.PARENTHESIS_BEGIN) {
204+ int l = token.getOffset() - left;
205+ StringBuilder sb = new StringBuilder(indent.length() + l);
206+ sb.append(indent);
207+ for (int i = 0; i < l; i++) {
208+ sb.append(' ');
209+ }
210+ if (! closed) sb.append(' ');
211+ return sb.toString();
212+ }
213+ return closed ? indent : indent + "\t";
214+ }
215+
216+ private String getCurrentText(JTextComponent t, Document doc) {
217+ Element root = doc.getDefaultRootElement();
218+ int row = root.getElementIndex(t.getCaretPosition());
219+ return getRowText(t, doc, root, row);
220+ }
221+
222+ private boolean isClosedBracket(String text) {
223+ char ch = 0;
224+ for (int i = 0; i < text.length(); i++) {
225+ ch = text.charAt(i);
226+ if (ch != ' ' && ch != '\t') { break; }
227+ }
228+ return ch == '}' || ch == ']' || ch == ')';
229+ }
230+
231+ /**
232+ * インデント調整後のキャレット位置を算出します。
233+ * 現在のキャレットの位置(インデックス値)から、取り除かれるインデントの文字数を引き、
234+ * 追加されるインデントの文字数を足して算出しています。
235+ *
236+ * @param text テキストコンポーネント オブジェクト
237+ * @param line 行全体の文字列
238+ * @param indent インデントを構成する空白文字(スペースとタブ)による文字列
239+ * @param leftPos 行の左端のインデックス(これより小さな値になると、前の行に移動してしまう)
240+ * @return インデント調整後のあるべきキャレット位置(インデックス値)
241+ */
242+ private int getNextCaretPosition(JTextComponent text, String line,
243+ String indent, int leftPos) {
244+ int d = getLeftBrank(line);
245+ int pos = text.getCaretPosition();
246+ int ret = pos - d + indent.length();
247+ return ret < leftPos ? leftPos : ret;
248+ }
249+
250+ /**
251+ * 渡された文字列の、左側(先頭側)の空白文字(スペースとタブ)の文字数を算出します。
252+ *
253+ * @param line 対象となる文字列
254+ * @return 左端に検出された空白文字の数
255+ */
256+ private int getLeftBrank(String line) {
257+ int i;
258+ for (i = 0; i < line.length(); i++) {
259+ char c = line.charAt(i);
260+ if (c != ' ' && c != '\t') { break; }
261+ }
262+ return i;
263+ }
264+
265+ private String getLeftTrimedText(String line) {
266+ int p0 = getLeftBrank(line);
267+ return line.substring(p0);
268+ }
269+
270+
271+ /**
272+ * カッコ類などキーワードの種類や位置情報を保持するためのオブジェクト。
273+ * 位置情報は、行と列の値で保持する。
274+ *
275+ * @author mshio
276+ */
277+ static class KeywordInfo {
278+ final int row;
279+ final Token<JavaType> token;
280+
281+ KeywordInfo(Token<JavaType> token, int row) {
282+ this.token = token;
283+ this.row = row;
284+ }
285+
286+ @Override
287+ public String toString() {
288+ return String.format("[token: %s, row: %d]", token, row);
289+ }
290+ }
291+}
旧リポジトリブラウザで表示