kopia lustrzana https://github.com/maccasoft/z80-tools
Implemented compiler with hex and listing generators
rodzic
210919aa89
commit
d23322ba26
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Marco Maccaferri and others.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under
|
||||
* the terms of the Eclipse Public License v1.0 which accompanies this
|
||||
* distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
|
||||
package com.maccasoft.tools;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.eclipse.swt.custom.StyleRange;
|
||||
import org.eclipse.swt.widgets.Display;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class ConsoleTest extends TestCase {
|
||||
|
||||
Display display;
|
||||
Shell shell;
|
||||
Console console;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
display = Display.getDefault();
|
||||
shell = new Shell(display);
|
||||
console = new Console(shell);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
shell.dispose();
|
||||
display.dispose();
|
||||
}
|
||||
|
||||
public void testWriteToOutputStream() throws Exception {
|
||||
OutputStream os = console.getOutputStream();
|
||||
os.write("Line 1\r\nLine 2\r\n".getBytes());
|
||||
assertEquals("Line 1\nLine 2\n", console.text.getText());
|
||||
assertNull(console.text.getStyleRangeAtOffset(console.text.getOffsetAtLine(0)));
|
||||
assertNull(console.text.getStyleRangeAtOffset(console.text.getOffsetAtLine(1)));
|
||||
}
|
||||
|
||||
public void testWriteToErrorStream() throws Exception {
|
||||
OutputStream os = console.getErrorStream();
|
||||
os.write("Line 1\r\nLine 2\r\n".getBytes());
|
||||
assertEquals("Line 1\nLine 2\n", console.text.getText());
|
||||
|
||||
StyleRange range0 = console.text.getStyleRangeAtOffset(console.text.getOffsetAtLine(0));
|
||||
assertEquals(console.errorColor, range0.foreground);
|
||||
|
||||
StyleRange range1 = console.text.getStyleRangeAtOffset(console.text.getOffsetAtLine(1));
|
||||
assertEquals(console.errorColor, range1.foreground);
|
||||
}
|
||||
|
||||
public void testWriteToBothStreams() throws Exception {
|
||||
console.getOutputStream().write("Line 1\r\n".getBytes());
|
||||
console.getErrorStream().write("Line 2\r\n".getBytes());
|
||||
|
||||
assertEquals("Line 1\nLine 2\n", console.text.getText());
|
||||
|
||||
StyleRange range0 = console.text.getStyleRangeAtOffset(console.text.getOffsetAtLine(0));
|
||||
assertNull(range0);
|
||||
|
||||
StyleRange range1 = console.text.getStyleRangeAtOffset(console.text.getOffsetAtLine(1));
|
||||
assertEquals(console.errorColor, range1.foreground);
|
||||
}
|
||||
|
||||
public void testWriteLineWithCRLF() throws Exception {
|
||||
OutputStream os = console.getOutputStream();
|
||||
os.write("Line\r\n".getBytes());
|
||||
assertEquals("Line\n", console.text.getText());
|
||||
}
|
||||
|
||||
public void testWriteLineWithCR() throws Exception {
|
||||
OutputStream os = console.getOutputStream();
|
||||
|
||||
os.write("Line 1\r".getBytes());
|
||||
assertEquals("Line 1", console.text.getText());
|
||||
|
||||
os.write("Line 2\r".getBytes());
|
||||
assertEquals("Line 2", console.text.getText());
|
||||
}
|
||||
|
||||
public void testWriteBlankLine() throws Exception {
|
||||
OutputStream os = console.getOutputStream();
|
||||
|
||||
os.write("Line 1\r\n".getBytes());
|
||||
assertEquals("Line 1\n", console.text.getText());
|
||||
|
||||
os.write("\n".getBytes());
|
||||
assertEquals("Line 1\n\n", console.text.getText());
|
||||
|
||||
os.write("Line 2\r".getBytes());
|
||||
assertEquals("Line 1\n\nLine 2", console.text.getText());
|
||||
}
|
||||
|
||||
public void testWriteUnterminatedLine() throws Exception {
|
||||
OutputStream os = console.getOutputStream();
|
||||
os.write("Line 1\r\nLine 2".getBytes());
|
||||
assertEquals("Line 1\nLine 2", console.text.getText());
|
||||
}
|
||||
|
||||
public void testWriteOutputStreamErrorLine() throws Exception {
|
||||
OutputStream os = console.getOutputStream();
|
||||
os.write("Line 1\r\nError : Line 2\r\n".getBytes());
|
||||
assertEquals("Line 1\nError : Line 2\n", console.text.getText());
|
||||
|
||||
StyleRange range0 = console.text.getStyleRangeAtOffset(console.text.getOffsetAtLine(0));
|
||||
assertNull(range0);
|
||||
|
||||
StyleRange range1 = console.text.getStyleRangeAtOffset(console.text.getOffsetAtLine(1));
|
||||
assertEquals(console.errorColor, range1.foreground);
|
||||
}
|
||||
|
||||
}
|
|
@ -11,14 +11,20 @@
|
|||
package com.maccasoft.tools;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintStream;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.io.Writer;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
@ -36,6 +42,7 @@ import org.eclipse.swt.custom.CTabFolder2Adapter;
|
|||
import org.eclipse.swt.custom.CTabFolderEvent;
|
||||
import org.eclipse.swt.custom.CTabItem;
|
||||
import org.eclipse.swt.custom.SashForm;
|
||||
import org.eclipse.swt.custom.StyledText;
|
||||
import org.eclipse.swt.events.DisposeEvent;
|
||||
import org.eclipse.swt.events.DisposeListener;
|
||||
import org.eclipse.swt.events.MenuEvent;
|
||||
|
@ -45,6 +52,7 @@ import org.eclipse.swt.events.SelectionEvent;
|
|||
import org.eclipse.swt.graphics.FontMetrics;
|
||||
import org.eclipse.swt.graphics.GC;
|
||||
import org.eclipse.swt.graphics.Image;
|
||||
import org.eclipse.swt.graphics.Point;
|
||||
import org.eclipse.swt.graphics.Rectangle;
|
||||
import org.eclipse.swt.layout.FillLayout;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
|
@ -59,6 +67,11 @@ import org.eclipse.swt.widgets.Shell;
|
|||
|
||||
import com.maccasoft.tools.internal.ImageRegistry;
|
||||
|
||||
import nl.grauw.glass.AssemblyException;
|
||||
import nl.grauw.glass.Line;
|
||||
import nl.grauw.glass.Source;
|
||||
import nl.grauw.glass.SourceBuilder;
|
||||
|
||||
public class Application {
|
||||
|
||||
public static final String APP_TITLE = "Z80 Tools";
|
||||
|
@ -67,9 +80,11 @@ public class Application {
|
|||
Display display;
|
||||
Shell shell;
|
||||
|
||||
SashForm sashForm;
|
||||
SashForm sashForm1;
|
||||
FileBrowser browser;
|
||||
SashForm sashForm2;
|
||||
CTabFolder tabFolder;
|
||||
Console console;
|
||||
|
||||
Preferences preferences;
|
||||
|
||||
|
@ -101,7 +116,7 @@ public class Application {
|
|||
|
||||
Rectangle screen = display.getClientArea();
|
||||
|
||||
Rectangle rect = new Rectangle(0, 0, (int) ((float) screen.width / (float) screen.height * 800), 800);
|
||||
Rectangle rect = new Rectangle(0, 0, (int) ((float) screen.width / (float) screen.height * 800), 850);
|
||||
rect.x = (screen.width - rect.width) / 2;
|
||||
rect.y = (screen.height - rect.height) / 2;
|
||||
if (rect.y < 0) {
|
||||
|
@ -455,7 +470,11 @@ public class Application {
|
|||
|
||||
@Override
|
||||
public void handleEvent(Event e) {
|
||||
|
||||
try {
|
||||
handleCompile();
|
||||
} catch (Exception e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -507,15 +526,18 @@ public class Application {
|
|||
FontMetrics fontMetrics = gc.getFontMetrics();
|
||||
gc.dispose();
|
||||
|
||||
sashForm = new SashForm(parent, SWT.HORIZONTAL);
|
||||
sashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
|
||||
sashForm1 = new SashForm(parent, SWT.HORIZONTAL);
|
||||
sashForm1.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
|
||||
|
||||
browser = new FileBrowser(sashForm);
|
||||
browser = new FileBrowser(sashForm1);
|
||||
browser.setRoots(new File[] {
|
||||
new File(System.getProperty("user.home"))
|
||||
});
|
||||
|
||||
tabFolder = new CTabFolder(sashForm, SWT.BORDER);
|
||||
sashForm2 = new SashForm(sashForm1, SWT.VERTICAL);
|
||||
sashForm2.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
|
||||
|
||||
tabFolder = new CTabFolder(sashForm2, SWT.BORDER);
|
||||
tabFolder.setTabHeight((int) (fontMetrics.getHeight() * 1.5));
|
||||
tabFolder.addSelectionListener(new SelectionAdapter() {
|
||||
|
||||
|
@ -533,9 +555,79 @@ public class Application {
|
|||
}
|
||||
});
|
||||
|
||||
sashForm.setWeights(new int[] {
|
||||
console = new Console(sashForm2);
|
||||
console.getStyledText().addListener(SWT.MouseDown, new Listener() {
|
||||
|
||||
@Override
|
||||
public void handleEvent(Event event) {
|
||||
try {
|
||||
StyledText control = (StyledText) event.widget;
|
||||
int offset = control.getOffsetAtLocation(new Point(event.x, event.y));
|
||||
String line = control.getLine(control.getLineAtOffset(offset));
|
||||
if (line.toLowerCase().contains(" error : ")) {
|
||||
int s = 0;
|
||||
int e = line.indexOf(')');
|
||||
if (e != -1) {
|
||||
line = line.substring(s, e + 1);
|
||||
|
||||
s = 0;
|
||||
e = line.indexOf('(');
|
||||
String name = line.substring(s, e);
|
||||
s = e + 1;
|
||||
if ((e = line.indexOf(':', s)) == -1) {
|
||||
e = line.indexOf(',', s);
|
||||
}
|
||||
int row = Integer.parseInt(line.substring(s, e)) - 1;
|
||||
if (row < 0) {
|
||||
row = 0;
|
||||
}
|
||||
s = e + 1;
|
||||
e = line.indexOf(')', s);
|
||||
int column = Integer.parseInt(line.substring(s, e)) - 1;
|
||||
if (column < 0) {
|
||||
column = 0;
|
||||
}
|
||||
switchToEditor(name, row, column);
|
||||
}
|
||||
}
|
||||
else if (line.toLowerCase().contains(" error: ") || line.toLowerCase().contains(" warning: ")) {
|
||||
int e = line.indexOf(':');
|
||||
String name = line.substring(0, e);
|
||||
int s = e + 1;
|
||||
e = line.indexOf(':', s);
|
||||
int row = Integer.parseInt(line.substring(s, e)) - 1;
|
||||
s = e + 1;
|
||||
int column = 0;
|
||||
if (line.charAt(s) != ' ') {
|
||||
e = line.indexOf(':', s);
|
||||
column = Integer.parseInt(line.substring(s, e)) - 1;
|
||||
}
|
||||
switchToEditor(name, row, column);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
void switchToEditor(String name, int line, int column) {
|
||||
CTabItem[] tabItem = tabFolder.getItems();
|
||||
for (int i = 0; i < tabItem.length; i++) {
|
||||
SourceEditorTab tab = (SourceEditorTab) tabItem[i].getData();
|
||||
if (name.equalsIgnoreCase(tab.getText())) {
|
||||
tab.getEditor().gotToLineColumn(line, column);
|
||||
tab.setFocus();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
sashForm1.setWeights(new int[] {
|
||||
20, 80
|
||||
});
|
||||
sashForm2.setWeights(new int[] {
|
||||
80, 20
|
||||
});
|
||||
|
||||
String lastPath = preferences.getLastPath();
|
||||
if (lastPath == null) {
|
||||
|
@ -785,6 +877,227 @@ public class Application {
|
|||
return true;
|
||||
}
|
||||
|
||||
private void handleCompile() throws Exception {
|
||||
CTabItem tabItem = tabFolder.getSelection();
|
||||
if (tabItem == null) {
|
||||
return;
|
||||
}
|
||||
SourceEditorTab tab = (SourceEditorTab) tabItem.getData();
|
||||
|
||||
console.clear();
|
||||
console.getOutputStream().write(new String("Compiling " + tab.getText() + "...").getBytes());
|
||||
|
||||
List<File> includePaths = new ArrayList<File>();
|
||||
if (tab.getFile() != null) {
|
||||
includePaths.add(tab.getFile().getParentFile());
|
||||
}
|
||||
final SourceBuilder builder = new SourceBuilder(includePaths);
|
||||
|
||||
final StringReader reader = new StringReader(tab.getEditor().getText());
|
||||
|
||||
final String name = tab.getText();
|
||||
final File file = tab.getFile();
|
||||
|
||||
new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
compile(builder, reader, name, file);
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
Source compile(SourceBuilder builder, Reader reader, String name, File file) {
|
||||
PrintStream out = new PrintStream(console.getOutputStream());
|
||||
PrintStream err = new PrintStream(console.getErrorStream());
|
||||
try {
|
||||
Source source = builder.parse(reader, new File(name));
|
||||
source.register();
|
||||
source.expand();
|
||||
source.resolve();
|
||||
|
||||
if (file != null) {
|
||||
String baseName = name;
|
||||
if (baseName.indexOf('.') != -1) {
|
||||
baseName = baseName.substring(0, baseName.lastIndexOf('.'));
|
||||
}
|
||||
|
||||
OutputStreamWriter os = new OutputStreamWriter(new FileOutputStream(new File(file.getParentFile(), baseName + ".LST")));
|
||||
os.write(buildListing(new ArrayList<Line>(source.getLines())).toString());
|
||||
os.close();
|
||||
|
||||
os = new OutputStreamWriter(new FileOutputStream(new File(file.getParentFile(), baseName + ".HEX")));
|
||||
os.write(buildIntelHexString(new ArrayList<Line>(source.getLines())).toString());
|
||||
os.close();
|
||||
}
|
||||
|
||||
int lower = Integer.MAX_VALUE;
|
||||
int higher = Integer.MIN_VALUE;
|
||||
for (Line line : source.getLines()) {
|
||||
if (line.getSize() != 0) {
|
||||
lower = Math.min(lower, line.getScope().getAddress());
|
||||
higher = Math.max(higher, line.getScope().getAddress());
|
||||
}
|
||||
}
|
||||
out.println();
|
||||
out.println(String.format("Compiled %d lines from %04XH to %04XH (%d bytes)", source.getLines().size(), lower, higher, higher - lower + 1));
|
||||
|
||||
return source;
|
||||
|
||||
} catch (AssemblyException ex) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
Iterator<AssemblyException.Context> iter = ex.contexts.iterator();
|
||||
if (iter.hasNext()) {
|
||||
AssemblyException.Context context = iter.next();
|
||||
sb.append(context.file.getName());
|
||||
sb.append(":");
|
||||
sb.append(context.line + 1);
|
||||
if (context.column != -1) {
|
||||
sb.append(":");
|
||||
sb.append(context.column);
|
||||
}
|
||||
sb.append(": error: ");
|
||||
sb.append(ex.getPlainMessage());
|
||||
}
|
||||
|
||||
out.println();
|
||||
err.println(sb.toString());
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
StringBuilder buildListing(List<Line> lines) throws IOException {
|
||||
int column;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (Line line : lines) {
|
||||
try {
|
||||
int address = line.getScope().getAddress();
|
||||
byte[] code = line.getBytes();
|
||||
|
||||
sb.append(String.format("%05d %04X ", line.getLineNumber() + 1, address));
|
||||
|
||||
column = 0;
|
||||
int codeIndex = 0;
|
||||
for (int i = 0; codeIndex < code.length && (column + 3) < 24; i++, codeIndex++, address++) {
|
||||
if (i != 0) {
|
||||
sb.append(' ');
|
||||
column++;
|
||||
}
|
||||
sb.append(String.format("%02X", code[codeIndex]));
|
||||
column += 2;
|
||||
}
|
||||
while (column < 24 + 1) {
|
||||
sb.append(' ');
|
||||
column++;
|
||||
}
|
||||
|
||||
sb.append(line.getSourceText());
|
||||
|
||||
while (codeIndex < code.length) {
|
||||
sb.append("\r\n");
|
||||
sb.append(String.format("%05d %04X ", line.getLineNumber() + 1, address));
|
||||
|
||||
column = 0;
|
||||
for (int i = 0; codeIndex < code.length && (column + 3) < 24; i++, codeIndex++, address++) {
|
||||
if (i != 0) {
|
||||
sb.append(' ');
|
||||
column++;
|
||||
}
|
||||
sb.append(String.format("%02X", code[codeIndex]));
|
||||
column += 2;
|
||||
}
|
||||
}
|
||||
|
||||
sb.append("\r\n");
|
||||
} catch (AssemblyException e) {
|
||||
e.addContext(line);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
return sb;
|
||||
}
|
||||
|
||||
StringBuilder buildIntelHexString(List<Line> lines) throws IOException {
|
||||
int addr = -1;
|
||||
int nextAddr = -1;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
Collections.sort(lines, new Comparator<Line>() {
|
||||
|
||||
@Override
|
||||
public int compare(Line o1, Line o2) {
|
||||
return o1.getScope().getAddress() - o2.getScope().getAddress();
|
||||
}
|
||||
});
|
||||
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
for (Line line : lines) {
|
||||
try {
|
||||
byte[] code = line.getBytes();
|
||||
if (code.length == 0) {
|
||||
continue;
|
||||
}
|
||||
if (line.getScope().getAddress() != nextAddr) {
|
||||
os.close();
|
||||
|
||||
byte[] data = os.toByteArray();
|
||||
if (data.length != 0) {
|
||||
sb.append(toHexString(addr, data));
|
||||
}
|
||||
|
||||
nextAddr = addr = line.getScope().getAddress();
|
||||
os = new ByteArrayOutputStream();
|
||||
}
|
||||
os.write(code);
|
||||
nextAddr += code.length;
|
||||
} catch (AssemblyException e) {
|
||||
e.addContext(line);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
os.close();
|
||||
byte[] data = os.toByteArray();
|
||||
if (data.length != 0) {
|
||||
sb.append(toHexString(addr, data));
|
||||
}
|
||||
|
||||
sb.append(":00000001FF\r\n");
|
||||
|
||||
return sb;
|
||||
}
|
||||
|
||||
static String toHexString(int addr, byte[] data) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
int i = 0;
|
||||
|
||||
while ((data.length - i) > 0) {
|
||||
int l = data.length - i;
|
||||
if (l > 24) {
|
||||
l = 24;
|
||||
}
|
||||
sb.append(String.format(":%02X%04X%02X", l, addr, 0));
|
||||
|
||||
int checksum = l + (addr & 0xFF) + ((addr >> 8) & 0xFF) + 0;
|
||||
for (int n = 0; n < l; n++, i++, addr++) {
|
||||
sb.append(String.format("%02X", data[i]));
|
||||
checksum += data[i];
|
||||
}
|
||||
|
||||
sb.append(String.format("%02X\r\n", (-checksum) & 0xFF));
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
static {
|
||||
System.setProperty("SWT_GTK3", "0");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,200 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Marco Maccaferri and others.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under
|
||||
* the terms of the Eclipse Public License v1.0 which accompanies this
|
||||
* distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
|
||||
package com.maccasoft.tools;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.custom.StyleRange;
|
||||
import org.eclipse.swt.custom.StyledText;
|
||||
import org.eclipse.swt.events.DisposeEvent;
|
||||
import org.eclipse.swt.events.DisposeListener;
|
||||
import org.eclipse.swt.graphics.Color;
|
||||
import org.eclipse.swt.graphics.Font;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Display;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
|
||||
public class Console {
|
||||
Composite container;
|
||||
StyledText text;
|
||||
|
||||
ConsoleOutputStream outputStream;
|
||||
ConsoleOutputStream errorStream;
|
||||
|
||||
Font font;
|
||||
Color errorColor;
|
||||
|
||||
private class ConsoleOutputStream extends OutputStream {
|
||||
|
||||
boolean isError;
|
||||
|
||||
int moreLinesToMark;
|
||||
|
||||
StringBuilder lineBuilder;
|
||||
|
||||
public ConsoleOutputStream(boolean isError) {
|
||||
this.isError = isError;
|
||||
|
||||
this.moreLinesToMark = 0;
|
||||
|
||||
lineBuilder = new StringBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(final int b) throws IOException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(final byte[] b, final int off, final int len) throws IOException {
|
||||
Display.getDefault().syncExec(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
appendBytes(b, off, len);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void appendBytes(byte[] b, int off, int len) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
char c = (char) b[off + i];
|
||||
if (c == '\r') {
|
||||
int ofs = getLastLineOffset();
|
||||
String s = lineBuilder.toString();
|
||||
text.replaceTextRange(ofs, text.getCharCount() - ofs, s);
|
||||
updateStyle(ofs, s);
|
||||
lineBuilder = new StringBuilder();
|
||||
}
|
||||
else if (c == '\n') {
|
||||
if (lineBuilder.length() > 0) {
|
||||
int ofs = getLastLineOffset();
|
||||
String s = lineBuilder.toString();
|
||||
text.replaceTextRange(ofs, text.getCharCount() - ofs, s);
|
||||
updateStyle(ofs, s);
|
||||
lineBuilder = new StringBuilder();
|
||||
}
|
||||
text.append("\n");
|
||||
}
|
||||
else {
|
||||
lineBuilder.append(c);
|
||||
}
|
||||
}
|
||||
if (lineBuilder.length() > 0) {
|
||||
int ofs = getLastLineOffset();
|
||||
String s = lineBuilder.toString();
|
||||
text.replaceTextRange(ofs, text.getCharCount() - ofs, s);
|
||||
updateStyle(ofs, s);
|
||||
}
|
||||
|
||||
text.setCaretOffset(text.getCharCount());
|
||||
if (text.getLineCount() > 0) {
|
||||
text.setTopIndex(text.getLineCount() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
int getLastLineOffset() {
|
||||
int index = text.getLineCount() - 1;
|
||||
return text.getOffsetAtLine(index);
|
||||
}
|
||||
|
||||
void updateStyle(int start, String line) {
|
||||
if (isError) {
|
||||
text.setStyleRange(new StyleRange(start, line.length(), errorColor, null));
|
||||
}
|
||||
else if (line.contains(": error :") || line.contains(": error:")) {
|
||||
text.setStyleRange(new StyleRange(start, line.length(), errorColor, null));
|
||||
moreLinesToMark += 3;
|
||||
}
|
||||
else if (line.contains("Error : ")) {
|
||||
text.setStyleRange(new StyleRange(start, line.length(), errorColor, null));
|
||||
moreLinesToMark += 2;
|
||||
}
|
||||
else if (moreLinesToMark > 0) {
|
||||
text.setStyleRange(new StyleRange(start, line.length(), errorColor, null));
|
||||
moreLinesToMark--;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public Console(Composite parent) {
|
||||
container = new Composite(parent, SWT.NONE);
|
||||
GridLayout layout = new GridLayout(1, false);
|
||||
layout.marginWidth = layout.marginHeight = 0;
|
||||
container.setLayout(layout);
|
||||
container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
|
||||
|
||||
Label label = new Label(container, SWT.NONE);
|
||||
label.setText("Console");
|
||||
GridData gridData = new GridData(SWT.FILL, SWT.CENTER, true, false);
|
||||
gridData.horizontalIndent = 5;
|
||||
label.setLayoutData(gridData);
|
||||
|
||||
text = new StyledText(container, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
|
||||
text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
|
||||
text.setMargins(5, 5, 5, 5);
|
||||
text.setTabs(4);
|
||||
|
||||
if ("win32".equals(SWT.getPlatform())) {
|
||||
font = new Font(parent.getDisplay(), "Courier New", 9, SWT.NONE);
|
||||
}
|
||||
else {
|
||||
font = new Font(parent.getDisplay(), "mono", 9, SWT.NONE);
|
||||
}
|
||||
text.setFont(font);
|
||||
|
||||
errorColor = parent.getDisplay().getSystemColor(SWT.COLOR_RED);
|
||||
|
||||
text.addDisposeListener(new DisposeListener() {
|
||||
|
||||
@Override
|
||||
public void widgetDisposed(DisposeEvent e) {
|
||||
font.dispose();
|
||||
}
|
||||
});
|
||||
|
||||
outputStream = new ConsoleOutputStream(false);
|
||||
errorStream = new ConsoleOutputStream(true);
|
||||
}
|
||||
|
||||
public Composite getControl() {
|
||||
return container;
|
||||
}
|
||||
|
||||
public StyledText getStyledText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
text.setText("\r\n");
|
||||
}
|
||||
|
||||
public OutputStream getOutputStream() {
|
||||
return outputStream;
|
||||
}
|
||||
|
||||
public OutputStream getErrorStream() {
|
||||
return errorStream;
|
||||
}
|
||||
}
|
Ładowanie…
Reference in New Issue