diff options
Diffstat (limited to 'languages/lib/debugger')
-rw-r--r-- | languages/lib/debugger/Mainpage.dox | 36 | ||||
-rw-r--r-- | languages/lib/debugger/Makefile.am | 13 | ||||
-rw-r--r-- | languages/lib/debugger/debugger.cpp | 209 | ||||
-rw-r--r-- | languages/lib/debugger/debugger.h | 132 | ||||
-rw-r--r-- | languages/lib/debugger/kdevdebugger.cpp | 182 | ||||
-rw-r--r-- | languages/lib/debugger/kdevdebugger.h | 88 |
6 files changed, 660 insertions, 0 deletions
diff --git a/languages/lib/debugger/Mainpage.dox b/languages/lib/debugger/Mainpage.dox new file mode 100644 index 00000000..2e141fd3 --- /dev/null +++ b/languages/lib/debugger/Mainpage.dox @@ -0,0 +1,36 @@ +/** +@mainpage The KDevelop %Debugger Support Library + +This library contains classes to implement debugger support for a programming language. + +<b>Link with</b>: -llang_debugger + +<b>Include path</b>: -I\$(kde_includes)/kdevelop/languages/debugger + +\section usingdebugger Where to use this library + +Each debugger support plugin must interact with an editor to set breakpoints, +jump to execution points, etc. This kind of interaction is implemented in +@ref Debugger class. Your debugger support plugin just need to create +an instance of @ref Debugger class and connect its signals, for example: +@code +m_debugger = new Debugger( partController() ); + +connect( m_debugger, SIGNAL(toggledBreakpoint(const QString &, int)), + debuggerBreakpointWidget, SLOT(slotToggleBreakpoint(const QString &, int)) ); +connect( m_debugger, SIGNAL(editedBreakpoint(const QString &, int)), + debuggerBreakpointWidget, SLOT(slotEditBreakpoint(const QString &, int)) ); +connect( m_debugger, SIGNAL(toggledBreakpointEnabled(const QString &, int)), + debuggerBreakpointWidget, SLOT(slotToggleBreakpointEnabled(const QString &, int)) ); +@endcode +Then m_debugger instance can be used for example, to jump to the execution point: +@code +m_debugger->gotoExecutionPoint(fileUrl, lineNumber); +@endcode +or to set a breakpoint: +@code +m_debugger->setBreakpoint(fileName, lineNumber, id, enabled, pending); +@endcode + +*/ + diff --git a/languages/lib/debugger/Makefile.am b/languages/lib/debugger/Makefile.am new file mode 100644 index 00000000..cdeee852 --- /dev/null +++ b/languages/lib/debugger/Makefile.am @@ -0,0 +1,13 @@ +INCLUDES = -I$(top_srcdir)/lib/interfaces $(all_includes) +METASOURCES = AUTO +lib_LTLIBRARIES = liblang_debugger.la +liblang_debugger_la_LDFLAGS = $(all_libraries) +liblang_debugger_la_LIBADD = $(LIB_QT) $(LIB_KDECORE) $(LIB_KPARTS) -lktexteditor +liblang_debugger_la_SOURCES = kdevdebugger.cpp debugger.cpp +langincludedirdir = $(includedir)/kdevelop/languages/debugger +langincludedir_HEADERS = debugger.h kdevdebugger.h + +DOXYGEN_REFERENCES = dcop interfaces kdecore kdefx kdeui khtml kmdi kio kjs kparts kutils kdevinterfaces kdevutil +DOXYGEN_PROJECTNAME = KDevelop Debugger Support Library +DOXYGEN_DOCDIRPREFIX = kdevlang +include ../../../Doxyfile.am diff --git a/languages/lib/debugger/debugger.cpp b/languages/lib/debugger/debugger.cpp new file mode 100644 index 00000000..92765efe --- /dev/null +++ b/languages/lib/debugger/debugger.cpp @@ -0,0 +1,209 @@ + +#include "debugger.h" + +#include <kdebug.h> +#include <klocale.h> +#include <ktexteditor/document.h> + +// #include "editorproxy.h" +#include <kdevpartcontroller.h> + + +using namespace KTextEditor; + +Debugger *Debugger::s_instance = 0; + +Debugger::Debugger(KDevPartController *partController) + :m_partController(partController) +{ + connect( m_partController, SIGNAL(partAdded(KParts::Part*)), + this, SLOT(partAdded(KParts::Part*)) ); +} + + +Debugger::~Debugger() +{} + + +// Debugger *Debugger::getInstance() +// { +// if (!s_instance) +// s_instance = new Debugger; +// +// return s_instance; +// } + + +void Debugger::setBreakpoint(const QString &fileName, int lineNum, int id, bool enabled, bool pending) +{ + KParts::Part *part = m_partController->partForURL(KURL(fileName)); + if( !part ) + return; + + MarkInterface *iface = dynamic_cast<MarkInterface*>(part); + if (!iface) + return; + + // Temporarily disconnect so we don't get confused by receiving extra + // marksChanged signals + disconnect( part, SIGNAL(marksChanged()), this, SLOT(marksChanged()) ); + iface->removeMark( lineNum, Breakpoint | ActiveBreakpoint | ReachedBreakpoint | DisabledBreakpoint ); + + BPItem bpItem(fileName, lineNum); + QValueList<BPItem>::Iterator it = BPList.find(bpItem); + if (it != BPList.end()) + { +// kdDebug(9012) << "Removing BP=" << fileName << ":" << lineNum << endl; + BPList.remove(it); + } + + // An id of -1 means this breakpoint should be hidden from the user. + // I believe this functionality is not used presently. + if( id != -1 ) + { + uint markType = Breakpoint; + if( !pending ) + markType |= ActiveBreakpoint; + if( !enabled ) + markType |= DisabledBreakpoint; + iface->addMark( lineNum, markType ); +// kdDebug(9012) << "Appending BP=" << fileName << ":" << lineNum << endl; + BPList.append(BPItem(fileName, lineNum)); + } + + connect( part, SIGNAL(marksChanged()), this, SLOT(marksChanged()) ); +} + + +void Debugger::clearExecutionPoint() +{ + QPtrListIterator<KParts::Part> it(*m_partController->parts()); + for ( ; it.current(); ++it) + { + MarkInterface *iface = dynamic_cast<MarkInterface*>(it.current()); + if (!iface) + continue; + + QPtrList<Mark> list = iface->marks(); + QPtrListIterator<Mark> markIt(list); + for( ; markIt.current(); ++markIt ) + { + Mark* mark = markIt.current(); + if( mark->type & ExecutionPoint ) + iface->removeMark( mark->line, ExecutionPoint ); + } + } +} + + +void Debugger::gotoExecutionPoint(const KURL &url, int lineNum) +{ + clearExecutionPoint(); + + m_partController->editDocument(url, lineNum); + + KParts::Part *part = m_partController->partForURL(url); + if( !part ) + return; + MarkInterface *iface = dynamic_cast<MarkInterface*>(part); + if( !iface ) + return; + + iface->addMark( lineNum, ExecutionPoint ); +} + +void Debugger::marksChanged() +{ + if(sender()->inherits("KTextEditor::Document") ) + { + KTextEditor::Document* doc = (KTextEditor::Document*) sender(); + MarkInterface* iface = KTextEditor::markInterface( doc ); + + if (iface) + { + if( !m_partController->partForURL( doc->url() ) ) + return; // Probably means the document is being closed. + + KTextEditor::Mark *m; + QValueList<BPItem> oldBPList = BPList; + QPtrList<KTextEditor::Mark> newMarks = iface->marks(); + + // Compare the oldBPlist to the new list from the editor. + // + // If we don't have some of the old breakpoints in the new list + // then they have been moved by the user adding or removing source + // code. Remove these old breakpoints + // + // If we _can_ find these old breakpoints in the newlist then + // nothing has happened to them. We can just ignore these and to + // do that we must remove them from the new list. + + bool bpchanged = false; + + for (uint i = 0; i < oldBPList.count(); i++) + { + if (oldBPList[i].fileName() != doc->url().path()) + continue; + + bool found=false; + for (uint newIdx=0; newIdx < newMarks.count(); newIdx++) + { + m = newMarks.at(newIdx); + if ((m->type & Breakpoint) && + m->line == oldBPList[i].lineNum() && + doc->url().path() == oldBPList[i].fileName()) + { + newMarks.remove(newIdx); + found=true; + break; + } + } + + if (!found) + { + emit toggledBreakpoint( doc->url().path(), oldBPList[i].lineNum() ); + bpchanged = true; + } + } + + // Any breakpoints left in the new list are the _new_ position of + // the moved breakpoints. So add these as new breakpoints via + // toggling them. + for (uint i = 0; i < newMarks.count(); i++) + { + m = newMarks.at(i); + if (m->type & Breakpoint) + { + emit toggledBreakpoint( doc->url().path(), m->line ); + bpchanged = true; + } + } + + if ( bpchanged && m_partController->activePart() == doc ) + { + //bring focus back to the editor + m_partController->activatePart( doc ); + } + } + } +} + + +void Debugger::partAdded( KParts::Part* part ) +{ + MarkInterfaceExtension *iface = dynamic_cast<MarkInterfaceExtension*>(part); + if( !iface ) + return; + + iface->setDescription((MarkInterface::MarkTypes)Breakpoint, i18n("Breakpoint")); + iface->setPixmap((MarkInterface::MarkTypes)Breakpoint, *inactiveBreakpointPixmap()); + iface->setPixmap((MarkInterface::MarkTypes)ActiveBreakpoint, *activeBreakpointPixmap()); + iface->setPixmap((MarkInterface::MarkTypes)ReachedBreakpoint, *reachedBreakpointPixmap()); + iface->setPixmap((MarkInterface::MarkTypes)DisabledBreakpoint, *disabledBreakpointPixmap()); + iface->setPixmap((MarkInterface::MarkTypes)ExecutionPoint, *executionPointPixmap()); + iface->setMarksUserChangable( Bookmark | Breakpoint ); + + connect( part, SIGNAL(marksChanged()), this, SLOT(marksChanged()) ); +} + +#include "debugger.moc" diff --git a/languages/lib/debugger/debugger.h b/languages/lib/debugger/debugger.h new file mode 100644 index 00000000..ed545f28 --- /dev/null +++ b/languages/lib/debugger/debugger.h @@ -0,0 +1,132 @@ +#ifndef __DEBUGGER_H__ +#define __DEBUGGER_H__ + +#include <qvaluelist.h> + +#include "kdevdebugger.h" + +#include <kparts/part.h> +#include <ktexteditor/markinterface.h> + +#include <kdeversion.h> +#include <ktexteditor/markinterfaceextension.h> + +class KDevPartController; + +/** +* Describes a single breakpoint in the system +* +* This is used so that we can track the breakpoints and move them appropriately +* as the user adds or removes lines of code before breakpoints. +*/ + +class BPItem +{ +public: + /** + * default ctor - required from QValueList + */ + BPItem() : m_fileName(""), m_lineNum(0) + {} + + BPItem( const QString& fileName, const uint lineNum) + : m_fileName(fileName), + m_lineNum(lineNum) + {} + + uint lineNum() const { return m_lineNum; } + QString fileName() const { return m_fileName; } + + bool operator==( const BPItem& rhs ) const + { + return (m_fileName == rhs.m_fileName + && m_lineNum == rhs.m_lineNum); + } + +private: + QString m_fileName; + uint m_lineNum; +}; + + +/** +* Handles signals from the editor that relate to breakpoints and the execution +* point of the debugger. +* We may change, add or remove breakpoints in this class. +*/ +class Debugger : public KDevDebugger +{ + Q_OBJECT + +public: + + /** + */ +// static Debugger *getInstance(); + + /** + * Controls the breakpoint icon being displayed in the editor through the + * markinterface + * + * @param fileName The breakpoint is added or removed from this file + * @param lineNum ... at this line number + * @param id This is an internal id. which has a special number + * that prevents us changing the mark icon. (why?) + * @param enabled The breakpoint could be enabled, disabled + * @param pending pending or active. Each state has a different icon. + */ + void setBreakpoint(const QString &fileName, int lineNum, + int id, bool enabled, bool pending); + + /** + * Displays an icon in the file at the line that the debugger has stoped + * at. + * @param url The file the debugger has stopped at. + * @param lineNum The line number to display. Note: We may not know it. + */ + void gotoExecutionPoint(const KURL &url, int lineNum=-1); + + /** + * Remove the executution point being displayed. + */ + void clearExecutionPoint(); + +// protected: + + Debugger(KDevPartController *partController); + ~Debugger(); + +private slots: + + /** + * Whenever a new part is added this slot gets triggered and we then + * look for a MarkInterfaceExtension part. When it is a + * MarkInterfaceExtension part we set the various pixmaps of the + * breakpoint icons. + */ + void partAdded( KParts::Part* part ); + + /** + * Called by the TextEditor interface when the marks have changed position + * because the user has added or removed source. + * In here we figure out if we need to reset the breakpoints due to + * these source changes. + */ + void marksChanged(); + +private: + enum MarkType { + Bookmark = KTextEditor::MarkInterface::markType01, + Breakpoint = KTextEditor::MarkInterface::markType02, + ActiveBreakpoint = KTextEditor::MarkInterface::markType03, + ReachedBreakpoint = KTextEditor::MarkInterface::markType04, + DisabledBreakpoint = KTextEditor::MarkInterface::markType05, + ExecutionPoint = KTextEditor::MarkInterface::markType06 + }; + + static Debugger *s_instance; + KDevPartController *m_partController; + QValueList<BPItem> BPList; +}; + +#endif diff --git a/languages/lib/debugger/kdevdebugger.cpp b/languages/lib/debugger/kdevdebugger.cpp new file mode 100644 index 00000000..01b4d4f7 --- /dev/null +++ b/languages/lib/debugger/kdevdebugger.cpp @@ -0,0 +1,182 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Matthias Hoelzer-Kluepfel <hoelzer@kde.org> + Copyright (C) 2002 John Firebaugh <jfirebaugh@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +#include "kdevdebugger.h" + +KDevDebugger::KDevDebugger(QObject *parent, const char *name) + : QObject(parent, name) +{ +} + + +KDevDebugger::~KDevDebugger() +{ +} + +const QPixmap* KDevDebugger::inactiveBreakpointPixmap() +{ + const char*breakpoint_gr_xpm[]={ + "11 16 6 1", + "c c #c6c6c6", + "d c #2c2c2c", + "# c #000000", + ". c None", + "a c #ffffff", + "b c #555555", + "...........", + "...........", + "...#####...", + "..#aaaaa#..", + ".#abbbbbb#.", + "#abbbbbbbb#", + "#abcacacbd#", + "#abbbbbbbb#", + "#abcacacbd#", + "#abbbbbbbb#", + ".#bbbbbbb#.", + "..#bdbdb#..", + "...#####...", + "...........", + "...........", + "..........."}; + static QPixmap pixmap( breakpoint_gr_xpm ); + return &pixmap; +} + +const QPixmap* KDevDebugger::activeBreakpointPixmap() +{ + const char* breakpoint_xpm[]={ + "11 16 6 1", + "c c #c6c6c6", + ". c None", + "# c #000000", + "d c #840000", + "a c #ffffff", + "b c #ff0000", + "...........", + "...........", + "...#####...", + "..#aaaaa#..", + ".#abbbbbb#.", + "#abbbbbbbb#", + "#abcacacbd#", + "#abbbbbbbb#", + "#abcacacbd#", + "#abbbbbbbb#", + ".#bbbbbbb#.", + "..#bdbdb#..", + "...#####...", + "...........", + "...........", + "..........."}; + static QPixmap pixmap( breakpoint_xpm ); + return &pixmap; +} + +const QPixmap* KDevDebugger::reachedBreakpointPixmap() +{ + const char*breakpoint_bl_xpm[]={ + "11 16 7 1", + "a c #c0c0ff", + "# c #000000", + "c c #0000c0", + "e c #0000ff", + "b c #dcdcdc", + "d c #ffffff", + ". c None", + "...........", + "...........", + "...#####...", + "..#ababa#..", + ".#bcccccc#.", + "#acccccccc#", + "#bcadadace#", + "#acccccccc#", + "#bcadadace#", + "#acccccccc#", + ".#ccccccc#.", + "..#cecec#..", + "...#####...", + "...........", + "...........", + "..........."}; + static QPixmap pixmap( breakpoint_bl_xpm ); + return &pixmap; +} + +const QPixmap* KDevDebugger::disabledBreakpointPixmap() +{ + const char*breakpoint_wh_xpm[]={ + "11 16 7 1", + "a c #c0c0ff", + "# c #000000", + "c c #0000c0", + "e c #0000ff", + "b c #dcdcdc", + "d c #ffffff", + ". c None", + "...........", + "...........", + "...#####...", + "..#ddddd#..", + ".#ddddddd#.", + "#ddddddddd#", + "#ddddddddd#", + "#ddddddddd#", + "#ddddddddd#", + "#ddddddddd#", + ".#ddddddd#.", + "..#ddddd#..", + "...#####...", + "...........", + "...........", + "..........."}; + static QPixmap pixmap( breakpoint_wh_xpm ); + return &pixmap; +} + +const QPixmap* KDevDebugger::executionPointPixmap() +{ + const char*exec_xpm[]={ + "11 16 4 1", + "a c #00ff00", + "b c #000000", + ". c None", + "# c #00c000", + "...........", + "...........", + "...........", + "#a.........", + "#aaa.......", + "#aaaaa.....", + "#aaaaaaa...", + "#aaaaaaaaa.", + "#aaaaaaa#b.", + "#aaaaa#b...", + "#aaa#b.....", + "#a#b.......", + "#b.........", + "...........", + "...........", + "..........."}; + static QPixmap pixmap( exec_xpm ); + return &pixmap; +} + +#include "kdevdebugger.moc" diff --git a/languages/lib/debugger/kdevdebugger.h b/languages/lib/debugger/kdevdebugger.h new file mode 100644 index 00000000..24bd2c7b --- /dev/null +++ b/languages/lib/debugger/kdevdebugger.h @@ -0,0 +1,88 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Matthias Hoelzer-Kluepfel <hoelzer@kde.org> + Copyright (C) 2002 John Firebaugh <jfirebaugh@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +#ifndef _KDEVDEBUGGER_H_ +#define _KDEVDEBUGGER_H_ + + +#include <qobject.h> +#include <qpixmap.h> + + +#include <kurl.h> + +/** +* Base class to handle signals from the editor that relate to breakpoints +* and the execution point of the debugger. +*/ +class KDevDebugger : public QObject +{ + Q_OBJECT + +public: + + KDevDebugger(QObject *parent=0, const char *name=0); + ~KDevDebugger(); + + /** + * Sets a breakpoint in the editor document belong to fileName. + * If id==-1, the breakpoint is deleted. + */ + virtual void setBreakpoint(const QString &fileName, int lineNum, + int id, bool enabled, bool pending) = 0; + + /** + * Goes to a given location in a source file and marks the line. + * This is used by the debugger to mark the location where the + * the debugger has stopped. + */ + virtual void gotoExecutionPoint(const KURL &url, int lineNum=0) = 0; + + /** + * Clear the execution point. Usefull if debugging has ended. + */ + virtual void clearExecutionPoint() = 0; + + static const QPixmap* inactiveBreakpointPixmap(); + static const QPixmap* activeBreakpointPixmap(); + static const QPixmap* reachedBreakpointPixmap(); + static const QPixmap* disabledBreakpointPixmap(); + static const QPixmap* executionPointPixmap(); + +signals: + + /** + * The user has toggled a breakpoint. + */ + void toggledBreakpoint(const QString &fileName, int lineNum); + + /* + * The user wants to edit the properties of a breakpoint. + */ + void editedBreakpoint(const QString &fileName, int lineNum); + + /** + * The user wants to enable/disable a breakpoint. + */ + void toggledBreakpointEnabled(const QString &fileName, int lineNum); + +}; + + +#endif |