summaryrefslogtreecommitdiffstats
path: root/languages/lib/debugger
diff options
context:
space:
mode:
Diffstat (limited to 'languages/lib/debugger')
-rw-r--r--languages/lib/debugger/Mainpage.dox36
-rw-r--r--languages/lib/debugger/Makefile.am13
-rw-r--r--languages/lib/debugger/debugger.cpp209
-rw-r--r--languages/lib/debugger/debugger.h132
-rw-r--r--languages/lib/debugger/kdevdebugger.cpp182
-rw-r--r--languages/lib/debugger/kdevdebugger.h88
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