1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-06-17 22:23:10 +03:00

Resynced with Processing/Wiring IDE code: improved auto-format, better performance for EditorConsole, etc...

This commit is contained in:
David A. Mellis
2006-03-26 19:12:53 +00:00
parent 2de016c367
commit 3ea01968d7
22 changed files with 3213 additions and 1343 deletions

View File

@ -35,13 +35,25 @@ import javax.swing.event.*;
/**
* Filters key events for tab expansion/indent/etc.
* <p/>
* For version 0099, some changes have been made to make the indents
* smarter. There are still issues though:
* + indent happens when it picks up a curly brace on the previous line,
* but not if there's a blank line between them.
* + It also doesn't handle single indent situations where a brace
* isn't used (i.e. an if statement or for loop that's a single line).
* It shouldn't actually be using braces.
* Solving these issues, however, would probably best be done by a
* smarter parser/formatter, rather than continuing to hack this class.
*/
public class EditorListener {
Editor editor;
JEditTextArea textarea;
boolean externalEditor;
boolean expandTabs;
boolean tabsExpand;
boolean tabsIndent;
int tabSize;
String tabString;
boolean autoIndent;
@ -61,8 +73,9 @@ public class EditorListener {
public void applyPreferences() {
expandTabs = Preferences.getBoolean("editor.tabs.expand");
int tabSize = Preferences.getInteger("editor.tabs.size");
tabsExpand = Preferences.getBoolean("editor.tabs.expand");
//tabsIndent = Preferences.getBoolean("editor.tabs.indent");
tabSize = Preferences.getInteger("editor.tabs.size");
tabString = Editor.EMPTY.substring(0, tabSize);
autoIndent = Preferences.getBoolean("editor.indent");
externalEditor = Preferences.getBoolean("editor.external");
@ -74,7 +87,13 @@ public class EditorListener {
//}
// called by JEditTextArea inside processKeyEvent
/**
* Intercepts key pressed events for JEditTextArea.
* <p/>
* Called by JEditTextArea inside processKeyEvent(). Note that this
* won't intercept actual characters, because those are fired on
* keyTyped().
*/
public boolean keyPressed(KeyEvent event) {
// don't do things if the textarea isn't editable
if (externalEditor) return false;
@ -92,21 +111,148 @@ public class EditorListener {
}
// TODO i don't like these accessors. clean em up later.
if (!editor.sketch.current.modified) {
if (!editor.sketch.modified) {
if ((code == KeyEvent.VK_BACK_SPACE) || (code == KeyEvent.VK_TAB) ||
(code == KeyEvent.VK_ENTER) || ((c >= 32) && (c < 128))) {
editor.sketch.setModified();
editor.sketch.setModified(true);
}
}
if ((code == KeyEvent.VK_UP) &&
((event.getModifiers() & KeyEvent.CTRL_MASK) != 0)) {
// back up to the last empty line
char contents[] = textarea.getText().toCharArray();
//int origIndex = textarea.getCaretPosition() - 1;
int caretIndex = textarea.getCaretPosition();
int index = calcLineStart(caretIndex - 1, contents);
//System.out.println("line start " + (int) contents[index]);
index -= 2; // step over the newline
//System.out.println((int) contents[index]);
boolean onlySpaces = true;
while (index > 0) {
if (contents[index] == 10) {
if (onlySpaces) {
index++;
break;
} else {
onlySpaces = true; // reset
}
} else if (contents[index] != ' ') {
onlySpaces = false;
}
index--;
}
// if the first char, index will be -2
if (index < 0) index = 0;
if ((event.getModifiers() & KeyEvent.SHIFT_MASK) != 0) {
textarea.setSelectionStart(caretIndex);
textarea.setSelectionEnd(index);
} else {
textarea.setCaretPosition(index);
}
event.consume();
return true;
} else if ((code == KeyEvent.VK_DOWN) &&
((event.getModifiers() & KeyEvent.CTRL_MASK) != 0)) {
char contents[] = textarea.getText().toCharArray();
int caretIndex = textarea.getCaretPosition();
int index = caretIndex;
int lineStart = 0;
boolean onlySpaces = false; // don't count this line
while (index < contents.length) {
if (contents[index] == 10) {
if (onlySpaces) {
index = lineStart; // this is it
break;
} else {
lineStart = index + 1;
onlySpaces = true; // reset
}
} else if (contents[index] != ' ') {
onlySpaces = false;
}
index++;
}
// if the first char, index will be -2
//if (index < 0) index = 0;
//textarea.setSelectionStart(index);
//textarea.setSelectionEnd(index);
if ((event.getModifiers() & KeyEvent.SHIFT_MASK) != 0) {
textarea.setSelectionStart(caretIndex);
textarea.setSelectionEnd(index);
} else {
textarea.setCaretPosition(index);
}
event.consume();
return true;
}
switch ((int) c) {
case 9: // expand tabs
if (expandTabs) {
//tc.replaceSelection(tabString);
if (tabsExpand) {
textarea.setSelectedText(tabString);
event.consume();
return true;
} else if (tabsIndent) {
// this code is incomplete
// if this brace is the only thing on the line, outdent
//char contents[] = getCleanedContents();
char contents[] = textarea.getText().toCharArray();
// index to the character to the left of the caret
int prevCharIndex = textarea.getCaretPosition() - 1;
// now find the start of this line
int lineStart = calcLineStart(prevCharIndex, contents);
int lineEnd = lineStart;
while ((lineEnd < contents.length - 1) &&
(contents[lineEnd] != 10)) {
lineEnd++;
}
// get the number of braces, to determine whether this is an indent
int braceBalance = 0;
int index = lineStart;
while ((index < contents.length) &&
(contents[index] != 10)) {
if (contents[index] == '{') {
braceBalance++;
} else if (contents[index] == '}') {
braceBalance--;
}
index++;
}
// if it's a starting indent, need to ignore it, so lineStart
// will be the counting point. but if there's a closing indent,
// then the lineEnd should be used.
int where = (braceBalance > 0) ? lineStart : lineEnd;
int indent = calcBraceIndent(where, contents);
if (indent == -1) {
// no braces to speak of, do nothing
indent = 0;
} else {
indent += tabSize;
}
// and the number of spaces it has
int spaceCount = calcSpaceCount(prevCharIndex, contents);
textarea.setSelectionStart(lineStart);
textarea.setSelectionEnd(lineStart + spaceCount);
textarea.setSelectedText(Editor.EMPTY.substring(0, indent));
event.consume();
return true;
}
break;
@ -115,13 +261,18 @@ public class EditorListener {
if (autoIndent) {
char contents[] = textarea.getText().toCharArray();
// this is the position of the caret, if the textarea
// only used a single kind of line ending
// this is the previous character
// (i.e. when you hit return, it'll be the last character
// just before where the newline will be inserted)
int origIndex = textarea.getCaretPosition() - 1;
// NOTE all this cursing about CRLF stuff is probably moot
// NOTE since the switch to JEditTextArea, which seems to use
// NOTE only LFs internally (thank god). disabling for 0099.
// walk through the array to the current caret position,
// and count how many weirdo windows line endings there are,
// which would be throwing off the caret position number
/*
int offset = 0;
int realIndex = origIndex;
for (int i = 0; i < realIndex-1; i++) {
@ -130,38 +281,140 @@ public class EditorListener {
realIndex++;
}
}
// back up until \r \r\n or \n.. @#($* cross platform
//System.out.println(origIndex + " offset = " + offset);
origIndex += offset; // ARGH!#(* WINDOWS#@($*
*/
int index = origIndex;
int spaceCount = 0;
boolean finished = false;
while ((index != -1) && (!finished)) {
if ((contents[index] == 10) ||
(contents[index] == 13)) {
finished = true;
index++; // maybe ?
} else {
index--; // new
int spaceCount = calcSpaceCount(origIndex, contents);
//int origCount = spaceCount;
// now before inserting this many spaces, walk forward from
// the caret position, so that the number of spaces aren't
// just being duplicated again
int index = origIndex + 1;
int extraCount = 0;
while ((index < contents.length) &&
(contents[index] == ' ')) {
//spaceCount--;
extraCount++;
index++;
}
// hitting return on a line with spaces *after* the caret
// can cause trouble. for simplicity's sake, just ignore this case.
//if (spaceCount < 0) spaceCount = origCount;
if (spaceCount - extraCount > 0) {
spaceCount -= extraCount;
}
// if the last character was a left curly brace, then indent
if (origIndex != -1) {
if (contents[origIndex] == '{') {
spaceCount += tabSize;
}
}
String insertion = "\n" + Editor.EMPTY.substring(0, spaceCount);
textarea.setSelectedText(insertion);
// mark this event as already handled
event.consume();
return true;
}
break;
case '}':
if (autoIndent) {
// first remove anything that was there (in case this multiple
// characters are selected, so that it's not in the way of the
// spaces for the auto-indent
if (textarea.getSelectionStart() != textarea.getSelectionEnd()) {
textarea.setSelectedText("");
}
// if this brace is the only thing on the line, outdent
char contents[] = textarea.getText().toCharArray();
// index to the character to the left of the caret
int prevCharIndex = textarea.getCaretPosition() - 1;
// backup from the current caret position to the last newline,
// checking for anything besides whitespace along the way.
// if there's something besides whitespace, exit without
// messing any sort of indenting.
int index = prevCharIndex;
boolean finished = false;
while ((index != -1) && (!finished)) {
if (contents[index] == 10) {
finished = true;
index++;
} else if (contents[index] != ' ') {
// don't do anything, this line has other stuff on it
return false;
} else {
index--;
}
}
if (!finished) return false; // brace with no start
int lineStartIndex = index;
/*
// now that we know things are ok to be indented, walk
// backwards to the last { to see how far its line is indented.
// this isn't perfect cuz it'll pick up commented areas,
// but that's not really a big deal and can be fixed when
// this is all given a more complete (proper) solution.
index = prevCharIndex;
int braceDepth = 1;
finished = false;
while ((index != -1) && (!finished)) {
if (contents[index] == '}') {
// aww crap, this means we're one deeper
// and will have to find one more extra {
braceDepth++;
index--;
} else if (contents[index] == '{') {
braceDepth--;
if (braceDepth == 0) {
finished = true;
} // otherwise just teasing, keep going..
} else {
index--;
}
}
// never found a proper brace, be safe and don't do anything
if (!finished) return false;
// check how many spaces on the line with the matching open brace
int pairedSpaceCount = calcSpaceCount(index, contents);
//System.out.println(pairedSpaceCount);
*/
int pairedSpaceCount = calcBraceIndent(prevCharIndex, contents); //, 1);
if (pairedSpaceCount == -1) return false;
/*
// now walk forward and figure out how many spaces there are
while ((index < contents.length) && (index >= 0) &&
(contents[index++] == ' ')) {
spaceCount++;
}
*/
// seems that \r is being inserted anyway
// so no need to insert the platform's line separator
String insertion = "\n" + Editor.EMPTY.substring(0, spaceCount);
//tc.replaceSelection(insertion);
textarea.setSelectedText(insertion);
// microsoft vm version:
//tc.setCaretPosition(oldCarrot + insertion.length() - 1);
// sun vm version:
// tc.setCaretPosition(oldCarrot + insertion.length());
// number of spaces found on this line
//int newSpaceCount = Math.max(0, spaceCount - tabSize);
// number of spaces on this current line
//int spaceCount = calcSpaces(caretIndex, contents);
//System.out.println("spaces is " + spaceCount);
//String insertion = "\n" + Editor.EMPTY.substring(0, spaceCount);
//int differential = newSpaceCount - spaceCount;
//System.out.println("diff is " + differential);
//int newStart = textarea.getSelectionStart() + differential;
//textarea.setSelectionStart(newStart);
//textarea.setSelectedText("}");
textarea.setSelectionStart(lineStartIndex);
textarea.setSelectedText(Editor.EMPTY.substring(0, pairedSpaceCount));
// mark this event as already handled
event.consume();
return true;
}
@ -169,4 +422,143 @@ public class EditorListener {
}
return false;
}
/**
* Return the index for the first character on this line.
*/
protected int calcLineStart(int index, char contents[]) {
// backup from the current caret position to the last newline,
// so that we can figure out how far this line was indented
int spaceCount = 0;
boolean finished = false;
while ((index != -1) && (!finished)) {
if ((contents[index] == 10) ||
(contents[index] == 13)) {
finished = true;
//index++; // maybe ?
} else {
index--; // new
}
}
// add one because index is either -1 (the start of the document)
// or it's the newline character for the previous line
return index + 1;
}
/**
* Calculate the number of spaces on this line.
*/
protected int calcSpaceCount(int index, char contents[]) {
index = calcLineStart(index, contents);
int spaceCount = 0;
// now walk forward and figure out how many spaces there are
while ((index < contents.length) && (index >= 0) &&
(contents[index++] == ' ')) {
spaceCount++;
}
return spaceCount;
}
/**
* Walk back from 'index' until the brace that seems to be
* the beginning of the current block, and return the number of
* spaces found on that line.
*/
protected int calcBraceIndent(int index, char contents[]) {
// now that we know things are ok to be indented, walk
// backwards to the last { to see how far its line is indented.
// this isn't perfect cuz it'll pick up commented areas,
// but that's not really a big deal and can be fixed when
// this is all given a more complete (proper) solution.
int braceDepth = 1;
boolean finished = false;
while ((index != -1) && (!finished)) {
if (contents[index] == '}') {
// aww crap, this means we're one deeper
// and will have to find one more extra {
braceDepth++;
//if (braceDepth == 0) {
//finished = true;
//}
index--;
} else if (contents[index] == '{') {
braceDepth--;
if (braceDepth == 0) {
finished = true;
}
index--;
} else {
index--;
}
}
// never found a proper brace, be safe and don't do anything
if (!finished) return -1;
// check how many spaces on the line with the matching open brace
//int pairedSpaceCount = calcSpaceCount(index, contents);
//System.out.println(pairedSpaceCount);
return calcSpaceCount(index, contents);
}
/**
* Get the character array and blank out the commented areas.
* This hasn't yet been tested, the plan was to make auto-indent
* less gullible (it gets fooled by braces that are commented out).
*/
protected char[] getCleanedContents() {
char c[] = textarea.getText().toCharArray();
int index = 0;
while (index < c.length - 1) {
if ((c[index] == '/') && (c[index+1] == '*')) {
c[index++] = 0;
c[index++] = 0;
while ((index < c.length - 1) &&
!((c[index] == '*') && (c[index+1] == '/'))) {
c[index++] = 0;
}
} else if ((c[index] == '/') && (c[index+1] == '/')) {
// clear out until the end of the line
while ((index < c.length) && (c[index] != 10)) {
c[index++] = 0;
}
if (index != c.length) {
index++; // skip over the newline
}
}
}
return c;
}
/*
protected char[] getCleanedContents() {
char c[] = textarea.getText().toCharArray();
boolean insideMulti; // multi-line comment
boolean insideSingle; // single line double slash
//for (int i = 0; i < c.length - 1; i++) {
int index = 0;
while (index < c.length - 1) {
if (insideMulti && (c[index] == '*') && (c[index+1] == '/')) {
insideMulti = false;
index += 2;
} else if ((c[index] == '/') && (c[index+1] == '*')) {
insideMulti = true;
index += 2;
} else if ((c[index] == '/') && (c[index+1] == '/')) {
// clear out until the end of the line
while (c[index] != 10) {
c[index++] = 0;
}
index++;
}
}
}
*/
}