Procházet zdrojové kódy

Backtrace stack report support in remote debugger, basic IDE support for examining the stack sources, small fixes

Ivan Safrin před 13 roky
rodič
revize
54e9b1a16d

+ 3 - 0
Core/Contents/Include/OSBasics.h

@@ -31,8 +31,11 @@ class _PolyExport OSFileEntry {
 
 	public:
 		OSFileEntry() {};
+		OSFileEntry(const Polycode::String& fullPath, int type);
 		OSFileEntry(const Polycode::String& path, const Polycode::String& name, int type);
 		
+		void init(const Polycode::String& path, const Polycode::String& name, int type);
+		
 		Polycode::String name;
 		Polycode::String extension;
 		Polycode::String nameWithoutExtension;

+ 2 - 1
Core/Contents/Include/PolyData.h

@@ -40,8 +40,9 @@ namespace Polycode {
 		/**
 		* Loads data from a file.
 		* @param fileName Path to the file to load data from.
+		* @return True if susccessful, false if not
 		*/						
-		void loadFromFile(const String& fileName);
+		bool loadFromFile(const String& fileName);
 		
 		/**
 		* Retuns data as a string with the specified encoding.

+ 24 - 0
Core/Contents/Source/OSBasics.cpp

@@ -58,7 +58,29 @@ void ctow(WCHAR* Dest, const char* Source)
 
 #endif
 
+OSFileEntry::OSFileEntry(const Polycode::String& fullPath, int type) {
+	std::vector<String> parts = fullPath.split("/");
+	
+	if(parts.size() > 0) {
+		String path = parts[0];
+
+		if(parts.size() > 1) {		
+			for(int i=1; i < parts.size()-1; i++) {
+				path += "/" + parts[i];
+			}
+			init(path, parts[parts.size()-1], type);
+		}
+	} else {
+		init("", fullPath, type);
+	}
+	
+}
+
 OSFileEntry::OSFileEntry(const String& path, const String& name, int type) {
+	init(path, name, type);
+}
+
+void OSFileEntry::init(const Polycode::String& path, const Polycode::String& name, int type) {
 	this->basePath = path;
 	this->fullPath = path + "/" + name;
 	this->name = name;
@@ -73,8 +95,10 @@ OSFileEntry::OSFileEntry(const String& path, const String& name, int type) {
 		extension = "";
 		nameWithoutExtension = name;
 	}
+
 }
 
+
 void OSFILE::debugDump() {
 	long tellval = OSBasics::tell(this);
 	OSBasics::seek(this, 0, SEEK_SET);

+ 5 - 2
Core/Contents/Source/PolyData.cpp

@@ -60,8 +60,10 @@ bool Data::saveToFile(const String& fileName) const {
 	return true;
 }
 
-void Data::loadFromFile(const String& fileName) {
+bool Data::loadFromFile(const String& fileName) {
 	OSFILE *file = OSBasics::open(fileName, "rb");
+	if(!file)
+		return false;
 	
 	OSBasics::seek(file, 0L, SEEK_END);
 	dataSize = OSBasics::tell(file);
@@ -78,7 +80,8 @@ void Data::loadFromFile(const String& fileName) {
 	
 	OSBasics::read(data, sizeof(char), dataSize, file);	
 	OSBasics::close(file);
-		
+
+	return true;
 }
 
 String Data::getAsString(int encoding) const {

+ 62 - 0
IDE/Contents/Include/PolycodeConsole.h

@@ -24,11 +24,66 @@
 
 #include "PolycodeUI.h"
 #include "Polycode.h"
+#include "PolycodeProject.h"
 
 using namespace Polycode;
 
 class PolycodeRemoteDebugger;
 
+class BackTraceEvent : public Event {
+	public:
+		BackTraceEvent() : Event() { eventType = "BackTraceEvent"; };
+		~BackTraceEvent() {}
+		
+		static const int EVENT_BACKTRACE_SELECTED = 0;
+		
+		String fileName;
+		unsigned int lineNumber;
+		PolycodeProject *project;
+};
+
+class BackTraceEntry : public UIElement {
+	public:
+		BackTraceEntry(String fileName, int lineNumber, PolycodeProject *project);
+		~BackTraceEntry();
+		
+		void Select();
+		void Deselect();
+		
+		void handleEvent(Event *event);
+		
+		void Resize(Number width, Number height);	
+	
+	protected:
+	
+		PolycodeProject *project;
+	
+		String fileName;
+		unsigned int lineNumber;
+		
+		ScreenShape *labelBg;	
+		ScreenLabel *label;
+};
+
+class BackTraceWindow : public UIElement {
+	public:
+		BackTraceWindow();
+		~BackTraceWindow();
+		
+		void handleEvent(Event *event);
+		
+		void addBackTrace(String fileName, int lineNumber, PolycodeProject *project);
+						
+		void Resize(Number width, Number height);
+		
+		void adjustEntries();
+		
+	protected:			
+		ScreenShape *labelBg;
+		std::vector<BackTraceEntry*> entries;
+		
+};
+
 class PolycodeConsole : public UIElement {
 	public:
 		PolycodeConsole();
@@ -41,13 +96,20 @@ class PolycodeConsole : public UIElement {
 		void setDebugger(PolycodeRemoteDebugger *debugger);
 		
 		static void print(String msg);
+
+		static void addBacktrace(String fileName, int lineNumber, PolycodeProject *project);
+
+		void _addBacktrace(String fileName, int lineNumber, PolycodeProject *project);
 		
 		void Resize(Number width, Number height);
 		
 		static void setInstance(PolycodeConsole *newInstance);
 		
+		BackTraceWindow *backtraceWindow;		
 	protected:
 	
+		UIHSizer *backtraceSizer;
+	
 		PolycodeRemoteDebugger *debugger;
 		
 		static PolycodeConsole *instance;

+ 4 - 0
IDE/Contents/Include/PolycodeEditor.h

@@ -44,9 +44,13 @@ public:
 	
 	bool isReadOnly() { return _isReadOnly; }
 	
+	String getEditorType() { return editorType; }
+	
 protected:
 	String filePath;
 	bool _isReadOnly;
+	
+	String editorType;
 };
 
 

+ 1 - 1
IDE/Contents/Include/PolycodeFrame.h

@@ -71,7 +71,7 @@ public:
 	PolycodeProjectBrowser *projectBrowser;
 		
 	UIImageButton *playButton;
-	UIHSizer *mainSizer;	
+	UIHSizer *mainSizer;
 	
 	PolycodeConsole *console;
 						

+ 4 - 0
IDE/Contents/Include/PolycodeIDEApp.h

@@ -53,6 +53,10 @@ public:
 	void saveConfigFile();
 	void loadConfigFile();
 	
+	void openFileInProject(PolycodeProject *project, String filePath);
+	
+	void openFile(OSFileEntry file);
+	
 	// menu commands
 	void renameFile();
 	void removeFile();

+ 18 - 1
IDE/Contents/Include/PolycodeRemoteDebugger.h

@@ -24,9 +24,22 @@
 
 #include "Polycode.h"
 #include "PolycodeConsole.h"
+#include "PolycodeProjectManager.h"
 
 using namespace Polycode;
 
+typedef struct {
+	unsigned int lineNumber;
+	char errorMessage[256];	
+	char fileName[256];
+	unsigned int backTraceSize;	
+} RemoteErrorData;
+
+typedef struct {
+	unsigned int lineNumber;
+	char fileName[256];
+} RemoteBacktraceData;
+
 class DebuggerClient { 
 	public:
 		ServerClient *client;
@@ -34,7 +47,7 @@ class DebuggerClient {
 
 class PolycodeRemoteDebugger : EventHandler {
 	public:
-		PolycodeRemoteDebugger();
+		PolycodeRemoteDebugger(PolycodeProjectManager *projectManager);
 		~PolycodeRemoteDebugger();
 		
 		void injectCode(String code);
@@ -50,8 +63,12 @@ class PolycodeRemoteDebugger : EventHandler {
 
 		static const int EVENT_INJECT_CODE = 36;
 			
+		static const int EVENT_DEBUG_BACKTRACE_INFO = 37;
+					
 	protected:
 		
+		PolycodeProjectManager *projectManager;
+		
 		Server *server;
 		std::vector<DebuggerClient*> debuggerClients;
 

+ 2 - 0
IDE/Contents/Include/PolycodeTextEditor.h

@@ -56,6 +56,8 @@ public:
 	void Resize(int x, int y);
 	void saveFile();
 	
+	void highlightLine(unsigned int lineNumber);
+	
 protected:
 
 	PolycodeSyntaxHighlighter *syntaxHighligher;

+ 140 - 4
IDE/Contents/Source/PolycodeConsole.cpp

@@ -25,12 +25,138 @@
 
 PolycodeConsole* PolycodeConsole::instance = NULL;
 
+BackTraceEntry::BackTraceEntry(String fileName, int lineNumber, PolycodeProject *project) : UIElement() {
+
+
+	this->project = project;
+	this->fileName = fileName;
+	this->lineNumber = lineNumber;
+
+	Config *conf = CoreServices::getInstance()->getConfig();	
+	String fontName = conf->getStringValue("Polycode", "uiDefaultFontName");
+	int fontSize = conf->getNumericValue("Polycode", "uiDefaultFontSize");	
+
+	labelBg = new ScreenShape(ScreenShape::SHAPE_RECT, 20,20);
+	labelBg->setPositionMode(ScreenEntity::POSITION_TOPLEFT);
+	labelBg->setColor(0.0, 0.0, 0.0, 0.15);
+	labelBg->processInputEvents = true;
+	addChild(labelBg);	
+	
+	labelBg->addEventListener(this, InputEvent::EVENT_MOUSEDOWN);
+	
+	label = new ScreenLabel(fileName+" on line "+String::IntToString(lineNumber), fontSize, fontName);
+	addChild(label);
+	label->setPosition(5,2);
+	
+}
+
+void BackTraceEntry::handleEvent(Event *event) {
+	if(event->getDispatcher() == labelBg) {
+		if(event->getEventCode() == InputEvent::EVENT_MOUSEDOWN) {
+			Select();
+		}
+	}
+}
+
+void BackTraceEntry::Select() {
+	BackTraceEvent *event = new BackTraceEvent();
+	event->fileName = fileName;
+	event->lineNumber = lineNumber;
+	event->project = project;		
+	
+	dispatchEvent(event, BackTraceEvent::EVENT_BACKTRACE_SELECTED);
+		
+	labelBg->setColor(0.0, 0.0, 1.0, 0.35);
+}
+
+void BackTraceEntry::Deselect() {
+	labelBg->setColor(0.0, 0.0, 0.0, 0.15);
+}
+
+
+BackTraceEntry::~BackTraceEntry() {
+
+}
+
+void BackTraceEntry::Resize(Number width, Number height) {
+	labelBg->setShapeSize(width, 20);
+
+}
+
+BackTraceWindow::BackTraceWindow() : UIElement() {
+
+	Config *conf = CoreServices::getInstance()->getConfig();	
+	String fontName = conf->getStringValue("Polycode", "uiDefaultFontName");
+	int fontSize = conf->getNumericValue("Polycode", "uiDefaultFontSize");		
+
+	labelBg = new ScreenShape(ScreenShape::SHAPE_RECT, 20,20);
+	labelBg->setPositionMode(ScreenEntity::POSITION_TOPLEFT);
+	labelBg->setColor(0.0, 0.0, 0.0, 0.35);
+	addChild(labelBg);
+	
+	ScreenLabel *label = new ScreenLabel("CRASH STACK", fontSize, fontName);
+	addChild(label);
+	label->setPosition(5,2);
+	
+}	
+
+void BackTraceWindow::Resize(Number width, Number height) {
+	labelBg->setShapeSize(width, 20);
+	this->width = width;
+	this->height = height;	
+	adjustEntries();
+}
+
+void BackTraceWindow::adjustEntries() {
+	for(int i=0; i < entries.size(); i++) {
+		entries[i]->Resize(width, 20);
+		entries[i]->setPosition(0, 20 + (i * 21));
+	}
+}
+
+void BackTraceWindow::handleEvent(Event *event) {
+	for(int i=0; i < entries.size(); i++) {
+		if(event->getDispatcher() == entries[i]) {
+			if(event->getEventCode() == BackTraceEvent::EVENT_BACKTRACE_SELECTED && event->getEventType() == "BackTraceEvent") {
+				for(int j=0; j < entries.size(); j++) {
+					entries[j]->Deselect();
+				}
+				BackTraceEvent *btEvent = (BackTraceEvent*) event;
+												
+				BackTraceEvent *_event = new BackTraceEvent();
+				_event->fileName = btEvent->fileName;
+				_event->lineNumber = btEvent->lineNumber;
+				_event->project = btEvent->project;		
+				
+				dispatchEvent(_event, BackTraceEvent::EVENT_BACKTRACE_SELECTED);
+			}
+		}
+	}
+}
+
+void BackTraceWindow::addBackTrace(String fileName, int lineNumber, PolycodeProject *project) {
+	BackTraceEntry *entry = new BackTraceEntry(fileName, lineNumber, project);
+	entry->addEventListener(this, BackTraceEvent::EVENT_BACKTRACE_SELECTED);
+	entries.push_back(entry);
+	addChild(entry);
+	adjustEntries();	
+}
+
+BackTraceWindow::~BackTraceWindow() {
+	
+}
 
 PolycodeConsole::PolycodeConsole() : UIElement() {
 
+	backtraceSizer = new UIHSizer(100,100,300,false);
+	addChild(backtraceSizer);
+	
 	debugger = NULL;
 	debugTextInput = new UITextInput(true, 100, 100);
-	addChild(debugTextInput);
+	backtraceSizer->addLeftChild(debugTextInput);
+
+	backtraceWindow = new BackTraceWindow();
+	backtraceSizer->addRightChild(backtraceWindow);
 
 	consoleTextInput = new UITextInput(false, 100, 100);
 	addChild(consoleTextInput);	
@@ -53,6 +179,7 @@ void PolycodeConsole::setDebugger(PolycodeRemoteDebugger *debugger) {
 void PolycodeConsole::handleEvent(Event *event) {
 	if(event->getDispatcher() == consoleTextInput) {
 		if(event->getEventCode() == Event::COMPLETE_EVENT && event->getEventType() == "Event") {
+			_print(">"+consoleTextInput->getText()+"\n");
 			if(debugger) {
 				if(!debugger->isConnected()) {
 					_print("Unable to inject code. No debugger clients connected.\n");
@@ -60,7 +187,7 @@ void PolycodeConsole::handleEvent(Event *event) {
 					debugger->injectCode(consoleTextInput->getText());
 				}
 			}	
-
+			
 			consoleTextInput->setText("");
 		}
 	}
@@ -74,14 +201,23 @@ void PolycodeConsole::print(String msg) {
 	instance->_print(msg);
 }
 
+void PolycodeConsole::addBacktrace(String fileName, int lineNumber, PolycodeProject *project) {
+	instance->_addBacktrace(fileName, lineNumber, project);
+}
+
+void PolycodeConsole::_addBacktrace(String fileName, int lineNumber, PolycodeProject *project) {
+	backtraceWindow->addBackTrace(fileName, lineNumber, project);
+}
+
+
 void PolycodeConsole::_print(String msg) {
 	debugTextInput->setText(debugTextInput->getText()+msg);
 	debugTextInput->getScrollContainer()->setScrollValue(0, 1.0);
 }
 
 void PolycodeConsole::Resize(Number width, Number height) {
-	debugTextInput->Resize(width, height-25);
-	debugTextInput->setPosition(0, 0);
+	backtraceSizer->Resize(width, height-25);
+	backtraceSizer->setPosition(0, 0);
 
 	consoleTextInput->Resize(width, 25);
 	consoleTextInput->setPosition(0, height-25);

+ 67 - 22
IDE/Contents/Source/PolycodeIDEApp.cpp

@@ -35,6 +35,8 @@ PolycodeIDEApp::PolycodeIDEApp(PolycodeView *view) : EventDispatcher() {
 	CoreServices::getInstance()->getResourceManager()->addArchive("default.pak");
 	CoreServices::getInstance()->getResourceManager()->addDirResource("default");	
 
+	CoreServices::getInstance()->getResourceManager()->addArchive("api.pak");
+
 	CoreServices::getInstance()->getConfig()->loadConfig("Polycode", RESOURCE_PATH"UIThemes/default/theme.xml");
 	CoreServices::getInstance()->getResourceManager()->addDirResource(RESOURCE_PATH"UIThemes/default/", false);
 	CoreServices::getInstance()->getResourceManager()->addDirResource(RESOURCE_PATH"Images/", false);	
@@ -51,6 +53,8 @@ PolycodeIDEApp::PolycodeIDEApp(PolycodeView *view) : EventDispatcher() {
 	frame = new PolycodeFrame();
 	frame->setPositionMode(ScreenEntity::POSITION_TOPLEFT);
 
+	frame->console->backtraceWindow->addEventListener(this, BackTraceEvent::EVENT_BACKTRACE_SELECTED);
+
 	frame->textInputPopup->addEventListener(this, UIEvent::OK_EVENT);	
 	frame->newProjectWindow->addEventListener(this, UIEvent::OK_EVENT);
 	frame->newFileWindow->addEventListener(this, UIEvent::OK_EVENT);	
@@ -69,7 +73,7 @@ PolycodeIDEApp::PolycodeIDEApp(PolycodeView *view) : EventDispatcher() {
 	frame->Resize(core->getXRes(), core->getYRes());	
 	core->setVideoMode(1000, 700, false, false, 0, 0);
 	
-	debugger = new PolycodeRemoteDebugger();
+	debugger = new PolycodeRemoteDebugger(projectManager);
 	frame->console->setDebugger(debugger);
 	
 	editorManager->registerEditorFactory(new PolycodeImageEditorFactory());
@@ -175,7 +179,68 @@ void PolycodeIDEApp::saveFile() {
 	}
 }
 
+void PolycodeIDEApp::openFileInProject(PolycodeProject *project, String filePath) {
+	OSFileEntry fileEntry = OSFileEntry(project->getRootFolder()+"/"+filePath, OSFileEntry::TYPE_FILE);	
+	OSFILE *file = OSBasics::open(project->getRootFolder()+"/"+filePath,"r");
+	
+	if(file) {
+		OSBasics::close(file);
+		openFile(fileEntry);		
+	} else {
+		fileEntry = OSFileEntry(filePath, OSFileEntry::TYPE_FILE);	
+		file = OSBasics::open(filePath,"r");	
+		if(file) {
+			OSBasics::close(file);
+			openFile(fileEntry);							
+		} else {
+			PolycodeConsole::print("File not available.\n");
+		}
+	}
+
+}
+
+void PolycodeIDEApp::openFile(OSFileEntry file) {
+	PolycodeEditor *editor;
+	editor = editorManager->getEditorForPath(file.fullPath);
+	if(editor) {
+		frame->showEditor(editor);				
+	} else {
+		editor = editorManager->createEditorForExtension(file.extension);
+		if(editor) {
+			if(editor->openFile(file)) {
+				frame->addEditor(editor);					
+				frame->showEditor(editor);
+			} else {
+				delete editor;
+				editor = NULL;
+			}
+		}
+	}
+							
+	if(editor) {
+		editorManager->setCurrentEditor(editor);
+	}
+		
+}
+
 void PolycodeIDEApp::handleEvent(Event *event) {
+
+	if(event->getDispatcher() == frame->console->backtraceWindow) {
+		if(event->getEventType() == "BackTraceEvent" && event->getEventCode() == BackTraceEvent::EVENT_BACKTRACE_SELECTED) {
+			BackTraceEvent *btEvent = (BackTraceEvent*) event;
+			openFileInProject(btEvent->project, btEvent->fileName);
+			
+			PolycodeEditor *editor = editorManager->getCurrentEditor();
+			if(editor) {
+				if(editor->getEditorType() == "PolycodeTextEditor") {
+					PolycodeTextEditor *textEditor = (PolycodeTextEditor*) editor;
+					textEditor->highlightLine(btEvent->lineNumber);
+				}
+				
+			}	
+		}
+	}
+
 	if(event->getDispatcher() == core) {
 		switch(event->getEventCode()) {
 			case Core::EVENT_CORE_RESIZE:
@@ -219,27 +284,7 @@ void PolycodeIDEApp::handleEvent(Event *event) {
 				return;			
 			
 			if(selectedData) {
-			PolycodeEditor *editor;
-			editor = editorManager->getEditorForPath(selectedData->fileEntry.fullPath);
-			if(editor) {
-				frame->showEditor(editor);				
-			} else {
-				editor = editorManager->createEditorForExtension(selectedData->fileEntry.extension);
-				if(editor) {
-					if(editor->openFile(selectedData->fileEntry)) {
-						frame->addEditor(editor);					
-						frame->showEditor(editor);
-					} else {
-						delete editor;
-						editor = NULL;
-					}
-				}
-			}
-				
-				if(editor) {
-					editorManager->setCurrentEditor(editor);
-				}
-				
+				openFile(selectedData->fileEntry);
 			}
 		}
 	}

+ 17 - 5
IDE/Contents/Source/PolycodeRemoteDebugger.cpp

@@ -23,8 +23,10 @@
 #include "PolycodeRemoteDebugger.h"
 
 
-PolycodeRemoteDebugger::PolycodeRemoteDebugger() {
+PolycodeRemoteDebugger::PolycodeRemoteDebugger(PolycodeProjectManager *projectManager) {
 	server = new Server(4630, 1);
+	
+	this->projectManager = projectManager;
 
 	server->addEventListener(this, ServerEvent::EVENT_CLIENT_CONNECTED);
 	server->addEventListener(this, ServerEvent::EVENT_CLIENT_DISCONNECTED);		
@@ -60,12 +62,22 @@ void PolycodeRemoteDebugger::handleEvent(Event *event) {
 						}
 						break;	
 						case EVENT_DEBUG_ERROR:
-						{
-							String printStr = String(clientEvent->data);
-							PolycodeConsole::print(printStr);		
-							PolycodeConsole::print("\n");							
+						{			
+							RemoteErrorData *data = (RemoteErrorData*)clientEvent->data;			
+							PolycodeConsole::print("Error in file "+String(data->fileName)+" on line "+String::IntToString(data->lineNumber)+"\n");
+							PolycodeConsole::print(String(data->errorMessage)+"\n");
+							PolycodeConsole::print("Backtrace:\n");
+						}
+						break;			
+						case EVENT_DEBUG_BACKTRACE_INFO:
+						{			
+							RemoteBacktraceData *data = (RemoteBacktraceData*)clientEvent->data;			
+							PolycodeConsole::print("In file "+String(data->fileName)+" on line "+String::IntToString(data->lineNumber)+"\n");
+							
+							PolycodeConsole::addBacktrace(String(data->fileName), data->lineNumber, projectManager->getActiveProject());
 						}
 						break;							
+										
 					}
 				break;
 			}

+ 10 - 3
IDE/Contents/Source/PolycodeTextEditor.cpp

@@ -38,7 +38,7 @@ PolycodeSyntaxHighlighter::PolycodeSyntaxHighlighter(String extension) {
 	separators = String("[ [ ] { } ; . , : # ( ) \t \n = + - / \\ ' \"").split(" ");
 	separators.push_back(" ");
 	
-	keywords = String("true false class self break do end else elseif function if local nil not or repeat return then until while").split(" ");
+	keywords = String("require true false class self break do end else elseif function if local nil not or repeat return then until while").split(" ");
 }
 
 PolycodeSyntaxHighlighter::~PolycodeSyntaxHighlighter() {
@@ -198,6 +198,7 @@ std::vector<SyntaxHighlightToken> PolycodeSyntaxHighlighter::parseLua(String tex
 }
 
 PolycodeTextEditor::PolycodeTextEditor() : PolycodeEditor(true){
+	editorType = "PolycodeTextEditor";
 }
 
 PolycodeTextEditor::~PolycodeTextEditor() {
@@ -218,14 +219,20 @@ bool PolycodeTextEditor::openFile(OSFileEntry filePath) {
 	}
 	
 	Data *data = new Data();
-	data->loadFromFile(filePath.fullPath);	
-	textInput->setText(data->getAsString(String::ENCODING_UTF8));
+	if(data->loadFromFile(filePath.fullPath)) {
+		textInput->setText(data->getAsString(String::ENCODING_UTF8));
+	}
 	delete data;
 	
 	PolycodeEditor::openFile(filePath);
 	return true;
 }
 
+void PolycodeTextEditor::highlightLine(unsigned int lineNumber) {
+	int lineSize = textInput->getLineText(lineNumber-1).length();
+	textInput->setSelection(lineNumber-1, lineNumber-1, 0, lineSize);
+}
+
 void PolycodeTextEditor::saveFile() {
 	Data *data = new Data();
 	data->setFromString(textInput->getText(), String::ENCODING_UTF8);

+ 2 - 0
Modules/Contents/UI/Include/PolyUITextInput.h

@@ -103,6 +103,8 @@ namespace Polycode {
 			
 			void setNumberOnly(bool val);
 		
+			String getLineText(unsigned int index);
+		
 			String getSelectionText();
 			void insertText(String text);
 			

+ 8 - 0
Modules/Contents/UI/Source/PolyUITextInput.cpp

@@ -696,6 +696,14 @@ void UITextInput::insertText(String text) {
 	restructLines();	
 }
 
+String UITextInput::getLineText(unsigned int index) {
+	if(index < lines.size()) {
+		return lines[index]->getText();
+	} else {
+		return "";
+	}
+}
+
 String UITextInput::getSelectionText() {
 	String totalText = L"";
 	if(selectionTop == selectionBottom) {

+ 26 - 2
Player/Contents/Include/PolycodePlayer.h

@@ -39,6 +39,18 @@ extern "C" {
 
 using namespace Polycode;
 
+typedef struct {
+	unsigned int lineNumber;
+	char errorMessage[256];	
+	char fileName[256];
+	unsigned int backTraceSize;	
+} RemoteErrorData;
+
+typedef struct {
+	unsigned int lineNumber;
+	char fileName[256];
+} RemoteBacktraceData;
+
 class PolycodeRemoteDebuggerClient : public EventDispatcher {
 	public:
 		PolycodeRemoteDebuggerClient();
@@ -51,11 +63,19 @@ class PolycodeRemoteDebuggerClient : public EventDispatcher {
 		static const int EVENT_DEBUG_RESIZE = 34;
 		static const int EVENT_DEBUG_REMOVE = 35;
 		
-		static const int EVENT_INJECT_CODE = 36;		
+		static const int EVENT_INJECT_CODE = 36;
+		
+		static const int EVENT_DEBUG_BACKTRACE_INFO = 37;
 	
 		Client *client;
 };
 
+class BackTraceEntry {
+	public:
+		String fileName;
+		unsigned int lineNumber;
+};
+
 class PolycodeDebugEvent : public Event {
 public:
 	PolycodeDebugEvent();
@@ -63,7 +83,10 @@ public:
 
 	int lineNumber;
 	String errorString;
+	String fileName;
 	
+	std::vector<BackTraceEntry> backTrace;
+		
 	int xRes;
 	int yRes;
 	
@@ -106,6 +129,8 @@ public:
 	
 	Core *core;	
 	
+	String fullPath;
+		
 protected:
 
 	Timer *debuggerTimer;
@@ -116,7 +141,6 @@ protected:
 	
 	bool useDebugger;
 	
-	String fullPath;
 	
 	bool doCodeInject;
 	String injectCodeString;

+ 9 - 1
Player/Contents/Platform/Darwin/MyDocument.h

@@ -36,7 +36,15 @@ public:
 		PolycodeDebugEvent *debugEvent = (PolycodeDebugEvent*)event;		
 		switch(event->getEventCode()) {
 			case PolycodeDebugEvent::EVENT_ERROR:
-				[playerDocument handleDebugError: [NSString stringWithCString:debugEvent->errorString.c_str()] onLine: debugEvent->lineNumber];
+			{
+				String fullError = "Error in file: "+debugEvent->fileName+" on line "+String::IntToString(debugEvent->lineNumber)+"\n"+debugEvent->errorString+"\n\n Backtrace:\n\n";
+			
+				for(int i=0; i < debugEvent->backTrace.size(); i++) {
+					fullError += "In file "+debugEvent->backTrace[i].fileName + " on line " + String::IntToString(debugEvent->backTrace[i].lineNumber)+"\n";
+				}
+			
+				[playerDocument handleDebugError: [NSString stringWithCString:fullError.c_str()] onLine: debugEvent->lineNumber];
+			}
 				break;
 			case PolycodeDebugEvent::EVENT_PRINT:
 				[playerDocument printToConsole: [NSString stringWithCString:debugEvent->errorString.c_str()]];				

+ 1 - 3
Player/Contents/Platform/Darwin/MyDocument.mm

@@ -79,9 +79,7 @@ NSTextStorage *textStorage = [consoleTextView textStorage];
 	[consoleTextView setInsertionPointColor: [NSColor whiteColor]];
 [textStorage beginEditing];
 
-NSMutableString *fullText = [[NSMutableString alloc] initWithString:@"Error:\""];
-[fullText appendString:error];
-[fullText appendFormat:@"\" on line %d.", lineNumber];
+NSMutableString *fullText = [[NSMutableString alloc] initWithString: error];
 NSMutableAttributedString *str = [[NSMutableAttributedString alloc ]initWithString: fullText];
 [fullText release];
 

+ 111 - 32
Player/Contents/Source/PolycodePlayer.cpp

@@ -35,7 +35,21 @@ void PolycodeRemoteDebuggerClient::handleEvent(Event *event) {
 			client->sendReliableDataToServer((char*)debugEvent->errorString.c_str(), debugEvent->errorString.length()+1, EVENT_DEBUG_PRINT);
 		break;
 		case PolycodeDebugEvent::EVENT_ERROR:
-			client->sendReliableDataToServer((char*)debugEvent->errorString.c_str(), debugEvent->errorString.length()+1, EVENT_DEBUG_ERROR);
+			RemoteErrorData data;
+			strcpy(data.errorMessage, debugEvent->errorString.c_str());
+			strcpy(data.fileName, debugEvent->fileName.c_str());
+			data.lineNumber = debugEvent->lineNumber;
+			data.backTraceSize = debugEvent->backTrace.size();
+			
+			client->sendReliableDataToServer((char*)&data, sizeof(data), EVENT_DEBUG_ERROR);
+			
+			for(int i=0; i < debugEvent->backTrace.size(); i++) {
+				RemoteBacktraceData btData;
+				strcpy(btData.fileName, debugEvent->backTrace[i].fileName.c_str());
+				btData.lineNumber = debugEvent->backTrace[i].lineNumber;
+				
+				client->sendReliableDataToServer((char*)&btData, sizeof(btData), EVENT_DEBUG_BACKTRACE_INFO);				
+			}
 		break;		
 	}
 }
@@ -46,6 +60,35 @@ PolycodeRemoteDebuggerClient::~PolycodeRemoteDebuggerClient() {
 }
 
 extern "C" {	
+
+	
+static void dumpstack (lua_State *L) {
+  int i;
+  int top=lua_gettop(L);
+  printf("dumpstack -- \n");
+  for (i=1; i<=top; i++) {
+    printf("%d\t%s\t",i,luaL_typename(L,i));
+    switch (lua_type(L, i)) {
+      case LUA_TNUMBER:
+        printf("%g\n",lua_tonumber(L,i));
+        break;
+      case LUA_TSTRING:
+        printf("%s\n",lua_tostring(L,i));
+        break;
+      case LUA_TBOOLEAN:
+        printf("%s\n", (lua_toboolean(L, i) ? "true" : "false"));
+        break;
+      case LUA_TNIL:
+        printf("%s\n", "nil");
+        break;
+      default:
+        printf("%p\n",lua_topointer(L,i));
+        break;
+    }
+  }
+  printf("dumpstack -- END\n");
+}	
+
 //	extern int luaopen_Tau(lua_State* L); // declare the wrapped module
 		//	loadFileIntoState(L, "Polycode Player.app/Contents/Resources/API/class.lua");
 	
@@ -85,22 +128,55 @@ extern "C" {
 	}
 
 	static int customError(lua_State *L) {
-		const char *msg = lua_tostring(L, 1);
 		
+		PolycodePlayer *player = (PolycodePlayer*)CoreServices::getInstance()->getCore()->getUserPointer();		
+		
+		std::vector<BackTraceEntry> backTrace;
+		lua_Debug entry;
+		int depth = 0;		
+		while (lua_getstack(L, depth, &entry)) {
+			int status = lua_getinfo(L, "Sln", &entry);
+			printf(">>>> %s(%d): %s\n", entry.short_src, entry.currentline, entry.name ? entry.name : "?");
+			std::vector<String> bits = String(entry.short_src).split("\"");
+			if(bits.size() > 1) {
+				String fileName = bits[1];
+				if(fileName != "class.lua") {
+					
+					BackTraceEntry trace;
+					trace.lineNumber = entry.currentline;
+					trace.fileName = fileName;
+					backTrace.push_back(trace);
+					
+					//backTrace += "In file: " + fileName + " on line " + String::IntToString(entry.currentline)+"\n";
+				}
+			}
+			depth++;
+		}
+		
+		if(backTrace.size() < 1)
+			return 0;
+			
+		backTrace[backTrace.size()-1].fileName = player->fullPath;
+
+		const char *msg = lua_tostring(L, -1);		
 		if (msg == NULL) msg = "(error with no message)";
 		lua_pop(L, 1);
-			
+		
+		String errorString;
 		std::vector<String> info = String(msg).split(":");
 			
-		PolycodeDebugEvent *event = new PolycodeDebugEvent();			
 		if(info.size() > 2) {
-			event->errorString = info[2];
-			event->lineNumber = atoi(info[1].c_str());
+			errorString = info[2];
 		} else {
-			event->errorString = std::string(msg);
-			event->lineNumber = 0;
+			errorString = msg;
 		}
-		PolycodePlayer *player = (PolycodePlayer*)CoreServices::getInstance()->getCore()->getUserPointer();		
+						
+		PolycodeDebugEvent *event = new PolycodeDebugEvent();			
+		event->errorString = errorString;
+		event->backTrace = backTrace;		
+		event->fileName = backTrace[0].fileName;
+		event->lineNumber = backTrace[0].lineNumber;
+
 		player->dispatchEvent(event, PolycodeDebugEvent::EVENT_ERROR);
 				
 		return 0;
@@ -121,11 +197,23 @@ extern "C" {
 		return 0;
 	}	
 	
+	
 	int PolycodePlayer::report (lua_State *L, int status) {
-		const char *msg;
+		const char *msg;			
 			
 		Logger::log("Error status: %d\n", status);
-		if (status) {
+		if (status) {		
+		
+//			dumpstack(L);
+//	traceback(L);
+
+/*		
+			lua_Debug ar;
+			if(lua_getstack(L, 1, &ar)) {
+				lua_getinfo(L, "Sl", &ar);
+				printf("NEW SHIT: source: %s, line: %d\n", ar.source, ar.currentline);
+			}
+*/		
 			msg = lua_tostring(L, -1);
 			if (msg == NULL) msg = "(error with no message)";
 			Logger::log("status=%d, %s\n", status, msg);
@@ -161,6 +249,8 @@ extern "C" {
 		 */
 		luaL_openlibs(L);
 		
+		luaopen_debug(L);
+		
 		luaopen_Polycode(L);
 		//luaopen_Tau(L);	// load the wrappered module
 		
@@ -265,41 +355,30 @@ extern "C" {
 			Logger::log("Error opening entrypoint file (%s)\n", fileName.c_str());
 		}
 		
-		
-		String postpend = ""; //" \nif update == nil then\nfunction update(e)\nend\nend\nwhile CORE:Update() do\nupdate(CORE:getElapsed())\nend";
-		
-		//String fullScript = prepend + prepend2 + prepend3 + fileData;// + postpend;
+				
 		String fullScript = fileData;
-		//String fullScript = fileData;// + postpend;
 		
 		doneLoading = true;
 		
 		//lua_gc(L, LUA_GCSTOP, 0);
 		
 		
-/*
-		lua_pushliteral(L, "debug");
-		lua_gettable(L, LUA_GLOBALSINDEX);
-		lua_pushliteral(L, "traceback");  // correct fn name?
-		lua_gettable(L, -2);
 
-*/				
+		lua_getfield (L, LUA_GLOBALSINDEX, "__customError");
+		int errH = lua_gettop(L);
+
 		//CoreServices::getInstance()->getCore()->lockMutex(CoreServices::getRenderMutex());			
-		if (report(L, luaL_loadstring(L, fullScript.c_str()) || lua_pcall(L, 0,0,0))) {
-			
+		if (report(L, luaL_loadstring(L, fullScript.c_str()))) {			
 			//CoreServices::getInstance()->getCore()->unlockMutex(CoreServices::getRenderMutex());			
 			Logger::log("CRASH LOADING SCRIPT FILE\n");
 //			exit(1);				
-		} else  {
-		//	CoreServices::getInstance()->getCore()->unlockMutex(CoreServices::getRenderMutex());			
-			if (report(L, luaL_loadstring(L, postpend.c_str()) || lua_pcall(L, 0,0,0))) {	
-//				exit(1);
-				Logger::log("CRASH IN SCRIPT EXECUTION FILE\n");			
-			} else  {
-
+		} else {
+		
+		
+			if (lua_pcall(L, 0,0,errH)) {
+				Logger::log("CRASH EXECUTING FILE\n");
 			}
 		}
-
 	}
 }